From 261a70c1fedbfe818956f78aae9c677f4e0fbe7b Mon Sep 17 00:00:00 2001 From: Andrew Dodd Date: Thu, 13 Dec 2012 00:37:26 -0500 Subject: Use legacy NL80211 STA events for older drivers This allows tethering on devices with older bcmdhd drivers to be fixed. It conditionally reverts b638fe75d3cb9d21c67386173f10afe65053cc4d "nl80211: Use native cfg80211 sta events" for these boards. Use BOARD_LEGACY_NL80211_STA_EVENTS to enable this conditional revert. Forward-port to JB MR1, squashed in Steve Kondik's commit to handle additional changes. Change-Id: I4e436c57819944515455725cfd7ac7eeb31552ca --- hostapd/Android.mk | 4 ++ src/drivers/driver_nl80211.c | 121 +++++++++++++++++++++++++++++++++++++- wpa_supplicant/Android.mk | 4 ++ wpa_supplicant/config_ssid.h | 2 +- wpa_supplicant/events.c | 20 ++++++- wpa_supplicant/wpa_supplicant.c | 5 ++ wpa_supplicant/wpa_supplicant_i.h | 4 +- 7 files changed, 154 insertions(+), 6 deletions(-) diff --git a/hostapd/Android.mk b/hostapd/Android.mk index ee153d0..fefc40b 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -28,6 +28,10 @@ ifeq ($(BOARD_WLAN_DEVICE), bcmdhd) L_CFLAGS += -DANDROID_P2P endif +ifeq ($(BOARD_LEGACY_NL80211_STA_EVENTS),true) +L_CFLAGS += -DLEGACY_STA_EVENTS +endif + ifeq ($(BOARD_WLAN_DEVICE), qcwcn) L_CFLAGS += -DANDROID_QCOM_WCN L_CFLAGS += -DANDROID_P2P diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 4574938..5be2d48 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -306,6 +306,11 @@ static int android_pno_start(struct i802_bss *bss, static int android_pno_stop(struct i802_bss *bss); #endif /* ANDROID */ #ifdef ANDROID_P2P +#ifdef LEGACY_STA_EVENTS +static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, + enum wpa_event_type type, + const u8 *frame, size_t len); +#endif /* LEGACY_STA_EVENTS */ 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); @@ -1098,6 +1103,20 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, u16 status; mgmt = (const struct ieee80211_mgmt *) frame; +#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (LEGACY_STA_EVENTS) + if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) { + if (len < 24 + sizeof(mgmt->u.assoc_req)) { + wpa_printf(MSG_DEBUG, "nl80211: Too short association event " + "frame"); + return; + } + os_memset(&event, 0, sizeof(event)); + event.assoc_info.freq = drv->assoc_freq; + event.assoc_info.req_ies = (u8 *) mgmt->u.assoc_req.variable; + event.assoc_info.req_ies_len = len - 24 - sizeof(mgmt->u.assoc_req); + event.assoc_info.addr = mgmt->sa; + } else { +#endif if (len < 24 + sizeof(mgmt->u.assoc_resp)) { wpa_printf(MSG_DEBUG, "nl80211: Too short association event " "frame"); @@ -1132,6 +1151,10 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, event.assoc_info.freq = drv->assoc_freq; +#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (LEGACY_STA_EVENTS) + } +#endif + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } @@ -1304,6 +1327,14 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, event.rx_action.data = &mgmt->u.action.category + 1; event.rx_action.len = frame + len - event.rx_action.data; wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); +#if defined (LEGACY_STA_EVENTS) + } else if (stype == WLAN_FC_STYPE_ASSOC_REQ) { + mlme_event_assoc(drv, frame, len); + } else if (stype == WLAN_FC_STYPE_DISASSOC) { + mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, frame, len); + } else if (stype == WLAN_FC_STYPE_DEAUTH) { + mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, frame, len); +#endif } else { event.rx_mgmt.frame = frame; event.rx_mgmt.frame_len = len; @@ -1389,6 +1420,13 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, if (type == EVENT_DISASSOC) { event.disassoc_info.locally_generated = !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN); + +#if defined (LEGACY_STA_EVENTS) + if (drv->nlmode == NL80211_IFTYPE_AP || + drv->nlmode == NL80211_IFTYPE_P2P_GO) { + event.disassoc_info.addr = mgmt->sa; + } else +#endif event.disassoc_info.addr = bssid; event.disassoc_info.reason_code = reason_code; if (frame + len > mgmt->u.disassoc.variable) { @@ -1399,6 +1437,13 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, } else { event.deauth_info.locally_generated = !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN); + +#if defined (LEGACY_STA_EVENTS) + if (drv->nlmode == NL80211_IFTYPE_AP || + drv->nlmode == NL80211_IFTYPE_P2P_GO) { + event.deauth_info.addr = mgmt->sa; + } else +#endif event.deauth_info.addr = bssid; event.deauth_info.reason_code = reason_code; if (frame + len > mgmt->u.deauth.variable) { @@ -2669,7 +2714,7 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->poll_command_supported = info.poll_command_supported; drv->data_tx_status = info.data_tx_status; -#ifdef ANDROID_P2P +#if defined(ANDROID_P2P) && !defined(LEGACY_STA_EVENTS) if(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) { /* Driver is new enough to support monitorless mode*/ wpa_printf(MSG_DEBUG, "nl80211: Driver is new " @@ -5328,6 +5373,14 @@ static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss, data, data_len, NULL, 1, noack, 1); } +#if defined (LEGACY_STA_EVENTS) + if (freq == 0) + freq = bss->freq; + if ( is_ap_interface(drv->nlmode)) { + return nl80211_send_frame_cmd(bss, freq, 0, + data, data_len, &drv->send_action_cookie, 0, noack, 1); + } +#else if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) { if (freq == 0) @@ -5339,7 +5392,7 @@ static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss, &drv->send_action_cookie, no_cck, noack, offchanok); } - +#endif if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { /* @@ -5567,6 +5620,9 @@ static int wpa_driver_nl80211_set_ap(void *priv, params->short_slot_time, params->ht_opmode, params->isolate, params->basic_rates); } +#if defined(HOSTAPD) && defined(LEGACY_STA_EVENTS) + wpa_driver_nl80211_probe_req_report(priv, 1); +#endif return ret; nla_put_failure: nlmsg_free(msg); @@ -5604,8 +5660,14 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss, NL80211_CHAN_HT40PLUS); break; default: +#if !(defined (ANDROID_P2P) || defined (LEGACY_STA_EVENTS)) +/* Should be change to HT20 as a default value because P2P firmware does not support 11n for BCM4329 */ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20); +#else + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_NO_HT); +#endif break; } } @@ -6329,6 +6391,14 @@ static int nl80211_setup_ap(struct i802_bss *bss) /* Try to survive without this */ } +#if defined (LEGACY_STA_EVENTS) + /* For AP mode, enable probe req report even if device_ap_sme + * is not enabled + */ + wpa_printf(MSG_DEBUG, "nl80211: Enabling probe req report"); + wpa_driver_nl80211_probe_req_report(bss, 1); +#endif + return 0; } @@ -6391,7 +6461,8 @@ static int wpa_driver_nl80211_hapd_send_eapol( u8 *pos; int res; int qos = flags & WPA_STA_WMM; -#ifndef ANDROID_P2P + +#if defined (LEGACY_STA_EVENTS) || !defined (ANDROID_P2P) if (drv->device_ap_sme || !drv->use_monitor) #else if (drv->device_ap_sme && !drv->use_monitor) @@ -8402,7 +8473,51 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report) (WLAN_FC_STYPE_PROBE_REQ << 4), NULL, 0) < 0) goto out_err; +#if defined (LEGACY_STA_EVENTS) + if (drv->nlmode != NL80211_IFTYPE_AP && + drv->nlmode != NL80211_IFTYPE_P2P_GO) { + wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only " + "allowed in AP or P2P GO mode (iftype=%d)", + drv->nlmode); + goto done; + } + if (nl80211_register_frame(bss, bss->nl_preq, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ASSOC_REQ << 4), + NULL, 0) < 0) { + goto out_err; + } + if (nl80211_register_frame(bss, bss->nl_preq, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_REASSOC_REQ << 4), + NULL, 0) < 0) { + goto out_err; + } + + if (nl80211_register_frame(bss, bss->nl_preq, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_DISASSOC << 4), + NULL, 0) < 0) { + goto out_err; + } + + if (nl80211_register_frame(bss, bss->nl_preq, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_DEAUTH << 4), + NULL, 0) < 0) { + goto out_err; + } + + if (nl80211_register_frame(bss, bss->nl_preq, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ACTION << 4), + NULL, 0) < 0) { + goto out_err; + } + +done: +#endif /* ANDROID_P2P */ eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq), wpa_driver_nl80211_event_receive, bss->nl_cb, bss->nl_preq); diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 4f58a92..6d94cb2 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -38,6 +38,10 @@ L_CFLAGS += -DANDROID_QCOM_WCN L_CFLAGS += -DANDROID_P2P endif +ifeq ($(BOARD_LEGACY_NL80211_STA_EVENTS),true) +L_CFLAGS += -DLEGACY_STA_EVENTS +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_ssid.h b/wpa_supplicant/config_ssid.h index ff97379..3c4f3ef 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -458,7 +458,7 @@ struct wpa_ssid { */ int export_keys; -#ifdef ANDROID_P2P +#if defined(ANDROID_P2P) && !defined(LEGACY_STA_EVENTS) /** * assoc_retry - Number of times association should be retried. */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 4b1d992..40aee44 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2531,7 +2531,25 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_assoc_reject(wpa_s, data); #ifdef ANDROID_P2P -#ifdef CONFIG_P2P +#if defined(LEGACY_STA_EVENTS) + /* If assoc reject is reported by the driver, then avoid + * waiting for the authentication timeout. Cancel the + * authentication timeout and retry the assoc. + */ + if(wpa_s->assoc_retries++ < 5) { + wpa_printf(MSG_ERROR, "Retrying assoc " + "Iteration:%d", wpa_s->assoc_retries); + wpa_supplicant_cancel_auth_timeout(wpa_s); + + /* Clear the states */ + wpa_sm_notify_disassoc(wpa_s->wpa); + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 1, 0); + } else + wpa_s->assoc_retries = 0; +#else if defined(CONFIG_P2P) else { if(!wpa_s->current_ssid) { wpa_printf(MSG_ERROR, "current_ssid == NULL"); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index d8f3c44..a54239f 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -647,9 +647,14 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_supplicant_state_txt(state)); #ifdef ANDROID_P2P +#ifdef LEGACY_STA_EVENTS + if(state == WPA_ASSOCIATED || (state <= WPA_INACTIVE)) + wpa_s->assoc_retries = 0; +#else if(state == WPA_ASSOCIATED && wpa_s->current_ssid) { wpa_s->current_ssid->assoc_retry = 0; } +#endif #endif /* ANDROID_P2P */ if (state != WPA_SCANNING) diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 55f3d88..aa97684 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -309,7 +309,9 @@ struct wpa_supplicant { struct wpa_bss *current_bss; int ap_ies_from_associnfo; unsigned int assoc_freq; - +#ifdef LEGACY_STA_EVENTS + unsigned int assoc_retries; +#endif /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ int pairwise_cipher; int group_cipher; -- cgit v1.1