#include "priv_netlink.h"
#include "driver_wext.h"
#include "ieee802_11_defs.h"
+#include "wpa_common.h"
#ifdef CONFIG_CLIENT_MLME
#include <netpacket/packet.h>
#endif /* CONFIG_CLIENT_MLME */
-struct wpa_driver_wext_data {
- void *ctx;
- int event_sock;
- int ioctl_sock;
- int mlme_sock;
- char ifname[IFNAMSIZ + 1];
- int ifindex;
- int ifindex2;
- u8 *assoc_req_ies;
- size_t assoc_req_ies_len;
- u8 *assoc_resp_ies;
- size_t assoc_resp_ies_len;
- struct wpa_driver_capa capa;
- int has_capability;
- int we_version_compiled;
-
- /* for set_auth_alg fallback */
- int use_crypt;
- int auth_alg_fallback;
-
- int operstate;
-
- char mlmedev[IFNAMSIZ + 1];
-
- int scan_complete_events;
-};
static int wpa_driver_wext_flush_pmkid(void *priv);
}
-static int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
- int idx, u32 value)
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value)
{
struct iwreq iwr;
int ret = 0;
iwr.u.param.value = value;
if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
- perror("ioctl[SIOCSIWAUTH]");
- fprintf(stderr, "WEXT auth param %d value 0x%x - ",
- idx, value);
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
ret = errno == EOPNOTSUPP ? -2 : -1;
}
wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
MACSTR,
MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
- if (os_memcmp(iwe->u.ap_addr.sa_data,
- "\x00\x00\x00\x00\x00\x00", ETH_ALEN) ==
- 0 ||
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
os_memcmp(iwe->u.ap_addr.sa_data,
"\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
0) {
(ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
(ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
- (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT" : "");
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
/*
* Some drivers send the association event before the operup event--in
* this case, lifting operstate in wpa_driver_wext_set_operstate()
/*
* Some drivers do not report frequency, but a channel.
* Try to map this to frequency by assuming they are using
- * IEEE 802.11b/g.
+ * IEEE 802.11b/g. But don't overwrite a previously parsed
+ * frequency if the driver sends both frequency and channel,
+ * since the driver may be sending an A-band channel that we
+ * don't handle here.
*/
+
+ if (res->res.freq)
+ return;
+
if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
res->res.freq = 2407 + 5 * iwe->u.freq.m;
return;
clen -= sizeof(struct iw_param);
custom += sizeof(struct iw_param);
}
- res->maxrate = maxrate;
+
+ /* Convert the maxrate from WE-style (b/s units) to
+ * 802.11 rates (500000 b/s units).
+ */
+ res->maxrate = maxrate / 500000;
}
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
- wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x",
- drv->capa.key_mgmt, drv->capa.enc);
+ if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
+ "flags 0x%x",
+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
} else {
wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
"assuming WPA is not supported");
}
+static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
+ const u8 *psk)
+{
+ struct iw_encode_ext *ext;
+ struct iwreq iwr;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ return 0;
+
+ if (!psk)
+ return 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ ext = os_zalloc(sizeof(*ext) + PMK_LEN);
+ if (ext == NULL)
+ return -1;
+
+ iwr.u.encoding.pointer = (caddr_t) ext;
+ iwr.u.encoding.length = sizeof(*ext) + PMK_LEN;
+ ext->key_len = PMK_LEN;
+ os_memcpy(&ext->key, psk, ext->key_len);
+ ext->alg = IW_ENCODE_ALG_PMK;
+
+ ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
+ if (ret < 0)
+ perror("ioctl[SIOCSIWENCODEEXT] PMK");
+ os_free(ext);
+
+ return ret;
+}
+
+
static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg,
const u8 *addr, int key_idx,
int set_tx, const u8 *seq,
case WPA_ALG_CCMP:
ext->alg = IW_ENCODE_ALG_CCMP;
break;
+ case WPA_ALG_PMK:
+ ext->alg = IW_ENCODE_ALG_PMK;
+ break;
+#ifdef WEXT_MFP_PENDING
+#ifdef CONFIG_IEEE80211W
+ case WPA_ALG_IGTK:
+ ext->alg = IW_ENCODE_ALG_AES_CMAC;
+ break;
+#endif /* CONFIG_IEEE80211W */
+#endif /* WEXT_MFP_PENDING */
default:
wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
__FUNCTION__, alg);
}
-static int wpa_driver_wext_cipher2wext(int cipher)
+int wpa_driver_wext_cipher2wext(int cipher)
{
switch (cipher) {
case CIPHER_NONE:
}
-static int wpa_driver_wext_keymgmt2wext(int keymgmt)
+int wpa_driver_wext_keymgmt2wext(int keymgmt)
{
switch (keymgmt) {
case KEY_MGMT_802_1X:
}
-static int
-wpa_driver_wext_associate(void *priv,
- struct wpa_driver_associate_params *params)
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params)
{
struct wpa_driver_wext_data *drv = priv;
int ret = 0;
allow_unencrypted_eapol = 0;
else
allow_unencrypted_eapol = 1;
-
+
+ if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
+ ret = -1;
if (wpa_driver_wext_set_auth_param(drv,
IW_AUTH_RX_UNENCRYPTED_EAPOL,
allow_unencrypted_eapol) < 0)
ret = -1;
+#ifdef WEXT_MFP_PENDING
+#ifdef CONFIG_IEEE80211W
+ switch (params->mgmt_frame_protection) {
+ case NO_MGMT_FRAME_PROTECTION:
+ value = IW_AUTH_MFP_DISABLED;
+ break;
+ case MGMT_FRAME_PROTECTION_OPTIONAL:
+ value = IW_AUTH_MFP_OPTIONAL;
+ break;
+ case MGMT_FRAME_PROTECTION_REQUIRED:
+ value = IW_AUTH_MFP_REQUIRED;
+ break;
+ };
+ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
+ ret = -1;
+#endif /* CONFIG_IEEE80211W */
+#endif /* WEXT_MFP_PENDING */
if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
ret = -1;
if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
- int ret = 0;
+ int ret = -1, flags;
+ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
+ ret = 0;
+ goto done;
+ }
- if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+ if (errno != EBUSY) {
perror("ioctl[SIOCSIWMODE]");
- ret = -1;
+ goto done;
+ }
+
+ /* mac80211 doesn't allow mode changes while the device is up, so if
+ * the device isn't in the mode we're about to change to, take device
+ * down, try to set the mode again, and bring it back up.
+ */
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWMODE]");
+ goto done;
+ }
+
+ if (iwr.u.mode == new_mode) {
+ ret = 0;
+ goto done;
+ }
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
+ (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+
+ /* Try to set the mode again while the interface is down */
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
+ perror("ioctl[SIOCSIWMODE]");
+ else
+ ret = 0;
+
+ /* Ignore return value of get_ifflags to ensure that the device
+ * is always up like it was before this function was called.
+ */
+ (void) wpa_driver_wext_get_ifflags(drv, &flags);
+ (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
}
+done:
return ret;
}
}
-static int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
{
struct wpa_driver_wext_data *drv = priv;
if (!drv->has_capability)