Browse Source

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.
Jouni Malinen 14 years ago
parent
commit
0c80427d77
3 changed files with 51 additions and 2 deletions
  1. 16 0
      src/drivers/driver.h
  2. 30 1
      src/drivers/driver_ndis.c
  3. 5 1
      wpa_supplicant/wpa_supplicant.c

+ 16 - 0
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;
 };
 
 /**

+ 30 - 1
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,

+ 5 - 1
wpa_supplicant/wpa_supplicant.c

@@ -1024,6 +1024,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 		return;
 	}
 
+	os_memset(&params, 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(&params, 0, sizeof(params));
 	if (bss) {
 		params.bssid = bss->bssid;
 		params.ssid = bss->ssid;