wpa_supplicant: Add Wake-on-WLAN configuration support
Add a new wowlan_triggers option to wpa_supplicant.conf. The triggers in this key will be used to configure the kernel wowlan configuration. For now, support only simple flags. More complex triggers can be added later on. Signed-off-by: Eliad Peller <eliadx.peller@intel.com>
This commit is contained in:
parent
959214b260
commit
e4fa8b120b
7 changed files with 205 additions and 0 deletions
|
@ -682,6 +682,16 @@ enum hide_ssid {
|
||||||
HIDDEN_SSID_ZERO_CONTENTS
|
HIDDEN_SSID_ZERO_CONTENTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wowlan_triggers {
|
||||||
|
u8 any;
|
||||||
|
u8 disconnect;
|
||||||
|
u8 magic_pkt;
|
||||||
|
u8 gtk_rekey_failure;
|
||||||
|
u8 eap_identity_req;
|
||||||
|
u8 four_way_handshake;
|
||||||
|
u8 rfkill_release;
|
||||||
|
};
|
||||||
|
|
||||||
struct wpa_driver_ap_params {
|
struct wpa_driver_ap_params {
|
||||||
/**
|
/**
|
||||||
* head - Beacon head from IEEE 802.11 header to IEs before TIM IE
|
* head - Beacon head from IEEE 802.11 header to IEs before TIM IE
|
||||||
|
@ -1032,6 +1042,8 @@ struct wpa_driver_capa {
|
||||||
*/
|
*/
|
||||||
const u8 *extended_capa, *extended_capa_mask;
|
const u8 *extended_capa, *extended_capa_mask;
|
||||||
unsigned int extended_capa_len;
|
unsigned int extended_capa_len;
|
||||||
|
|
||||||
|
struct wowlan_triggers wowlan_triggers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2518,6 +2530,13 @@ struct wpa_driver_ops {
|
||||||
int (*set_qos_map)(void *priv, const u8 *qos_map_set,
|
int (*set_qos_map)(void *priv, const u8 *qos_map_set,
|
||||||
u8 qos_map_set_len);
|
u8 qos_map_set_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set_wowlan - Set wake-on-wireless triggers
|
||||||
|
* @priv: Private driver interface data
|
||||||
|
* @triggers: wowlan triggers
|
||||||
|
*/
|
||||||
|
int (*set_wowlan)(void *priv, const struct wowlan_triggers *triggers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* signal_poll - Get current connection information
|
* signal_poll - Get current connection information
|
||||||
* @priv: Private driver interface data
|
* @priv: Private driver interface data
|
||||||
|
|
|
@ -3697,6 +3697,35 @@ static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
|
||||||
|
struct nlattr *tb)
|
||||||
|
{
|
||||||
|
struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
|
||||||
|
|
||||||
|
if (tb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
|
||||||
|
tb, NULL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (triggers[NL80211_WOWLAN_TRIG_ANY])
|
||||||
|
capa->wowlan_triggers.any = 1;
|
||||||
|
if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
|
||||||
|
capa->wowlan_triggers.disconnect = 1;
|
||||||
|
if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
|
||||||
|
capa->wowlan_triggers.magic_pkt = 1;
|
||||||
|
if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
|
||||||
|
capa->wowlan_triggers.gtk_rekey_failure = 1;
|
||||||
|
if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
|
||||||
|
capa->wowlan_triggers.eap_identity_req = 1;
|
||||||
|
if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
|
||||||
|
capa->wowlan_triggers.four_way_handshake = 1;
|
||||||
|
if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
|
||||||
|
capa->wowlan_triggers.rfkill_release = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
||||||
{
|
{
|
||||||
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
||||||
|
@ -3820,6 +3849,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wiphy_info_wowlan_triggers(capa,
|
||||||
|
tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
|
||||||
|
|
||||||
return NL_SKIP;
|
return NL_SKIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12137,6 +12169,57 @@ nla_put_failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int nl80211_set_wowlan(void *priv,
|
||||||
|
const struct wowlan_triggers *triggers)
|
||||||
|
{
|
||||||
|
struct i802_bss *bss = priv;
|
||||||
|
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||||
|
struct nl_msg *msg;
|
||||||
|
struct nlattr *wowlan_triggers;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
msg = nlmsg_alloc();
|
||||||
|
if (!msg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
|
||||||
|
|
||||||
|
nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WOWLAN);
|
||||||
|
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
|
||||||
|
|
||||||
|
wowlan_triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
|
||||||
|
if (!wowlan_triggers)
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
if (triggers->any)
|
||||||
|
NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
|
||||||
|
if (triggers->disconnect)
|
||||||
|
NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
|
||||||
|
if (triggers->magic_pkt)
|
||||||
|
NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
|
||||||
|
if (triggers->gtk_rekey_failure)
|
||||||
|
NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE);
|
||||||
|
if (triggers->eap_identity_req)
|
||||||
|
NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST);
|
||||||
|
if (triggers->four_way_handshake)
|
||||||
|
NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE);
|
||||||
|
if (triggers->rfkill_release)
|
||||||
|
NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE);
|
||||||
|
|
||||||
|
nla_nest_end(msg, wowlan_triggers);
|
||||||
|
|
||||||
|
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
||||||
|
if (ret)
|
||||||
|
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
nlmsg_free(msg);
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
.name = "nl80211",
|
.name = "nl80211",
|
||||||
.desc = "Linux nl80211/cfg80211",
|
.desc = "Linux nl80211/cfg80211",
|
||||||
|
@ -12227,4 +12310,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
#endif /* ANDROID */
|
#endif /* ANDROID */
|
||||||
.vendor_cmd = nl80211_vendor_cmd,
|
.vendor_cmd = nl80211_vendor_cmd,
|
||||||
.set_qos_map = nl80211_set_qos_map,
|
.set_qos_map = nl80211_set_qos_map,
|
||||||
|
.set_wowlan = nl80211_set_wowlan,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2022,6 +2022,7 @@ void wpa_config_free(struct wpa_config *config)
|
||||||
os_free(config->sae_groups);
|
os_free(config->sae_groups);
|
||||||
wpabuf_free(config->ap_vendor_elements);
|
wpabuf_free(config->ap_vendor_elements);
|
||||||
os_free(config->osu_dir);
|
os_free(config->osu_dir);
|
||||||
|
os_free(config->wowlan_triggers);
|
||||||
os_free(config);
|
os_free(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3875,6 +3876,7 @@ static const struct global_parse_data global_fields[] = {
|
||||||
{ INT(sched_scan_interval), 0 },
|
{ INT(sched_scan_interval), 0 },
|
||||||
{ INT(tdls_external_control), 0},
|
{ INT(tdls_external_control), 0},
|
||||||
{ STR(osu_dir), 0 },
|
{ STR(osu_dir), 0 },
|
||||||
|
{ STR(wowlan_triggers), 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef FUNC
|
#undef FUNC
|
||||||
|
|
|
@ -1022,6 +1022,13 @@ struct wpa_config {
|
||||||
* directory.
|
* directory.
|
||||||
*/
|
*/
|
||||||
char *osu_dir;
|
char *osu_dir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wowlan_triggers - Wake-on-WLAN triggers
|
||||||
|
*
|
||||||
|
* If set, these wowlan triggers will be configured.
|
||||||
|
*/
|
||||||
|
char *wowlan_triggers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1155,6 +1155,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
|
||||||
fprintf(f, "tdls_external_control=%d\n",
|
fprintf(f, "tdls_external_control=%d\n",
|
||||||
config->tdls_external_control);
|
config->tdls_external_control);
|
||||||
|
|
||||||
|
if (config->wowlan_triggers)
|
||||||
|
fprintf(f, "wowlan_triggers=\"%s\"\n",
|
||||||
|
config->wowlan_triggers);
|
||||||
|
|
||||||
if (config->bgscan)
|
if (config->bgscan)
|
||||||
fprintf(f, "bgscan=\"%s\"\n", config->bgscan);
|
fprintf(f, "bgscan=\"%s\"\n", config->bgscan);
|
||||||
}
|
}
|
||||||
|
|
|
@ -614,6 +614,14 @@ static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
|
||||||
qos_map_set_len);
|
qos_map_set_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
|
||||||
|
const struct wowlan_triggers *triggers)
|
||||||
|
{
|
||||||
|
if (!wpa_s->driver->set_wowlan)
|
||||||
|
return -1;
|
||||||
|
return wpa_s->driver->set_wowlan(wpa_s->drv_priv, triggers);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s,
|
static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s,
|
||||||
int vendor_id, int subcmd, const u8 *data,
|
int vendor_id, int subcmd, const u8 *data,
|
||||||
size_t data_len, struct wpabuf *buf)
|
size_t data_len, struct wpabuf *buf)
|
||||||
|
|
|
@ -3123,6 +3123,79 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_driver_capa *capa)
|
||||||
|
{
|
||||||
|
struct wowlan_triggers triggers;
|
||||||
|
char *start, *end, *buf;
|
||||||
|
int last, ret;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#undef CHECK_TRIGGER
|
||||||
|
|
||||||
|
ret = wpa_drv_wowlan(wpa_s, &triggers);
|
||||||
|
out:
|
||||||
|
os_free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
|
static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
|
||||||
const char *rn)
|
const char *rn)
|
||||||
{
|
{
|
||||||
|
@ -3650,6 +3723,14 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
|
||||||
if (wpa_bss_init(wpa_s) < 0)
|
if (wpa_bss_init(wpa_s) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set Wake-on-WLAN triggers, if configured.
|
||||||
|
* Note: We don't restore/remove the triggers on shutdown (it doesn't
|
||||||
|
* have effect anyway when the interface is down).
|
||||||
|
*/
|
||||||
|
if (wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
#ifdef CONFIG_EAP_PROXY
|
#ifdef CONFIG_EAP_PROXY
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
Loading…
Reference in a new issue