hostapd: Add wowlan_triggers config param
New kernels in wiphy_suspend() will call cfg80211_leave_all() that will eventually end up in cfg80211_stop_ap() unless wowlan_triggers were set. For now, use the parameters from the station mode as-is. It may be desirable to extend (or constraint) this in the future for specific AP mode needs. Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
This commit is contained in:
parent
f03996565a
commit
88cb27c7a5
7 changed files with 102 additions and 61 deletions
|
@ -3172,6 +3172,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
conf->local_pwr_constraint = val;
|
conf->local_pwr_constraint = val;
|
||||||
} else if (os_strcmp(buf, "spectrum_mgmt_required") == 0) {
|
} else if (os_strcmp(buf, "spectrum_mgmt_required") == 0) {
|
||||||
conf->spectrum_mgmt_required = atoi(pos);
|
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 {
|
} else {
|
||||||
wpa_printf(MSG_ERROR,
|
wpa_printf(MSG_ERROR,
|
||||||
"Line %d: unknown configuration item '%s'",
|
"Line %d: unknown configuration item '%s'",
|
||||||
|
|
|
@ -212,6 +212,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||||
|
|
||||||
if (hapd->driver->get_capa &&
|
if (hapd->driver->get_capa &&
|
||||||
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
|
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
|
||||||
|
struct wowlan_triggers *triggs;
|
||||||
|
|
||||||
iface->drv_flags = capa.flags;
|
iface->drv_flags = capa.flags;
|
||||||
iface->smps_modes = capa.smps_modes;
|
iface->smps_modes = capa.smps_modes;
|
||||||
iface->probe_resp_offloads = capa.probe_resp_offloads;
|
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_mask = capa.extended_capa_mask;
|
||||||
iface->extended_capa_len = capa.extended_capa_len;
|
iface->extended_capa_len = capa.extended_capa_len;
|
||||||
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
|
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;
|
return 0;
|
||||||
|
|
|
@ -542,6 +542,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||||
|
|
||||||
os_free(conf->sae_groups);
|
os_free(conf->sae_groups);
|
||||||
|
|
||||||
|
os_free(conf->wowlan_triggers);
|
||||||
|
|
||||||
os_free(conf->server_id);
|
os_free(conf->server_id);
|
||||||
|
|
||||||
os_free(conf);
|
os_free(conf);
|
||||||
|
|
|
@ -535,6 +535,8 @@ struct hostapd_bss_config {
|
||||||
unsigned int sae_anti_clogging_threshold;
|
unsigned int sae_anti_clogging_threshold;
|
||||||
int *sae_groups;
|
int *sae_groups;
|
||||||
|
|
||||||
|
char *wowlan_triggers; /* Wake-on-WLAN triggers */
|
||||||
|
|
||||||
#ifdef CONFIG_TESTING_OPTIONS
|
#ifdef CONFIG_TESTING_OPTIONS
|
||||||
u8 bss_load_test[5];
|
u8 bss_load_test[5];
|
||||||
u8 bss_load_test_set;
|
u8 bss_load_test_set;
|
||||||
|
|
|
@ -4362,6 +4362,10 @@ const char * channel_width_to_string(enum chan_width width);
|
||||||
int ht_supported(const struct hostapd_hw_modes *mode);
|
int ht_supported(const struct hostapd_hw_modes *mode);
|
||||||
int vht_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 */
|
/* NULL terminated array of linked in driver wrappers */
|
||||||
extern struct wpa_driver_ops *wpa_drivers[];
|
extern struct wpa_driver_ops *wpa_drivers[];
|
||||||
|
|
||||||
|
|
|
@ -140,3 +140,79 @@ int vht_supported(const struct hostapd_hw_modes *mode)
|
||||||
*/
|
*/
|
||||||
return (mode->vht_mcs_set[0] & 0x3) != 3;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
|
||||||
const struct wpa_driver_capa *capa)
|
const struct wpa_driver_capa *capa)
|
||||||
{
|
{
|
||||||
struct wowlan_triggers triggers;
|
struct wowlan_triggers *triggers;
|
||||||
char *start, *end, *buf;
|
int ret = 0;
|
||||||
int last, ret;
|
|
||||||
|
|
||||||
if (!wpa_s->conf->wowlan_triggers)
|
if (!wpa_s->conf->wowlan_triggers)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
buf = os_strdup(wpa_s->conf->wowlan_triggers);
|
triggers = wpa_get_wowlan_triggers(wpa_s->conf->wowlan_triggers, capa);
|
||||||
if (buf == NULL)
|
if (triggers) {
|
||||||
return -1;
|
ret = wpa_drv_wowlan(wpa_s, triggers);
|
||||||
|
os_free(triggers);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#undef CHECK_TRIGGER
|
|
||||||
|
|
||||||
ret = wpa_drv_wowlan(wpa_s, &triggers);
|
|
||||||
out:
|
|
||||||
os_free(buf);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue