Add chan_switch to ctrl interface of wpa_supplicant and hostapd
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Thu, 14 Nov 2013 10:28:32 +0000 (12:28 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 17 Nov 2013 15:12:58 +0000 (17:12 +0200)
Add chan_switch to the control interface of wpa_supplicant and hostapd,
and also to wpa_cli and hostapd_cli.

Signed-hostap: Andrei Otcheretianski <andrei.otcheretianski@intel.com>

hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
src/ap/ctrl_iface_ap.c
src/ap/ctrl_iface_ap.h
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/wpa_cli.c

index 3f181fa..2d0379f 100644 (file)
@@ -1111,6 +1111,22 @@ static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
+static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos)
+{
+#ifdef NEED_AP_MLME
+       struct csa_settings settings;
+       int ret = hostapd_parse_csa_settings(pos, &settings);
+
+       if (ret)
+               return ret;
+
+       return hostapd_switch_channel(hapd, &settings);
+#else /* NEED_AP_MLME */
+       return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                                       void *sock_ctx)
 {
@@ -1297,6 +1313,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                if (hostapd_ctrl_iface_radar(hapd, buf + 6))
                        reply_len = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
+       } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+               if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12))
+                       reply_len = -1;
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;
index a1fdf6e..b2d3e5b 100644 (file)
@@ -846,6 +846,45 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
+                                      int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+       int i;
+       char *tmp;
+       int total;
+
+       if (argc < 2) {
+               printf("Invalid chan_switch command: needs at least two "
+                      "arguments (count and freq)\n"
+                      "usage: <cs_count> <freq> [sec_channel_offset=] "
+                      "[center_freq1=] [center_freq2=] [bandwidth=] "
+                      "[blocktx] [ht|vht]\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
+                         argv[0], argv[1]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long CHAN_SWITCH command.\n");
+               return -1;
+       }
+
+       total = res;
+       for (i = 2; i < argc; i++) {
+               tmp = cmd + total;
+               res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
+               if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
+                       printf("Too long CHAN_SWITCH command.\n");
+                       return -1;
+               }
+               total += res;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 struct hostapd_cli_cmd {
        const char *cmd;
        int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -891,6 +930,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "get", hostapd_cli_cmd_get },
        { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
        { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
+       { "chan_switch", hostapd_cli_cmd_chan_switch },
        { NULL, NULL }
 };
 
index 5d99566..ac33068 100644 (file)
@@ -380,3 +380,46 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
 
        return len;
 }
+
+
+int hostapd_parse_csa_settings(const char *pos,
+                              struct csa_settings *settings)
+{
+       char *end;
+
+       if (!settings)
+               return -1;
+
+       os_memset(settings, 0, sizeof(*settings));
+       settings->cs_count = strtol(pos, &end, 10);
+       if (pos == end) {
+               wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
+               return -1;
+       }
+
+       settings->freq_params.freq = atoi(end);
+       if (settings->freq_params.freq == 0) {
+               wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
+               return -1;
+       }
+
+#define SET_CSA_SETTING(str) \
+       do { \
+               const char *pos2 = os_strstr(pos, " " #str "="); \
+               if (pos2) { \
+                       pos2 += sizeof(" " #str "=") - 1; \
+                       settings->freq_params.str = atoi(pos2); \
+               } \
+       } while (0)
+
+       SET_CSA_SETTING(center_freq1);
+       SET_CSA_SETTING(center_freq2);
+       SET_CSA_SETTING(bandwidth);
+       SET_CSA_SETTING(sec_channel_offset);
+       settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
+       settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
+       settings->block_tx = !!os_strstr(pos, " blocktx");
+#undef SET_CSA_SETTING
+
+       return 0;
+}
index a22a2a7..ee58b4c 100644 (file)
@@ -21,5 +21,8 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
                                    const char *txtaddr);
 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
                              size_t buflen);
+int hostapd_parse_csa_settings(const char *pos,
+                              struct csa_settings *settings);
+
 
 #endif /* CTRL_IFACE_AP_H */
index ef18dbd..cbe67a4 100644 (file)
@@ -1072,6 +1072,18 @@ int ap_switch_channel(struct wpa_supplicant *wpa_s,
 }
 
 
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
+{
+       struct csa_settings settings;
+       int ret = hostapd_parse_csa_settings(pos, &settings);
+
+       if (ret)
+               return ret;
+
+       return ap_switch_channel(wpa_s, &settings);
+}
+
+
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
                       int offset)
 {
index f62b8ba..33a3d0f 100644 (file)
@@ -52,6 +52,7 @@ int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
 int ap_switch_channel(struct wpa_supplicant *wpa_s,
                      struct csa_settings *settings);
+int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
                       int offset);
 struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
index 798c55b..280441e 100644 (file)
@@ -5701,6 +5701,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
                if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+               if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
+                       reply_len = -1;
 #endif /* CONFIG_AP */
        } else if (os_strcmp(buf, "SUSPEND") == 0) {
                wpas_notify_suspend(wpa_s->global);
index 3519616..c689e8f 100644 (file)
@@ -1723,6 +1723,13 @@ static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
 {
        return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
 }
+
+static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
+                                   char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv);
+}
+
 #endif /* CONFIG_AP */
 
 
@@ -2704,6 +2711,11 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "disassociate", wpa_cli_cmd_disassociate, NULL,
          cli_cmd_flag_none,
          "<addr> = disassociate a station" },
+       { "chan_switch", wpa_cli_cmd_chanswitch, NULL,
+         cli_cmd_flag_none,
+         "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]"
+         " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]"
+         " = CSA parameters" },
 #endif /* CONFIG_AP */
        { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
          "= notification of suspend/hibernate" },