Accumulative patch from commit 932659696e2755bb1ecd6a27e1968fd27eef4948
9326596 nl80211: Remove unused WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT
0d08efa P2P: Use the number of concurrent channels in P2P flows
a21816a Use wpa_drv_shared_freq() if get_radio_name() is not supported
53c5dfc Change share_vif_oper_freq() to handle multiple freqs
4752147 nl80211: Report the number of concurrent support channels
d7df0fa Clean up wpa_supplicant_event() with deauth/disassoc helper functions
fd9f170 Remove unnecessary nested ifdef CONFIG_AP
13adc57 IBSS RSN: Add peer restart detection
b21990b nl80211: Register for AUTH frames when joining an IBSS network
c91f796 nl80211: Support not specifying the frame frequency
ec384c5 IBSS RSN: Fix disconnect() with internal SME
ed07764 nl80211: Remove redundant assignment of ifindex
4ed8d95 TDLS: Tear down TDLS using wpas_drv_tlds_oper() if not external
831770b Cancel delayed scheduled scan when wpa_supplicant cleans up
69dd296 WDS: Fix WEP usage with nl80211 wds_sta=1
c8ebeda wpa_supplicant: Add support for VHT BSS membership selector
3f9a813 hostapd: Add a config option to control beaconing
182b2e5 Add missing host_to_le32() for big endian hosts
3f53c00 nl80211: Ignore disconnect event in case of locally generated request
Change-Id: Ia7368e71ae40966a92970ac82b002c09a7971d41
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a24abaf..8edf086 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -577,6 +577,7 @@
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 @@
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 9922e07..5e7dbf7 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -133,7 +133,8 @@
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 d39216f..7c0d2e8 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -551,6 +551,24 @@
}
+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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 687c042..62d68b8 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,48 +439,135 @@
}
-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 ieee80211_mgmt auth;
+ const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
+ struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
+
+ if (wpa_s->driver->send_frame == NULL)
+ return -1;
+
+ 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 -1;
+ return NULL;
- 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;
+ 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 -1;
- }
-
- if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) {
- ibss_rsn_free(peer);
- return -1;
+ 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);
+ }
+
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;
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator "
+ "for now-authenticated peer " MACSTR, MAC2STR(peer->addr));
+
+ return ibss_rsn_auth_init(ibss_rsn, peer);
+}
+
+
void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
{
struct ibss_rsn_peer *peer, *prev;
@@ -617,10 +705,21 @@
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 @@
* 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 @@
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 1da94ab..5a8eda4 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 @@
size_t supp_ie_len;
struct wpa_state_machine *auth;
+ int authentication_status;
};
struct ibss_rsn {
@@ -40,5 +50,7 @@
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 37f5ad3..08ae9e5 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -105,13 +105,64 @@
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 @@
{
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 @@
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 @@
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 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;
+ }
+
+ 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;
}
}
- 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;
- }
+ res = 1;
- return 0;
+exit_free:
+ os_free(freqs);
+ return res;
}
@@ -3891,56 +3915,75 @@
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;
- }
- 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;
+ goto exit_ok;
}
- return 0;
+ 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;
+ }
+ break;
+ }
+
+ 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 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 @@
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 @@
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 @@
"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;
- }
- } 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;
- }
- }
+ freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+ if (!freqs)
+ return -1;
- 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;
- }
- } 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 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);
+ 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;
+ }
+ }
+
+ 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 {
+ for (i = 0; i < num; i++) {
+ if (freqs[i] == freq)
+ break;
+ }
+
+ 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 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 @@
}
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 @@
{
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 @@
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 8cd0f1d..9b6cd46 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -488,44 +488,6 @@
#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 @@
/* 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 @@
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 @@
/**
+ * 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 e892479..2144787 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -15,6 +15,7 @@
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 0371628..925d132 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -805,7 +805,7 @@
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 a7cc507..04404c1 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -25,7 +25,7 @@
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_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 f6b881b..a6bd935 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -421,6 +421,7 @@
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 @@
/* 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 @@
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 @@
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 @@
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 9240863..0858bbc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -722,6 +722,8 @@
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_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 */