From 9651deba52dafbdbea603a0d326033e02bc1c7f8 Mon Sep 17 00:00:00 2001 From: Chaoli Zhou Date: Wed, 28 Jul 2021 18:51:08 +0800 Subject: [PATCH] Support vendor element configuration for AP mode from wpa_supplicant Support adding/deleting vendor elements dynamically for AP mode while it is started by wpa_supplicant instead of hostapd which already supported this. This adds ap_assocresp_elements global parameter and UPDATE_BEACON control interface command to take the changed values into effect. Usage in wpa_cli: Add vendor IE for (Re)Association Response frames > set ap_assocresp_elements=xxxx Add vendor IE for Beacon/Probe Response frames > set ap_vendor_elements=xxxx Delete vendor IE from (Re)Association Response frames > set ap_assocresp_elements Delete vendor IE from Beacon/Probe Response frames > set ap_vendor_elements To make vendor IE changes take effect > update_beacon Signed-off-by: Chaoli Zhou --- wpa_supplicant/ap.c | 30 ++++++++++++++++++++++++++++++ wpa_supplicant/ap.h | 1 + wpa_supplicant/config.c | 33 ++++++++++++++++++++++++++++++--- wpa_supplicant/config.h | 11 +++++++++++ wpa_supplicant/config_file.c | 12 ++++++++++++ wpa_supplicant/ctrl_iface.c | 3 +++ wpa_supplicant/wpa_cli.c | 11 +++++++++++ 7 files changed, 98 insertions(+), 3 deletions(-) diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 415f08789..13015ac6f 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -763,6 +763,10 @@ no_wps: bss->vendor_elements = wpabuf_dup(wpa_s->conf->ap_vendor_elements); } + if (wpa_s->conf->ap_assocresp_elements) { + bss->assocresp_elements = + wpabuf_dup(wpa_s->conf->ap_assocresp_elements); + } bss->ftm_responder = wpa_s->conf->ftm_responder; bss->ftm_initiator = wpa_s->conf->ftm_initiator; @@ -1813,6 +1817,32 @@ int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd) #endif /* CONFIG_MESH */ #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + +int wpas_ap_update_beacon(struct wpa_supplicant *wpa_s) +{ + struct hostapd_data *hapd; + + if (!wpa_s->ap_iface) + return -1; + hapd = wpa_s->ap_iface->bss[0]; + + wpabuf_free(hapd->conf->assocresp_elements); + hapd->conf->assocresp_elements = NULL; + if (wpa_s->conf->ap_assocresp_elements) { + hapd->conf->assocresp_elements = + wpabuf_dup(wpa_s->conf->ap_assocresp_elements); + } + + wpabuf_free(hapd->conf->vendor_elements); + hapd->conf->vendor_elements = NULL; + if (wpa_s->conf->ap_vendor_elements) { + hapd->conf->vendor_elements = + wpabuf_dup(wpa_s->conf->ap_vendor_elements); + } + + return ieee802_11_set_beacon(hapd); +} + #endif /* CONFIG_CTRL_IFACE */ diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 6c6e94cdf..7bc1b781e 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -88,6 +88,7 @@ void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s); int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr, char *buf, size_t len); int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd); +int wpas_ap_update_beacon(struct wpa_supplicant *wpa_s); void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s, struct dfs_event *radar); diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index e8e9fd432..6c4d67d40 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2951,6 +2951,7 @@ void wpa_config_free(struct wpa_config *config) os_free(config->ext_password_backend); os_free(config->sae_groups); wpabuf_free(config->ap_vendor_elements); + wpabuf_free(config->ap_assocresp_elements); os_free(config->osu_dir); os_free(config->bgscan); os_free(config->wowlan_triggers); @@ -4913,9 +4914,9 @@ static int wpa_config_process_ap_vendor_elements( u8 *p; if (!len) { - wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements", - line); - return -1; + wpabuf_free(config->ap_vendor_elements); + config->ap_vendor_elements = NULL; + return 0; } tmp = wpabuf_alloc(len); @@ -4941,6 +4942,31 @@ static int wpa_config_process_ap_vendor_elements( } +static int wpa_config_process_ap_assocresp_elements( + const struct global_parse_data *data, + struct wpa_config *config, int line, const char *pos) +{ + struct wpabuf *tmp; + + if (!*pos) { + wpabuf_free(config->ap_assocresp_elements); + config->ap_assocresp_elements = NULL; + return 0; + } + + tmp = wpabuf_parse_bin(pos); + if (!tmp) { + wpa_printf(MSG_ERROR, "Line %d: invalid ap_assocresp_elements", + line); + return -1; + } + wpabuf_free(config->ap_assocresp_elements); + config->ap_assocresp_elements = tmp; + + return 0; +} + + #ifdef CONFIG_CTRL_IFACE static int wpa_config_process_no_ctrl_interface( const struct global_parse_data *data, @@ -5155,6 +5181,7 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 }, { INT(dtim_period), 0 }, { INT(beacon_int), 0 }, + { FUNC(ap_assocresp_elements), 0 }, { FUNC(ap_vendor_elements), 0 }, { INT_RANGE(ignore_old_scan_res, 0, 1), 0 }, { FUNC(freq_list), 0 }, diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 68679c6e3..0320d9eeb 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1241,6 +1241,17 @@ struct wpa_config { */ struct wpabuf *ap_vendor_elements; + /** + * ap_assocresp_elements: Vendor specific elements for (Re)Association + * Response frames + * + * This parameter can be used to define additional vendor specific + * elements for (Re)Association Response frames in AP/P2P GO mode. The + * format for these element(s) is a hexdump of the raw information + * elements (id+len+payload for one or more elements). + */ + struct wpabuf *ap_assocresp_elements; + /** * ignore_old_scan_res - Ignore scan results older than request * diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index a535e3f08..1ad02b988 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1364,6 +1364,18 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) } } + if (config->ap_assocresp_elements) { + int i, len = wpabuf_len(config->ap_assocresp_elements); + const u8 *p = wpabuf_head_u8(config->ap_assocresp_elements); + + if (len > 0) { + fprintf(f, "ap_assocresp_elements="); + for (i = 0; i < len; i++) + fprintf(f, "%02x", *p++); + fprintf(f, "\n"); + } + } + if (config->ignore_old_scan_res) fprintf(f, "ignore_old_scan_res=%d\n", config->ignore_old_scan_res); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 8bdf5772f..96667e4d8 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -12055,6 +12055,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "STOP_AP") == 0) { if (wpas_ap_stop_ap(wpa_s)) reply_len = -1; + } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) { + if (wpas_ap_update_beacon(wpa_s)) + 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 fea7b85e0..32d006f52 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -499,6 +499,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos) "p2p_search_delay", "mac_addr", "rand_addr_lifetime", "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", "reassoc_same_bss_optim", "wps_priority", + "ap_assocresp_elements", #ifdef CONFIG_TESTING_OPTIONS "ignore_auth_resp", #endif /* CONFIG_TESTING_OPTIONS */ @@ -2037,6 +2038,13 @@ static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc, return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv); } + +static int wpa_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "UPDATE_BEACON"); +} + #endif /* CONFIG_AP */ @@ -3563,6 +3571,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { " [sec_channel_offset=] [center_freq1=]" " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]" " = CSA parameters" }, + { "update_beacon", wpa_cli_cmd_update_beacon, NULL, + cli_cmd_flag_none, + "= update Beacon frame contents"}, #endif /* CONFIG_AP */ { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none, "= notification of suspend/hibernate" },