From 0c80427d773faae883414d132e6f8196b9f4f904 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 4 Sep 2010 13:56:12 +0300 Subject: [PATCH] NDIS: Fix association for WPS provisioning with protected AP Some NDIS drivers require a workaround to allow them to associate with a WPS AP that is already using protection (Privacy field = 1). Let driver_ndis.c know if the AP is already using Privacy and if so, configure a dummy WEP key to force the driver to associate. --- src/drivers/driver.h | 16 ++++++++++++++++ src/drivers/driver_ndis.c | 31 ++++++++++++++++++++++++++++++- wpa_supplicant/wpa_supplicant.c | 6 +++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 3c3bf9c9f..4e40a3839 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -281,6 +281,13 @@ struct wpa_driver_auth_params { int local_state_change; }; +enum wps_mode { + WPS_MODE_NONE /* no WPS provisioning being used */, + WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */, + WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection + */ +}; + /** * struct wpa_driver_associate_params - Association parameters * Data for struct wpa_driver_ops::associate(). @@ -460,6 +467,15 @@ struct wpa_driver_associate_params { * association. */ const u8 *prev_bssid; + + /** + * wps - WPS mode + * + * If the driver needs to do special configuration for WPS association, + * this variable provides more information on what type of association + * is being requested. Most drivers should not need ot use this. + */ + enum wps_mode wps; }; /** diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 462dd81f5..6ce4200a4 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -1066,6 +1066,7 @@ wpa_driver_ndis_associate(void *priv, { struct wpa_driver_ndis_data *drv = priv; u32 auth_mode, encr, priv_mode, mode; + u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; drv->mode = params->mode; @@ -1091,7 +1092,6 @@ wpa_driver_ndis_associate(void *priv, if (params->key_mgmt_suite == KEY_MGMT_NONE || params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) { /* Re-set WEP keys if static WEP configuration is used. */ - u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int i; for (i = 0; i < 4; i++) { if (!params->wep_key[i]) @@ -1125,6 +1125,22 @@ wpa_driver_ndis_associate(void *priv, } else if (params->key_mgmt_suite == KEY_MGMT_WPS) { auth_mode = Ndis802_11AuthModeOpen; priv_mode = Ndis802_11PrivFilterAcceptAll; + if (params->wps == WPS_MODE_PRIVACY) { + u8 dummy_key[5] = { 0x11, 0x22, 0x33, 0x44, 0x55 }; + /* + * Some NDIS drivers refuse to associate in open mode + * configuration due to Privacy field mismatch, so use + * a workaround to make the configuration look like + * matching one for WPS provisioning. + */ + wpa_printf(MSG_DEBUG, "NDIS: Set dummy WEP key as a " + "workaround to allow driver to associate " + "for WPS"); + wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP, + bcast, 0, 1, + NULL, 0, dummy_key, + sizeof(dummy_key)); + } #endif /* CONFIG_WPS */ } else { priv_mode = Ndis802_11PrivFilter8021xWEP; @@ -1148,6 +1164,12 @@ wpa_driver_ndis_associate(void *priv, encr = Ndis802_11Encryption1Enabled; break; case CIPHER_NONE: +#ifdef CONFIG_WPS + if (params->wps == WPS_MODE_PRIVACY) { + encr = Ndis802_11Encryption1Enabled; + break; + } +#endif /* CONFIG_WPS */ if (params->group_suite == CIPHER_CCMP) encr = Ndis802_11Encryption3Enabled; else if (params->group_suite == CIPHER_TKIP) @@ -1156,7 +1178,14 @@ wpa_driver_ndis_associate(void *priv, encr = Ndis802_11EncryptionDisabled; break; default: +#ifdef CONFIG_WPS + if (params->wps == WPS_MODE_PRIVACY) { + encr = Ndis802_11Encryption1Enabled; + break; + } +#endif /* CONFIG_WPS */ encr = Ndis802_11EncryptionDisabled; + break; }; if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index bb7c913cd..69c926a77 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1024,6 +1024,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } + os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; if (bss) { #ifdef CONFIG_IEEE80211R @@ -1131,6 +1132,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wpa_ie_len = 0; wpabuf_free(wps_ie); wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); + if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY)) + params.wps = WPS_MODE_PRIVACY; + else + params.wps = WPS_MODE_OPEN; #endif /* CONFIG_WPS */ } else { wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); @@ -1175,7 +1180,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, } wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING); - os_memset(¶ms, 0, sizeof(params)); if (bss) { params.bssid = bss->bssid; params.ssid = bss->ssid;