diff options
| -rw-r--r-- | hostapd/Android.mk | 12 | ||||
| -rw-r--r-- | src/drivers/driver.h | 19 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 108 | ||||
| -rw-r--r-- | src/rsn_supp/tdls.c | 26 | ||||
| -rw-r--r-- | src/rsn_supp/wpa.h | 1 | ||||
| -rw-r--r-- | wpa_supplicant/Android.mk | 15 | ||||
| -rw-r--r-- | wpa_supplicant/config.c | 2 | ||||
| -rw-r--r-- | wpa_supplicant/config.h | 7 | ||||
| -rw-r--r-- | wpa_supplicant/config_file.c | 6 | ||||
| -rw-r--r-- | wpa_supplicant/ctrl_iface.c | 4 | ||||
| -rw-r--r-- | wpa_supplicant/driver_i.h | 8 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 81 |
12 files changed, 255 insertions, 34 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 74c9b27a..edaf6fc8 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -27,16 +27,10 @@ L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\" # Disable unused parameter warnings L_CFLAGS += -Wno-unused-parameter -ifeq ($(BOARD_WLAN_DEVICE), bcmdhd) -L_CFLAGS += -DANDROID_P2P -endif - -ifeq ($(BOARD_WLAN_DEVICE), qcwcn) -L_CFLAGS += -DANDROID_P2P -endif - -ifeq ($(BOARD_WLAN_DEVICE), mrvl) +# Set Android extended P2P functionality L_CFLAGS += -DANDROID_P2P +ifeq ($(BOARD_HOSTAPD_PRIVATE_LIB),) +L_CFLAGS += -DANDROID_P2P_STUB endif # Use Android specific directory for control interface sockets diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 00565a7b..481ddd65 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -682,6 +682,16 @@ enum hide_ssid { 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 { /** * 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; unsigned int extended_capa_len; + + struct wowlan_triggers wowlan_triggers; }; @@ -2519,6 +2531,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 b0c8a35f..9cbe6f35 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -372,12 +372,29 @@ extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len); #endif /* ANDROID */ #ifdef ANDROID_P2P +#ifdef ANDROID_P2P_STUB +int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) { + return 0; +} +int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) { + return 0; +} +int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) { + return -1; +} +int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp, + const struct wpabuf *assocresp) { + return 0; +} +#else /* ANDROID_P2P_STUB */ int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration); int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len); int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow); int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, const struct wpabuf *proberesp, const struct wpabuf *assocresp); +#endif /* ANDROID_P2P_STUB */ #endif /* ANDROID_P2P */ static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); @@ -3680,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) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -3803,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; } @@ -4824,6 +4873,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0, IF_OPER_UP); + eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx); rfkill_deinit(drv->rfkill); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); @@ -7704,6 +7754,12 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds); } + /* + * Tell cfg80211 that the interface belongs to the socket that created + * it, and the interface should be deleted when the socket is closed. + */ + NLA_PUT_FLAG(msg, NL80211_ATTR_IFACE_SOCKET_OWNER); + ret = send_and_recv_msgs(drv, msg, handler, arg); msg = NULL; if (ret) { @@ -12113,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 = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -12203,4 +12310,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/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index ea293699..3b146560 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -84,6 +84,8 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx); static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer); static void wpa_tdls_disable_peer_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer); +static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, + u16 reason_code); #define TDLS_MAX_IE_LEN 80 @@ -230,9 +232,9 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, struct wpa_tdls_peer *peer; wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u " - "dialog_token=%u status_code=%u msg_len=%u", + "dialog_token=%u status_code=%u peer_capab=%u msg_len=%u", MAC2STR(dest), action_code, dialog_token, status_code, - (unsigned int) msg_len); + peer_capab, (unsigned int) msg_len); if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, status_code, peer_capab, msg, msg_len)) { @@ -677,7 +679,8 @@ static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, } -int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code) +static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, + u16 reason_code) { struct wpa_tdls_peer *peer; struct wpa_tdls_ftie *ftie; @@ -759,9 +762,6 @@ skip_ies: reason_code, 0, rbuf, pos - rbuf); os_free(rbuf); - /* clear the Peerkey statemachine */ - wpa_tdls_peer_free(sm, peer); - return 0; } @@ -1310,14 +1310,15 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, } #endif /* CONFIG_TDLS_TESTING */ +skip_ies: + if (peer->vht_capabilities) peer_capab |= TDLS_PEER_VHT; - else if (peer->ht_capabilities) + if (peer->ht_capabilities) peer_capab |= TDLS_PEER_HT; - else if (peer->wmm_capable) + if (peer->wmm_capable) peer_capab |= TDLS_PEER_WMM; -skip_ies: status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0, peer_capab, rbuf, pos - rbuf); os_free(rbuf); @@ -2462,7 +2463,8 @@ void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr) * Disable previous link to allow renegotiation to be completed * on AP path. */ - wpa_tdls_disable_peer_link(sm, peer); + wpa_tdls_do_teardown(sm, peer, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); } } @@ -2588,8 +2590,8 @@ void wpa_tdls_teardown_peers(struct wpa_sm *sm) wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR, MAC2STR(peer->addr)); if (sm->tdls_external_setup) - wpa_tdls_send_teardown(sm, peer->addr, - WLAN_REASON_DEAUTH_LEAVING); + wpa_tdls_do_teardown(sm, peer, + WLAN_REASON_DEAUTH_LEAVING); else wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 61d441a9..e98967c9 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -379,7 +379,6 @@ void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len); void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len); int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr); void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr); -int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code); int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code); int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr); int wpa_tdls_init(struct wpa_sm *sm); diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index f56267c8..ca9d82d5 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -27,24 +27,21 @@ L_CFLAGS += -DANDROID_LOG_NAME=\"wpa_supplicant\" # Disable unused parameter warnings L_CFLAGS += -Wno-unused-parameter +# Set Android extended P2P functionality +L_CFLAGS += -DANDROID_P2P +ifeq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),) +L_CFLAGS += -DANDROID_P2P_STUB +endif + # Disable roaming in wpa_supplicant ifdef CONFIG_NO_ROAMING L_CFLAGS += -DCONFIG_NO_ROAMING endif ifeq ($(BOARD_WLAN_DEVICE), bcmdhd) -L_CFLAGS += -DANDROID_P2P L_CFLAGS += -DP2P_CONCURRENT_SEARCH_DELAY=0 endif -ifeq ($(BOARD_WLAN_DEVICE), qcwcn) -L_CFLAGS += -DANDROID_P2P -endif - -ifeq ($(BOARD_WLAN_DEVICE), mrvl) -L_CFLAGS += -DANDROID_P2P -endif - # Use Android specific directory for control interface sockets L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/wpa_supplicant\" diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 698b4592..b5a5d788 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2022,6 +2022,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); } @@ -3875,6 +3876,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 26b1233a..bf3f3f79 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1022,6 +1022,13 @@ struct wpa_config { * directory. */ char *osu_dir; + + /** + * wowlan_triggers - Wake-on-WLAN 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 38429467..3cfe5ba9 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -775,7 +775,7 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) for (i = 0; i < cred->num_domain; i++) fprintf(f, "\tdomain=\"%s\"\n", cred->domain[i]); if (cred->domain_suffix_match) - fprintf(f, "\tdomain_suffix_match=\"%s\"", + fprintf(f, "\tdomain_suffix_match=\"%s\"\n", cred->domain_suffix_match); if (cred->roaming_consortium_len) { fprintf(f, "\troaming_consortium="); @@ -1155,6 +1155,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/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index b8b6d951..14664df0 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -5534,7 +5534,7 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd, data_len /= 2; data = os_malloc(data_len); if (!data) - return -ENOBUFS; + return -1; if (hexstr2bin(pos, data, data_len)) { wpa_printf(MSG_DEBUG, @@ -5547,7 +5547,7 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd, reply = wpabuf_alloc((buflen - 1) / 2); if (!reply) { os_free(data); - return -ENOBUFS; + return -1; } ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len, diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 938ece69..beeb0590 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 af7b847b..f56b198b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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, 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) 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 { size_t len; |
