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/hostapd/config_file.c b/hostapd/config_file.c
index 8e6f35a..bf17abe 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1781,6 +1781,8 @@
}
} 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 68c4069..c46dff5 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -389,6 +389,9 @@
# 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 a744ba6..c9b2599 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -243,6 +243,7 @@
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 8205d13..3072562 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -296,19 +296,19 @@
}
-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 70fab55..cfc30ce 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -31,8 +31,8 @@
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 780b2e2..ac67001 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -806,7 +806,8 @@
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 5503af1..35282af 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1818,6 +1818,30 @@
}
+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 @@
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 @@
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 833f1b2..21235f2 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -129,7 +129,7 @@
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 0604fef..160ac0c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -61,6 +61,7 @@
};
#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 @@
#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 @@
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 @@
* @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 bcd0a94..eaecc36 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -310,6 +310,9 @@
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 @@
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_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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
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 c392d57..6b5679c 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -375,14 +375,6 @@
*/
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 e4f7031..29f0b95 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -205,6 +205,7 @@
#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 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 */