Cumulative patch from commit a313d17de943cbaf12cbf67d666af14791be8ad2
a313d17 Extend random MAC address support to allow OUI to be kept
1cbdb9d Add helper function for generating random MAC addresses with same OUI
97ed9a0 nl80211: Remove bridge FDB entry upon sta_remove()
39323bc AP: hostapd_setup_bss() code clean-up
1595eb9 P2P: Add support for 60 GHz social channel
b6ebdfb Extend STATUS command with frequency information
375f4a3 hostapd: Avoid dead code with P2P not enabled
6a60488 dbus: Add a global property to set or unset WFD IEs
4bd7e16 wifi_display: Add a utility function to set WFD subelements from IEs
d417744 wifi_display: Add a utility function to get the sub-elements as IEs
a8833b8 util: Don't use "\e"
8c6f4a5 ap_config.c: fix typo for "capabilities"
6e252b0 WPS: Fix WPS-in-search check when STA_AUTOCONNECT is disabled
e5fdc05 P2P: Remove unecessary sanity check for global p2p
ee285df P2P: Flush services based on global p2p init and not p2p ifaces
7139cf4 P2P: Decrement sd_pending_bcast_queries when sd returns success
dbdc9a1 nl80211: Fix memory leak on start radar detection error path
ed8e005 hostap: nl80211 use nl80211_put_freq_params
c267753 Add support for using random local MAC address
4d8fb63 Add helper function for generating random MAC addresses
fee354c nl80211: Add command for changing local MAC address
e49cabc P2P: Set timeout when starting GO Negotiation from Probe Req RX
7549c17 P2P: Clear pending_listen_freq when starting GO Neg/Invite
b497a21 nl80211: Ignore auth/assoc events when testing driver-SME
79e2b1c Add PMKSA_FLUSH ctrl_iface command
55c2bfa wpa_cli: Support action scripts with global ctrl_iface
063f850 wpa_cli: Increase event buffer size to 4096 bytes
fa0e917 wpa_cli: Fix PING in interactive mode with ifname_prefix
c53a9bf Check for driver's DFS offload capability before handling DFS
068e387 STA: Update scan results for ap_scan=1 skip-selection case also
7a4a93b dbus: Add SignalPoll() method to report current signal properties
a6ab82d Android: Add NO_EVENTS parameter to status command
df2508d P2P: Check os_get_random() return value more consistently
54461f3 RADIUS server: Remove unreachable code
e4474c1 FT: Fix hostapd with driver-based SME to authorize the STA
0800f9e nl80211: Add roaming policy update using QCA vendor command
0ef023e Add support for driver command to update roaming policy
0cd9846 nl80211: Print debug info on STA flag changes
17e2091 P2P: Fix radio work issue with wait-for-peer GO Negotiation
76db5b6 Work around broken AP PMKSA caching implementation
b08d5fa WPS: Set EAPOL workarounds dynamically based on association
8511a0f WPS: Extend internal entropy pool help for key/snonce derivation
abc0553 Remove WPA_EVENT_SCAN_STARTED message from MSG_INFO log
c45dabb P2P: Deauth p2p client just after dbus notify
3ee1856 nl80211: Register eloop after hs20 action frame
3bd3257 dbus: add BSS Age property to indicate last-seen time
5c61d21 openssl: Fix memory leak in openssl ec deinit
10e7948 Fix hostapd GET_CONFIG wpa_pairwise_cipher value
3a413e0 RADIUS client: Check getsockname() return value
9c196f7 HTTP: Fix OCSP status check
cb5ef95 SME: Verify that os_get_random() succeeds for SA Query
c9cd78e RADIUS server: Fix IPv6 radiusAuthClientAddress mask
5e62cfd P2P: Verify that os_get_random() succeeds
6473e80 EAP-PAX server: Add explicit CID length limit
6a6566c Remove unnecessarily shadowed local variable
df756b3 hostapd: Remove unused variable assignment
e47abdb TDLS: Decline Setup Request with status code 37 if BSSID does not match
ce2002a TDLS: Add RSN and Timeout interval IEs in TDLS Discovery Response frame
1c2aa04 P2P: Do not add P2P IEs on P2P disabled interface
f2e9083 nl80211: Add more RTM_NEWLINK/DELLINK debug messages
728ff2f nl80211: Fix RTM_DELLINK processing for bridge events
e5a4b85 WPS: Merge mixed-WPA/WPA2 credentials if received in same session
db9418b Add printf NULL checks to silence static analyzer
4e53675 P2P: Overwrite pending interface only after verifying BSS entry
04a258e hostapd: Check that EVENT_ASSOC data is present before using it
1cc0d6a wpa_supplicant: Use freq_list scan filtar in sched_scan
Change-Id: Ibc18f6761b3ccfe8fb4479f26f53e70942068bc8
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 4c0e3f8..44de826 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3178,7 +3178,6 @@
struct hostapd_config * hostapd_config_read(const char *fname)
{
struct hostapd_config *conf;
- struct hostapd_bss_config *bss;
FILE *f;
char buf[512], *pos;
int line = 0;
@@ -3207,9 +3206,11 @@
return NULL;
}
- bss = conf->last_bss = conf->bss[0];
+ conf->last_bss = conf->bss[0];
while (fgets(buf, sizeof(buf), f)) {
+ struct hostapd_bss_config *bss;
+
bss = conf->last_bss;
line++;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 9ce7829..591c395 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1010,7 +1010,7 @@
return pos - buf;
pos += ret;
- ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
+ ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
" ");
if (ret < 0)
return pos - buf;
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 1c4a84c..09b7284 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -844,6 +844,8 @@
hostapd_cli_close_connection();
os_free(ctrl_ifname);
ctrl_ifname = os_strdup(argv[0]);
+ if (ctrl_ifname == NULL)
+ return -1;
if (hostapd_cli_open_connection(ctrl_ifname)) {
printf("Connected to interface '%s.\n", ctrl_ifname);
diff --git a/hostapd/main.c b/hostapd/main.c
index af4d85d..c3af704 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -99,14 +99,15 @@
else if (hapd && hapd->conf)
os_snprintf(format, maxlen, "%s:%s%s %s",
hapd->conf->iface, module_str ? " " : "",
- module_str, txt);
+ module_str ? module_str : "", txt);
else if (addr)
os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
MAC2STR(addr), module_str ? " " : "",
- module_str, txt);
+ module_str ? module_str : "", txt);
else
os_snprintf(format, maxlen, "%s%s%s",
- module_str, module_str ? ": " : "", txt);
+ module_str ? module_str : "",
+ module_str ? ": " : "", txt);
if ((conf_stdout & module) && level >= conf_stdout_level) {
wpa_debug_print_timestamp();
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index d127550..c7da69e 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -761,7 +761,7 @@
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
- "allowed, disabling HT capabilites");
+ "allowed, disabling HT capabilities");
}
if (full_config && conf->ieee80211n &&
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index b3b6149..4cae0d9 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -113,6 +113,10 @@
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
return eid;
+ /* Let host drivers add this IE if DFS support is offloaded */
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return eid;
+
/*
* There is no DFS support and power constraint was not directly
* requested by config option.
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 93804de..3bde720 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -340,6 +340,9 @@
sta->auth_alg, req_ies, req_ies_len);
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+
+ if (sta->auth_alg == WLAN_AUTH_FT)
+ ap_sta_set_authorized(hapd, sta, 1);
#else /* CONFIG_IEEE80211R */
/* Keep compiler silent about unused variables */
if (status) {
@@ -350,6 +353,8 @@
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
+ hostapd_set_sta_flags(hapd, sta);
+
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
else
@@ -1044,6 +1049,8 @@
data->eapol_rx.data_len);
break;
case EVENT_ASSOC:
+ if (!data)
+ return;
hostapd_notif_assoc(hapd, data->assoc_info.addr,
data->assoc_info.req_ies,
data->assoc_info.req_ies_len,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 26aca2b..3142391 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -693,10 +693,10 @@
u8 if_addr[ETH_ALEN];
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
- __func__, hapd, hapd->conf->iface, first);
+ __func__, hapd, conf->iface, first);
#ifdef EAP_SERVER_TNC
- if (hapd->conf->tnc && tncs_global_init() < 0) {
+ if (conf->tnc && tncs_global_init() < 0) {
wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
return -1;
}
@@ -704,37 +704,37 @@
if (hapd->started) {
wpa_printf(MSG_ERROR, "%s: Interface %s was already started",
- __func__, hapd->conf->iface);
+ __func__, conf->iface);
return -1;
}
hapd->started = 1;
if (!first || first == -1) {
- if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
+ if (hostapd_mac_comp_empty(conf->bssid) == 0) {
/* Allocate the next available BSSID. */
do {
inc_byte_array(hapd->own_addr, ETH_ALEN);
} while (mac_in_conf(hapd->iconf, hapd->own_addr));
} else {
/* Allocate the configured BSSID. */
- os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
+ os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
if (hostapd_mac_comp(hapd->own_addr,
hapd->iface->bss[0]->own_addr) ==
0) {
wpa_printf(MSG_ERROR, "BSS '%s' may not have "
"BSSID set to the MAC address of "
- "the radio", hapd->conf->iface);
+ "the radio", conf->iface);
return -1;
}
}
hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
- hapd->conf->iface, hapd->own_addr, hapd,
+ conf->iface, hapd->own_addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
- hapd->conf->bridge[0] ? hapd->conf->bridge :
- NULL, first == -1)) {
+ conf->bridge[0] ? conf->bridge : NULL,
+ first == -1)) {
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
MACSTR ")", MAC2STR(hapd->own_addr));
hapd->interface_added = 0;
@@ -749,7 +749,7 @@
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
- if (hostapd_setup_encryption(hapd->conf->iface, hapd))
+ if (hostapd_setup_encryption(conf->iface, hapd))
return -1;
/*
@@ -783,9 +783,8 @@
if (!hostapd_drv_none(hapd)) {
wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
" and ssid \"%s\"",
- hapd->conf->iface, MAC2STR(hapd->own_addr),
- wpa_ssid_txt(hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len));
+ conf->iface, MAC2STR(hapd->own_addr),
+ wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
}
if (hostapd_setup_wpa_psk(conf)) {
@@ -810,17 +809,17 @@
return -1;
}
- if (hapd->conf->radius_das_port) {
+ if (conf->radius_das_port) {
struct radius_das_conf das_conf;
os_memset(&das_conf, 0, sizeof(das_conf));
- das_conf.port = hapd->conf->radius_das_port;
- das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+ das_conf.port = conf->radius_das_port;
+ das_conf.shared_secret = conf->radius_das_shared_secret;
das_conf.shared_secret_len =
- hapd->conf->radius_das_shared_secret_len;
- das_conf.client_addr = &hapd->conf->radius_das_client_addr;
- das_conf.time_window = hapd->conf->radius_das_time_window;
+ conf->radius_das_shared_secret_len;
+ das_conf.client_addr = &conf->radius_das_client_addr;
+ das_conf.time_window = conf->radius_das_time_window;
das_conf.require_event_timestamp =
- hapd->conf->radius_das_require_event_timestamp;
+ conf->radius_das_require_event_timestamp;
das_conf.ctx = hapd;
das_conf.disconnect = hostapd_das_disconnect;
hapd->radius_das = radius_das_init(&das_conf);
@@ -847,7 +846,7 @@
return -1;
}
- if ((hapd->conf->wpa || hapd->conf->osen) && hostapd_setup_wpa(hapd))
+ if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd))
return -1;
if (accounting_init(hapd)) {
@@ -855,8 +854,8 @@
return -1;
}
- if (hapd->conf->ieee802_11f &&
- (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
+ if (conf->ieee802_11f &&
+ (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
"failed.");
return -1;
@@ -881,7 +880,7 @@
return -1;
}
- if (!hapd->conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
+ if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
return -1;
if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
@@ -1182,12 +1181,15 @@
iface->conf->channel, iface->freq);
#ifdef NEED_AP_MLME
- /* Check DFS */
- res = hostapd_handle_dfs(iface);
- if (res <= 0) {
- if (res < 0)
- goto fail;
- return res;
+ /* Handle DFS only if it is not offloaded to the driver */
+ if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) {
+ /* Check DFS */
+ res = hostapd_handle_dfs(iface);
+ if (res <= 0) {
+ if (res < 0)
+ goto fail;
+ return res;
+ }
}
#endif /* NEED_AP_MLME */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 60f0768..efd2a72 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -956,12 +956,12 @@
dev_addr = addr;
} else
dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
-#endif /* CONFIG_P2P */
if (dev_addr)
os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else
+#endif /* CONFIG_P2P */
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
if (authorized) {
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 4d9efd5..de0b222 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -32,6 +32,13 @@
*
* @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event
*
+ * @QCA_NL80211_VENDOR_SUBCMD_ROAMING: Set roaming policy for drivers that use
+ * internal BSS-selection. This command uses
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY to specify the new roaming policy
+ * for the current connection (i.e., changes policy set by the nl80211
+ * Connect command). @QCA_WLAN_VENDOR_ATTR_MAC_ADDR may optionally be
+ * included to indicate which BSS to use in case roaming is disabled.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency
* ranges to avoid to reduce issues due to interference or internal
* co-existence information in the driver. The event data structure is
@@ -47,7 +54,8 @@
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
QCA_NL80211_VENDOR_SUBCMD_TEST = 1,
- /* subcmds 2..9 not yet allocated */
+ /* subcmds 2..8 not yet allocated */
+ QCA_NL80211_VENDOR_SUBCMD_ROAMING = 9,
QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11,
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
@@ -66,9 +74,19 @@
QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3,
/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
QCA_WLAN_VENDOR_ATTR_IFINDEX = 4,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_ROAMING, u32 with values defined
+ * by enum qca_roaming_policy. */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
+ QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
};
+
+enum qca_roaming_policy {
+ QCA_ROAMING_NOT_ALLOWED,
+ QCA_ROAMING_ALLOWED_WITHIN_ESS,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index f02aaac..8876ebf 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1067,6 +1067,7 @@
if (e == NULL)
return;
BN_clear_free(e->order);
+ BN_clear_free(e->prime);
EC_GROUP_free(e->group);
BN_CTX_free(e->bnctx);
os_free(e);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 352c163..501314b 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2804,6 +2804,30 @@
*/
int (*status)(void *priv, char *buf, size_t buflen);
+ /**
+ * roaming - Set roaming policy for driver-based BSS selection
+ * @priv: Private driver interface data
+ * @allowed: Whether roaming within ESS is allowed
+ * @bssid: Forced BSSID if roaming is disabled or %NULL if not set
+ * Returns: Length of written status information or -1 on failure
+ *
+ * This optional callback can be used to update roaming policy from the
+ * associate() command (bssid being set there indicates that the driver
+ * should not roam before getting this roaming() call to allow roaming.
+ * If the driver does not indicate WPA_DRIVER_FLAGS_BSS_SELECTION
+ * capability, roaming policy is handled within wpa_supplicant and there
+ * is no need to implement or react to this callback.
+ */
+ int (*roaming)(void *priv, int allowed, const u8 *bssid);
+
+ /**
+ * set_mac_addr - Set MAC address
+ * @priv: Private driver interface data
+ * @addr: MAC address to use or %NULL for setting back to permanent
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_mac_addr)(void *priv, const u8 *addr);
+
#ifdef CONFIG_MACSEC
int (*macsec_init)(void *priv, struct macsec_init_params *params);
@@ -4172,6 +4196,9 @@
/* Convert wpa_event_type to a string for logging */
const char * event_to_string(enum wpa_event_type event);
+/* Convert chan_width to a string for logging and control interfaces */
+const char * channel_width_to_string(enum chan_width width);
+
/* NULL terminated array of linked in driver wrappers */
extern struct wpa_driver_ops *wpa_drivers[];
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 3058cd5..77e6905 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -84,3 +84,24 @@
return "UNKNOWN";
#undef E2S
}
+
+
+const char * channel_width_to_string(enum chan_width width)
+{
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ return "20 MHz (no HT)";
+ case CHAN_WIDTH_20:
+ return "20 MHz";
+ case CHAN_WIDTH_40:
+ return "40 MHz";
+ case CHAN_WIDTH_80:
+ return "80 MHz";
+ case CHAN_WIDTH_80P80:
+ return "80+80 MHz";
+ case CHAN_WIDTH_160:
+ return "160 MHz";
+ default:
+ return "unknown";
+ }
+}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 8ebf7d9..5c922a0 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -19,6 +19,9 @@
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
+#ifdef CONFIG_LIBNL3_ROUTE
+#include <netlink/route/neighbour.h>
+#endif /* CONFIG_LIBNL3_ROUTE */
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
@@ -253,6 +256,7 @@
struct dl_list list;
struct dl_list wiphy_list;
char phyname[32];
+ u8 perm_addr[ETH_ALEN];
void *ctx;
int ifindex;
int if_removed;
@@ -307,8 +311,11 @@
unsigned int start_iface_up:1;
unsigned int test_use_roc_tx:1;
unsigned int ignore_deauth_event:1;
+ unsigned int roaming_vendor_cmd_avail:1;
unsigned int dfs_vendor_cmd_avail:1;
unsigned int have_low_prio_scan:1;
+ unsigned int force_connect_cmd:1;
+ unsigned int addr_changed:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
@@ -324,6 +331,8 @@
int eapol_sock; /* socket for EAPOL frames */
+ struct nl_sock *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+
int default_if_indices[16];
int *if_indices;
int num_if_indices;
@@ -1243,8 +1252,9 @@
}
extra[sizeof(extra) - 1] = '\0';
- wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_flags=0x%x (%s%s%s%s)",
- ifi->ifi_index, ifname, extra, ifi->ifi_flags,
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ ifi->ifi_index, ifname, extra, ifi->ifi_family,
+ ifi->ifi_flags,
(ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
(ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
@@ -1340,6 +1350,7 @@
struct rtattr *attr;
u32 brid = 0;
char ifname[IFNAMSIZ + 1];
+ char extra[100], *pos, *end;
drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
if (!drv) {
@@ -1348,6 +1359,9 @@
return;
}
+ extra[0] = '\0';
+ pos = extra;
+ end = pos + sizeof(extra);
ifname[0] = '\0';
attrlen = len;
@@ -1362,12 +1376,30 @@
break;
case IFLA_MASTER:
brid = nla_get_u32((struct nlattr *) attr);
+ pos += os_snprintf(pos, end - pos, " master=%u", brid);
+ break;
+ case IFLA_OPERSTATE:
+ pos += os_snprintf(pos, end - pos, " operstate=%u",
+ nla_get_u32((struct nlattr *) attr));
+ break;
+ case IFLA_LINKMODE:
+ pos += os_snprintf(pos, end - pos, " linkmode=%u",
+ nla_get_u32((struct nlattr *) attr));
break;
}
attr = RTA_NEXT(attr, attrlen);
}
+ extra[sizeof(extra) - 1] = '\0';
- if (ifname[0])
+ wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ ifi->ifi_index, ifname, extra, ifi->ifi_family,
+ ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid))
wpa_driver_nl80211_event_dellink(drv, ifname);
if (ifi->ifi_family == AF_BRIDGE && brid) {
@@ -1387,6 +1419,17 @@
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore auth event when using driver SME");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24 + sizeof(mgmt->u.auth)) {
@@ -1453,6 +1496,17 @@
union wpa_event_data event;
u16 status;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore assoc event when using driver SME");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "nl80211: Associate event");
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
@@ -3846,9 +3900,14 @@
continue;
}
vinfo = nla_data(nl);
- if (vinfo->subcmd ==
- QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY)
+ switch (vinfo->subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+ drv->roaming_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
drv->dfs_vendor_cmd_avail = 1;
+ break;
+ }
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
vinfo->vendor_id, vinfo->subcmd);
@@ -4550,7 +4609,7 @@
#ifdef CONFIG_HS20
/* WNM-Notification */
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
- return -1;
+ ret = -1;
#endif /* CONFIG_HS20 */
nl80211_mgmt_handle_register_eloop(bss);
@@ -4822,6 +4881,7 @@
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
bss->addr))
return -1;
+ os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
if (send_rfkill_event) {
eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
@@ -4877,6 +4937,8 @@
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"interface %s from bridge %s: %s",
bss->ifname, bss->brname, strerror(errno));
+ if (drv->rtnl_sk)
+ nl_socket_free(drv->rtnl_sk);
}
if (bss->added_bridge) {
if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
@@ -4910,6 +4972,16 @@
if (!drv->start_iface_up)
(void) i802_set_iface_flags(bss, 0);
+
+ if (drv->addr_changed) {
+ linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ drv->perm_addr) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore permanent MAC address");
+ }
+ }
+
if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
if (!drv->hostapd || !drv->start_mode_ap)
wpa_driver_nl80211_set_mode(bss,
@@ -7686,6 +7758,43 @@
}
+static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_addr;
+ int err;
+
+ rn = rtnl_neigh_alloc();
+ if (!rn)
+ return;
+
+ rtnl_neigh_set_family(rn, AF_BRIDGE);
+ rtnl_neigh_set_ifindex(rn, bss->ifindex);
+ nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
+ if (!nl_addr) {
+ rtnl_neigh_put(rn);
+ return;
+ }
+ rtnl_neigh_set_lladdr(rn, nl_addr);
+
+ err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+ if (err < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
+ MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
+ bss->ifindex, nl_geterror(err));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
+ MACSTR, MAC2STR(addr));
+ }
+
+ nl_addr_put(nl_addr);
+ rtnl_neigh_put(rn);
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -7706,6 +7815,10 @@
wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
" --> %d (%s)",
bss->ifname, MAC2STR(addr), ret, strerror(-ret));
+
+ if (drv->rtnl_sk)
+ rtnl_neigh_delete_fdb_entry(bss, addr);
+
if (ret == -ENOENT)
return 0;
return ret;
@@ -8480,6 +8593,11 @@
struct nlattr *flags;
struct nl80211_sta_flag_update upd;
+ wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
+ " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
+ bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
+ !!(total_flags & WPA_STA_AUTHORIZED));
+
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
@@ -9984,6 +10102,22 @@
i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
goto failed;
+#ifdef CONFIG_LIBNL3_ROUTE
+ if (bss->added_if_into_bridge) {
+ drv->rtnl_sk = nl_socket_alloc();
+ if (drv->rtnl_sk == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
+ goto failed;
+ }
+
+ if (nl_connect(drv->rtnl_sk, NETLINK_ROUTE)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
+ strerror(errno));
+ goto failed;
+ }
+ }
+#endif /* CONFIG_LIBNL3_ROUTE */
+
drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
if (drv->eapol_sock < 0) {
wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
@@ -10000,6 +10134,7 @@
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
params->own_addr))
goto failed;
+ os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
memcpy(bss->addr, params->own_addr, ETH_ALEN);
@@ -10959,6 +11094,7 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
+ drv->force_connect_cmd = 1;
}
if (os_strstr(param, "no_offchannel_tx=1")) {
@@ -11450,60 +11586,18 @@
nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
- if (freq->vht_enabled) {
- switch (freq->bandwidth) {
- case 20:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_20);
- break;
- case 40:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_40);
- break;
- case 80:
- if (freq->center_freq2)
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_80P80);
- else
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_80);
- break;
- case 160:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_160);
- break;
- default:
- return -1;
- }
- NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
- if (freq->center_freq2)
- NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
- freq->center_freq2);
- } else if (freq->ht_enabled) {
- switch (freq->sec_channel_offset) {
- case -1:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT40MINUS);
- break;
- case 1:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT40PLUS);
- break;
- default:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT20);
- break;
- }
- }
+ if (nl80211_put_freq_params(msg, freq) < 0)
+ goto nla_put_failure;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
"%d (%s)", ret, strerror(-ret));
nla_put_failure:
+ nlmsg_free(msg);
return -1;
}
@@ -11954,6 +12048,7 @@
res = os_snprintf(pos, end - pos,
"phyname=%s\n"
+ "perm_addr=" MACSTR "\n"
"drv_ifindex=%d\n"
"operstate=%d\n"
"scan_state=%s\n"
@@ -11970,6 +12065,7 @@
"eapol_tx_sock=%d\n"
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
drv->phyname,
+ MAC2STR(drv->perm_addr),
drv->ifindex,
drv->operstate,
scan_state_str(drv->scan_state),
@@ -12352,6 +12448,90 @@
}
+static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
+
+ if (!drv->roaming_vendor_cmd_avail) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
+ return -1;
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
+ NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ROAMING);
+
+ params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!params)
+ goto nla_put_failure;
+ NLA_PUT_U32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
+ allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
+ QCA_ROAMING_NOT_ALLOWED);
+ if (bssid)
+ NLA_PUT(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid);
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ nla_put_failure:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_set_mac_addr(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int new_addr = addr != NULL;
+
+ if (!addr)
+ addr = drv->perm_addr;
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
+ return -1;
+
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: failed to set_mac_addr for %s to " MACSTR,
+ bss->ifname, MAC2STR(addr));
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
+ 1) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore interface UP after failed set_mac_addr");
+ }
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
+ bss->ifname, MAC2STR(addr));
+ drv->addr_changed = new_addr;
+ os_memcpy(bss->addr, addr, ETH_ALEN);
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore interface UP after set_mac_addr");
+ }
+
+ return 0;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -12443,4 +12623,6 @@
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
.set_wowlan = nl80211_set_wowlan,
+ .roaming = nl80211_roaming,
+ .set_mac_addr = nl80211_set_mac_addr,
};
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 40aaba5..cdb913e 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -36,6 +36,10 @@
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+ifdef CONFIG_LIBNL3_ROUTE
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+endif
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index db8561a..9fa70d9 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -31,6 +31,10 @@
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+ifdef CONFIG_LIBNL3_ROUTE
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+endif
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
diff --git a/src/eap_server/eap_server_pax.c b/src/eap_server/eap_server_pax.c
index c87848c..d9d4375 100644
--- a/src/eap_server/eap_server_pax.c
+++ b/src/eap_server/eap_server_pax.c
@@ -287,7 +287,7 @@
struct eap_pax_hdr *resp;
u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
const u8 *pos;
- size_t len, left;
+ size_t len, left, cid_len;
int i;
if (data->state != PAX_STD_1)
@@ -320,7 +320,12 @@
wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
return;
}
- data->cid_len = WPA_GET_BE16(pos);
+ cid_len = WPA_GET_BE16(pos);
+ if (cid_len > 1500) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Too long CID");
+ return;
+ }
+ data->cid_len = cid_len;
os_free(data->cid);
data->cid = os_malloc(data->cid_len);
if (data->cid == NULL) {
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index cf3506d..70258be 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -255,12 +255,14 @@
* delay authentication. Use a short timeout to send the first
* EAPOL-Start if Authenticator does not start authentication.
*/
-#ifdef CONFIG_WPS
- /* Reduce latency on starting WPS negotiation. */
- sm->startWhen = 1;
-#else /* CONFIG_WPS */
- sm->startWhen = 3;
-#endif /* CONFIG_WPS */
+ if (sm->conf.wps) {
+ /* Reduce latency on starting WPS negotiation. */
+ wpa_printf(MSG_DEBUG,
+ "EAPOL: Using shorter startWhen for WPS");
+ sm->startWhen = 1;
+ } else {
+ sm->startWhen = 2;
+ }
}
eapol_enable_timer_tick(sm);
sm->eapolEap = FALSE;
@@ -1242,7 +1244,7 @@
return 0;
}
#ifdef CONFIG_WPS
- if (sm->conf.workaround &&
+ if (sm->conf.wps && sm->conf.workaround &&
plen < len - sizeof(*hdr) &&
hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
@@ -1491,6 +1493,7 @@
sm->conf.required_keys = conf->required_keys;
sm->conf.fast_reauth = conf->fast_reauth;
sm->conf.workaround = conf->workaround;
+ sm->conf.wps = conf->wps;
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
/* Using EAP Proxy, so skip EAP state machine update */
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index d76c8c2..5b37314 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -58,6 +58,11 @@
* external_sim - Use external processing for SIM/USIM operations
*/
int external_sim;
+
+ /**
+ * wps - Whether this connection is used for WPS
+ */
+ int wps;
};
struct eapol_sm;
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 3a5486b..7d4a03c 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -259,7 +259,8 @@
return;
}
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +
p2p->min_disc_int) * 100;
if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)
@@ -1286,8 +1287,8 @@
} else if (p2p_channel_random_social(&p2p->cfg->channels,
&p2p->op_reg_class,
&p2p->op_channel) == 0) {
- p2p_dbg(p2p, "Select random available social channel %d from 2.4 GHz band as operating channel preference",
- p2p->op_channel);
+ p2p_dbg(p2p, "Select random available social channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
} else {
/* Select any random available channel from the first available
* operating class */
@@ -1824,8 +1825,17 @@
struct p2p_data *p2p = eloop_ctx;
if (p2p->go_neg_peer == NULL)
return;
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_go_neg_start");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p->go_neg_peer->status = P2P_SC_SUCCESS;
+ /*
+ * Set new timeout to make sure a previously set one does not expire
+ * too quickly while waiting for the GO Negotiation to complete.
+ */
+ p2p_set_timeout(p2p, 0, 500000);
p2p_connect_send(p2p, p2p->go_neg_peer);
}
@@ -1835,6 +1845,10 @@
struct p2p_data *p2p = eloop_ctx;
if (p2p->invite_peer == NULL)
return;
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_invite_start");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
p2p->invite_dev_pw_id);
@@ -2480,7 +2494,8 @@
p2p->max_disc_int = 3;
p2p->max_disc_tu = -1;
- os_get_random(&p2p->next_tie_breaker, 1);
+ if (os_get_random(&p2p->next_tie_breaker, 1) < 0)
+ p2p->next_tie_breaker = 0;
p2p->next_tie_breaker &= 0x01;
if (cfg->sd_request)
p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
@@ -2773,6 +2788,19 @@
return;
}
+ if (p2p->sd_query->for_all_peers) {
+ /* Update the pending broadcast SD query count for this device
+ */
+ p2p->sd_peer->sd_pending_bcast_queries--;
+
+ /*
+ * If there are no pending broadcast queries for this device,
+ * mark it as done (-1).
+ */
+ if (p2p->sd_peer->sd_pending_bcast_queries == 0)
+ p2p->sd_peer->sd_pending_bcast_queries = -1;
+ }
+
/* Wait for response from the peer */
p2p_set_state(p2p, P2P_SD_DURING_FIND);
p2p_set_timeout(p2p, 0, 200000);
@@ -3003,7 +3031,8 @@
* make it less likely to hit cases where we could end up in
* sync with peer not listening.
*/
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
timeout += r % 100000;
}
p2p_set_timeout(p2p, 0, timeout);
@@ -4075,6 +4104,13 @@
}
+int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
+ u8 *op_channel)
+{
+ return p2p_channel_random_social(&p2p->channels, op_class, op_channel);
+}
+
+
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
u8 forced)
{
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index dee79df..076a2ac 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1691,6 +1691,20 @@
*/
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
+/**
+ * p2p_config_get_random_social - Return a random social channel
+ * @p2p: P2P config
+ * @op_class: Selected operating class
+ * @op_channel: Selected social channel
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used before p2p_init is called. A random social channel
+ * from supports bands 2.4 GHz (channels 1,6,11) and 60 GHz (channel 2) is
+ * returned on success.
+ */
+int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
+ u8 *op_channel);
+
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
u8 forced);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index bd7a2cf..21fae3f 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -958,7 +958,10 @@
p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
dev->flags |= P2P_DEV_NOT_YET_READY;
os_get_reltime(&dev->go_neg_wait_started);
- p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
+ if (p2p->state == P2P_CONNECT_LISTEN)
+ p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
+ else
+ p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
p2p_set_timeout(p2p, 0, 0);
} else {
p2p_dbg(p2p, "Stop GO Negotiation attempt");
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 6235b1d..13119c2 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -301,16 +301,6 @@
ret = -1;
}
- /* Update the pending broadcast SD query count for this device */
- dev->sd_pending_bcast_queries--;
-
- /*
- * If there are no pending broadcast queries for this device, mark it as
- * done (-1).
- */
- if (dev->sd_pending_bcast_queries == 0)
- dev->sd_pending_bcast_queries = -1;
-
wpabuf_free(req);
return ret;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 189300a..23acce7 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -149,6 +149,15 @@
return 0;
}
+ if (freq >= 58320 && freq <= 64800) {
+ if ((freq - 58320) % 2160)
+ return -1;
+
+ *op_class = 180; /* 60 GHz, channels 1..4 */
+ *channel = (freq - 56160) / 2160;
+ return 0;
+ }
+
return -1;
}
@@ -441,7 +450,8 @@
static u8 p2p_channel_pick_random(const u8 *channels, unsigned int num_channels)
{
unsigned int r;
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
r %= num_channels;
return channels[r];
}
@@ -481,7 +491,7 @@
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
u8 *op_channel)
{
- u8 chan[3];
+ u8 chan[4];
unsigned int num_channels = 0;
/* Try to find available social channels from 2.4 GHz */
@@ -492,11 +502,18 @@
if (p2p_channels_includes(chans, 81, 11))
chan[num_channels++] = 11;
+ /* Try to find available social channels from 60 GHz */
+ if (p2p_channels_includes(chans, 180, 2))
+ chan[num_channels++] = 2;
+
if (num_channels == 0)
return -1;
- *op_class = 81;
*op_channel = p2p_channel_pick_random(chan, num_channels);
+ if (*op_channel == 2)
+ *op_class = 180;
+ else
+ *op_class = 81;
return 0;
}
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 10056a6..e2766e2 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1080,19 +1080,23 @@
switch (nserv->addr.af) {
case AF_INET:
claddrlen = sizeof(claddr);
- getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
- wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
- inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
+ if (getsockname(sel_sock, (struct sockaddr *) &claddr,
+ &claddrlen) == 0) {
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntoa(claddr.sin_addr),
+ ntohs(claddr.sin_port));
+ }
break;
#ifdef CONFIG_IPV6
case AF_INET6: {
claddrlen = sizeof(claddr6);
- getsockname(sel_sock, (struct sockaddr *) &claddr6,
- &claddrlen);
- wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
- inet_ntop(AF_INET6, &claddr6.sin6_addr,
- abuf, sizeof(abuf)),
- ntohs(claddr6.sin6_port));
+ if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
+ &claddrlen) == 0) {
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntop(AF_INET6, &claddr6.sin6_addr,
+ abuf, sizeof(abuf)),
+ ntohs(claddr6.sin6_port));
+ }
break;
}
#endif /* CONFIG_IPV6 */
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 24348a3..00394b4 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1926,7 +1926,7 @@
if (inet_ntop(AF_INET6, &cli->addr6, abuf,
sizeof(abuf)) == NULL)
abuf[0] = '\0';
- if (inet_ntop(AF_INET6, &cli->mask6, abuf,
+ if (inet_ntop(AF_INET6, &cli->mask6, mbuf,
sizeof(mbuf)) == NULL)
mbuf[0] = '\0';
}
@@ -2048,8 +2048,6 @@
sess = s;
break;
}
- if (sess)
- break;
}
if (sess)
break;
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index cd34223..93ae143 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1382,11 +1382,85 @@
struct wpa_tdls_peer *peer,
u8 dialog_token)
{
+ size_t buf_len = 0;
+ struct wpa_tdls_timeoutie timeoutie;
+ u16 rsn_capab;
+ u8 *rbuf, *pos, *count_pos;
+ u16 count;
+ struct rsn_ie_hdr *hdr;
+ int status;
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
"(peer " MACSTR ")", MAC2STR(peer->addr));
+ if (!wpa_tdls_get_privacy(sm))
+ goto skip_rsn_ies;
- return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
- dialog_token, 0, 0, NULL, 0);
+ /* Filling RSN IE */
+ hdr = (struct rsn_ie_hdr *) peer->rsnie_i;
+ hdr->elem_id = WLAN_EID_RSN;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ pos += RSN_SELECTOR_LEN;
+ count_pos = pos;
+ pos += 2;
+ count = 0;
+
+ /*
+ * AES-CCMP is the default encryption preferred for TDLS, so
+ * RSN IE is filled only with CCMP cipher suite.
+ * Note: TKIP is not used to encrypt TDLS link.
+ *
+ * Regardless of the cipher used on the AP connection, select CCMP
+ * here.
+ */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ pos += RSN_SELECTOR_LEN;
+ count++;
+ WPA_PUT_LE16(count_pos, count);
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE);
+ pos += RSN_SELECTOR_LEN;
+
+ rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+ rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+ WPA_PUT_LE16(pos, rsn_capab);
+ pos += 2;
+ hdr->len = (pos - (u8 *) hdr) - 2;
+ peer->rsnie_i_len = pos - peer->rsnie_i;
+
+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for Discovery Response",
+ (u8 *) hdr, hdr->len + 2);
+skip_rsn_ies:
+ buf_len = 0;
+ if (wpa_tdls_get_privacy(sm)) {
+ /* Peer RSN IE, Lifetime */
+ buf_len += peer->rsnie_i_len +
+ sizeof(struct wpa_tdls_timeoutie);
+ }
+ rbuf = os_zalloc(buf_len + 1);
+ if (rbuf == NULL) {
+ wpa_tdls_peer_free(sm, peer);
+ return -1;
+ }
+ pos = rbuf;
+
+ if (!wpa_tdls_get_privacy(sm))
+ goto skip_ies;
+ /* Initiator RSN IE */
+ pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len);
+ /* Lifetime */
+ peer->lifetime = TPK_LIFETIME;
+ pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+ sizeof(timeoutie), peer->lifetime);
+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime);
+skip_ies:
+ status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+ dialog_token, 0, 0, rbuf, pos - rbuf);
+ os_free(rbuf);
+
+ return status;
}
@@ -1743,7 +1817,7 @@
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS");
- status = WLAN_STATUS_NOT_IN_SAME_BSS;
+ status = WLAN_STATUS_REQUEST_DECLINED;
goto error;
}
diff --git a/src/utils/common.c b/src/utils/common.c
index 5b017e5..9902004 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -362,7 +362,7 @@
*txt++ = '\\';
*txt++ = '\\';
break;
- case '\e':
+ case '\033':
*txt++ = '\\';
*txt++ = 'e';
break;
@@ -427,7 +427,7 @@
pos++;
break;
case 'e':
- buf[len++] = '\e';
+ buf[len++] = '\033';
pos++;
break;
case 'x':
@@ -846,3 +846,23 @@
os_free(bin);
}
}
+
+
+int random_mac_addr(u8 *addr)
+{
+ if (os_get_random(addr, ETH_ALEN) < 0)
+ return -1;
+ addr[0] &= 0xfe; /* unicast */
+ addr[0] |= 0x02; /* locally administered */
+ return 0;
+}
+
+
+int random_mac_addr_keep_oui(u8 *addr)
+{
+ if (os_get_random(addr + 3, 3) < 0)
+ return -1;
+ addr[0] &= 0xfe; /* unicast */
+ addr[0] |= 0x02; /* locally administered */
+ return 0;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 2bc8fe1..14d9ad1 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -538,6 +538,9 @@
void str_clear_free(char *str);
void bin_clear_free(void *bin, size_t len);
+int random_mac_addr(u8 *addr);
+int random_mac_addr_keep_oui(u8 *addr);
+
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index eb79b86..0c18269 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -1099,7 +1099,6 @@
certs = NULL;
}
if (ctx->peer_issuer_issuer) {
- X509 *cert;
cert = X509_dup(ctx->peer_issuer_issuer);
if (cert && !sk_X509_push(certs, cert)) {
tls_show_errors(
@@ -1178,9 +1177,10 @@
if (status == V_OCSP_CERTSTATUS_GOOD)
return 1;
- if (status == V_OCSP_CERTSTATUS_REVOKED)
+ if (status == V_OCSP_CERTSTATUS_REVOKED) {
ctx->last_err = "Server certificate has been revoked";
return 0;
+ }
if (ctx->ocsp == MANDATORY_OCSP) {
wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
ctx->last_err = "OCSP status unknown";
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index f7d41b4..9f5a90c 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -175,6 +175,12 @@
}
wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+ if (wps->wps->ap && random_pool_ready() != 1) {
+ wpa_printf(MSG_INFO,
+ "WPS: Not enough entropy in random pool to proceed - do not allow AP PIN to be used");
+ return NULL;
+ }
+
msg = wpabuf_alloc(1000);
if (msg == NULL)
return NULL;
@@ -268,8 +274,12 @@
char hex[65];
u8 psk[32];
/* Generate a random per-device PSK */
- if (random_get_bytes(psk, sizeof(psk)) < 0)
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(psk, sizeof(psk)) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
return -1;
+ }
wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
psk, sizeof(psk));
wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)",
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 00c8299..b90cc25 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1640,8 +1640,12 @@
!wps->wps->registrar->disable_auto_conf) {
u8 r[16];
/* Generate a random passphrase */
- if (random_get_bytes(r, sizeof(r)) < 0)
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(r, sizeof(r)) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
return -1;
+ }
os_free(wps->new_psk);
wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
if (wps->new_psk == NULL)
@@ -1674,7 +1678,10 @@
wps->new_psk = os_malloc(wps->new_psk_len);
if (wps->new_psk == NULL)
return -1;
- if (random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
os_free(wps->new_psk);
wps->new_psk = NULL;
return -1;
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index f99a8a7..7d01a5f 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -489,6 +489,8 @@
if (changes & WPA_BSS_RATES_CHANGED_FLAG)
wpas_notify_bss_rates_changed(wpa_s, bss->id);
+
+ wpas_notify_bss_seen(wpa_s, bss->id);
}
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 8cd4a2f..b7f259b 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1754,6 +1754,7 @@
#ifdef CONFIG_HS20
{ INT(update_identifier) },
#endif /* CONFIG_HS20 */
+ { INT_RANGE(mac_addr, 0, 2) },
};
#undef OFFSET
@@ -2211,6 +2212,7 @@
#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
#endif /* CONFIG_IEEE80211W */
+ ssid->mac_addr = -1;
}
@@ -3287,6 +3289,7 @@
config->wmm_ac_params[2] = ac_vi;
config->wmm_ac_params[3] = ac_vo;
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
+ config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3909,6 +3912,9 @@
{ STR(osu_dir), 0 },
{ STR(wowlan_triggers), 0 },
{ INT(p2p_search_delay), 0},
+ { INT(mac_addr), 0 },
+ { INT(rand_addr_lifetime), 0 },
+ { INT(preassoc_mac_addr), 0 },
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 52add9d..3fd4192 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -27,6 +27,7 @@
#define DEFAULT_ACCESS_NETWORK_TYPE 15
#define DEFAULT_SCAN_CUR_FREQ 0
#define DEFAULT_P2P_SEARCH_DELAY 500
+#define DEFAULT_RAND_ADDR_LIFETIME 60
#include "config_ssid.h"
#include "wps/wps.h"
@@ -1051,6 +1052,33 @@
* resources.
*/
unsigned int p2p_search_delay;
+
+ /**
+ * mac_addr - MAC address policy default
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address for each ESS connection
+ * 2 = like 1, but maintain OUI (with local admin bit set)
+ *
+ * By default, permanent MAC address is used unless policy is changed by
+ * the per-network mac_addr parameter. Global mac_addr=1 can be used to
+ * change this default behavior.
+ */
+ int mac_addr;
+
+ /**
+ * rand_addr_lifetime - Lifetime of random MAC address in seconds
+ */
+ unsigned int rand_addr_lifetime;
+
+ /**
+ * preassoc_mac_addr - Pre-association MAC address policy
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address
+ * 2 = like 1, but maintain OUI (with local admin bit set)
+ */
+ int preassoc_mac_addr;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 73ad57a..5c8f045 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -742,6 +742,7 @@
#ifdef CONFIG_HS20
INT(update_identifier);
#endif /* CONFIG_HS20 */
+ write_int(f, "mac_addr", ssid->mac_addr, -1);
#undef STR
#undef INT
@@ -1179,6 +1180,16 @@
if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY)
fprintf(f, "p2p_search_delay=%u\n",
config->p2p_search_delay);
+
+ if (config->mac_addr)
+ fprintf(f, "mac_addr=%d\n", config->mac_addr);
+
+ if (config->rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME)
+ fprintf(f, "rand_addr_lifetime=%u\n",
+ config->rand_addr_lifetime);
+
+ if (config->preassoc_mac_addr)
+ fprintf(f, "preassoc_mac_addr=%d\n", config->preassoc_mac_addr);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index ab474ff..f50b2d4 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -651,6 +651,21 @@
#ifdef CONFIG_HS20
int update_identifier;
#endif /* CONFIG_HS20 */
+
+ unsigned int wps_run;
+
+ /**
+ * mac_addr - MAC address policy
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address for each ESS connection
+ * 2 = like 1, but maintain OUI (with local admin bit set)
+ *
+ * Internally, special value -1 is used to indicate that the parameter
+ * was not specified in the configuration (i.e., default behavior is
+ * followed).
+ */
+ int mac_addr;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 79806d9..54cd1ec 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -41,6 +41,7 @@
#include "autoscan.h"
#include "wnm_sta.h"
#include "offchannel.h"
+#include "drivers/driver.h"
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
@@ -1539,6 +1540,11 @@
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
+ ret = os_snprintf(pos, end - pos, "freq=%u\n",
+ wpa_s->assoc_freq);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
if (ssid) {
u8 *_ssid = ssid->ssid;
size_t ssid_len = ssid->ssid_len;
@@ -2479,6 +2485,8 @@
struct wpa_ssid *remove_ssid = ssid;
id = ssid->id;
ssid = ssid->next;
+ if (wpa_s->last_ssid == remove_ssid)
+ wpa_s->last_ssid = NULL;
wpas_notify_network_removed(wpa_s, remove_ssid);
wpa_config_remove_network(wpa_s->conf, id);
}
@@ -2497,6 +2505,9 @@
return -1;
}
+ if (wpa_s->last_ssid == ssid)
+ wpa_s->last_ssid = NULL;
+
if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
#ifdef CONFIG_SME
wpa_s->sme.prev_bssid_set = 0;
@@ -2571,9 +2582,10 @@
static int wpa_supplicant_ctrl_iface_set_network(
struct wpa_supplicant *wpa_s, char *cmd)
{
- int id;
+ int id, ret, prev_bssid_set;
struct wpa_ssid *ssid;
char *name, *value;
+ u8 prev_bssid[ETH_ALEN];
/* cmd: "<network id> <variable name> <value>" */
name = os_strchr(cmd, ' ');
@@ -2599,8 +2611,15 @@
return -1;
}
- return wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
- value);
+ prev_bssid_set = ssid->bssid_set;
+ os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
+ ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
+ value);
+ if (ret == 0 &&
+ (ssid->bssid_set != prev_bssid_set ||
+ os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
+ wpas_notify_network_bssid_set_changed(wpa_s, ssid);
+ return ret;
}
@@ -5545,28 +5564,6 @@
#endif /* CONFIG_WNM */
-/* Get string representation of channel width */
-static const char * channel_width_name(enum chan_width width)
-{
- switch (width) {
- case CHAN_WIDTH_20_NOHT:
- return "20 MHz (no HT)";
- case CHAN_WIDTH_20:
- return "20 MHz";
- case CHAN_WIDTH_40:
- return "40 MHz";
- case CHAN_WIDTH_80:
- return "80 MHz";
- case CHAN_WIDTH_80P80:
- return "80+80 MHz";
- case CHAN_WIDTH_160:
- return "160 MHz";
- default:
- return "unknown";
- }
-}
-
-
static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -5591,7 +5588,7 @@
if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
- channel_width_name(si.chanwidth));
+ channel_width_to_string(si.chanwidth));
if (ret < 0 || ret > end - pos)
return -1;
pos += ret;
@@ -6520,6 +6517,8 @@
} else if (os_strcmp(buf, "PMKSA") == 0) {
reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
reply_size);
+ } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
} else if (os_strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index e9f6589..3d22552 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1960,6 +1960,9 @@
case WPAS_DBUS_BSS_PROP_IES:
prop = "IEs";
break;
+ case WPAS_DBUS_BSS_PROP_AGE:
+ prop = "Age";
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -2094,6 +2097,12 @@
wpas_dbus_getter_global_capabilities,
NULL
},
+#ifdef CONFIG_WIFI_DISPLAY
+ { "WFDIEs", WPAS_DBUS_NEW_INTERFACE, "ay",
+ wpas_dbus_getter_global_wfd_ies,
+ wpas_dbus_setter_global_wfd_ies
+ },
+#endif /* CONFIG_WIFI_DISPLAY */
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -2384,6 +2393,10 @@
wpas_dbus_getter_bss_ies,
NULL
},
+ { "Age", WPAS_DBUS_NEW_IFACE_BSS, "u",
+ wpas_dbus_getter_bss_age,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -2518,6 +2531,13 @@
END_ARGS
}
},
+ { "SignalPoll", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_signal_poll,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
{
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 881d351..5f32bbf 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -41,6 +41,7 @@
WPAS_DBUS_BSS_PROP_RSN,
WPAS_DBUS_BSS_PROP_WPS,
WPAS_DBUS_BSS_PROP_IES,
+ WPAS_DBUS_BSS_PROP_AGE,
};
#define WPAS_DBUS_OBJECT_PATH_MAX 150
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 6dc5f76..9f6c4a3 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -27,6 +27,7 @@
#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
#include "dbus_common_i.h"
+#include "drivers/driver.h"
static const char *debug_strings[] = {
"excessive", "msgdump", "debug", "info", "warning", "error", NULL
@@ -1401,6 +1402,88 @@
}
+/**
+ * wpas_dbus_handler_signal_poll - Request immediate signal properties
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "SignalPoll" method call of a network device. Requests
+ * that wpa_supplicant read signal properties like RSSI, noise, and link
+ * speed and return them.
+ */
+DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ struct wpa_signal_info si;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, iter_dict, variant_iter;
+ int ret;
+
+ ret = wpa_drv_signal_poll(wpa_s, &si);
+ if (ret) {
+ return dbus_message_new_error(message, DBUS_ERROR_FAILED,
+ "Failed to read signal");
+ }
+
+ reply = dbus_message_new_method_return(message);
+ if (reply == NULL)
+ goto nomem;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter))
+ goto nomem;
+ if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+ goto nomem;
+
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "rssi", si.current_signal))
+ goto nomem;
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
+ si.current_txrate / 1000))
+ goto nomem;
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", si.current_noise))
+ goto nomem;
+ if (!wpa_dbus_dict_append_uint32(&iter_dict, "frequency", si.frequency))
+ goto nomem;
+
+ if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
+ if (!wpa_dbus_dict_append_string(&iter_dict, "width",
+ channel_width_to_string(si.chanwidth)))
+ goto nomem;
+ }
+
+ if (si.center_frq1 > 0 && si.center_frq2 > 0) {
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+ si.center_frq1))
+ goto nomem;
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+ si.center_frq2))
+ goto nomem;
+ }
+
+ if (si.avg_signal) {
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+ si.avg_signal))
+ goto nomem;
+ }
+
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
+ goto nomem;
+ if (!dbus_message_iter_close_container(&iter, &variant_iter))
+ goto nomem;
+
+ return reply;
+
+nomem:
+ if (reply)
+ dbus_message_unref(reply);
+ reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+ return reply;
+}
+
+
/*
* wpas_dbus_handler_disconnect - Terminate the current connection
* @message: Pointer to incoming dbus message
@@ -3955,6 +4038,35 @@
/**
+ * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for BSS age
+ */
+dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
+ void *user_data)
+{
+ struct bss_handler_args *args = user_data;
+ struct wpa_bss *res;
+ struct os_reltime now, diff = { 0, 0 };
+ u32 age;
+
+ res = get_bss_helper(args, error, __func__);
+ if (!res)
+ return FALSE;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &res->last_update, &diff);
+ age = diff.sec > 0 ? diff.sec : 0;
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
+ error);
+}
+
+
+/**
* wpas_dbus_getter_enabled - Check whether network is enabled or disabled
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 461970d..51cf5f3 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -87,6 +87,9 @@
DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -268,6 +271,9 @@
dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
void *user_data);
+dbus_bool_t wpas_dbus_getter_bss_age(DBusMessageIter *iter, DBusError *error,
+ void *user_data);
+
dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
void *user_data);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index c9ecc7b..7867f0c 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -26,6 +26,7 @@
#include "ap/wps_hostapd.h"
#include "../p2p_supplicant.h"
+#include "../wifi_display.h"
/**
* Parses out the mac address from the peer object path.
@@ -2589,3 +2590,77 @@
return NULL;
}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
+ DBusError *error, void *user_data)
+{
+ struct wpa_global *global = user_data;
+ struct wpabuf *ie;
+ dbus_bool_t ret;
+
+ ie = wifi_display_get_wfd_ie(global);
+ if (ie == NULL)
+ return wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_BYTE,
+ NULL, 0, error);
+
+ ret = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ wpabuf_head(ie),
+ wpabuf_len(ie), error);
+ wpabuf_free(ie);
+
+ return ret;
+}
+
+
+dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
+ DBusError *error, void *user_data)
+{
+ struct wpa_global *global = user_data;
+ DBusMessageIter variant, array;
+ struct wpabuf *ie = NULL;
+ const u8 *data;
+ int len;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+ goto err;
+
+ dbus_message_iter_recurse(iter, &variant);
+ if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
+ goto err;
+
+ dbus_message_iter_recurse(&variant, &array);
+ dbus_message_iter_get_fixed_array(&array, &data, &len);
+ if (len == 0) {
+ wifi_display_enable(global, 0);
+ wifi_display_deinit(global);
+
+ return TRUE;
+ }
+
+ ie = wpabuf_alloc(len);
+ if (ie == NULL)
+ goto err;
+
+ wpabuf_put_data(ie, data, len);
+ if (wifi_display_subelem_set_from_ies(global, ie) != 0)
+ goto err;
+
+ if (global->wifi_display == 0)
+ wifi_display_enable(global, 1);
+
+ wpabuf_free(ie);
+
+ return TRUE;
+err:
+ wpabuf_free(ie);
+
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index 67dbfc9..6e67c89 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -210,5 +210,16 @@
DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
DBusMessage *message, struct wpa_supplicant *wpa_s);
+#ifdef CONFIG_WIFI_DISPLAY
+
+dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
+dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
+#endif /* CONFIG_WIFI_DISPLAY */
#endif /* DBUS_NEW_HANDLERS_P2P_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 00703d9..cba32a9 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -632,6 +632,22 @@
data, data_len, buf);
}
+static inline int wpa_drv_roaming(struct wpa_supplicant *wpa_s, int allowed,
+ const u8 *bssid)
+{
+ if (!wpa_s->driver->roaming)
+ return -1;
+ return wpa_s->driver->roaming(wpa_s->drv_priv, allowed, bssid);
+}
+
+static inline int wpa_drv_set_mac_addr(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
+{
+ if (!wpa_s->driver->set_mac_addr)
+ return -1;
+ return wpa_s->driver->set_mac_addr(wpa_s->drv_priv, addr);
+}
+
#ifdef CONFIG_MACSEC
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index ba9e083..081b585 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2163,10 +2163,12 @@
}
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)) {
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPS ||
+ wpas_wps_searching(wpa_s))) {
wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
- "reconnect (wps=%d wpa_state=%d)",
+ "reconnect (wps=%d/%d wpa_state=%d)",
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
+ wpas_wps_searching(wpa_s),
wpa_s->wpa_state);
if (wpa_s->wpa_state == WPA_COMPLETED &&
wpa_s->current_ssid &&
@@ -2998,15 +3000,17 @@
wpa_s->own_scan_running = 1;
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
wpa_s->manual_scan_use_id) {
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED "id=%u",
- wpa_s->manual_scan_id);
+ wpa_msg_ctrl(wpa_s, MSG_INFO,
+ WPA_EVENT_SCAN_STARTED "id=%u",
+ wpa_s->manual_scan_id);
} else {
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
+ wpa_msg_ctrl(wpa_s, MSG_INFO,
+ WPA_EVENT_SCAN_STARTED);
}
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
wpa_s->external_scan_running = 1;
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
}
break;
case EVENT_SCAN_RESULTS:
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 3986268..3a89674 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -597,6 +597,7 @@
{
struct gas_query_pending *query = work->ctx;
struct gas_query *gas = query->gas;
+ struct wpa_supplicant *wpa_s = gas->wpa_s;
if (deinit) {
if (work->started) {
@@ -609,6 +610,14 @@
return;
}
+ if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to assign random MAC address for GAS");
+ gas_query_free(query, 1);
+ radio_work_done(work);
+ return;
+ }
+
gas->work = work;
if (gas_query_tx(gas, query, query->req) < 0) {
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 3b730cf..617ce84 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -345,6 +345,12 @@
}
+void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id)
+{
+ wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_AGE, id);
+}
+
+
void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
{
wpas_dbus_signal_blob_added(wpa_s, name);
@@ -627,3 +633,18 @@
"status='%s' parameter='%s'",
status, parameter);
}
+
+
+void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (wpa_s->current_ssid != ssid)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Network bssid config changed for the current network - within-ESS roaming %s",
+ ssid->bssid_set ? "disabled" : "enabled");
+
+ wpa_drv_roaming(wpa_s, !ssid->bssid_set,
+ ssid->bssid_set ? ssid->bssid : NULL);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 58675ac..7feb530 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -71,6 +71,7 @@
unsigned int id);
void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
unsigned int id);
+void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id);
void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name);
void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name);
@@ -127,5 +128,7 @@
const u8 *ie, size_t ie_len, u32 ssi_signal);
void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
const char *parameter);
+void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 3eea9e8..ca45b5b 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -286,8 +286,10 @@
struct wpa_supplicant *wpa_s = ctx;
struct wpa_driver_scan_params *params = NULL;
struct wpabuf *wps_ie, *ies;
+ unsigned int num_channels = 0;
+ int social_channels_freq[] = { 2412, 2437, 2462, 60480 };
size_t ielen;
- u8 *n;
+ u8 *n, i;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -341,25 +343,34 @@
switch (type) {
case P2P_SCAN_SOCIAL:
- params->freqs = os_malloc(4 * sizeof(int));
+ params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1,
+ sizeof(int));
if (params->freqs == NULL)
goto fail;
- params->freqs[0] = 2412;
- params->freqs[1] = 2437;
- params->freqs[2] = 2462;
- params->freqs[3] = 0;
+ for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
+ if (p2p_supported_freq(wpa_s->global->p2p,
+ social_channels_freq[i]))
+ params->freqs[num_channels++] =
+ social_channels_freq[i];
+ }
+ params->freqs[num_channels++] = 0;
break;
case P2P_SCAN_FULL:
break;
case P2P_SCAN_SOCIAL_PLUS_ONE:
- params->freqs = os_malloc(5 * sizeof(int));
+ params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 2,
+ sizeof(int));
if (params->freqs == NULL)
goto fail;
- params->freqs[0] = 2412;
- params->freqs[1] = 2437;
- params->freqs[2] = 2462;
- params->freqs[3] = freq;
- params->freqs[4] = 0;
+ for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
+ if (p2p_supported_freq(wpa_s->global->p2p,
+ social_channels_freq[i]))
+ params->freqs[num_channels++] =
+ social_channels_freq[i];
+ }
+ if (p2p_supported_freq(wpa_s->global->p2p, freq))
+ params->freqs[num_channels++] = freq;
+ params->freqs[num_channels++] = 0;
break;
}
@@ -449,11 +460,16 @@
(ssid && ssid->mode == WPAS_MODE_INFRA)) {
wpa_s->reassociate = 0;
wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
gtype = "client";
} else
gtype = "GO";
+
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
+ wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
+
+ if (os_strcmp(gtype, "client") == 0)
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
if (wpa_s->cross_connect_in_use) {
wpa_s->cross_connect_in_use = 0;
wpa_msg_global(wpa_s->parent, MSG_INFO,
@@ -511,9 +527,6 @@
*/
wpa_s->global->p2p_go_wait_client.sec = 0;
- if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
- wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
-
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
struct wpa_global *global;
char *ifname;
@@ -3466,7 +3479,7 @@
u8 min_chan;
u8 max_chan;
u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw;
+ enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160 } bw;
};
static struct p2p_oper_class_map op_class[] = {
@@ -3491,6 +3504,7 @@
* removing invalid channels.
*/
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
+ { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160 },
{ -1, 0, 0, 0, 0, BW20 }
};
@@ -3862,7 +3876,6 @@
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
{
struct p2p_config p2p;
- unsigned int r;
int i;
if (wpa_s->conf->p2p_disabled)
@@ -3914,22 +3927,32 @@
p2p.config_methods = wpa_s->wps->config_methods;
}
+ if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to configure supported channel list");
+ return -1;
+ }
+
if (wpa_s->conf->p2p_listen_reg_class &&
wpa_s->conf->p2p_listen_channel) {
p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
p2p.channel = wpa_s->conf->p2p_listen_channel;
p2p.channel_forced = 1;
} else {
- p2p.reg_class = 81;
/*
* Pick one of the social channels randomly as the listen
* channel.
*/
- os_get_random((u8 *) &r, sizeof(r));
- p2p.channel = 1 + (r % 3) * 5;
+ if (p2p_config_get_random_social(&p2p, &p2p.reg_class,
+ &p2p.channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to select random social channel as listen channel");
+ return -1;
+ }
p2p.channel_forced = 0;
}
- wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
+ wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d:%d",
+ p2p.reg_class, p2p.channel);
if (wpa_s->conf->p2p_oper_reg_class &&
wpa_s->conf->p2p_oper_channel) {
@@ -3940,13 +3963,17 @@
"%d:%d", p2p.op_reg_class, p2p.op_channel);
} else {
- p2p.op_reg_class = 81;
/*
- * Use random operation channel from (1, 6, 11) if no other
- * preference is indicated.
+ * Use random operation channel from 2.4 GHz band social
+ * channels (1, 6, 11) or band 60 GHz social channel (2) if no
+ * other preference is indicated.
*/
- os_get_random((u8 *) &r, sizeof(r));
- p2p.op_channel = 1 + (r % 3) * 5;
+ if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class,
+ &p2p.op_channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to select random social channel as operation channel");
+ return -1;
+ }
p2p.cfg_op_channel = 0;
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
"%d:%d", p2p.op_reg_class, p2p.op_channel);
@@ -3963,12 +3990,6 @@
} else
os_memcpy(p2p.country, "XX\x04", 3);
- if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
- wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
- "channel list");
- return -1;
- }
-
os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type,
WPS_DEV_TYPE_LEN);
@@ -4073,11 +4094,8 @@
struct wpa_supplicant *wpa_s, *tmp;
wpa_s = global->ifaces;
- if (wpa_s)
- wpas_p2p_service_flush(wpa_s);
- if (global->p2p == NULL)
- return;
+ wpas_p2p_service_flush(global->p2p_init_wpa_s);
/* Remove remaining P2P group interfaces */
while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
@@ -4354,8 +4372,8 @@
p2p_get_interface_addr(wpa_s->global->p2p,
wpa_s->pending_join_dev_addr,
iface_addr) == 0 &&
- os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0)
- {
+ os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0
+ && !wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr)) {
wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface "
"address for join from " MACSTR " to " MACSTR
" based on newly discovered P2P peer entry",
@@ -5027,7 +5045,8 @@
wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
"channel: %d MHz", freq);
} else {
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
freq = 2412 + (r % 3) * 25;
wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
"channel: %d MHz", freq);
@@ -5044,7 +5063,8 @@
wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
"channel: %d MHz", freq);
} else {
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
freq = 5180 + (r % 4) * 20;
if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
wpa_printf(MSG_DEBUG, "P2P: Could not select "
@@ -5074,12 +5094,14 @@
unsigned int i, r;
/* first try some random selection of the social channels */
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ return -1;
for (i = 0; i < 3; i++) {
params->freq = 2412 + ((r + i) % 3) * 25;
if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
- freq_included(channels, params->freq))
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
goto out;
}
@@ -5087,11 +5109,28 @@
for (i = 0; i < 11; i++) {
params->freq = 2412 + i * 5;
if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
- freq_included(channels, params->freq))
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
goto out;
}
- wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel allowed");
+ /* try social channel class 180 channel 2 */
+ params->freq = 58320 + 1 * 2160;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+
+ /* try all channels in reg. class 180 */
+ for (i = 0; i < 4; i++) {
+ params->freq = 58320 + i * 2160;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: No 2.4 and 60 GHz channel allowed");
return -1;
out:
wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference known)",
@@ -5795,6 +5834,8 @@
if (wpa_s->global->p2p_disabled)
return -1;
+ if (wpa_s->conf->p2p_disabled)
+ return -1;
if (wpa_s->global->p2p == NULL)
return -1;
if (bss == NULL)
@@ -6323,8 +6364,10 @@
* Pick one of the social channels randomly as the
* listen channel.
*/
- os_get_random((u8 *) &r, sizeof(r));
- channel = 1 + (r % 3) * 5;
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ channel = 1;
+ else
+ channel = 1 + (r % 3) * 5;
channel_forced = 0;
}
ret = p2p_set_listen_channel(p2p, reg_class, channel,
@@ -6348,8 +6391,10 @@
* Use random operation channel from (1, 6, 11)
*if no other preference is indicated.
*/
- os_get_random((u8 *) &r, sizeof(r));
- op_channel = 1 + (r % 3) * 5;
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ op_channel = 1;
+ else
+ op_channel = 1 + (r % 3) * 5;
cfg_op_channel = 0;
}
ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel,
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 40eb8d8..debceb9 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -158,6 +158,13 @@
return;
}
+ if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to assign random MAC address for a scan");
+ radio_work_done(work);
+ return;
+ }
+
wpa_supplicant_notify_scanning(wpa_s, 1);
if (wpa_s->clear_driver_scan_cache)
@@ -1244,6 +1251,13 @@
if (wpa_s->conf->filter_rssi)
params.filter_rssi = wpa_s->conf->filter_rssi;
+ /* See if user specified frequencies. If so, scan only those. */
+ if (wpa_s->conf->freq_list && !params.freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Optimize scan based on conf->freq_list");
+ int_array_concat(¶ms.freqs, wpa_s->conf->freq_list);
+ }
+
scan_params = ¶ms;
scan:
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 5188b9f..e4f2d12 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1318,7 +1318,10 @@
wpa_s->sme.sa_query_trans_id = nbuf;
wpa_s->sme.sa_query_count++;
- os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+ if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
+ return;
+ }
timeout = sa_query_retry_timeout;
sec = ((timeout / 1000) * 1024) / 1000;
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
index b6f9236..6dc41de 100644
--- a/wpa_supplicant/wifi_display.c
+++ b/wpa_supplicant/wifi_display.c
@@ -36,6 +36,34 @@
}
+struct wpabuf * wifi_display_get_wfd_ie(struct wpa_global *global)
+{
+ struct wpabuf *ie;
+ size_t len;
+ int i;
+
+ if (global->p2p == NULL)
+ return NULL;
+
+ len = 0;
+ for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
+ if (global->wfd_subelem[i])
+ len += wpabuf_len(global->wfd_subelem[i]);
+ }
+
+ ie = wpabuf_alloc(len);
+ if (ie == NULL)
+ return NULL;
+
+ for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
+ if (global->wfd_subelem[i])
+ wpabuf_put_buf(ie, global->wfd_subelem[i]);
+ }
+
+ return ie;
+}
+
+
static int wifi_display_update_wfd_ie(struct wpa_global *global)
{
struct wpabuf *ie, *buf;
@@ -238,6 +266,60 @@
}
+int wifi_display_subelem_set_from_ies(struct wpa_global *global,
+ struct wpabuf *ie)
+{
+ int subelements[MAX_WFD_SUBELEMS] = {};
+ const u8 *pos, *end;
+ int len, subelem;
+ struct wpabuf *e;
+
+ wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
+ ie, ie ? (unsigned long) wpabuf_len(ie) : 0);
+
+ if (ie == NULL || wpabuf_len(ie) < 6)
+ return -1;
+
+ pos = wpabuf_head(ie);
+ end = pos + wpabuf_len(ie);
+
+ while (end > pos) {
+ if (pos + 3 > end)
+ break;
+
+ len = WPA_GET_BE16(pos + 1) + 3;
+
+ wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
+ *pos, len - 3);
+
+ if (pos + len > end)
+ break;
+
+ subelem = *pos;
+ if (subelem < MAX_WFD_SUBELEMS && subelements[subelem] == 0) {
+ e = wpabuf_alloc_copy(pos, len);
+ if (e == NULL)
+ return -1;
+
+ wpabuf_free(global->wfd_subelem[subelem]);
+ global->wfd_subelem[subelem] = e;
+ subelements[subelem] = 1;
+ }
+
+ pos += len;
+ }
+
+ for (subelem = 0; subelem < MAX_WFD_SUBELEMS; subelem++) {
+ if (subelements[subelem] == 0) {
+ wpabuf_free(global->wfd_subelem[subelem]);
+ global->wfd_subelem[subelem] = NULL;
+ }
+ }
+
+ return wifi_display_update_wfd_ie(global);
+}
+
+
int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
char *buf, size_t buflen)
{
diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h
index 7554817..0966bdb 100644
--- a/wpa_supplicant/wifi_display.h
+++ b/wpa_supplicant/wifi_display.h
@@ -13,7 +13,10 @@
int wifi_display_init(struct wpa_global *global);
void wifi_display_deinit(struct wpa_global *global);
void wifi_display_enable(struct wpa_global *global, int enabled);
+struct wpabuf *wifi_display_get_wfd_ie(struct wpa_global *global);
int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
+int wifi_display_subelem_set_from_ies(struct wpa_global *global,
+ struct wpabuf *ie);
int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
char *buf, size_t buflen);
char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 8811d6f..18b9b77 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -532,6 +532,13 @@
}
+static int wpa_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
+}
+
+
static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
print_help(argc > 0 ? argv[0] : NULL);
@@ -2519,6 +2526,9 @@
{ "pmksa", wpa_cli_cmd_pmksa, NULL,
cli_cmd_flag_none,
"= show PMKSA cache" },
+ { "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL,
+ cli_cmd_flag_none,
+ "= flush PMKSA cache entries" },
{ "reassociate", wpa_cli_cmd_reassociate, NULL,
cli_cmd_flag_none,
"= force reassociation" },
@@ -3178,15 +3188,29 @@
{
const char *pos;
char *copy = NULL, *id, *pos2;
+ const char *ifname = ctrl_ifname;
+ char ifname_buf[100];
pos = msg;
+ if (os_strncmp(pos, "IFNAME=", 7) == 0) {
+ const char *end;
+ end = os_strchr(pos + 7, ' ');
+ if (end && (unsigned int) (end - pos) < sizeof(ifname_buf)) {
+ pos += 7;
+ os_memcpy(ifname_buf, pos, end - pos);
+ ifname_buf[end - pos] = '\0';
+ ifname = ifname_buf;
+ pos = end + 1;
+ }
+ }
if (*pos == '<') {
+ const char *prev = pos;
/* skip priority */
pos = os_strchr(pos, '>');
if (pos)
pos++;
else
- pos = msg;
+ pos = prev;
}
if (str_match(pos, WPA_EVENT_CONNECTED)) {
@@ -3223,37 +3247,37 @@
if (wpa_cli_connected <= 0 || new_id != wpa_cli_last_id) {
wpa_cli_connected = 1;
wpa_cli_last_id = new_id;
- wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
+ wpa_cli_exec(action_file, ifname, "CONNECTED");
}
} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
if (wpa_cli_connected) {
wpa_cli_connected = 0;
- wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
+ wpa_cli_exec(action_file, ifname, "DISCONNECTED");
}
} else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, WPS_EVENT_FAIL)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, AP_STA_CONNECTED)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, AP_STA_DISCONNECTED)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
- wpa_cli_exec(action_file, ctrl_ifname, pos);
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
@@ -3385,7 +3409,7 @@
return;
}
while (wpa_ctrl_pending(ctrl) > 0) {
- char buf[256];
+ char buf[4096];
size_t len = sizeof(buf) - 1;
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
buf[len] = '\0';
@@ -3449,10 +3473,18 @@
static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
{
- if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
- printf("Connection to wpa_supplicant lost - trying to "
- "reconnect\n");
- wpa_cli_close_connection();
+ if (ctrl_conn) {
+ int res;
+ char *prefix = ifname_prefix;
+
+ ifname_prefix = NULL;
+ res = _wpa_ctrl_command(ctrl_conn, "PING", 0);
+ ifname_prefix = prefix;
+ if (res) {
+ printf("Connection to wpa_supplicant lost - trying to "
+ "reconnect\n");
+ wpa_cli_close_connection();
+ }
}
if (!ctrl_conn)
wpa_cli_reconnect();
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 9d21fe0..d128992 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -300,6 +300,7 @@
wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
eapol_conf.external_sim = wpa_s->conf->external_sim;
+ eapol_conf.wps = wpa_s->key_mgmt == WPA_KEY_MGMT_WPS;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
#endif /* IEEE8021X_EAPOL */
@@ -1382,6 +1383,68 @@
}
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
+{
+ struct os_reltime now;
+ u8 addr[ETH_ALEN];
+
+ os_get_reltime(&now);
+ if (wpa_s->last_mac_addr_style == style &&
+ wpa_s->last_mac_addr_change.sec != 0 &&
+ !os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
+ wpa_s->conf->rand_addr_lifetime)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Previously selected random MAC address has not yet expired");
+ return 0;
+ }
+
+ switch (style) {
+ case 1:
+ if (random_mac_addr(addr) < 0)
+ return -1;
+ break;
+ case 2:
+ os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
+ if (random_mac_addr_keep_oui(addr) < 0)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to set random MAC address");
+ return -1;
+ }
+
+ os_get_reltime(&wpa_s->last_mac_addr_change);
+ wpa_s->mac_addr_changed = 1;
+ wpa_s->last_mac_addr_style = style;
+
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return -1;
+ }
+
+ wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
+ MAC2STR(addr));
+
+ return 0;
+}
+
+
+int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING ||
+ !wpa_s->conf->preassoc_mac_addr)
+ return 0;
+
+ return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr);
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
/**
@@ -1396,6 +1459,34 @@
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
struct wpa_connect_work *cwork;
+ int rand_style;
+
+ if (ssid->mac_addr == -1)
+ rand_style = wpa_s->conf->mac_addr;
+ else
+ rand_style = ssid->mac_addr;
+
+ if (wpa_s->last_ssid == ssid) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+ } else if (rand_style > 0) {
+ if (wpas_update_random_addr(wpa_s, rand_style) < 0)
+ return;
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+ } else if (wpa_s->mac_addr_changed) {
+ if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not restore permanent MAC address");
+ return;
+ }
+ wpa_s->mac_addr_changed = 0;
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
+ }
+ wpa_s->last_ssid = ssid;
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
@@ -2664,6 +2755,8 @@
return -1;
}
+ wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
return 0;
}
@@ -2711,6 +2804,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
MAC2STR(wpa_s->own_addr));
+ os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
if (wpa_s->bridge_ifname[0]) {
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 2a0dc20..89da0da 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -332,6 +332,25 @@
# 1: Scan current operating frequency if another VIF on the same radio
# is already associated.
+# MAC address policy default
+# 0 = use permanent MAC address
+# 1 = use random MAC address for each ESS connection
+# 2 = like 1, but maintain OUI (with local admin bit set)
+#
+# By default, permanent MAC address is used unless policy is changed by
+# the per-network mac_addr parameter. Global mac_addr=1 can be used to
+# change this default behavior.
+#mac_addr=0
+
+# Lifetime of random MAC address in seconds (default: 60)
+#rand_addr_lifetime=60
+
+# MAC address policy for pre-association operations (scanning, ANQP)
+# 0 = use permanent MAC address
+# 1 = use random MAC address
+# 2 = like 1, but maintain OUI (with local admin bit set)
+#preassoc_mac_addr=0
+
# Interworking (IEEE 802.11u)
# Enable Interworking
@@ -962,6 +981,12 @@
# Beacon interval (default: 100 TU)
#beacon_int=100
+# MAC address policy
+# 0 = use permanent MAC address
+# 1 = use random MAC address for each ESS connection
+# 2 = like 1, but maintain OUI (with local admin bit set)
+#mac_addr=0
+
# disable_ht: Whether HT (802.11n) should be disabled.
# 0 = HT enabled (if AP supports it)
# 1 = HT disabled
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index bf3d19d..f941923 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -391,6 +391,7 @@
struct l2_packet_data *l2;
struct l2_packet_data *l2_br;
unsigned char own_addr[ETH_ALEN];
+ unsigned char perm_addr[ETH_ALEN];
char ifname[100];
#ifdef CONFIG_CTRL_IFACE_DBUS
char *dbus_path;
@@ -421,6 +422,7 @@
int disconnected; /* all connections disabled; i.e., do no reassociate
* before this has been cleared */
struct wpa_ssid *current_ssid;
+ struct wpa_ssid *last_ssid;
struct wpa_bss *current_bss;
int ap_ies_from_associnfo;
unsigned int assoc_freq;
@@ -600,6 +602,7 @@
struct wps_context *wps;
int wps_success; /* WPS success event received */
struct wps_er *wps_er;
+ unsigned int wps_run;
int blacklist_cleared;
struct wpabuf *pending_eapol_rx;
@@ -608,6 +611,10 @@
unsigned int last_eapol_matches_bssid:1;
unsigned int eap_expected_failure:1;
unsigned int reattach:1; /* reassociation to the same BSS requested */
+ unsigned int mac_addr_changed:1;
+
+ struct os_reltime last_mac_addr_change;
+ int last_mac_addr_style;
struct ibss_rsn *ibss_rsn;
@@ -957,6 +964,8 @@
size_t ssid_len);
void wpas_request_connection(struct wpa_supplicant *wpa_s);
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
+int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 350b122..09b5961 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -142,11 +142,29 @@
if (pmksa_cache_get_current(wpa_s->wpa) &&
type == IEEE802_1X_TYPE_EAPOL_START) {
- /* Trying to use PMKSA caching - do not send EAPOL-Start frames
- * since they will trigger full EAPOL authentication. */
- wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
- "EAPOL-Start");
- return -1;
+ /*
+ * We were trying to use PMKSA caching and sending EAPOL-Start
+ * would abort that and trigger full EAPOL authentication.
+ * However, we've already waited for the AP/Authenticator to
+ * start 4-way handshake or EAP authentication, and apparently
+ * it has not done so since the startWhen timer has reached zero
+ * to get the state machine sending EAPOL-Start. This is not
+ * really supposed to happen, but an interoperability issue with
+ * a deployed AP has been identified where the connection fails
+ * due to that AP failing to operate correctly if PMKID is
+ * included in the Association Request frame. To work around
+ * this, assume PMKSA caching failed and try to initiate full
+ * EAP authentication.
+ */
+ if (!wpa_s->current_ssid ||
+ wpa_s->current_ssid->eap_workaround) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Timeout on waiting for the AP to initiate 4-way handshake for PMKSA caching or EAP authentication - try to force it to start EAP authentication");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "RSN: PMKSA caching - do not send EAPOL-Start");
+ return -1;
+ }
}
if (is_zero_ether_addr(wpa_s->bssid)) {
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index fd0d14a..40a5c69 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -286,11 +286,54 @@
/* compare security parameters */
if (ssid->auth_alg != new_ssid->auth_alg ||
ssid->key_mgmt != new_ssid->key_mgmt ||
- ssid->proto != new_ssid->proto ||
- ssid->pairwise_cipher != new_ssid->pairwise_cipher ||
ssid->group_cipher != new_ssid->group_cipher)
continue;
+ /*
+ * Some existing WPS APs will send two creds in case they are
+ * configured for mixed mode operation (WPA+WPA2 and TKIP+CCMP).
+ * Try to merge these two creds if they are received in the same
+ * M8 message.
+ */
+ if (ssid->wps_run && ssid->wps_run == new_ssid->wps_run &&
+ wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
+ if (new_ssid->passphrase && ssid->passphrase &&
+ os_strcmp(new_ssid->passphrase, ssid->passphrase) !=
+ 0) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: M8 Creds with different passphrase - do not merge");
+ continue;
+ }
+
+ if (new_ssid->psk_set &&
+ (!ssid->psk_set ||
+ os_memcmp(new_ssid->psk, ssid->psk, 32) != 0)) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: M8 Creds with different PSK - do not merge");
+ continue;
+ }
+
+ if ((new_ssid->passphrase && !ssid->passphrase) ||
+ (!new_ssid->passphrase && ssid->passphrase)) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: M8 Creds with different passphrase/PSK type - do not merge");
+ continue;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "WPS: Workaround - merge likely WPA/WPA2-mixed mode creds in same M8 message");
+ new_ssid->proto |= ssid->proto;
+ new_ssid->pairwise_cipher |= ssid->pairwise_cipher;
+ } else {
+ /*
+ * proto and pairwise_cipher difference matter for
+ * non-mixed-mode creds.
+ */
+ if (ssid->proto != new_ssid->proto ||
+ ssid->pairwise_cipher != new_ssid->pairwise_cipher)
+ continue;
+ }
+
/* Remove the duplicated older network entry. */
wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
wpas_notify_network_removed(wpa_s, ssid);
@@ -411,6 +454,7 @@
}
wpa_config_set_network_defaults(ssid);
+ ssid->wps_run = wpa_s->wps_run;
os_free(ssid->ssid);
ssid->ssid = os_malloc(cred->ssid_len);
@@ -1004,6 +1048,9 @@
{
struct wpa_bss *bss;
+ wpa_s->wps_run++;
+ if (wpa_s->wps_run == 0)
+ wpa_s->wps_run++;
wpa_s->after_wps = 0;
wpa_s->known_wps_freq = 0;
if (freq) {