]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/ctrl_iface.c
Maintain maximum blacklist count over list clear operations
[thirdparty/hostap.git] / wpa_supplicant / ctrl_iface.c
index 8038b9c28ba45807ca17c3972139b1a1578806c1..328d382fa6800fb3f539529f4ad87221d1afde61 100644 (file)
@@ -750,31 +750,6 @@ static int wpa_supplicant_ctrl_iface_wps_check_pin(
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
-                                            char *cmd)
-{
-       char *path, *method, *name;
-
-       path = os_strchr(cmd, ' ');
-       if (path == NULL)
-               return -1;
-       *path++ = '\0';
-
-       method = os_strchr(path, ' ');
-       if (method == NULL)
-               return -1;
-       *method++ = '\0';
-
-       name = os_strchr(method, ' ');
-       if (name != NULL)
-               *name++ = '\0';
-
-       return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
 #ifdef CONFIG_WPS_NFC
 
 static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
@@ -846,6 +821,149 @@ static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
        return ret;
 }
 
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+                                             char *reply, size_t max_len)
+{
+       struct wpabuf *buf;
+       int res;
+
+       buf = wpas_wps_nfc_handover_req(wpa_s);
+       if (buf == NULL)
+               return -1;
+
+       res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+                                        wpabuf_len(buf));
+       reply[res++] = '\n';
+       reply[res] = '\0';
+
+       wpabuf_free(buf);
+
+       return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+                                         char *cmd, char *reply,
+                                         size_t max_len)
+{
+       char *pos;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (os_strcmp(cmd, "NDEF") != 0)
+               return -1;
+
+       if (os_strcmp(pos, "WPS") == 0) {
+               return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
+                                                         max_len);
+       }
+
+       return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+                                             char *reply, size_t max_len)
+{
+       struct wpabuf *buf;
+       int res;
+
+       buf = wpas_wps_nfc_handover_sel(wpa_s);
+       if (buf == NULL)
+               return -1;
+
+       res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+                                        wpabuf_len(buf));
+       reply[res++] = '\n';
+       reply[res] = '\0';
+
+       wpabuf_free(buf);
+
+       return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+                                         char *cmd, char *reply,
+                                         size_t max_len)
+{
+       char *pos;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (os_strcmp(cmd, "NDEF") != 0)
+               return -1;
+
+       if (os_strcmp(pos, "WPS") == 0) {
+               return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
+                                                         max_len);
+       }
+
+       return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+                                        char *cmd, char *reply,
+                                        size_t max_len)
+{
+       size_t len;
+       struct wpabuf *buf;
+       int ret;
+
+       len = os_strlen(cmd);
+       if (len & 0x01)
+               return -1;
+       len /= 2;
+
+       buf = wpabuf_alloc(len);
+       if (buf == NULL)
+               return -1;
+       if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+               wpabuf_free(buf);
+               return -1;
+       }
+
+       ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+       wpabuf_free(buf);
+
+       return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+                                        char *cmd)
+{
+       size_t len;
+       struct wpabuf *buf;
+       int ret;
+
+       len = os_strlen(cmd);
+       if (len & 0x01)
+               return -1;
+       len /= 2;
+
+       buf = wpabuf_alloc(len);
+       if (buf == NULL)
+               return -1;
+       if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+               wpabuf_free(buf);
+               return -1;
+       }
+
+       ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+       wpabuf_free(buf);
+
+       return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -1282,6 +1400,45 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                        return pos - buf;
                pos += ret;
        }
+
+       if (wpa_s->current_ssid) {
+               struct wpa_cred *cred;
+               char *type;
+
+               for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+                       if (wpa_s->current_ssid->parent_cred != cred)
+                               continue;
+                       if (!cred->domain)
+                               continue;
+
+                       ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
+                                         cred->domain);
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+
+                       if (wpa_s->current_bss == NULL ||
+                           wpa_s->current_bss->anqp == NULL)
+                               res = -1;
+                       else
+                               res = interworking_home_sp_cred(
+                                       wpa_s, cred,
+                                       wpa_s->current_bss->anqp->domain_name);
+                       if (res > 0)
+                               type = "home";
+                       else if (res == 0)
+                               type = "roaming";
+                       else
+                               type = "unknown";
+
+                       ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+
+                       break;
+               }
+       }
 #endif /* CONFIG_HS20 */
 
        if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
@@ -1985,8 +2142,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
 #endif /* CONFIG_SME */
                        wpa_sm_set_config(wpa_s->wpa, NULL);
                        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-                       wpa_supplicant_disassociate(wpa_s,
-                                                   WLAN_REASON_DEAUTH_LEAVING);
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                }
                return 0;
        }
@@ -2018,7 +2175,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                wpa_sm_set_config(wpa_s->wpa, NULL);
                eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
        }
 
        if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
@@ -2187,20 +2345,62 @@ static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
+                                struct wpa_cred *cred)
+{
+       struct wpa_ssid *ssid;
+       char str[20];
+
+       if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+               return -1;
+       }
+
+       /* Remove any network entry created based on the removed credential */
+       ssid = wpa_s->conf->ssid;
+       while (ssid) {
+               if (ssid->parent_cred == cred) {
+                       wpa_printf(MSG_DEBUG, "Remove network id %d since it "
+                                  "used the removed credential", ssid->id);
+                       os_snprintf(str, sizeof(str), "%d", ssid->id);
+                       ssid = ssid->next;
+                       wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
+               } else
+                       ssid = ssid->next;
+       }
+
+       return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
                                                 char *cmd)
 {
        int id;
-       struct wpa_cred *cred;
+       struct wpa_cred *cred, *prev;
 
-       /* cmd: "<cred id>" or "all" */
+       /* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
        if (os_strcmp(cmd, "all") == 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
                cred = wpa_s->conf->cred;
                while (cred) {
-                       id = cred->id;
+                       prev = cred;
                        cred = cred->next;
-                       wpa_config_remove_cred(wpa_s->conf, id);
+                       wpas_ctrl_remove_cred(wpa_s, prev);
+               }
+               return 0;
+       }
+
+       if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
+                          cmd + 8);
+               cred = wpa_s->conf->cred;
+               while (cred) {
+                       prev = cred;
+                       cred = cred->next;
+                       if (prev->domain &&
+                           os_strcmp(prev->domain, cmd + 8) == 0)
+                               wpas_ctrl_remove_cred(wpa_s, prev);
                }
                return 0;
        }
@@ -2209,14 +2409,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
 
        cred = wpa_config_get_cred(wpa_s->conf, id);
-       if (cred == NULL ||
-           wpa_config_remove_cred(wpa_s->conf, id) < 0) {
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
-                          id);
-               return -1;
-       }
-
-       return 0;
+       return wpas_ctrl_remove_cred(wpa_s, cred);
 }
 
 
@@ -3790,6 +3983,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
        char *pos, *end;
        char devtype[WPS_DEV_TYPE_BUFSIZE];
        struct wpa_ssid *ssid;
+       size_t i;
 
        if (!wpa_s->global->p2p)
                return -1;
@@ -3843,6 +4037,18 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
                return pos - buf;
        pos += res;
 
+       for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
+       {
+               const u8 *t;
+               t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
+               res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
+                                 wps_dev_type_bin2str(t, devtype,
+                                                      sizeof(devtype)));
+               if (res < 0 || res >= end - pos)
+                       return pos - buf;
+               pos += res;
+       }
+
        ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
        if (ssid) {
                res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
@@ -4071,6 +4277,30 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
        if (os_strcmp(cmd, "disallow_freq") == 0)
                return p2p_ctrl_disallow_freq(wpa_s, param);
 
+       if (os_strcmp(cmd, "disc_int") == 0) {
+               int min_disc_int, max_disc_int, max_disc_tu;
+               char *pos;
+
+               pos = param;
+
+               min_disc_int = atoi(pos);
+               pos = os_strchr(pos, ' ');
+               if (pos == NULL)
+                       return -1;
+               *pos++ = '\0';
+
+               max_disc_int = atoi(pos);
+               pos = os_strchr(pos, ' ');
+               if (pos == NULL)
+                       return -1;
+               *pos++ = '\0';
+
+               max_disc_tu = atoi(pos);
+
+               return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
+                                       max_disc_int, max_disc_tu);
+       }
+
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
                   cmd);
 
@@ -4489,7 +4719,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        int reply_len;
 
        if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
-           os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+           os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+           os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+           os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
                wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
                                      (const u8 *) buf, os_strlen(buf));
        } else {
@@ -4554,6 +4786,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        reply_len = -1;
                else {
+                       wpa_s->extra_blacklist_count = 0;
                        wpa_s->disconnected = 0;
                        wpa_s->reassociate = 1;
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -4564,6 +4797,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        reply_len = -1;
                else if (wpa_s->disconnected) {
+                       wpa_s->extra_blacklist_count = 0;
                        wpa_s->disconnected = 0;
                        wpa_s->reassociate = 1;
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -4608,11 +4842,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
                if (wpas_wps_cancel(wpa_s))
                        reply_len = -1;
-#ifdef CONFIG_WPS_OOB
-       } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
-               if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
-                       reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
 #ifdef CONFIG_WPS_NFC
        } else if (os_strcmp(buf, "WPS_NFC") == 0) {
                if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
@@ -4627,6 +4856,18 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
                                                               buf + 17))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+               reply_len = wpas_ctrl_nfc_get_handover_req(
+                       wpa_s, buf + 21, reply, reply_size);
+       } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+               reply_len = wpas_ctrl_nfc_get_handover_sel(
+                       wpa_s, buf + 21, reply, reply_size);
+       } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+               reply_len = wpas_ctrl_nfc_rx_handover_req(
+                       wpa_s, buf + 20, reply, reply_size);
+       } else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+               if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+                       reply_len = -1;
 #endif /* CONFIG_WPS_NFC */
        } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
@@ -4855,14 +5096,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                            ((wpa_s->wpa_state <= WPA_SCANNING) ||
                             (wpa_s->wpa_state == WPA_COMPLETED))) {
                                wpa_s->normal_scans = 0;
-                               wpa_s->scan_req = 2;
+                               wpa_s->scan_req = MANUAL_SCAN_REQ;
                                wpa_supplicant_req_scan(wpa_s, 0, 0);
                        } else if (wpa_s->sched_scanning) {
                                wpa_printf(MSG_DEBUG, "Stop ongoing "
                                           "sched_scan to allow requested "
                                           "full scan to proceed");
                                wpa_supplicant_cancel_sched_scan(wpa_s);
-                               wpa_s->scan_req = 2;
+                               wpa_s->scan_req = MANUAL_SCAN_REQ;
                                wpa_supplicant_req_scan(wpa_s, 0, 0);
                        } else {
                                wpa_printf(MSG_DEBUG, "Ongoing scan action - "