From patchwork Thu Apr 24 05:45:39 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilan Peer X-Patchwork-Id: 342102 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from maxx.maxx.shmoo.com (maxx.shmoo.com [205.134.188.171]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4004214019F for ; Thu, 24 Apr 2014 16:44:10 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id BFF929D3FF; Thu, 24 Apr 2014 02:43:34 -0400 (EDT) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zxhjVe6InnEn; Thu, 24 Apr 2014 02:43:34 -0400 (EDT) Received: from maxx.shmoo.com (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id A59AF17C047; Thu, 24 Apr 2014 02:42:37 -0400 (EDT) X-Original-To: mailman-post+hostap@maxx.shmoo.com Delivered-To: mailman-post+hostap@maxx.shmoo.com Received: from localhost (localhost [127.0.0.1]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id A4FD017C047 for ; Thu, 24 Apr 2014 02:42:36 -0400 (EDT) X-Virus-Scanned: amavisd-new at maxx.shmoo.com Received: from maxx.maxx.shmoo.com ([127.0.0.1]) by localhost (maxx.shmoo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 9GqgxurMArKR for ; Thu, 24 Apr 2014 02:42:29 -0400 (EDT) Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by maxx.maxx.shmoo.com (Postfix) with ESMTP id 853C09D2F3 for ; Thu, 24 Apr 2014 02:42:16 -0400 (EDT) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP; 23 Apr 2014 23:42:16 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.97,917,1389772800"; d="scan'208";a="518584166" Received: from unknown (HELO ipeer-e6430-1.jer.intel.com) ([10.12.217.158]) by fmsmga001.fm.intel.com with ESMTP; 23 Apr 2014 23:42:14 -0700 From: Ilan Peer To: hostap@lists.shmoo.com Subject: [PATCH] wpa_supplicant: add wowlan configuration support Date: Thu, 24 Apr 2014 08:45:39 +0300 Message-Id: <1398318340-31142-7-git-send-email-ilan.peer@intel.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1398318340-31142-1-git-send-email-ilan.peer@intel.com> References: <1398318340-31142-1-git-send-email-ilan.peer@intel.com> Cc: Eliad Peller X-BeenThere: hostap@lists.shmoo.com X-Mailman-Version: 2.1.11 Precedence: list List-Id: HostAP Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: hostap-bounces@lists.shmoo.com Errors-To: hostap-bounces@lists.shmoo.com From: Eliad Peller 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 --- src/drivers/driver.h | 15 ++++++++ src/drivers/driver_nl80211.c | 80 +++++++++++++++++++++++++++++++++++++++ wpa_supplicant/config.c | 2 + wpa_supplicant/config.h | 7 ++++ wpa_supplicant/config_file.c | 4 ++ wpa_supplicant/driver_i.h | 8 ++++ wpa_supplicant/wpa_supplicant.c | 80 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 196 insertions(+) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 13bf718..94b5ae6 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -682,6 +682,12 @@ enum hide_ssid { HIDDEN_SSID_ZERO_CONTENTS }; +struct wowlan_triggers { + u8 any, disconnect, magic_pkt, gtk_rekey_failure, + eap_identity_req, four_way_handshake, + rfkill_release; +}; + struct wpa_driver_ap_params { /** * head - Beacon head from IEEE 802.11 header to IEs before TIM IE @@ -1026,6 +1032,8 @@ struct wpa_driver_capa { */ const u8 *extended_capa, *extended_capa_mask; unsigned int extended_capa_len; + + struct wowlan_triggers wowlan_triggers; }; @@ -2513,6 +2521,13 @@ struct wpa_driver_ops { 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 * @priv: Private driver interface data * @signal_info: Connection info structure diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 1300703..ad5cc4d 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -3674,6 +3674,33 @@ static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa, capa->probe_resp_offloads = probe_resp_offload_support(protocols); } +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) { @@ -3798,6 +3825,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; } @@ -12082,6 +12112,55 @@ nla_put_failure: return -ENOBUFS; } +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 = { .name = "nl80211", @@ -12173,4 +12252,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #endif /* ANDROID */ .vendor_cmd = nl80211_vendor_cmd, .set_qos_map = nl80211_set_qos_map, + .set_wowlan = nl80211_set_wowlan, }; diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index b4ee1f5..a5b909d 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2021,6 +2021,7 @@ void wpa_config_free(struct wpa_config *config) os_free(config->sae_groups); wpabuf_free(config->ap_vendor_elements); os_free(config->osu_dir); + os_free(config->wowlan_triggers); os_free(config); } @@ -3867,6 +3868,7 @@ static const struct global_parse_data global_fields[] = { { INT(sched_scan_interval), 0 }, { INT(tdls_external_control), 0}, { STR(osu_dir), 0 }, + { STR(wowlan_triggers), 0 }, }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index a398049..3ab5770 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1014,6 +1014,13 @@ struct wpa_config { * directory. */ char *osu_dir; + + /** + * wowlan_triggers - Wowlan triggers + * + * If set, these wowlan triggers will be configured + */ + char *wowlan_triggers; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 8f0561a..2313d75 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1146,6 +1146,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "tdls_external_control=%d\n", config->tdls_external_control); + if (config->wowlan_triggers) + fprintf(f, "wowlan_triggers=\"%s\"\n", + config->wowlan_triggers); + if (config->bgscan) fprintf(f, "bgscan=\"%s\"\n", config->bgscan); } diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 938ece6..beeb059 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -614,6 +614,14 @@ static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s, 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, int vendor_id, int subcmd, const u8 *data, size_t data_len, struct wpabuf *buf) diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 2cf595f..6e67ef7 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -3120,6 +3120,77 @@ int wpas_init_ext_pw(struct wpa_supplicant *wpa_s) return 0; } +static int wpas_check_wowlan_trigger(const char *start, const char *trigger, + int capa_trigger, u8 *param_trigger) +{ + if (os_strcmp(start, trigger)) + 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, const char *rn) @@ -3648,6 +3719,15 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, if (wpa_bss_init(wpa_s) < 0) return -1; + /* + * set wowlan 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 { size_t len;