]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/ctrl_iface.c
P2P: Use group formation timeout on persistent group GO
[thirdparty/hostap.git] / wpa_supplicant / ctrl_iface.c
index 49157bf98ace8fe6fc5039793e5ddce5e73d918a..cd1bb56f5746d313f6cd8a41ac366b2fc172f7d7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -50,7 +50,7 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
 
 static int pno_start(struct wpa_supplicant *wpa_s)
 {
-       int ret;
+       int ret, interval;
        size_t i, num_ssid;
        struct wpa_ssid *ssid;
        struct wpa_driver_scan_params params;
@@ -108,7 +108,10 @@ static int pno_start(struct wpa_supplicant *wpa_s)
        if (wpa_s->conf->filter_rssi)
                params.filter_rssi = wpa_s->conf->filter_rssi;
 
-       ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+       interval = wpa_s->conf->sched_scan_interval ?
+               wpa_s->conf->sched_scan_interval : 10;
+
+       ret = wpa_drv_sched_scan(wpa_s, &params, interval * 1000);
        os_free(params.filter_ssids);
        if (ret == 0)
                wpa_s->pno = 1;
@@ -577,6 +580,7 @@ static int wpa_supplicant_ctrl_iface_tdls_teardown(
        struct wpa_supplicant *wpa_s, char *addr)
 {
        u8 peer[ETH_ALEN];
+       int ret;
 
        if (hwaddr_aton(addr, peer)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
@@ -587,8 +591,14 @@ static int wpa_supplicant_ctrl_iface_tdls_teardown(
        wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
                   MAC2STR(peer));
 
-       return wpa_tdls_teardown_link(wpa_s->wpa, peer,
-                                     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+       if (wpa_tdls_is_external_setup(wpa_s->wpa))
+               ret = wpa_tdls_teardown_link(
+                       wpa_s->wpa, peer,
+                       WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+       else
+               ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+       return ret;
 }
 
 #endif /* CONFIG_TDLS */
@@ -1496,7 +1506,10 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
        }
 #ifdef CONFIG_SAE
        if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
-           wpa_s->sme.sae.state == SAE_ACCEPTED && !wpa_s->ap_iface) {
+#ifdef CONFIG_AP
+           !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+           wpa_s->sme.sae.state == SAE_ACCEPTED) {
                ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
                                  wpa_s->sme.sae.group);
                if (ret < 0 || ret >= end - pos)
@@ -4193,7 +4206,8 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
+       return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL,
+                                            0);
 }
 
 
@@ -4552,6 +4566,11 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
                                        max_disc_int, max_disc_tu);
        }
 
+       if (os_strcmp(cmd, "per_sta_psk") == 0) {
+               wpa_s->global->p2p_per_sta_psk = !!atoi(param);
+               return 0;
+       }
+
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
                   cmd);
 
@@ -4617,6 +4636,25 @@ static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
        return wpas_p2p_ext_listen(wpa_s, period, interval);
 }
 
+
+static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+       const char *pos;
+       u8 peer[ETH_ALEN];
+       int iface_addr = 0;
+
+       pos = cmd;
+       if (os_strncmp(pos, "iface=", 6) == 0) {
+               iface_addr = 1;
+               pos += 6;
+       }
+       if (hwaddr_aton(pos, peer))
+               return -1;
+
+       wpas_p2p_remove_client(wpa_s, peer, iface_addr);
+       return 0;
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -4999,23 +5037,76 @@ static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd
 #endif /* CONFIG_WNM */
 
 
+/* Get string representation of channel width */
+static const char * channel_width_name(enum chan_width width)
+{
+       switch (width) {
+       case CHAN_WIDTH_20_NOHT:
+               return "20 MHz (no HT)";
+       case CHAN_WIDTH_20:
+               return "20 MHz";
+       case CHAN_WIDTH_40:
+               return "40 MHz";
+       case CHAN_WIDTH_80:
+               return "80 MHz";
+       case CHAN_WIDTH_80P80:
+               return "80+80 MHz";
+       case CHAN_WIDTH_160:
+               return "160 MHz";
+       default:
+               return "unknown";
+       }
+}
+
+
 static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
                                      size_t buflen)
 {
        struct wpa_signal_info si;
        int ret;
+       char *pos, *end;
 
        ret = wpa_drv_signal_poll(wpa_s, &si);
        if (ret)
                return -1;
 
-       ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+       pos = buf;
+       end = buf + buflen;
+
+       ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
                          "NOISE=%d\nFREQUENCY=%u\n",
                          si.current_signal, si.current_txrate / 1000,
                          si.current_noise, si.frequency);
-       if (ret < 0 || (unsigned int) ret > buflen)
+       if (ret < 0 || ret > end - pos)
                return -1;
-       return ret;
+       pos += ret;
+
+       if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
+               ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
+                                 channel_width_name(si.chanwidth));
+               if (ret < 0 || ret > end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       if (si.center_frq1 > 0 && si.center_frq2 > 0) {
+               ret = os_snprintf(pos, end - pos,
+                                 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
+                                 si.center_frq1, si.center_frq2);
+               if (ret < 0 || ret > end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       if (si.avg_signal) {
+               ret = os_snprintf(pos, end - pos,
+                                 "AVG_RSSI=%d\n", si.avg_signal);
+               if (ret < 0 || ret >= end - pos)
+                       return -1;
+               pos += ret;
+       }
+
+       return pos - buf;
 }
 
 
@@ -5385,6 +5476,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
                if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
+               if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
+                       reply_len = -1;
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_WIFI_DISPLAY
        } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -5871,6 +5965,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
                "P2P_UNAUTHORIZE ",
                "P2P_PRESENCE_REQ ",
                "P2P_EXT_LISTEN ",
+               "P2P_REMOVE_CLIENT ",
                NULL
        };
        int found = 0;
@@ -5929,6 +6024,102 @@ static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
 }
 
 
+static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
+{
+       char *value;
+
+       value = os_strchr(cmd, ' ');
+       if (value == NULL)
+               return -1;
+       *value++ = '\0';
+
+       wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
+
+#ifdef CONFIG_WIFI_DISPLAY
+       if (os_strcasecmp(cmd, "wifi_display") == 0) {
+               wifi_display_enable(global, !!atoi(value));
+               return 0;
+       }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+       return -1;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
+{
+       int ret = 0;
+       struct wpa_supplicant *wpa_s;
+
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (!wpa_s->conf->update_config) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
+                       continue;
+               }
+
+               if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
+                       ret = 1;
+               } else {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
+               }
+       }
+
+       return ret;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+static int wpas_global_ctrl_iface_status(struct wpa_global *global,
+                                        char *buf, size_t buflen)
+{
+       char *pos, *end;
+       int ret;
+       struct wpa_supplicant *wpa_s;
+
+       pos = buf;
+       end = buf + buflen;
+
+#ifdef CONFIG_P2P
+       if (global->p2p && !global->p2p_disabled) {
+               ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+                                 "\n"
+                                 "p2p_state=%s\n",
+                                 MAC2STR(global->p2p_dev_addr),
+                                 p2p_get_state_txt(global->p2p));
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       } else if (global->p2p) {
+               ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+       ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
+                         !!global->wifi_display);
+       if (ret < 0 || ret >= end - pos)
+               return pos - buf;
+       pos += ret;
+#endif /* CONFIG_WIFI_DISPLAY */
+
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               ret = os_snprintf(pos, end - pos, "ifname=%s\n"
+                                 "address=" MACSTR "\n",
+                                 wpa_s->ifname, MAC2STR(wpa_s->own_addr));
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+
+       return pos - buf;
+}
+
+
 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
                                                char *buf, size_t *resp_len)
 {
@@ -5986,6 +6177,17 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
                wpas_notify_suspend(global);
        } else if (os_strcmp(buf, "RESUME") == 0) {
                wpas_notify_resume(global);
+       } else if (os_strncmp(buf, "SET ", 4) == 0) {
+               if (wpas_global_ctrl_iface_set(global, buf + 4))
+                       reply_len = -1;
+#ifndef CONFIG_NO_CONFIG_WRITE
+       } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
+               if (wpas_global_ctrl_iface_save_config(global))
+                       reply_len = -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+       } else if (os_strcmp(buf, "STATUS") == 0) {
+               reply_len = wpas_global_ctrl_iface_status(global, reply,
+                                                         reply_size);
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;