From 334bf36ac5fa13303286a44fa04a0fd7ff8630dc Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 14 Nov 2013 12:28:32 +0200 Subject: [PATCH] Add chan_switch to ctrl interface of wpa_supplicant and hostapd Add chan_switch to the control interface of wpa_supplicant and hostapd, and also to wpa_cli and hostapd_cli. Signed-hostap: Andrei Otcheretianski --- hostapd/ctrl_iface.c | 19 ++++++++++++++++ hostapd/hostapd_cli.c | 40 ++++++++++++++++++++++++++++++++++ src/ap/ctrl_iface_ap.c | 43 +++++++++++++++++++++++++++++++++++++ src/ap/ctrl_iface_ap.h | 3 +++ wpa_supplicant/ap.c | 12 +++++++++++ wpa_supplicant/ap.h | 1 + wpa_supplicant/ctrl_iface.c | 3 +++ wpa_supplicant/wpa_cli.c | 12 +++++++++++ 8 files changed, 133 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 3f181fa82..2d0379f3b 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -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; diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index a1fdf6ed3..b2d3e5ba5 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -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: [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 } }; diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 5d99566bf..ac330682b 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -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; +} diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h index a22a2a7c6..ee58b4c96 100644 --- a/src/ap/ctrl_iface_ap.h +++ b/src/ap/ctrl_iface_ap.h @@ -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 */ diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index ef18dbd4e..cbe67a4a8 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -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) { diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index f62b8babf..33a3d0f75 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -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, diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 798c55b41..280441ed7 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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); diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 3519616d4..c689e8f4d 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -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, " = disassociate a station" }, + { "chan_switch", wpa_cli_cmd_chanswitch, NULL, + cli_cmd_flag_none, + " [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" },