am 772e12cf: Cumulative security CVE-2014-3686 patch
* commit '772e12cfed81754a9fd890be7bc77bc602a549b5':
Cumulative security CVE-2014-3686 patch
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 95f28d3..9e62bef 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -835,6 +835,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 0ad6187..fe30b41 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" },
@@ -3169,15 +3179,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)) {
@@ -3214,37 +3238,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;
@@ -3376,7 +3400,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';
@@ -3440,10 +3464,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) {