WPS: Merge mixed-WPA/WPA2 credentials if received in same session
authorHu Wang <huw@qti.qualcomm.com>
Fri, 29 Aug 2014 17:11:13 +0000 (20:11 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 29 Aug 2014 17:25:18 +0000 (20:25 +0300)
Some deployed APs send two credentials when in mixed-WPA/WPA2
configuration; one for the WPA-Personal/TKIP and the other for
WPA2-Personal/CCMP. Previously, this would result in two network blocks
getting added for the single AP. This can be somewhat confusing and
unnecessary, so merge such credentials into a single one that allows
both WPA and WPA2 to be used.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
wpa_supplicant/config_ssid.h
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wps_supplicant.c

index ab474ff..26b91bd 100644 (file)
@@ -651,6 +651,8 @@ struct wpa_ssid {
 #ifdef CONFIG_HS20
        int update_identifier;
 #endif /* CONFIG_HS20 */
+
+       unsigned int wps_run;
 };
 
 #endif /* CONFIG_SSID_H */
index bf3d19d..be779d8 100644 (file)
@@ -600,6 +600,7 @@ struct wpa_supplicant {
        struct wps_context *wps;
        int wps_success; /* WPS success event received */
        struct wps_er *wps_er;
+       unsigned int wps_run;
        int blacklist_cleared;
 
        struct wpabuf *pending_eapol_rx;
index fd0d14a..40a5c69 100644 (file)
@@ -286,11 +286,54 @@ static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
                /* compare security parameters */
                if (ssid->auth_alg != new_ssid->auth_alg ||
                    ssid->key_mgmt != new_ssid->key_mgmt ||
-                   ssid->proto != new_ssid->proto ||
-                   ssid->pairwise_cipher != new_ssid->pairwise_cipher ||
                    ssid->group_cipher != new_ssid->group_cipher)
                        continue;
 
+               /*
+                * Some existing WPS APs will send two creds in case they are
+                * configured for mixed mode operation (WPA+WPA2 and TKIP+CCMP).
+                * Try to merge these two creds if they are received in the same
+                * M8 message.
+                */
+               if (ssid->wps_run && ssid->wps_run == new_ssid->wps_run &&
+                   wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
+                       if (new_ssid->passphrase && ssid->passphrase &&
+                           os_strcmp(new_ssid->passphrase, ssid->passphrase) !=
+                           0) {
+                               wpa_printf(MSG_DEBUG,
+                                          "WPS: M8 Creds with different passphrase - do not merge");
+                               continue;
+                       }
+
+                       if (new_ssid->psk_set &&
+                           (!ssid->psk_set ||
+                            os_memcmp(new_ssid->psk, ssid->psk, 32) != 0)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "WPS: M8 Creds with different PSK - do not merge");
+                               continue;
+                       }
+
+                       if ((new_ssid->passphrase && !ssid->passphrase) ||
+                           (!new_ssid->passphrase && ssid->passphrase)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "WPS: M8 Creds with different passphrase/PSK type - do not merge");
+                               continue;
+                       }
+
+                       wpa_printf(MSG_DEBUG,
+                                  "WPS: Workaround - merge likely WPA/WPA2-mixed mode creds in same M8 message");
+                       new_ssid->proto |= ssid->proto;
+                       new_ssid->pairwise_cipher |= ssid->pairwise_cipher;
+               } else {
+                       /*
+                        * proto and pairwise_cipher difference matter for
+                        * non-mixed-mode creds.
+                        */
+                       if (ssid->proto != new_ssid->proto ||
+                           ssid->pairwise_cipher != new_ssid->pairwise_cipher)
+                               continue;
+               }
+
                /* Remove the duplicated older network entry. */
                wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
                wpas_notify_network_removed(wpa_s, ssid);
@@ -411,6 +454,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
        }
 
        wpa_config_set_network_defaults(ssid);
+       ssid->wps_run = wpa_s->wps_run;
 
        os_free(ssid->ssid);
        ssid->ssid = os_malloc(cred->ssid_len);
@@ -1004,6 +1048,9 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
 {
        struct wpa_bss *bss;
 
+       wpa_s->wps_run++;
+       if (wpa_s->wps_run == 0)
+               wpa_s->wps_run++;
        wpa_s->after_wps = 0;
        wpa_s->known_wps_freq = 0;
        if (freq) {