diff --git a/hostapd/config_file.c b/hostapd/config_file.c index ea7a018e8..61d371bb0 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -3172,6 +3172,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->local_pwr_constraint = val; } else if (os_strcmp(buf, "spectrum_mgmt_required") == 0) { conf->spectrum_mgmt_required = atoi(pos); + } else if (os_strcmp(buf, "wowlan_triggers") == 0) { + os_free(bss->wowlan_triggers); + bss->wowlan_triggers = os_strdup(pos); } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration item '%s'", diff --git a/hostapd/main.c b/hostapd/main.c index 5a4771147..daa6b0f8b 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -212,6 +212,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface) if (hapd->driver->get_capa && hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { + struct wowlan_triggers *triggs; + iface->drv_flags = capa.flags; iface->smps_modes = capa.smps_modes; iface->probe_resp_offloads = capa.probe_resp_offloads; @@ -219,6 +221,13 @@ static int hostapd_driver_init(struct hostapd_iface *iface) iface->extended_capa_mask = capa.extended_capa_mask; iface->extended_capa_len = capa.extended_capa_len; iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; + + triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa); + if (triggs && hapd->driver->set_wowlan) { + if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) + wpa_printf(MSG_ERROR, "set_wowlan failed"); + } + os_free(triggs); } return 0; diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 90f1630da..d8021a178 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -542,6 +542,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->sae_groups); + os_free(conf->wowlan_triggers); + os_free(conf->server_id); os_free(conf); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 8a444016d..3441b90a4 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -535,6 +535,8 @@ struct hostapd_bss_config { unsigned int sae_anti_clogging_threshold; int *sae_groups; + char *wowlan_triggers; /* Wake-on-WLAN triggers */ + #ifdef CONFIG_TESTING_OPTIONS u8 bss_load_test[5]; u8 bss_load_test_set; diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 8420a564d..3476e8e31 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -4362,6 +4362,10 @@ const char * channel_width_to_string(enum chan_width width); int ht_supported(const struct hostapd_hw_modes *mode); int vht_supported(const struct hostapd_hw_modes *mode); +struct wowlan_triggers * +wpa_get_wowlan_triggers(const char *wowlan_triggers, + const struct wpa_driver_capa *capa); + /* NULL terminated array of linked in driver wrappers */ extern struct wpa_driver_ops *wpa_drivers[]; diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index b9a0f5f4b..e0a7ebbfe 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -140,3 +140,79 @@ int vht_supported(const struct hostapd_hw_modes *mode) */ return (mode->vht_mcs_set[0] & 0x3) != 3; } + + +static int wpa_check_wowlan_trigger(const char *start, const char *trigger, + int capa_trigger, u8 *param_trigger) +{ + if (os_strcmp(start, trigger) != 0) + return 0; + if (!capa_trigger) + return 0; + + *param_trigger = 1; + return 1; +} + + +struct wowlan_triggers * +wpa_get_wowlan_triggers(const char *wowlan_triggers, + const struct wpa_driver_capa *capa) +{ + struct wowlan_triggers *triggers; + char *start, *end, *buf; + int last; + + if (!wowlan_triggers) + return NULL; + + buf = os_strdup(wowlan_triggers); + if (buf == NULL) + return NULL; + + triggers = os_zalloc(sizeof(*triggers)); + if (triggers == NULL) + goto out; + +#define CHECK_TRIGGER(trigger) \ + wpa_check_wowlan_trigger(start, #trigger, \ + capa->wowlan_triggers.trigger, \ + &triggers->trigger) + + start = buf; + while (*start != '\0') { + while (isblank(*start)) + start++; + if (*start == '\0') + break; + end = start; + while (!isblank(*end) && *end != '\0') + end++; + last = *end == '\0'; + *end = '\0'; + + if (!CHECK_TRIGGER(any) && + !CHECK_TRIGGER(disconnect) && + !CHECK_TRIGGER(magic_pkt) && + !CHECK_TRIGGER(gtk_rekey_failure) && + !CHECK_TRIGGER(eap_identity_req) && + !CHECK_TRIGGER(four_way_handshake) && + !CHECK_TRIGGER(rfkill_release)) { + wpa_printf(MSG_DEBUG, + "Unknown/unsupported wowlan trigger '%s'", + start); + os_free(triggers); + triggers = NULL; + goto out; + } + + if (last) + break; + start = end + 1; + } +#undef CHECK_TRIGGER + +out: + os_free(buf); + return triggers; +} diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 902102d4c..7e761e71a 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -3301,75 +3301,20 @@ int wpas_init_ext_pw(struct wpa_supplicant *wpa_s) } -static int wpas_check_wowlan_trigger(const char *start, const char *trigger, - int capa_trigger, u8 *param_trigger) -{ - if (os_strcmp(start, trigger) != 0) - return 0; - if (!capa_trigger) - return 0; - - *param_trigger = 1; - return 1; -} - - static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s, const struct wpa_driver_capa *capa) { - struct wowlan_triggers triggers; - char *start, *end, *buf; - int last, ret; + struct wowlan_triggers *triggers; + int ret = 0; if (!wpa_s->conf->wowlan_triggers) return 0; - buf = os_strdup(wpa_s->conf->wowlan_triggers); - if (buf == NULL) - return -1; - - os_memset(&triggers, 0, sizeof(triggers)); - -#define CHECK_TRIGGER(trigger) \ - wpas_check_wowlan_trigger(start, #trigger, \ - capa->wowlan_triggers.trigger, \ - &triggers.trigger) - - start = buf; - while (*start != '\0') { - while (isblank(*start)) - start++; - if (*start == '\0') - break; - end = start; - while (!isblank(*end) && *end != '\0') - end++; - last = *end == '\0'; - *end = '\0'; - - if (!CHECK_TRIGGER(any) && - !CHECK_TRIGGER(disconnect) && - !CHECK_TRIGGER(magic_pkt) && - !CHECK_TRIGGER(gtk_rekey_failure) && - !CHECK_TRIGGER(eap_identity_req) && - !CHECK_TRIGGER(four_way_handshake) && - !CHECK_TRIGGER(rfkill_release)) { - wpa_printf(MSG_DEBUG, - "Unknown/unsupported wowlan trigger '%s'", - start); - ret = -1; - goto out; - } - - if (last) - break; - start = end + 1; + triggers = wpa_get_wowlan_triggers(wpa_s->conf->wowlan_triggers, capa); + if (triggers) { + ret = wpa_drv_wowlan(wpa_s, triggers); + os_free(triggers); } -#undef CHECK_TRIGGER - - ret = wpa_drv_wowlan(wpa_s, &triggers); -out: - os_free(buf); return ret; }