WPS: Merge mixed-WPA/WPA2 credentials if received in same session

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>
This commit is contained in:
Hu Wang 2014-08-29 20:11:13 +03:00 committed by Jouni Malinen
parent db9418bb1b
commit e5a4b85b2f
3 changed files with 52 additions and 2 deletions

View file

@ -651,6 +651,8 @@ struct wpa_ssid {
#ifdef CONFIG_HS20 #ifdef CONFIG_HS20
int update_identifier; int update_identifier;
#endif /* CONFIG_HS20 */ #endif /* CONFIG_HS20 */
unsigned int wps_run;
}; };
#endif /* CONFIG_SSID_H */ #endif /* CONFIG_SSID_H */

View file

@ -600,6 +600,7 @@ struct wpa_supplicant {
struct wps_context *wps; struct wps_context *wps;
int wps_success; /* WPS success event received */ int wps_success; /* WPS success event received */
struct wps_er *wps_er; struct wps_er *wps_er;
unsigned int wps_run;
int blacklist_cleared; int blacklist_cleared;
struct wpabuf *pending_eapol_rx; struct wpabuf *pending_eapol_rx;

View file

@ -286,11 +286,54 @@ static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
/* compare security parameters */ /* compare security parameters */
if (ssid->auth_alg != new_ssid->auth_alg || if (ssid->auth_alg != new_ssid->auth_alg ||
ssid->key_mgmt != new_ssid->key_mgmt || 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) ssid->group_cipher != new_ssid->group_cipher)
continue; 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. */ /* Remove the duplicated older network entry. */
wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id); wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
wpas_notify_network_removed(wpa_s, ssid); 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); wpa_config_set_network_defaults(ssid);
ssid->wps_run = wpa_s->wps_run;
os_free(ssid->ssid); os_free(ssid->ssid);
ssid->ssid = os_malloc(cred->ssid_len); 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; 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->after_wps = 0;
wpa_s->known_wps_freq = 0; wpa_s->known_wps_freq = 0;
if (freq) { if (freq) {