diff options
| -rw-r--r-- | hostapd/config_file.c | 2 | ||||
| -rw-r--r-- | hostapd/hostapd.conf | 3 | ||||
| -rw-r--r-- | src/ap/ap_config.h | 1 | ||||
| -rw-r--r-- | src/ap/ap_drv_ops.c | 8 | ||||
| -rw-r--r-- | src/ap/ap_drv_ops.h | 4 | ||||
| -rw-r--r-- | src/ap/hostapd.c | 3 | ||||
| -rw-r--r-- | src/ap/ieee802_11.c | 44 | ||||
| -rw-r--r-- | src/ap/sta_info.c | 2 | ||||
| -rw-r--r-- | src/drivers/driver.h | 13 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 66 | ||||
| -rw-r--r-- | src/p2p/p2p.h | 8 | ||||
| -rw-r--r-- | src/utils/common.h | 1 | ||||
| -rw-r--r-- | wpa_supplicant/ctrl_iface.c | 11 | ||||
| -rw-r--r-- | wpa_supplicant/driver_i.h | 3 | ||||
| -rw-r--r-- | wpa_supplicant/events.c | 304 | ||||
| -rw-r--r-- | wpa_supplicant/ibss_rsn.c | 232 | ||||
| -rw-r--r-- | wpa_supplicant/ibss_rsn.h | 12 | ||||
| -rw-r--r-- | wpa_supplicant/p2p_supplicant.c | 382 | ||||
| -rw-r--r-- | wpa_supplicant/scan.c | 97 | ||||
| -rw-r--r-- | wpa_supplicant/scan.h | 1 | ||||
| -rw-r--r-- | wpa_supplicant/sme.c | 2 | ||||
| -rw-r--r-- | wpa_supplicant/sme.h | 4 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 77 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant_i.h | 5 |
24 files changed, 862 insertions, 423 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 8e6f35a5..bf17abec 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1781,6 +1781,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "wds_sta") == 0) { bss->wds_sta = atoi(pos); + } else if (os_strcmp(buf, "start_disabled") == 0) { + bss->start_disabled = atoi(pos); } else if (os_strcmp(buf, "ap_isolate") == 0) { bss->isolate = atoi(pos); } else if (os_strcmp(buf, "ap_max_inactivity") == 0) { diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 68c40694..c46dff5d 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -389,6 +389,9 @@ wmm_ac_vo_acm=0 # use a separate bridge. #wds_bridge=wds-br0 +# Start the AP with beaconing disabled by default. +#start_disabled=0 + # Client isolation can be used to prevent low-level bridging of frames between # associated stations in the BSS. By default, this bridging is allowed. #ap_isolate=1 diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index a744ba62..c9b25992 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -243,6 +243,7 @@ struct hostapd_bss_config { int num_deny_mac; int wds_sta; int isolate; + int start_disabled; int auth_algs; /* bitfield of allowed IEEE 802.11 authentication * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 8205d132..3072562e 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -296,19 +296,19 @@ int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname) } -int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, - int val) +int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds, + const u8 *addr, int aid, int val) { const char *bridge = NULL; if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL) - return 0; + return -1; if (hapd->conf->wds_bridge[0]) bridge = hapd->conf->wds_bridge; else if (hapd->conf->bridge[0]) bridge = hapd->conf->bridge; return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val, - bridge); + bridge, ifname_wds); } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 70fab553..cfc30ce4 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -31,8 +31,8 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, int enabled); int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname); int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname); -int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, - int val); +int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds, + const u8 *addr, int aid, int val); int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 780b2e2e..ac670015 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -806,7 +806,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - ieee802_11_set_beacon(hapd); + if (!hapd->conf->start_disabled) + ieee802_11_set_beacon(hapd); if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) return -1; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 5503af15..35282af0 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1818,6 +1818,30 @@ static void handle_auth_cb(struct hostapd_data *hapd, } +static void hostapd_set_wds_encryption(struct hostapd_data *hapd, + struct sta_info *sta, + char *ifname_wds) +{ + int i; + struct hostapd_ssid *ssid = sta->ssid; + + if (hapd->conf->ieee802_1x || hapd->conf->wpa) + return; + + for (i = 0; i < 4; i++) { + if (ssid->wep.key[i] && + hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i, + i == ssid->wep.idx, NULL, 0, + ssid->wep.key[i], ssid->wep.len[i])) { + wpa_printf(MSG_WARNING, + "Could not set WEP keys for WDS interface; %s", + ifname_wds); + break; + } + } +} + + static void handle_assoc_cb(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int reassoc, int ok) @@ -1920,8 +1944,15 @@ static void handle_assoc_cb(struct hostapd_data *hapd, goto fail; } - if (sta->flags & WLAN_STA_WDS) - hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1); + if (sta->flags & WLAN_STA_WDS) { + int ret; + char ifname_wds[IFNAMSIZ + 1]; + + ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr, + sta->aid, 1); + if (!ret) + hostapd_set_wds_encryption(hapd, sta, ifname_wds); + } if (sta->eapol_sm == NULL) { /* @@ -2162,11 +2193,18 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, return; if (wds && !(sta->flags & WLAN_STA_WDS)) { + int ret; + char ifname_wds[IFNAMSIZ + 1]; + wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for " "STA " MACSTR " (aid %u)", MAC2STR(sta->addr), sta->aid); sta->flags |= WLAN_STA_WDS; - hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1); + ret = hostapd_set_wds_sta(hapd, ifname_wds, + sta->addr, sta->aid, 1); + if (!ret) + hostapd_set_wds_encryption(hapd, sta, + ifname_wds); } return; } diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 833f1b23..21235f25 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -129,7 +129,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) ap_sta_set_authorized(hapd, sta, 0); if (sta->flags & WLAN_STA_WDS) - hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0); + hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); if (!(sta->flags & WLAN_STA_PREAUTH)) hostapd_drv_sta_remove(hapd, sta->addr); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 0604fefb..160ac0c7 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -61,6 +61,7 @@ struct hostapd_channel_data { }; #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0) +#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1) /** * struct hostapd_hw_modes - Supported hardware mode information @@ -832,8 +833,7 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE 0x00000400 /* This interface is P2P capable (P2P GO or P2P Client) */ #define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800 -/* Driver supports concurrent operations on multiple channels */ -#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT 0x00001000 +/* unused: 0x00001000 */ /* * Driver uses the initial interface for P2P management interface and non-P2P * purposes (e.g., connect to infra AP), but this interface cannot be used for @@ -911,6 +911,11 @@ struct wpa_driver_capa { unsigned int max_acl_mac_addrs; /** + * Number of supported concurrent channels + */ + unsigned int num_multichan_concurrent; + + /** * extended_capa - extended capabilities in driver/device * * Must be allocated and freed by driver and the pointers must be @@ -2049,10 +2054,12 @@ struct wpa_driver_ops { * @val: 1 = bind to 4-address WDS; 0 = unbind * @bridge_ifname: Bridge interface to use for the WDS station or %NULL * to indicate that bridge is not to be used + * @ifname_wds: Buffer to return the interface name for the new WDS + * station or %NULL to indicate name is not returned. * Returns: 0 on success, -1 on failure */ int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val, - const char *bridge_ifname); + const char *bridge_ifname, char *ifname_wds); /** * send_action - Transmit an Action frame diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index bcd0a94d..eaecc36c 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -310,6 +310,9 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, u64 *cookie, int no_cck, int no_ack, int offchanok); +static int nl80211_register_frame(struct i802_bss *bss, + struct nl_handle *hl_handle, + u16 type, const u8 *match, size_t match_len); static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report); #ifdef ANDROID @@ -1067,7 +1070,6 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv, return 1; if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) { - drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname); wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed " "interface"); wpa_driver_nl80211_finish_drv_init(drv); @@ -1829,12 +1831,19 @@ static void mlme_event_michael_mic_failure(struct i802_bss *bss, static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, struct nlattr *tb[]) { + u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4); + if (tb[NL80211_ATTR_MAC] == NULL) { wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined " "event"); return; } os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + /* register for any AUTH message */ + nl80211_register_frame(&drv->first_bss, drv->first_bss.nl_mgmt, + type, NULL, 0); + drv->associated = 1; wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined", MAC2STR(drv->bssid)); @@ -2881,6 +2890,8 @@ struct wiphy_info_data { struct wpa_driver_nl80211_data *drv; struct wpa_driver_capa *capa; + unsigned int num_multichan_concurrent; + unsigned int error:1; unsigned int device_ap_sme:1; unsigned int poll_command_supported:1; @@ -2891,7 +2902,6 @@ struct wiphy_info_data { unsigned int p2p_go_supported:1; unsigned int p2p_client_supported:1; unsigned int p2p_concurrent:1; - unsigned int p2p_multichan_concurrent:1; }; @@ -3001,8 +3011,8 @@ static int wiphy_info_iface_comb_process(struct wiphy_info_data *info, if (combination_has_p2p && combination_has_mgd) { info->p2p_concurrent = 1; - if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1) - info->p2p_multichan_concurrent = 1; + info->num_multichan_concurrent = + nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]); return 1; } @@ -3252,10 +3262,11 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; } - if (info->p2p_multichan_concurrent) { + if (info->num_multichan_concurrent > 1) { wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel " "concurrent (driver advertised support)"); - drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT; + drv->capa.num_multichan_concurrent = + info->num_multichan_concurrent; } /* default to 5000 since early versions of mac80211 don't set it */ @@ -5189,12 +5200,20 @@ nla_put_failure: static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, int reason_code) { + int ret; + wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code); nl80211_mark_disconnected(drv); - drv->ignore_next_local_disconnect = 0; /* Disconnect command doesn't need BSSID - it uses cached value */ - return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT, - reason_code, 0); + ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT, + reason_code, 0); + /* + * For locally generated disconnect, supplicant already generates a + * DEAUTH event, so ignore the event from NL80211. + */ + drv->ignore_next_local_disconnect = ret == 0; + + return ret; } @@ -5674,7 +5693,20 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band) mode = &phy_info->modes[*(phy_info->num_modes)]; os_memset(mode, 0, sizeof(*mode)); mode->mode = NUM_HOSTAPD_MODES; - mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN; + mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN | + HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN; + + /* + * Unsupported VHT MCS stream is defined as value 3, so the VHT + * MCS RX/TX map must be initialized with 0xffff to mark all 8 + * possible streams as unsupported. This will be overridden if + * driver advertises VHT support. + */ + mode->vht_mcs_set[0] = 0xff; + mode->vht_mcs_set[1] = 0xff; + mode->vht_mcs_set[4] = 0xff; + mode->vht_mcs_set[5] = 0xff; + *(phy_info->num_modes) += 1; phy_info->last_mode = nl_band->nla_type; phy_info->last_chan_idx = 0; @@ -7835,8 +7867,6 @@ static int wpa_driver_nl80211_connect( if (wpa_driver_nl80211_disconnect( drv, WLAN_REASON_PREV_AUTH_NOT_VALID)) return -1; - /* Ignore the next local disconnect message. */ - drv->ignore_next_local_disconnect = 1; ret = wpa_driver_nl80211_try_connect(drv, params); } return ret; @@ -8690,13 +8720,16 @@ static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, - const char *bridge_ifname) + const char *bridge_ifname, char *ifname_wds) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; char name[IFNAMSIZ + 1]; os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); + if (ifname_wds) + os_strlcpy(ifname_wds, name, IFNAMSIZ + 1); + wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name); if (val) { @@ -9216,12 +9249,13 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss, wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d " "no_ack=%d offchanok=%d", freq, wait, no_cck, no_ack, offchanok); + wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len); nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME); if (nl80211_set_iface_id(msg, bss) < 0) goto nla_put_failure; - - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + if (freq) + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); if (wait) NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait); if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX)) @@ -9809,7 +9843,7 @@ static int nl80211_set_param(void *priv, const char *param) struct wpa_driver_nl80211_data *drv = bss->drv; wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel " "concurrency"); - drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT; + drv->capa.num_multichan_concurrent = 2; } #endif #endif /* CONFIG_P2P */ diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index c392d571..6b5679c8 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -375,14 +375,6 @@ struct p2p_config { */ unsigned int max_listen; -#ifdef ANDROID_P2P - enum p2p_concurrency_type { - P2P_NON_CONCURRENT, - P2P_SINGLE_CHANNEL_CONCURRENT, - P2P_MULTI_CHANNEL_CONCURRENT, - } p2p_concurrency; -#endif - /** * cb_ctx - Context to use with callback functions */ diff --git a/src/utils/common.h b/src/utils/common.h index e4f70313..29f0b953 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -205,6 +205,7 @@ static inline unsigned int wpa_swap_32(unsigned int v) #define be_to_host16(n) (n) #define host_to_be16(n) (n) #define le_to_host32(n) bswap_32(n) +#define host_to_le32(n) bswap_32(n) #define be_to_host32(n) (n) #define host_to_be32(n) (n) #define le_to_host64(n) bswap_64(n) diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index a24abaf1..8edf0869 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -577,6 +577,7 @@ static int wpa_supplicant_ctrl_iface_tdls_teardown( struct wpa_supplicant *wpa_s, char *addr) { u8 peer[ETH_ALEN]; + int ret; if (hwaddr_aton(addr, peer)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid " @@ -587,8 +588,14 @@ static int wpa_supplicant_ctrl_iface_tdls_teardown( wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR, MAC2STR(peer)); - return wpa_tdls_teardown_link(wpa_s->wpa, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); + if (wpa_tdls_is_external_setup(wpa_s->wpa)) + ret = wpa_tdls_teardown_link( + wpa_s->wpa, peer, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); + else + ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); + + return ret; } #endif /* CONFIG_TDLS */ diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 9922e072..5e7dbf73 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -133,7 +133,8 @@ static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s, const u8 *addr, int reason_code) { if (wpa_s->driver->sta_deauth) { - return wpa_s->driver->sta_deauth(wpa_s->drv_priv, NULL, addr, + return wpa_s->driver->sta_deauth(wpa_s->drv_priv, + wpa_s->own_addr, addr, reason_code); } return -1; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index d39216f2..7c0d2e8f 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -551,6 +551,24 @@ static int ht_supported(const struct hostapd_hw_modes *mode) } +static int vht_supported(const struct hostapd_hw_modes *mode) +{ + if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) { + /* + * The driver did not indicate whether it supports VHT. Assume + * it does to avoid connection issues. + */ + return 1; + } + + /* + * A VHT non-AP STA shall support MCS 0-7 for one spatial stream. + * TODO: Verify if this complies with the standard + */ + return (mode->vht_mcs_set[0] & 0x3) != 3; +} + + static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { const struct hostapd_hw_modes *mode = NULL, *modes; @@ -616,6 +634,18 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) continue; } + /* There's also a VHT selector for 802.11ac */ + if (flagged && ((rate_ie[j] & 0x7f) == + BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) { + if (!vht_supported(mode)) { + wpa_dbg(wpa_s, MSG_DEBUG, + " hardware does not support " + "VHT PHY"); + return 0; + } + continue; + } + if (!flagged) continue; @@ -2311,6 +2341,23 @@ static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s, ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer); } + + +static void wpa_supplicant_event_ibss_auth(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (ssid == NULL) + return; + + /* check if the ssid is correctly configured as IBSS/RSN */ + if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt)) + return; + + ibss_rsn_handle_auth(wpa_s->ibss_rsn, data->rx_mgmt.frame, + data->rx_mgmt.frame_len); +} #endif /* CONFIG_IBSS_RSN */ @@ -2394,12 +2441,141 @@ static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s, } +static void wpas_event_disconnect(struct wpa_supplicant *wpa_s, const u8 *addr, + u16 reason_code, int locally_generated, + const u8 *ie, size_t ie_len, int deauth) +{ +#ifdef CONFIG_AP + if (wpa_s->ap_iface && addr) { + hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], addr); + return; + } + + if (wpa_s->ap_iface) { + wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in AP mode"); + return; + } +#endif /* CONFIG_AP */ + + wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated); + + if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED || + ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || + (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) && + eapol_sm_failed(wpa_s->eapol))) + wpas_auth_failed(wpa_s); + +#ifdef CONFIG_P2P + if (deauth && ie && ie_len > 0) { + if (wpas_p2p_deauth_notif(wpa_s, addr, reason_code, ie, ie_len, + locally_generated) > 0) { + /* + * The interface was removed, so cannot continue + * processing any additional operations after this. + */ + return; + } + } +#endif /* CONFIG_P2P */ + + wpa_supplicant_event_disassoc_finish(wpa_s, reason_code, + locally_generated); +} + + +static void wpas_event_disassoc(struct wpa_supplicant *wpa_s, + struct disassoc_info *info) +{ + u16 reason_code = 0; + int locally_generated = 0; + const u8 *addr = NULL; + const u8 *ie = NULL; + size_t ie_len = 0; + + wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification"); + + if (info) { + addr = info->addr; + ie = info->ie; + ie_len = info->ie_len; + reason_code = info->reason_code; + locally_generated = info->locally_generated; + wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", reason_code, + locally_generated ? " (locally generated)" : ""); + if (addr) + wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR, + MAC2STR(addr)); + wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)", + ie, ie_len); + } + +#ifdef CONFIG_AP + if (wpa_s->ap_iface && info && info->addr) { + hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], info->addr); + return; + } + + if (wpa_s->ap_iface) { + wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in AP mode"); + return; + } +#endif /* CONFIG_AP */ + +#ifdef CONFIG_P2P + if (info) { + wpas_p2p_disassoc_notif( + wpa_s, info->addr, reason_code, info->ie, info->ie_len, + locally_generated); + } +#endif /* CONFIG_P2P */ + + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) + sme_event_disassoc(wpa_s, info); + + wpas_event_disconnect(wpa_s, addr, reason_code, locally_generated, + ie, ie_len, 0); +} + + +static void wpas_event_deauth(struct wpa_supplicant *wpa_s, + struct deauth_info *info) +{ + u16 reason_code = 0; + int locally_generated = 0; + const u8 *addr = NULL; + const u8 *ie = NULL; + size_t ie_len = 0; + + wpa_dbg(wpa_s, MSG_DEBUG, "Deauthentication notification"); + + if (info) { + addr = info->addr; + ie = info->ie; + ie_len = info->ie_len; + reason_code = info->reason_code; + locally_generated = info->locally_generated; + wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", + reason_code, + locally_generated ? " (locally generated)" : ""); + if (addr) { + wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR, + MAC2STR(addr)); + } + wpa_hexdump(MSG_DEBUG, "Deauthentication frame IE(s)", + ie, ie_len); + } + + wpa_reset_ft_completed(wpa_s->wpa); + + wpas_event_disconnect(wpa_s, addr, reason_code, + locally_generated, ie, ie_len, 1); +} + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct wpa_supplicant *wpa_s = ctx; - u16 reason_code = 0; - int locally_generated = 0; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && event != EVENT_INTERFACE_ENABLED && @@ -2438,109 +2614,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_supplicant_event_assoc(wpa_s, data); break; case EVENT_DISASSOC: - wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification"); - if (data) { - wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", - data->disassoc_info.reason_code, - data->disassoc_info.locally_generated ? - " (locally generated)" : ""); - if (data->disassoc_info.addr) - wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR, - MAC2STR(data->disassoc_info.addr)); - } -#ifdef CONFIG_AP - if (wpa_s->ap_iface && data && data->disassoc_info.addr) { - hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], - data->disassoc_info.addr); - break; - } - if (wpa_s->ap_iface) { - wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in " - "AP mode"); - break; - } -#endif /* CONFIG_AP */ - if (data) { - reason_code = data->disassoc_info.reason_code; - locally_generated = - data->disassoc_info.locally_generated; - wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)", - data->disassoc_info.ie, - data->disassoc_info.ie_len); -#ifdef CONFIG_P2P - wpas_p2p_disassoc_notif( - wpa_s, data->disassoc_info.addr, reason_code, - data->disassoc_info.ie, - data->disassoc_info.ie_len, - locally_generated); -#endif /* CONFIG_P2P */ - } - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) - sme_event_disassoc(wpa_s, data); - /* fall through */ + wpas_event_disassoc(wpa_s, + data ? &data->disassoc_info : NULL); + break; case EVENT_DEAUTH: - if (event == EVENT_DEAUTH) { - wpa_dbg(wpa_s, MSG_DEBUG, - "Deauthentication notification"); - if (data) { - reason_code = data->deauth_info.reason_code; - locally_generated = - data->deauth_info.locally_generated; - wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", - data->deauth_info.reason_code, - data->deauth_info.locally_generated ? - " (locally generated)" : ""); - if (data->deauth_info.addr) { - wpa_dbg(wpa_s, MSG_DEBUG, " * address " - MACSTR, - MAC2STR(data->deauth_info. - addr)); - } - wpa_hexdump(MSG_DEBUG, - "Deauthentication frame IE(s)", - data->deauth_info.ie, - data->deauth_info.ie_len); - } - wpa_reset_ft_completed(wpa_s->wpa); - } -#ifdef CONFIG_AP - if (wpa_s->ap_iface && data && data->deauth_info.addr) { - hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], - data->deauth_info.addr); - break; - } - if (wpa_s->ap_iface) { - wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in " - "AP mode"); - break; - } -#endif /* CONFIG_AP */ - wpa_supplicant_event_disassoc(wpa_s, reason_code, - locally_generated); - if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED || - ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || - (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) && - eapol_sm_failed(wpa_s->eapol))) - wpas_auth_failed(wpa_s); -#ifdef CONFIG_P2P - if (event == EVENT_DEAUTH && data) { - if (wpas_p2p_deauth_notif(wpa_s, - data->deauth_info.addr, - reason_code, - data->deauth_info.ie, - data->deauth_info.ie_len, - locally_generated) > 0) { - /* - * The interface was removed, so cannot - * continue processing any additional - * operations after this. - */ - break; - } - } -#endif /* CONFIG_P2P */ - wpa_supplicant_event_disassoc_finish(wpa_s, reason_code, - locally_generated); + wpas_event_deauth(wpa_s, + data ? &data->deauth_info : NULL); break; case EVENT_MICHAEL_MIC_FAILURE: wpa_supplicant_event_michael_mic_failure(wpa_s, data); @@ -2740,12 +2819,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } -#ifdef CONFIG_AP wpas_ap_ch_switch(wpa_s, data->ch_switch.freq, data->ch_switch.ht_enabled, data->ch_switch.ch_offset); -#endif /* CONFIG_AP */ break; +#endif /* CONFIG_AP */ +#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN) case EVENT_RX_MGMT: { u16 fc, stype; const struct ieee80211_mgmt *mgmt; @@ -2755,7 +2834,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, fc = le_to_host16(mgmt->frame_control); stype = WLAN_FC_GET_STYPE(fc); +#ifdef CONFIG_AP if (wpa_s->ap_iface == NULL) { +#endif /* CONFIG_AP */ #ifdef CONFIG_P2P if (stype == WLAN_FC_STYPE_PROBE_REQ && data->rx_mgmt.frame_len > 24) { @@ -2771,9 +2852,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } #endif /* CONFIG_P2P */ +#ifdef CONFIG_IBSS_RSN + if (stype == WLAN_FC_STYPE_AUTH && + data->rx_mgmt.frame_len >= 30) { + wpa_supplicant_event_ibss_auth(wpa_s, data); + break; + } +#endif /* CONFIG_IBSS_RSN */ wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received " "management frame in non-AP mode"); break; +#ifdef CONFIG_AP } if (stype == WLAN_FC_STYPE_PROBE_REQ && @@ -2789,9 +2878,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } ap_mgmt_rx(wpa_s, &data->rx_mgmt); +#endif /* CONFIG_AP */ break; } -#endif /* CONFIG_AP */ +#endif /* CONFIG_AP || CONFIG_IBSS_RSN */ case EVENT_RX_ACTION: wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR " Category=%u DataLen=%d freq=%d MHz", diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 687c042f..62d68b8b 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -15,6 +15,7 @@ #include "ap/wpa_auth.h" #include "wpa_supplicant_i.h" #include "driver_i.h" +#include "common/ieee802_11_defs.h" #include "ibss_rsn.h" @@ -438,45 +439,132 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, } -int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) +static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq) { - struct ibss_rsn_peer *peer; + struct ieee80211_mgmt auth; + const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth); + struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; - if (ibss_rsn == NULL) + if (wpa_s->driver->send_frame == NULL) return -1; - if (ibss_rsn_get_peer(ibss_rsn, addr)) { - wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant " - "for peer " MACSTR " already running", - MAC2STR(addr)); - return 0; + os_memset(&auth, 0, sizeof(auth)); + + auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_AUTH); + os_memcpy(auth.da, da, ETH_ALEN); + os_memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN); + + auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN); + auth.u.auth.auth_transaction = host_to_le16(seq); + auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS); + + wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR, + seq, MAC2STR(da)); + + return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth, + auth_length, 0); +} + + +static int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer) +{ + return peer->authentication_status & + (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US); +} + + +static struct ibss_rsn_peer * +ibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr) +{ + struct ibss_rsn_peer *peer; + if (ibss_rsn == NULL) + return NULL; + + peer = ibss_rsn_get_peer(ibss_rsn, addr); + if (peer) { + wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR + " already running", MAC2STR(addr)); + return peer; } - wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and " - "Supplicant for peer " MACSTR, MAC2STR(addr)); + wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR, + MAC2STR(addr)); peer = os_zalloc(sizeof(*peer)); - if (peer == NULL) - return -1; + if (peer == NULL) { + wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory."); + return NULL; + } peer->ibss_rsn = ibss_rsn; os_memcpy(peer->addr, addr, ETH_ALEN); + peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED; - if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk) - < 0) { + if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, + ibss_rsn->psk) < 0) { ibss_rsn_free(peer); + return NULL; + } + + peer->next = ibss_rsn->peers; + ibss_rsn->peers = peer; + + return peer; +} + + +int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) +{ + struct ibss_rsn_peer *peer; + int res; + + /* if the peer already exists, exit immediately */ + peer = ibss_rsn_get_peer(ibss_rsn, addr); + if (peer) + return 0; + + peer = ibss_rsn_peer_init(ibss_rsn, addr); + if (peer == NULL) return -1; + + /* Open Authentication: send first Authentication frame */ + res = ibss_rsn_send_auth(ibss_rsn, addr, 1); + if (res) { + /* + * The driver may not support Authentication frame exchange in + * IBSS. Ignore authentication and go through EAPOL exchange. + */ + peer->authentication_status |= IBSS_RSN_AUTH_BY_US; + return ibss_rsn_auth_init(ibss_rsn, peer); } - if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) { - ibss_rsn_free(peer); + return 0; +} + + +static int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn, + struct ibss_rsn_peer *peer, int reason) +{ + int already_started; + + if (ibss_rsn == NULL || peer == NULL) return -1; + + already_started = ibss_rsn_is_auth_started(peer); + peer->authentication_status |= reason; + + if (already_started) { + wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already " + "started for peer " MACSTR, MAC2STR(peer->addr)); + return 0; } - peer->next = ibss_rsn->peers; - ibss_rsn->peers = peer; + wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator " + "for now-authenticated peer " MACSTR, MAC2STR(peer->addr)); - return 0; + return ibss_rsn_auth_init(ibss_rsn, peer); } @@ -617,10 +705,21 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, return -1; os_memcpy(tmp, buf, len); if (supp) { - wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant"); + peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER; + wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from " + MACSTR, MAC2STR(peer->addr)); wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len); } else { - wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator"); + if (ibss_rsn_is_auth_started(peer) == 0) { + wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for " + "Authenticator dropped as " MACSTR " is not " + "authenticated", MAC2STR(peer->addr)); + os_free(tmp); + return -1; + } + + wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator " + "from "MACSTR, MAC2STR(peer->addr)); wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len); } os_free(tmp); @@ -646,8 +745,16 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, * Create new IBSS peer based on an EAPOL message from the peer * Authenticator. */ - if (ibss_rsn_start(ibss_rsn, src_addr) < 0) + peer = ibss_rsn_peer_init(ibss_rsn, src_addr); + if (peer == NULL) return -1; + + /* assume the peer is authenticated already */ + wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer " + MACSTR, MAC2STR(src_addr)); + ibss_rsn_peer_authenticated(ibss_rsn, peer, + IBSS_RSN_AUTH_EAPOL_BY_US); + return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers, buf, len); } @@ -655,10 +762,89 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, return 0; } - void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk) { if (ibss_rsn == NULL) return; os_memcpy(ibss_rsn->psk, psk, PMK_LEN); } + + +static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, + struct ibss_rsn_peer *peer, + const u8* addr) +{ + wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR, + MAC2STR(addr)); + + if (peer && + peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) { + /* + * A peer sent us an Authentication frame even though it already + * started an EAPOL session. We should reinit state machines + * here, but it's much more complicated than just deleting and + * recreating the state machine + */ + wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station " + MACSTR, MAC2STR(addr)); + + ibss_rsn_stop(ibss_rsn, addr); + peer = NULL; + } + + if (!peer) { + peer = ibss_rsn_peer_init(ibss_rsn, addr); + if (!peer) + return; + + wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR, + MAC2STR(addr)); + } + + /* reply with an Authentication frame now, before sending an EAPOL */ + ibss_rsn_send_auth(ibss_rsn, addr, 2); + /* no need to start another AUTH challenge in the other way.. */ + ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US); +} + + +void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame, + size_t len) +{ + const struct ieee80211_mgmt *header; + struct ibss_rsn_peer *peer; + size_t auth_length; + + header = (const struct ieee80211_mgmt *) auth_frame; + auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth); + + if (ibss_rsn == NULL || len < auth_length) + return; + + if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN || + le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS) + return; + + peer = ibss_rsn_get_peer(ibss_rsn, header->sa); + + switch (le_to_host16(header->u.auth.auth_transaction)) { + case 1: + ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa); + break; + case 2: + wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from " + MACSTR, MAC2STR(header->sa)); + if (!peer) { + wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from " + "unknown STA " MACSTR, MAC2STR(header->sa)); + break; + } + + /* authentication has been completed */ + wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with "MACSTR, + MAC2STR(header->sa)); + ibss_rsn_peer_authenticated(ibss_rsn, peer, + IBSS_RSN_AUTH_BY_US); + break; + } +} diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h index 1da94ab8..5a8eda4b 100644 --- a/wpa_supplicant/ibss_rsn.h +++ b/wpa_supplicant/ibss_rsn.h @@ -11,6 +11,15 @@ struct ibss_rsn; +/* not authenticated */ +#define IBSS_RSN_AUTH_NOT_AUTHENTICATED 0x00 +/* remote peer sent an EAPOL message */ +#define IBSS_RSN_AUTH_EAPOL_BY_PEER 0x01 +/* we sent an AUTH message with seq 1 */ +#define IBSS_RSN_AUTH_BY_US 0x02 +/* we sent an EAPOL message */ +#define IBSS_RSN_AUTH_EAPOL_BY_US 0x04 + struct ibss_rsn_peer { struct ibss_rsn_peer *next; struct ibss_rsn *ibss_rsn; @@ -23,6 +32,7 @@ struct ibss_rsn_peer { size_t supp_ie_len; struct wpa_state_machine *auth; + int authentication_status; }; struct ibss_rsn { @@ -40,5 +50,7 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac); int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, const u8 *buf, size_t len); void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk); +void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame, + size_t len); #endif /* IBSS_RSN_H */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 37f5ad3a..08ae9e54 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -105,13 +105,64 @@ static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s); +/* + * Get the number of concurrent channels that the HW can operate, but that are + * currently not in use by any of the wpa_supplicant interfaces. + */ +static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s) +{ + int *freqs; + int num; + + freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); + if (!freqs) + return -1; + + num = get_shared_radio_freqs(wpa_s, freqs, + wpa_s->num_multichan_concurrent); + os_free(freqs); + + return wpa_s->num_multichan_concurrent - num; +} + + +/* + * Get the frequencies that are currently in use by one or more of the virtual + * interfaces, and that are also valid for P2P operation. + */ +static int wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s, + int *p2p_freqs, unsigned int len) +{ + int *freqs; + unsigned int num, i, j; + + freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); + if (!freqs) + return -1; + + num = get_shared_radio_freqs(wpa_s, freqs, + wpa_s->num_multichan_concurrent); + + os_memset(p2p_freqs, 0, sizeof(int) * len); + + for (i = 0, j = 0; i < num && j < len; i++) { + if (p2p_supported_freq(wpa_s->global->p2p, freqs[i])) + p2p_freqs[j++] = freqs[i]; + } + + os_free(freqs); + + return j; +} + + static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s, int freq) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; - if (freq > 0 && - (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) && + if (freq > 0 && wpa_s->num_multichan_concurrent > 1 && + wpas_p2p_num_unused_channels(wpa_s) > 0 && wpa_s->parent->conf->p2p_ignore_shared_freq) freq = 0; p2p_set_own_freq_preference(wpa_s->global->p2p, freq); @@ -2473,7 +2524,6 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *s; - u8 cur_bssid[ETH_ALEN]; int res; struct wpa_supplicant *grp; @@ -2550,25 +2600,15 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, accept_inv: wpas_p2p_set_own_freq_preference(wpa_s, 0); - if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 && - wpa_s->assoc_freq) { - wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match " - "the channel we are already using"); - *force_freq = wpa_s->assoc_freq; - wpas_p2p_set_own_freq_preference(wpa_s, wpa_s->assoc_freq); - } - - res = wpa_drv_shared_freq(wpa_s); - if (res > 0) { - wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match " - "with the channel we are already using on a " - "shared interface"); + /* Get one of the frequencies currently in use */ + if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) { + wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match a channel already used by one of the interfaces"); *force_freq = res; wpas_p2p_set_own_freq_preference(wpa_s, res); } - if (*force_freq > 0 && - (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) { + if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 && + wpas_p2p_num_unused_channels(wpa_s) > 0) { if (*go == 0) { /* We are the client */ wpa_printf(MSG_DEBUG, "P2P: Peer was found to be " @@ -3268,17 +3308,6 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.max_listen = wpa_s->max_remain_on_chan; -#ifdef ANDROID_P2P - if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) { - p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT; - wpa_printf(MSG_DEBUG, "P2P: Multi channel concurrency support"); - } else { - // Add support for WPA_DRIVER_FLAGS_P2P_CONCURRENT - p2p.p2p_concurrency = P2P_SINGLE_CHANNEL_CONCURRENT; - wpa_printf(MSG_DEBUG, "P2P: Single channel concurrency support"); - } -#endif - global->p2p = p2p_init(&p2p); if (global->p2p == NULL) return -1; @@ -3475,43 +3504,38 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s) static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq) { - struct wpa_supplicant *iface; - int shared_freq; - u8 bssid[ETH_ALEN]; + int *freqs, res, num, i; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) + if (wpas_p2p_num_unused_channels(wpa_s) > 0) { + /* Multiple channels are supported and not all are in use */ return 0; + } - for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { - if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s) - continue; - if (iface->current_ssid == NULL || iface->assoc_freq == 0) - continue; - if (iface->current_ssid->mode == WPAS_MODE_AP || - iface->current_ssid->mode == WPAS_MODE_P2P_GO) - shared_freq = iface->current_ssid->frequency; - else if (wpa_drv_get_bssid(iface, bssid) == 0) - shared_freq = iface->assoc_freq; - else - shared_freq = 0; + freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); + if (!freqs) + return 1; - if (shared_freq && freq != shared_freq) { - wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s " - "connected on %d MHz - new connection on " - "%d MHz", iface->ifname, shared_freq, freq); - return 1; - } + num = wpas_p2p_valid_oper_freqs(wpa_s, freqs, + wpa_s->num_multichan_concurrent); + if (num < 0) { + res = 1; + goto exit_free; } - shared_freq = wpa_drv_shared_freq(wpa_s); - if (shared_freq > 0 && shared_freq != freq) { - wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared " - "virtual interface connected on %d MHz - new " - "connection on %d MHz", shared_freq, freq); - return 1; + for (i = 0; i < num; i++) { + if (freqs[i] == freq) { + wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used", + freq); + res = 0; + goto exit_free; + } } - return 0; + res = 1; + +exit_free: + os_free(freqs); + return res; } @@ -3891,56 +3915,75 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, - int *force_freq, int *pref_freq, - int *oper_freq) + int *force_freq, int *pref_freq) { + int *freqs, res; + unsigned int freq_in_use = 0, num, i; + + freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); + if (!freqs) + return -1; + + num = get_shared_radio_freqs(wpa_s, freqs, + wpa_s->num_multichan_concurrent); + if (freq > 0) { if (!p2p_supported_freq(wpa_s->global->p2p, freq)) { wpa_printf(MSG_DEBUG, "P2P: The forced channel " "(%u MHz) is not supported for P2P uses", freq); - return -3; + res = -3; + goto exit_free; } - if (*oper_freq > 0 && freq != *oper_freq && - !(wpa_s->drv_flags & - WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) { - wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group " - "on %u MHz while connected on another " - "channel (%u MHz)", freq, *oper_freq); - return -2; + for (i = 0; i < num; i++) { + if (freqs[i] == freq) + freq_in_use = 1; + } + + if (num == wpa_s->num_multichan_concurrent && !freq_in_use) { + wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels", + freq); + res = -2; + goto exit_free; } wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the " "requested channel (%u MHz)", freq); *force_freq = freq; - } else if (*oper_freq > 0 && - !p2p_supported_freq(wpa_s->global->p2p, *oper_freq)) { - if (!(wpa_s->drv_flags & - WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) { - wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group " - "while connected on non-P2P supported " - "channel (%u MHz)", *oper_freq); - return -2; + goto exit_ok; + } + + for (i = 0; i < num; i++) { + if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i])) + continue; + + wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use", + *force_freq); + *force_freq = freqs[i]; + + if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) { + wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency we are already using"); + *pref_freq = *force_freq; } - wpa_printf(MSG_DEBUG, "P2P: Current operating channel " - "(%u MHz) not available for P2P - try to use " - "another channel", *oper_freq); - *force_freq = 0; - } else if (*oper_freq > 0 && *pref_freq == 0 && - (wpa_s->drv_flags & - WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) { - wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we " - "are already using (%u MHz) on another interface", - *oper_freq); - *pref_freq = *oper_freq; - } else if (*oper_freq > 0) { - wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the " - "channel we are already using (%u MHz) on another " - "interface", *oper_freq); - *force_freq = *oper_freq; + break; } - return 0; + if (i == num) { + if (num < wpa_s->num_multichan_concurrent) { + wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel"); + *force_freq = 0; + } else { + wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group"); + res = -2; + goto exit_free; + } + } + +exit_ok: + res = 0; +exit_free: + os_free(freqs); + return res; } @@ -3972,8 +4015,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int go_intent, int freq, int persistent_id, int pd, int ht40) { - int force_freq = 0, pref_freq = 0, oper_freq = 0; - u8 bssid[ETH_ALEN]; + int force_freq = 0, pref_freq = 0; int ret = 0, res; enum wpa_driver_if_type iftype; const u8 *if_addr; @@ -4045,20 +4087,10 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return ret; } - if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 && - wpa_s->assoc_freq) { - oper_freq = wpa_s->assoc_freq; - } else { - oper_freq = wpa_drv_shared_freq(wpa_s); - if (oper_freq < 0) - oper_freq = 0; - } - - res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq, - &oper_freq); + res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq); if (res) return res; - wpas_p2p_set_own_freq_preference(wpa_s, oper_freq); + wpas_p2p_set_own_freq_preference(wpa_s, force_freq); wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s); @@ -4259,9 +4291,9 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, int freq, int ht40, const struct p2p_channels *channels) { - u8 bssid[ETH_ALEN]; - int res; + int res, *freqs; unsigned int pref_freq; + unsigned int num, i; os_memset(params, 0, sizeof(*params)); params->role_go = 1; @@ -4341,64 +4373,54 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, "known)", params->freq); } - if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 && - wpa_s->assoc_freq && !freq) { - if (!p2p_supported_freq(wpa_s->global->p2p, wpa_s->assoc_freq) - || !freq_included(channels, wpa_s->assoc_freq)) { - if (wpa_s->drv_flags & - WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) { - wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on " - "the channel we are already using " - "(%u MHz) - allow multi-channel " - "concurrency", wpa_s->assoc_freq); - } else { - wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on " - "the channel we are already using " - "(%u MHz)", wpa_s->assoc_freq); - return -1; + freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); + if (!freqs) + return -1; + + res = wpas_p2p_valid_oper_freqs(wpa_s, freqs, + wpa_s->num_multichan_concurrent); + if (res < 0) { + os_free(freqs); + return -1; + } + num = res; + + if (!freq) { + for (i = 0; i < num; i++) { + if (freq_included(channels, freqs[i])) { + wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)", + freqs[i]); + params->freq = freqs[i]; + break; } - } else { - wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we " - "are already using (%u MHz)", - wpa_s->assoc_freq); - params->freq = wpa_s->assoc_freq; } - } - res = wpa_drv_shared_freq(wpa_s); - if (res > 0 && !freq && - (!p2p_supported_freq(wpa_s->global->p2p, res) || - !freq_included(channels, res))) { - if (wpa_s->drv_flags & - WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) { - wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the " - "channel we are already using on a shared " - "interface (%u MHz) - allow multi-channel " - "concurrency", res); - } else { - wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the " - "channel we are already using on a shared " - "interface (%u MHz)", res); - return -1; + if (i == num) { + if (num == wpa_s->num_multichan_concurrent) { + wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using"); + os_free(freqs); + return -1; + } else { + wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels"); + } } - } else if (res > 0 && !freq) { - wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are " - "already using on a shared interface"); - params->freq = res; - if (!freq_included(channels, params->freq)) { - wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not " - "accepted", params->freq); - return -1; + } else { + for (i = 0; i < num; i++) { + if (freqs[i] == freq) + break; } - } else if (res > 0 && freq != res && - !(wpa_s->drv_flags & - WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) { - wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz " - "while connected on another channel (%u MHz)", - freq, res); - return -1; - } + if (i == num) { + if (num == wpa_s->num_multichan_concurrent) { + wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq); + os_free(freqs); + return -1; + } else { + wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels"); + } + } + } + os_free(freqs); return 0; } @@ -5002,8 +5024,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int ht40, int pref_freq) { enum p2p_invite_role role; - u8 *bssid = NULL, bssid_buf[ETH_ALEN]; - int force_freq = 0, oper_freq = 0; + u8 *bssid = NULL; + int force_freq = 0; int res; wpa_s->global->p2p_invite_group = NULL; @@ -5038,19 +5060,7 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, } wpa_s->pending_invite_ssid_id = ssid->id; - if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 && - wpa_s->assoc_freq) { - oper_freq = wpa_s->assoc_freq; - if (bssid == NULL) - bssid = bssid_buf; - } else { - oper_freq = wpa_drv_shared_freq(wpa_s); - if (oper_freq < 0) - oper_freq = 0; - } - - res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq, - &oper_freq); + res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq); if (res) return res; @@ -5074,10 +5084,10 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, { struct wpa_global *global = wpa_s->global; enum p2p_invite_role role; - u8 *bssid = NULL, bssid_buf[ETH_ALEN]; + u8 *bssid = NULL; struct wpa_ssid *ssid; int persistent; - int force_freq = 0, oper_freq = 0, pref_freq = 0; + int force_freq = 0, pref_freq = 0; int res; wpa_s->p2p_persistent_go_freq = 0; @@ -5131,22 +5141,10 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; - if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 && - wpa_s->assoc_freq) { - oper_freq = wpa_s->assoc_freq; - if (bssid == NULL) - bssid = bssid_buf; - } else { - oper_freq = wpa_drv_shared_freq(wpa_s); - if (oper_freq < 0) - oper_freq = 0; - } - - res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq, - &oper_freq); + res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq); if (res) return res; - wpas_p2p_set_own_freq_preference(wpa_s, oper_freq); + wpas_p2p_set_own_freq_preference(wpa_s, force_freq); return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, force_freq, diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 8cd0f1d2..9b6cd466 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -488,44 +488,6 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s) #endif /* CONFIG_P2P */ -/* - * Find the operating frequency of any other virtual interface that is using - * the same radio concurrently. - */ -static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s) -{ - const char *rn, *rn2; - struct wpa_supplicant *ifs; - u8 bssid[ETH_ALEN]; - - if (!wpa_s->driver->get_radio_name) - return -1; - - rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv); - if (rn == NULL || rn[0] == '\0') - return -1; - - for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { - if (ifs == wpa_s || !ifs->driver->get_radio_name) - continue; - - rn2 = ifs->driver->get_radio_name(ifs->drv_priv); - if (!rn2 || os_strcmp(rn, rn2) != 0) - continue; - - if (ifs->current_ssid == NULL || ifs->assoc_freq == 0) - continue; - - if (ifs->current_ssid->mode == WPAS_MODE_AP || - ifs->current_ssid->mode == WPAS_MODE_P2P_GO) - return ifs->current_ssid->frequency; - if (wpa_drv_get_bssid(ifs, bssid) == 0) - return ifs->assoc_freq; - } - - return 0; -} - static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, u16 num_modes, @@ -828,14 +790,19 @@ ssid_list_set: /* Use current associated channel? */ if (wpa_s->conf->scan_cur_freq && !params.freqs) { - int freq = shared_vif_oper_freq(wpa_s); - if (freq > 0) { - wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current " - "operating channel (%d MHz) since " - "scan_cur_freq is enabled", freq); - params.freqs = os_zalloc(sizeof(int) * 2); - if (params.freqs) - params.freqs[0] = freq; + unsigned int num = wpa_s->num_multichan_concurrent; + + params.freqs = os_calloc(num + 1, sizeof(int)); + if (params.freqs) { + num = get_shared_radio_freqs(wpa_s, params.freqs, num); + if (num > 0) { + wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the " + "current operating channels since " + "scan_cur_freq is enabled"); + } else { + os_free(params.freqs); + params.freqs = NULL; + } } } @@ -873,18 +840,19 @@ scan: if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ && !scan_params->freqs && !params.freqs && wpas_is_p2p_prioritized(wpa_s) && - !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) && wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE && non_p2p_network_enabled(wpa_s)) { - int freq = shared_vif_oper_freq(wpa_s); - if (freq > 0) { - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current " - "operating channel (%d MHz) since driver does " - "not support multi-channel concurrency", freq); - params.freqs = os_zalloc(sizeof(int) * 2); - if (params.freqs) - params.freqs[0] = freq; - scan_params->freqs = params.freqs; + unsigned int num = wpa_s->num_multichan_concurrent; + + params.freqs = os_calloc(num + 1, sizeof(int)); + if (params.freqs) { + num = get_shared_radio_freqs(wpa_s, params.freqs, num); + if (num > 0 && num == wpa_s->num_multichan_concurrent) { + wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used"); + } else { + os_free(params.freqs); + params.freqs = NULL; + } } } #endif /* CONFIG_P2P */ @@ -1249,6 +1217,23 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) /** + * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan + * @wpa_s: Pointer to wpa_supplicant data + * + * This function is used to stop a delayed scheduled scan. + */ +void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->sched_scan_supported) + return; + + wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan"); + eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout, + wpa_s, NULL); +} + + +/** * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans * @wpa_s: Pointer to wpa_supplicant data * diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index e892479f..2144787b 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -15,6 +15,7 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s, int sec, int usec); int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s); void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s); +void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s); void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s); void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, int scanning); diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 03716280..925d1320 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -805,7 +805,7 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s, void sme_event_disassoc(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) + struct disassoc_info *info) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received"); if (wpa_s->sme.prev_bssid_set) { diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h index a7cc507e..04404c18 100644 --- a/wpa_supplicant/sme.h +++ b/wpa_supplicant/sme.h @@ -25,7 +25,7 @@ void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s, void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s, union wpa_event_data *data); void sme_event_disassoc(struct wpa_supplicant *wpa_s, - union wpa_event_data *data); + struct disassoc_info *info); void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *da, u16 reason_code); void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa, @@ -74,7 +74,7 @@ static inline void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s, } static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) + struct disassoc_info *info) { } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index f6b881b1..a6bd935c 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -421,6 +421,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_bss_deinit(wpa_s); + wpa_supplicant_cancel_delayed_sched_scan(wpa_s); wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_cancel_auth_timeout(wpa_s); eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL); @@ -1630,7 +1631,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, /* If multichannel concurrency is not supported, check for any frequency * conflict and take appropriate action. */ - if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) && + if ((wpa_s->num_multichan_concurrent < 2) && ((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq)) { wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)" , freq, params.freq); @@ -2985,6 +2986,8 @@ next_driver: wpa_s->extended_capa = capa.extended_capa; wpa_s->extended_capa_mask = capa.extended_capa_mask; wpa_s->extended_capa_len = capa.extended_capa_len; + wpa_s->num_multichan_concurrent = + capa.num_multichan_concurrent; } if (wpa_s->max_remain_on_chan == 0) wpa_s->max_remain_on_chan = 1000; @@ -2999,6 +3002,9 @@ next_driver: else iface->p2p_mgmt = 1; + if (wpa_s->num_multichan_concurrent == 0) + wpa_s->num_multichan_concurrent = 1; + if (wpa_supplicant_driver_init(wpa_s) < 0) return -1; @@ -3957,3 +3963,72 @@ int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s) return 0; } + + +/* + * Find the operating frequencies of any of the virtual interfaces that + * are using the same radio as the current interface. + */ +int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, + int *freq_array, unsigned int len) +{ + const char *rn, *rn2; + struct wpa_supplicant *ifs; + u8 bssid[ETH_ALEN]; + int freq; + unsigned int idx = 0, i; + + os_memset(freq_array, 0, sizeof(int) * len); + + /* First add the frequency of the local interface */ + if (wpa_s->current_ssid != NULL && wpa_s->assoc_freq != 0) { + if (wpa_s->current_ssid->mode == WPAS_MODE_AP || + wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO) + freq_array[idx++] = wpa_s->current_ssid->frequency; + else if (wpa_drv_get_bssid(wpa_s, bssid) == 0) + freq_array[idx++] = wpa_s->assoc_freq; + } + + /* If get_radio_name is not supported, use only the local freq */ + if (!wpa_s->driver->get_radio_name) { + freq = wpa_drv_shared_freq(wpa_s); + if (freq > 0 && idx < len && + (idx == 0 || freq_array[0] != freq)) + freq_array[idx++] = freq; + return idx; + } + + rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv); + if (rn == NULL || rn[0] == '\0') + return idx; + + for (ifs = wpa_s->global->ifaces, idx = 0; ifs && idx < len; + ifs = ifs->next) { + if (wpa_s == ifs || !ifs->driver->get_radio_name) + continue; + + rn2 = ifs->driver->get_radio_name(ifs->drv_priv); + if (!rn2 || os_strcmp(rn, rn2) != 0) + continue; + + if (ifs->current_ssid == NULL || ifs->assoc_freq == 0) + continue; + + if (ifs->current_ssid->mode == WPAS_MODE_AP || + ifs->current_ssid->mode == WPAS_MODE_P2P_GO) + freq = ifs->current_ssid->frequency; + else if (wpa_drv_get_bssid(ifs, bssid) == 0) + freq = ifs->assoc_freq; + else + continue; + + /* Hold only distinct freqs */ + for (i = 0; i < idx; i++) + if (freq_array[i] == freq) + break; + + if (i == idx) + freq_array[idx++] = freq; + } + return idx; +} diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 92408631..0858bbc0 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -722,6 +722,8 @@ struct wpa_supplicant { u8 last_gtk[32]; size_t last_gtk_len; #endif /* CONFIG_TESTING_GET_GTK */ + + unsigned int num_multichan_concurrent; }; @@ -860,4 +862,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_init_ext_pw(struct wpa_supplicant *wpa_s); +int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, + int *freq_array, unsigned int len); + #endif /* WPA_SUPPLICANT_I_H */ |
