Allow WPS APs for PIN enrollment even without Selected Registrar
[wpasupplicant] / wpa_supplicant / events.c
index 45b5ac3..703106c 100644 (file)
@@ -31,6 +31,8 @@
 #include "ieee802_11_defs.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
+#include "wps_supplicant.h"
+#include "ibss_rsn.h"
 
 
 static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
@@ -269,12 +271,18 @@ static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
 }
 
 
-static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
+static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
+                                        struct wpa_ssid *ssid,
                                         struct wpa_scan_res *bss)
 {
        struct wpa_ie_data ie;
        int proto_match = 0;
        const u8 *rsn_ie, *wpa_ie;
+       int ret;
+
+       ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
+       if (ret >= 0)
+               return ret;
 
        rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
        while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
@@ -409,13 +417,22 @@ wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
                }
 
                for (ssid = group; ssid; ssid = ssid->pnext) {
+                       int check_ssid = 1;
+
                        if (ssid->disabled) {
                                wpa_printf(MSG_DEBUG, "   skip - disabled");
                                continue;
                        }
 
-                       if (ssid_len != ssid->ssid_len ||
-                           os_memcmp(ssid_, ssid->ssid, ssid_len) != 0) {
+#ifdef CONFIG_WPS
+                       if (ssid->ssid_len == 0 &&
+                           wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+                               check_ssid = 0;
+#endif /* CONFIG_WPS */
+
+                       if (check_ssid &&
+                           (ssid_len != ssid->ssid_len ||
+                            os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
                                wpa_printf(MSG_DEBUG, "   skip - "
                                           "SSID mismatch");
                                continue;
@@ -429,7 +446,7 @@ wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
                                continue;
                        }
 
-                       if (!wpa_supplicant_ssid_bss_match(ssid, bss))
+                       if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
                                continue;
 
                        wpa_printf(MSG_DEBUG, "   selected WPA AP "
@@ -485,12 +502,27 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
                }
 
                for (ssid = group; ssid; ssid = ssid->pnext) {
+                       int check_ssid = ssid->ssid_len != 0;
+
                        if (ssid->disabled) {
                                wpa_printf(MSG_DEBUG, "   skip - disabled");
                                continue;
                        }
 
-                       if (ssid->ssid_len != 0 &&
+#ifdef CONFIG_WPS
+                       if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+                               /* Only allow wildcard SSID match if an AP
+                                * advertises active WPS operation that matches
+                                * with our mode. */
+                               check_ssid = 1;
+                               if (ssid->ssid_len == 0 &&
+                                   wpas_wps_ssid_wildcard_ok(wpa_s, ssid,
+                                                             bss))
+                                       check_ssid = 0;
+                       }
+#endif /* CONFIG_WPS */
+
+                       if (check_ssid &&
                            (ssid_len != ssid->ssid_len ||
                             os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
                                wpa_printf(MSG_DEBUG, "   skip - "
@@ -507,6 +539,7 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
                        }
                        
                        if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+                           !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
                            !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
                        {
                                wpa_printf(MSG_DEBUG, "   skip - "
@@ -596,9 +629,11 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
        } else {
                wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
                wpa_supplicant_dbus_notify_scan_results(wpa_s);
+               wpas_wps_notify_scan_results(wpa_s);
        }
 
-       if (wpa_s->conf->ap_scan == 2 || wpa_s->disconnected)
+       if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)) ||
+           wpa_s->disconnected)
                return;
 
        while (selected == NULL) {
@@ -613,12 +648,20 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
                        wpa_printf(MSG_DEBUG, "No APs found - clear blacklist "
                                   "and try again");
                        wpa_blacklist_clear(wpa_s);
+                       wpa_s->blacklist_cleared++;
                } else if (selected == NULL) {
                        break;
                }
        }
 
        if (selected) {
+               if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
+                       wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
+                               "PBC session overlap");
+                       timeout = 10;
+                       goto req_scan;
+               }
+
                /* Do not trigger new association unless the BSSID has changed
                 * or if reassociation is requested. If we are in process of
                 * associating with the selected BSSID, do not trigger new
@@ -862,6 +905,22 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s)
 }
 
 
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+static void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx,
+                                                   void *sock_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       if (!wpa_s->pending_mic_error_report)
+               return;
+
+       wpa_printf(MSG_DEBUG, "WPA: Sending pending MIC error report");
+       wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise);
+       wpa_s->pending_mic_error_report = 0;
+}
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+
+
 static void
 wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
                                         union wpa_event_data *data)
@@ -871,10 +930,25 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
 
        wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
        pairwise = (data && data->michael_mic_failure.unicast);
-       wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
        os_get_time(&t);
-       if (wpa_s->last_michael_mic_error &&
-           t.sec - wpa_s->last_michael_mic_error <= 60) {
+       if ((wpa_s->last_michael_mic_error &&
+            t.sec - wpa_s->last_michael_mic_error <= 60) ||
+           wpa_s->pending_mic_error_report) {
+               if (wpa_s->pending_mic_error_report) {
+                       /*
+                        * Send the pending MIC error report immediately since
+                        * we are going to start countermeasures and AP better
+                        * do the same.
+                        */
+                       wpa_sm_key_request(wpa_s->wpa, 1,
+                                          wpa_s->pending_mic_error_pairwise);
+               }
+
+               /* Send the new MIC error report immediately since we are going
+                * to start countermeasures and AP better do the same.
+                */
+               wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+
                /* initialize countermeasures */
                wpa_s->countermeasures = 1;
                wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
@@ -895,8 +969,46 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
                                       wpa_s, NULL);
                /* TODO: mark the AP rejected for 60 second. STA is
                 * allowed to associate with another AP.. */
+       } else {
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+               if (wpa_s->mic_errors_seen) {
+                       /*
+                        * Reduce the effectiveness of Michael MIC error
+                        * reports as a means for attacking against TKIP if
+                        * more than one MIC failure is noticed with the same
+                        * PTK. We delay the transmission of the reports by a
+                        * random time between 0 and 60 seconds in order to
+                        * force the attacker wait 60 seconds before getting
+                        * the information on whether a frame resulted in a MIC
+                        * failure.
+                        */
+                       u8 rval[4];
+                       int sec;
+
+                       if (os_get_random(rval, sizeof(rval)) < 0)
+                               sec = os_random() % 60;
+                       else
+                               sec = WPA_GET_BE32(rval) % 60;
+                       wpa_printf(MSG_DEBUG, "WPA: Delay MIC error report %d "
+                                  "seconds", sec);
+                       wpa_s->pending_mic_error_report = 1;
+                       wpa_s->pending_mic_error_pairwise = pairwise;
+                       eloop_cancel_timeout(
+                               wpa_supplicant_delayed_mic_error_report,
+                               wpa_s, NULL);
+                       eloop_register_timeout(
+                               sec, os_random() % 1000000,
+                               wpa_supplicant_delayed_mic_error_report,
+                               wpa_s, NULL);
+               } else {
+                       wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+               }
+#else /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+               wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
        }
        wpa_s->last_michael_mic_error = t.sec;
+       wpa_s->mic_errors_seen++;
 }
 
 
@@ -959,6 +1071,17 @@ wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211R */
 
 
+#ifdef CONFIG_IBSS_RSN
+static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
+                                               union wpa_event_data *data)
+{
+       if (data == NULL)
+               return;
+       ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
+}
+#endif /* CONFIG_IBSS_RSN */
+
+
 void wpa_supplicant_event(void *ctx, wpa_event_type event,
                          union wpa_event_data *data)
 {
@@ -998,6 +1121,11 @@ void wpa_supplicant_event(void *ctx, wpa_event_type event,
                wpa_supplicant_event_ft_response(wpa_s, data);
                break;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IBSS_RSN
+       case EVENT_IBSS_RSN_START:
+               wpa_supplicant_event_ibss_rsn_start(wpa_s, data);
+               break;
+#endif /* CONFIG_IBSS_RSN */
        default:
                wpa_printf(MSG_INFO, "Unknown event %d", event);
                break;