Accumulative patch from commit 17b8995cf5813d7c027cd7a6884700e791d72392
17b8995 Interworking: Try to use same BSS entry for storing GAS results
3db5439 Optimize Extended Capabilities element to be of minimal length
8cd6b7b hostapd/wpa_s: Use driver's extended capabilities
acb5464 Add ctrl_iface command FLUSH for clearing wpa_supplicant state
97236ce WPS: Skip rescanning after provisioning if AP was configured
4342326 Add ignore_old_scan_res configuration parameter
9599ccc WPS: Clear after_wps on new WPS connection
702621e WPS: Use latest updated BSS entry if multiple BSSID matches found
ab547b5 WPS: Add more helpful debug for invalid WPS_REG command parsing
a679c0f WPS: Allow hostapd process to control independent WPS interfaces
ccdff94 WPS AP: Add support for reconfiguration with in-memory config
8970bae nl80211: Use nla_nest_start/end instead of nla_put_nested
558d69e P2P: Omit P2P Group Info in case of no connected peers
65a32cd AP: Fix infinite loop in WPA state machine when out of random bytes
a5f61b2 Fix OLBC non-HT AP detection to check channel
69554d7 ap_list: Remove unused functions
08c99ca ap_list: Remove unused iteration list pointers
6b16917 ap_list: Remove unused fields
66f1f75 P2P: Fix provision discovery response handling in some cases
2f9b66d Extend ROAM command to handle multiple SSIDs per BSS
Change-Id: I46002b1d3bbf6e376c2ae09bcb2c824c54805bbd
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index e29ae2f..12d627a 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2509,6 +2509,8 @@
"wps_state", line);
errors++;
}
+ } else if (os_strcmp(buf, "wps_independent") == 0) {
+ bss->wps_independent = atoi(pos);
} else if (os_strcmp(buf, "ap_setup_locked") == 0) {
bss->ap_setup_locked = atoi(pos);
} else if (os_strcmp(buf, "uuid") == 0) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index eca3996..17bb7ed 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1124,6 +1124,14 @@
# 2 = WPS enabled, configured
#wps_state=2
+# Whether to manage this interface independently from other WPS interfaces
+# By default, a single hostapd process applies WPS operations to all configured
+# interfaces. This parameter can be used to disable that behavior for a subset
+# of interfaces. If this is set to non-zero for an interface, WPS commands
+# issued on that interface do not apply to other interfaces and WPS operations
+# performed on other interfaces do not affect this interface.
+#wps_independent=0
+
# AP can be configured into a locked state where new WPS Registrar are not
# accepted, but previously authorized Registrars (including the internal one)
# can continue to add new Enrollees.
diff --git a/hostapd/main.c b/hostapd/main.c
index 4b0da3c..881a053 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -274,6 +274,9 @@
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
iface->drv_flags = capa.flags;
iface->probe_resp_offloads = capa.probe_resp_offloads;
+ iface->extended_capa = capa.extended_capa;
+ iface->extended_capa_mask = capa.extended_capa_mask;
+ iface->extended_capa_len = capa.extended_capa_len;
}
return 0;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 6606f72..d9ef984 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -340,6 +340,7 @@
int wps_state;
#ifdef CONFIG_WPS
+ int wps_independent;
int ap_setup_locked;
u8 uuid[16];
char *wps_pin_requests;
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 18090ca..9f02151 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -50,7 +50,7 @@
}
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
+static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
{
struct ap_info *s;
@@ -87,34 +87,6 @@
}
-static void ap_ap_iter_list_add(struct hostapd_iface *iface,
- struct ap_info *ap)
-{
- if (iface->ap_iter_list) {
- ap->iter_prev = iface->ap_iter_list->iter_prev;
- iface->ap_iter_list->iter_prev = ap;
- } else
- ap->iter_prev = ap;
- ap->iter_next = iface->ap_iter_list;
- iface->ap_iter_list = ap;
-}
-
-
-static void ap_ap_iter_list_del(struct hostapd_iface *iface,
- struct ap_info *ap)
-{
- if (iface->ap_iter_list == ap)
- iface->ap_iter_list = ap->iter_next;
- else
- ap->iter_prev->iter_next = ap->iter_next;
-
- if (ap->iter_next)
- ap->iter_next->iter_prev = ap->iter_prev;
- else if (iface->ap_iter_list)
- iface->ap_iter_list->iter_prev = ap->iter_prev;
-}
-
-
static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
{
ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
@@ -148,7 +120,6 @@
{
ap_ap_hash_del(iface, ap);
ap_ap_list_del(iface, ap);
- ap_ap_iter_list_del(iface, ap);
iface->num_ap--;
os_free(ap);
@@ -171,25 +142,6 @@
}
-int ap_ap_for_each(struct hostapd_iface *iface,
- int (*func)(struct ap_info *s, void *data), void *data)
-{
- struct ap_info *s;
- int ret = 0;
-
- s = iface->ap_list;
-
- while (s) {
- ret = func(s, data);
- if (ret)
- break;
- s = s->next;
- }
-
- return ret;
-}
-
-
static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
{
struct ap_info *ap;
@@ -203,7 +155,6 @@
ap_ap_list_add(iface, ap);
iface->num_ap++;
ap_ap_hash_add(iface, ap);
- ap_ap_iter_list_add(iface, ap);
if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
@@ -223,7 +174,6 @@
struct ap_info *ap;
struct os_time now;
int new_ap = 0;
- size_t len;
int set_beacon = 0;
if (iface->conf->ap_table_max_size < 1)
@@ -239,24 +189,10 @@
new_ap = 1;
}
- ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
- ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
-
- if (elems->ssid) {
- len = elems->ssid_len;
- if (len >= sizeof(ap->ssid))
- len = sizeof(ap->ssid) - 1;
- os_memcpy(ap->ssid, elems->ssid, len);
- ap->ssid[len] = '\0';
- ap->ssid_len = len;
- }
-
merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
elems->supp_rates, elems->supp_rates_len,
elems->ext_supp_rates, elems->ext_supp_rates_len);
- ap->wpa = elems->wpa_ie != NULL;
-
if (elems->erp_info && elems->erp_info_len == 1)
ap->erp = elems->erp_info[0];
else
@@ -264,6 +200,8 @@
if (elems->ds_params && elems->ds_params_len == 1)
ap->channel = elems->ds_params[0];
+ else if (elems->ht_operation && elems->ht_operation_len >= 1)
+ ap->channel = elems->ht_operation[0];
else if (fi)
ap->channel = fi->channel;
@@ -272,11 +210,8 @@
else
ap->ht_support = 0;
- ap->num_beacons++;
os_get_time(&now);
ap->last_beacon = now.sec;
- if (fi)
- ap->datarate = fi->datarate;
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
@@ -288,17 +223,23 @@
if (!iface->olbc &&
ap_list_beacon_olbc(iface, ap)) {
iface->olbc = 1;
- wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
- "protection", MAC2STR(ap->addr));
+ wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
+ " (channel %d) - enable protection",
+ MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
- if (!iface->olbc_ht && !ap->ht_support) {
+ if (!iface->olbc_ht && !ap->ht_support &&
+ (ap->channel == 0 ||
+ ap->channel == iface->conf->channel ||
+ ap->channel == iface->conf->channel +
+ iface->conf->secondary_channel * 4)) {
iface->olbc_ht = 1;
hostapd_ht_operation_update(iface);
wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
- " - enable protection", MAC2STR(ap->addr));
+ " (channel %d) - enable protection",
+ MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index f0b4125..d0529a1 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -14,42 +14,24 @@
struct ap_info {
/* Note: next/prev pointers are updated whenever a new beacon is
* received because these are used to find the least recently used
- * entries. iter_next/iter_prev are updated only when adding new BSSes
- * and when removing old ones. These should be used when iterating
- * through the table in a manner that allows beacons to be received
- * during the iteration. */
+ * entries. */
struct ap_info *next; /* next entry in AP list */
struct ap_info *prev; /* previous entry in AP list */
struct ap_info *hnext; /* next entry in hash table list */
- struct ap_info *iter_next; /* next entry in AP iteration list */
- struct ap_info *iter_prev; /* previous entry in AP iteration list */
u8 addr[6];
- u16 beacon_int;
- u16 capability;
u8 supported_rates[WLAN_SUPP_RATES_MAX];
- u8 ssid[33];
- size_t ssid_len;
- int wpa;
int erp; /* ERP Info or -1 if ERP info element not present */
int channel;
- int datarate; /* in 100 kbps */
int ht_support;
- unsigned int num_beacons; /* number of beacon frames received */
os_time_t last_beacon;
-
- int already_seen; /* whether API call AP-NEW has already fetched
- * information about this AP */
};
struct ieee802_11_elems;
struct hostapd_frame_info;
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
-int ap_ap_for_each(struct hostapd_iface *iface,
- int (*func)(struct ap_info *s, void *data), void *data);
void ap_list_process_beacon(struct hostapd_iface *iface,
const struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 92fda56..a0ac38c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -108,19 +108,10 @@
}
-int hostapd_reload_config(struct hostapd_iface *iface)
+static void hostapd_clear_old(struct hostapd_iface *iface)
{
- struct hostapd_data *hapd = iface->bss[0];
- struct hostapd_config *newconf, *oldconf;
size_t j;
- if (iface->interfaces == NULL ||
- iface->interfaces->config_read_cb == NULL)
- return -1;
- newconf = iface->interfaces->config_read_cb(iface->config_fname);
- if (newconf == NULL)
- return -1;
-
/*
* Deauthenticate all stations since the new configuration may not
* allow them to use the BSS anymore.
@@ -136,6 +127,31 @@
radius_client_flush(iface->bss[j]->radius, 0);
#endif /* CONFIG_NO_RADIUS */
}
+}
+
+
+int hostapd_reload_config(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ struct hostapd_config *newconf, *oldconf;
+ size_t j;
+
+ if (iface->config_fname == NULL) {
+ /* Only in-memory config in use - assume it has been updated */
+ hostapd_clear_old(iface);
+ for (j = 0; j < iface->num_bss; j++)
+ hostapd_reload_bss(iface->bss[j]);
+ return 0;
+ }
+
+ if (iface->interfaces == NULL ||
+ iface->interfaces->config_read_cb == NULL)
+ return -1;
+ newconf = iface->interfaces->config_read_cb(iface->config_fname);
+ if (newconf == NULL)
+ return -1;
+
+ hostapd_clear_old(iface);
oldconf = hapd->iconf;
iface->conf = newconf;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index f5aed99..9a3bb68 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -220,7 +220,6 @@
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
- struct ap_info *ap_iter_list;
unsigned int drv_flags;
@@ -230,6 +229,10 @@
*/
unsigned int probe_resp_offloads;
+ /* extended capabilities supported by the driver */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 76f78a7..c36bbe3 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -164,10 +164,52 @@
#endif /* CONFIG_IEEE80211W */
+static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+{
+ *pos = 0x00;
+
+ switch (idx) {
+ case 0: /* Bits 0-7 */
+ break;
+ case 1: /* Bits 8-15 */
+ break;
+ case 2: /* Bits 16-23 */
+ if (hapd->conf->wnm_sleep_mode)
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ if (hapd->conf->bss_transition)
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+ break;
+ case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+ if (hapd->conf->time_advertisement == 2)
+ *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+ if (hapd->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+ break;
+ case 4: /* Bits 32-39 */
+ if (hapd->conf->tdls & TDLS_PROHIBIT)
+ *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+ if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
+ /* Bit 39 - TDLS Channel Switching Prohibited */
+ *pos |= 0x80;
+ }
+ break;
+ case 5: /* Bits 40-47 */
+ break;
+ case 6: /* Bits 48-55 */
+ if (hapd->conf->ssid.utf8_ssid)
+ *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+ break;
+ }
+}
+
+
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- u8 len = 0;
+ u8 len = 0, i;
if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
len = 5;
@@ -181,55 +223,30 @@
if (len < 4)
len = 4;
#endif /* CONFIG_WNM */
+ if (len < hapd->iface->extended_capa_len)
+ len = hapd->iface->extended_capa_len;
if (len == 0)
return eid;
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
- *pos++ = 0x00;
- *pos++ = 0x00;
+ for (i = 0; i < len; i++, pos++) {
+ hostapd_ext_capab_byte(hapd, pos, i);
- *pos = 0x00;
- if (hapd->conf->wnm_sleep_mode)
- *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
- if (hapd->conf->bss_transition)
- *pos |= 0x08; /* Bit 19 - BSS Transition */
- pos++;
+ if (i < hapd->iface->extended_capa_len) {
+ *pos &= ~hapd->iface->extended_capa_mask[i];
+ *pos |= hapd->iface->extended_capa[i];
+ }
+ }
- if (len < 4)
- return pos;
- *pos = 0x00;
-#ifdef CONFIG_WNM
- *pos |= 0x02; /* Bit 25 - SSID List */
-#endif /* CONFIG_WNM */
- if (hapd->conf->time_advertisement == 2)
- *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
- if (hapd->conf->interworking)
- *pos |= 0x80; /* Bit 31 - Interworking */
- pos++;
+ while (len > 0 && eid[1 + len] == 0) {
+ len--;
+ eid[1] = len;
+ }
+ if (len == 0)
+ return eid;
- if (len < 5)
- return pos;
- *pos = 0x00;
- if (hapd->conf->tdls & TDLS_PROHIBIT)
- *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
- if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
- *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
- pos++;
-
- if (len < 6)
- return pos;
- *pos = 0x00;
- pos++;
-
- if (len < 7)
- return pos;
- *pos = 0x00;
- if (hapd->conf->ssid.utf8_ssid)
- *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
- pos++;
-
- return pos;
+ return eid + 2 + len;
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index fa4b1cb..4f1f6fb 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1598,6 +1598,7 @@
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
wpa_group_ensure_init(sm->wpa_auth, sm->group);
+ sm->ReAuthenticationRequest = FALSE;
/*
* Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
@@ -1611,12 +1612,11 @@
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
"ANonce.");
- wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ sm->Disconnect = TRUE;
return;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
WPA_NONCE_LEN);
- sm->ReAuthenticationRequest = FALSE;
/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
* logical place than INITIALIZE since AUTHENTICATION2 can be
* re-entered on ReAuthenticationRequest without going through
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index e017972..69b34fe 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -45,6 +45,7 @@
struct wps_for_each_data {
int (*func)(struct hostapd_data *h, void *ctx);
void *ctx;
+ struct hostapd_data *calling_hapd;
};
@@ -57,7 +58,14 @@
return 0;
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
- int ret = data->func(hapd, data->ctx);
+ int ret;
+
+ if (hapd != data->calling_hapd &&
+ (hapd->conf->wps_independent ||
+ data->calling_hapd->conf->wps_independent))
+ continue;
+
+ ret = data->func(hapd, data->ctx);
if (ret)
return ret;
}
@@ -74,6 +82,7 @@
struct wps_for_each_data data;
data.func = func;
data.ctx = ctx;
+ data.calling_hapd = hapd;
if (iface->interfaces == NULL ||
iface->interfaces->for_each_interface == NULL)
return wps_for_each(iface, &data);
@@ -277,6 +286,114 @@
}
+static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
+ const struct wps_credential *cred)
+{
+ struct hostapd_bss_config *bss = hapd->conf;
+
+ wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
+
+ bss->wps_state = 2;
+ if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+ os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
+ bss->ssid.ssid_len = cred->ssid_len;
+ bss->ssid.ssid_set = 1;
+ }
+
+ if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+ (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+ bss->wpa = 3;
+ else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+ bss->wpa = 2;
+ else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ bss->wpa = 1;
+ else
+ bss->wpa = 0;
+
+ if (bss->wpa) {
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+ if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+ bss->wpa_pairwise = 0;
+ if (cred->encr_type & WPS_ENCR_AES)
+ bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+ if (cred->encr_type & WPS_ENCR_TKIP)
+ bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+ bss->wpa_pairwise,
+ bss->rsn_pairwise);
+
+ if (cred->key_len >= 8 && cred->key_len < 64) {
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
+ if (bss->ssid.wpa_passphrase)
+ os_memcpy(bss->ssid.wpa_passphrase, cred->key,
+ cred->key_len);
+ os_free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk = NULL;
+ } else if (cred->key_len == 64) {
+ os_free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk =
+ os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (bss->ssid.wpa_psk &&
+ hexstr2bin((const char *) cred->key,
+ bss->ssid.wpa_psk->psk, PMK_LEN) == 0) {
+ bss->ssid.wpa_psk->group = 1;
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = NULL;
+ }
+ }
+ bss->auth_algs = 1;
+ } else {
+ if ((cred->auth_type & WPS_AUTH_OPEN) &&
+ (cred->auth_type & WPS_AUTH_SHARED))
+ bss->auth_algs = 3;
+ else if (cred->auth_type & WPS_AUTH_SHARED)
+ bss->auth_algs = 2;
+ else
+ bss->auth_algs = 1;
+ if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx > 0 &&
+ cred->key_idx <= 4) {
+ struct hostapd_wep_keys *wep = &bss->ssid.wep;
+ int idx = cred->key_idx;
+ if (idx)
+ idx--;
+ wep->idx = idx;
+ if (cred->key_len == 10 || cred->key_len == 26) {
+ os_free(wep->key[idx]);
+ wep->key[idx] = os_malloc(cred->key_len / 2);
+ if (wep->key[idx] == NULL ||
+ hexstr2bin((const char *) cred->key,
+ wep->key[idx],
+ cred->key_len / 2))
+ return -1;
+ wep->len[idx] = cred->key_len / 2;
+ } else {
+ os_free(wep->key[idx]);
+ wep->key[idx] = os_malloc(cred->key_len);
+ if (wep->key[idx] == NULL)
+ return -1;
+ os_memcpy(wep->key[idx], cred->key,
+ cred->key_len);
+ wep->len[idx] = cred->key_len;
+ }
+ wep->keys_set = 1;
+ }
+ }
+
+ /* Schedule configuration reload after short period of time to allow
+ * EAP-WSC to be finished.
+ */
+ eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
+ NULL);
+
+ return 0;
+}
+
+
static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
{
const struct wps_credential *cred = ctx;
@@ -344,7 +461,7 @@
hapd->wps->wps_state = WPS_STATE_CONFIGURED;
if (hapd->iface->config_fname == NULL)
- return 0;
+ return hapd_wps_reconfig_in_memory(hapd, cred);
len = os_strlen(hapd->iface->config_fname) + 5;
tmp_fname = os_malloc(len);
if (tmp_fname == NULL)
@@ -706,7 +823,8 @@
return 0;
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
- if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+ if (hapd->wps && !hapd->conf->wps_independent &&
+ !is_nil_uuid(hapd->wps->uuid)) {
*uuid = hapd->wps->uuid;
return 1;
}
@@ -799,7 +917,7 @@
if (is_nil_uuid(hapd->conf->uuid)) {
const u8 *uuid;
uuid = get_own_uuid(hapd->iface);
- if (uuid) {
+ if (uuid && !conf->wps_independent) {
os_memcpy(wps->uuid, uuid, UUID_LEN);
wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
"interface", wps->uuid, UUID_LEN);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 63f90bc..14b64a6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -897,6 +897,15 @@
/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
unsigned int probe_resp_offloads;
+
+ /**
+ * extended_capa - extended capabilities in driver/device
+ *
+ * Must be allocated and freed by driver and the pointers must be
+ * valid for the lifetime of the driver, i.e., freed in deinit()
+ */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c2b9fff..cd266b4 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -214,6 +214,8 @@
int ignore_if_down_event;
struct rfkill_data *rfkill;
struct wpa_driver_capa capa;
+ u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
int has_capability;
int operstate;
@@ -2554,6 +2556,7 @@
struct wiphy_info_data {
+ struct wpa_driver_nl80211_data *drv;
struct wpa_driver_capa *capa;
unsigned int error:1;
@@ -2795,6 +2798,7 @@
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct wiphy_info_data *info = arg;
struct wpa_driver_capa *capa = info->capa;
+ struct wpa_driver_nl80211_data *drv = info->drv;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -2842,6 +2846,30 @@
wiphy_info_probe_resp_offload(capa,
tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+ if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+ drv->extended_capa == NULL) {
+ drv->extended_capa =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ if (drv->extended_capa) {
+ os_memcpy(drv->extended_capa,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ drv->extended_capa_len =
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+ }
+ drv->extended_capa_mask =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ if (drv->extended_capa_mask) {
+ os_memcpy(drv->extended_capa_mask,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ } else {
+ os_free(drv->extended_capa);
+ drv->extended_capa = NULL;
+ drv->extended_capa_len = 0;
+ }
+ }
+
return NL_SKIP;
}
@@ -2854,6 +2882,7 @@
os_memset(info, 0, sizeof(*info));
info->capa = &drv->capa;
+ info->drv = drv;
msg = nlmsg_alloc();
if (!msg)
@@ -3751,6 +3780,8 @@
if (drv->in_interface_list)
dl_list_del(&drv->list);
+ os_free(drv->extended_capa);
+ os_free(drv->extended_capa_mask);
os_free(drv);
}
@@ -3781,7 +3812,6 @@
struct wpa_driver_scan_params *params)
{
struct nl_msg *msg;
- int err;
size_t i;
msg = nlmsg_alloc();
@@ -3794,23 +3824,20 @@
goto fail;
if (params->num_ssids) {
- struct nl_msg *ssids = nlmsg_alloc();
+ struct nlattr *ssids;
+
+ ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
if (ssids == NULL)
goto fail;
for (i = 0; i < params->num_ssids; i++) {
wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
params->ssids[i].ssid,
params->ssids[i].ssid_len);
- if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid) < 0) {
- nlmsg_free(ssids);
+ if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid) < 0)
goto fail;
- }
}
- err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
- nlmsg_free(ssids);
- if (err < 0)
- goto fail;
+ nla_nest_end(msg, ssids);
}
if (params->extra_ies) {
@@ -3822,22 +3849,17 @@
}
if (params->freqs) {
- struct nl_msg *freqs = nlmsg_alloc();
+ struct nlattr *freqs;
+ freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
if (freqs == NULL)
goto fail;
for (i = 0; params->freqs[i]; i++) {
wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
"MHz", params->freqs[i]);
- if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
- nlmsg_free(freqs);
+ if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
goto fail;
- }
}
- err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
- freqs);
- nlmsg_free(freqs);
- if (err < 0)
- goto fail;
+ nla_nest_end(msg, freqs);
}
os_free(drv->filter_ssids);
@@ -3864,7 +3886,7 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1, timeout;
- struct nl_msg *msg, *rates = NULL;
+ struct nl_msg *msg = NULL;
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
drv->scan_for_auth = 0;
@@ -3874,9 +3896,11 @@
return -1;
if (params->p2p_probe) {
+ struct nlattr *rates;
+
wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
- rates = nlmsg_alloc();
+ rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
if (rates == NULL)
goto nla_put_failure;
@@ -3886,11 +3910,9 @@
* 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
* rates are left enabled.
*/
- NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+ NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
"\x0c\x12\x18\x24\x30\x48\x60\x6c");
- if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
- 0)
- goto nla_put_failure;
+ nla_nest_end(msg, rates);
NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
}
@@ -3944,7 +3966,6 @@
nla_put_failure:
nlmsg_free(msg);
- nlmsg_free(rates);
return ret;
}
@@ -3964,8 +3985,6 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
struct nl_msg *msg;
- struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
- struct nl_msg *match_set_rssi = NULL;
size_t i;
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
@@ -3984,46 +4003,42 @@
if ((drv->num_filter_ssids &&
(int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
params->filter_rssi) {
- match_sets = nlmsg_alloc();
+ struct nlattr *match_sets;
+ match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
if (match_sets == NULL)
goto nla_put_failure;
for (i = 0; i < drv->num_filter_ssids; i++) {
+ struct nlattr *match_set_ssid;
wpa_hexdump_ascii(MSG_MSGDUMP,
"nl80211: Sched scan filter SSID",
drv->filter_ssids[i].ssid,
drv->filter_ssids[i].ssid_len);
- match_set_ssid = nlmsg_alloc();
+ match_set_ssid = nla_nest_start(msg, i + 1);
if (match_set_ssid == NULL)
goto nla_put_failure;
- NLA_PUT(match_set_ssid,
- NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+ NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
drv->filter_ssids[i].ssid_len,
drv->filter_ssids[i].ssid);
- if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
- 0)
- goto nla_put_failure;
+ nla_nest_end(msg, match_sets);
}
if (params->filter_rssi) {
- match_set_rssi = nlmsg_alloc();
+ struct nlattr *match_set_rssi;
+ match_set_rssi = nla_nest_start(msg, 0);
if (match_set_rssi == NULL)
goto nla_put_failure;
- NLA_PUT_U32(match_set_rssi,
- NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
params->filter_rssi);
wpa_printf(MSG_MSGDUMP,
"nl80211: Sched scan RSSI filter %d dBm",
params->filter_rssi);
- if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
- goto nla_put_failure;
+ nla_nest_end(msg, match_set_rssi);
}
- if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
- match_sets) < 0)
- goto nla_put_failure;
+ nla_nest_end(msg, match_sets);
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -4041,9 +4056,6 @@
"scan interval %d msec", ret, interval);
nla_put_failure:
- nlmsg_free(match_set_ssid);
- nlmsg_free(match_sets);
- nlmsg_free(match_set_rssi);
nlmsg_free(msg);
return ret;
}
@@ -4532,18 +4544,15 @@
NL80211_KEYTYPE_GROUP);
}
} else if (addr && is_broadcast_ether_addr(addr)) {
- struct nl_msg *types;
- int err;
+ struct nlattr *types;
+
wpa_printf(MSG_DEBUG, " broadcast key");
- types = nlmsg_alloc();
+
+ types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types)
goto nla_put_failure;
- NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
- err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
- types);
- nlmsg_free(types);
- if (err)
- goto nla_put_failure;
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+ nla_nest_end(msg, types);
}
NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
@@ -4577,29 +4586,21 @@
else
NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
if (addr && is_broadcast_ether_addr(addr)) {
- struct nl_msg *types;
- int err;
- types = nlmsg_alloc();
+ struct nlattr *types;
+
+ types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types)
goto nla_put_failure;
- NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
- err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
- types);
- nlmsg_free(types);
- if (err)
- goto nla_put_failure;
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+ nla_nest_end(msg, types);
} else if (addr) {
- struct nl_msg *types;
- int err;
- types = nlmsg_alloc();
+ struct nlattr *types;
+
+ types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
if (!types)
goto nla_put_failure;
- NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
- err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
- types);
- nlmsg_free(types);
- if (err)
- goto nla_put_failure;
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+ nla_nest_end(msg, types);
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6071,7 +6072,7 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg, *wme = NULL;
+ struct nl_msg *msg;
struct nl80211_sta_flag_update upd;
int ret = -ENOBUFS;
@@ -6138,18 +6139,18 @@
NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
if (params->flags & WPA_STA_WMM) {
- wme = nlmsg_alloc();
+ struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
if (!wme)
goto nla_put_failure;
wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
- NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+ NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
- NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+ NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
(params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
WMM_QOSINFO_STA_SP_MASK);
- if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
- goto nla_put_failure;
+ nla_nest_end(msg, wme);
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6161,7 +6162,6 @@
if (ret == -EEXIST)
ret = 0;
nla_put_failure:
- nlmsg_free(wme);
nlmsg_free(msg);
return ret;
}
@@ -6245,7 +6245,7 @@
enum nl80211_iftype iftype,
const u8 *addr, int wds)
{
- struct nl_msg *msg, *flags = NULL;
+ struct nl_msg *msg;
int ifidx;
int ret = -ENOBUFS;
@@ -6262,20 +6262,15 @@
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
if (iftype == NL80211_IFTYPE_MONITOR) {
- int err;
+ struct nlattr *flags;
- flags = nlmsg_alloc();
+ flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
if (!flags)
goto nla_put_failure;
- NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+ NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
- err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
- nlmsg_free(flags);
-
- if (err)
- goto nla_put_failure;
+ nla_nest_end(msg, flags);
} else if (wds) {
NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
}
@@ -6908,19 +6903,14 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg, *flags = NULL;
+ struct nl_msg *msg;
+ struct nlattr *flags;
struct nl80211_sta_flag_update upd;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- flags = nlmsg_alloc();
- if (!flags) {
- nlmsg_free(msg);
- return -ENOMEM;
- }
-
nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -6931,35 +6921,34 @@
* Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
* can be removed eventually.
*/
+ flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+ if (!flags)
+ goto nla_put_failure;
if (total_flags & WPA_STA_AUTHORIZED)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
if (total_flags & WPA_STA_WMM)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
if (total_flags & WPA_STA_SHORT_PREAMBLE)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
if (total_flags & WPA_STA_MFP)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
if (total_flags & WPA_STA_TDLS_PEER)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+ NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
- if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
- goto nla_put_failure;
+ nla_nest_end(msg, flags);
os_memset(&upd, 0, sizeof(upd));
upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
upd.set = sta_flags_nl80211(flags_or);
NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
- nlmsg_free(flags);
-
return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
nlmsg_free(msg);
- nlmsg_free(flags);
return -ENOBUFS;
}
@@ -7664,6 +7653,11 @@
if (!drv->has_capability)
return -1;
os_memcpy(capa, &drv->capa, sizeof(*capa));
+ if (drv->extended_capa && drv->extended_capa_mask) {
+ capa->extended_capa = drv->extended_capa;
+ capa->extended_capa_mask = drv->extended_capa_mask;
+ capa->extended_capa_len = drv->extended_capa_len;
+ }
return 0;
}
@@ -9032,7 +9026,8 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg, *cqm = NULL;
+ struct nl_msg *msg;
+ struct nlattr *cqm;
int ret = -1;
wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
@@ -9046,20 +9041,18 @@
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- cqm = nlmsg_alloc();
+ cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
if (cqm == NULL)
goto nla_put_failure;
- NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
- NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
- if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
- goto nla_put_failure;
+ NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+ NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+ nla_nest_end(msg, cqm);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
nla_put_failure:
- nlmsg_free(cqm);
nlmsg_free(msg);
return ret;
}
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 81ad0ce..8edb1ca 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -77,25 +77,33 @@
else
len = end - pos;
if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
- hexstr2bin(pos, cred->ssid, len / 2))
+ hexstr2bin(pos, cred->ssid, len / 2)) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid");
return -1;
+ }
cred->ssid_len = len / 2;
pos = os_strstr(params, "new_auth=");
- if (pos == NULL)
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth");
return -1;
+ }
if (os_strncmp(pos + 9, "OPEN", 4) == 0)
cred->auth_type = WPS_AUTH_OPEN;
else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
cred->auth_type = WPS_AUTH_WPAPSK;
else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
cred->auth_type = WPS_AUTH_WPA2PSK;
- else
+ else {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth");
return -1;
+ }
pos = os_strstr(params, "new_encr=");
- if (pos == NULL)
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr");
return -1;
+ }
if (os_strncmp(pos + 9, "NONE", 4) == 0)
cred->encr_type = WPS_ENCR_NONE;
else if (os_strncmp(pos + 9, "WEP", 3) == 0)
@@ -104,8 +112,10 @@
cred->encr_type = WPS_ENCR_TKIP;
else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
cred->encr_type = WPS_ENCR_AES;
- else
+ else {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr");
return -1;
+ }
pos = os_strstr(params, "new_key=");
if (pos == NULL)
@@ -117,8 +127,10 @@
else
len = end - pos;
if ((len & 1) || len > 2 * sizeof(cred->key) ||
- hexstr2bin(pos, cred->key, len / 2))
+ hexstr2bin(pos, cred->key, len / 2)) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key");
return -1;
+ }
cred->key_len = len / 2;
return 1;
@@ -211,6 +223,8 @@
res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
if (res < 0) {
os_free(data);
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP "
+ "settings");
return NULL;
}
if (res == 1) {
@@ -222,6 +236,7 @@
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
+ wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed");
return NULL;
}
res = eap_get_config_fragment_size(sm);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index edb8d72..852ddf5 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -399,7 +399,6 @@
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
- u8 *group_info;
struct wpabuf *p2p_subelems, *ie;
struct p2p_group_member *m;
@@ -413,14 +412,18 @@
/* P2P Device Info */
p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
- /* P2P Group Info */
- group_info = wpabuf_put(p2p_subelems, 0);
- wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
- wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
- for (m = group->members; m; m = m->next)
- p2p_client_info(p2p_subelems, m);
- WPA_PUT_LE16(group_info + 1,
- (u8 *) wpabuf_put(p2p_subelems, 0) - group_info - 3);
+ /* P2P Group Info: Only when at least one P2P Client is connected */
+ if (group->members) {
+ u8 *group_info;
+ group_info = wpabuf_put(p2p_subelems, 0);
+ wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
+ wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
+ for (m = group->members; m; m = m->next)
+ p2p_client_info(p2p_subelems, m);
+ WPA_PUT_LE16(group_info + 1,
+ (u8 *) wpabuf_put(p2p_subelems, 0) - group_info -
+ 3);
+ }
ie = p2p_group_encaps_probe_resp(p2p_subelems);
wpabuf_free(p2p_subelems);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index d8f33b1..a1268e4 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -259,7 +259,7 @@
{
struct p2p_message msg;
struct p2p_device *dev;
- u16 report_config_methods = 0;
+ u16 report_config_methods = 0, req_config_methods;
int success = 0;
if (p2p_parse(data, len, &msg))
@@ -294,6 +294,12 @@
}
/*
+ * Use a local copy of the requested config methods since
+ * p2p_reset_pending_pd() can clear this in the peer entry.
+ */
+ req_config_methods = dev->req_config_methods;
+
+ /*
* If the response is from the peer to whom a user initiated request
* was sent earlier, we reset that state info here.
*/
@@ -301,9 +307,11 @@
os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
p2p_reset_pending_pd(p2p);
- if (msg.wps_config_methods != dev->req_config_methods) {
+ if (msg.wps_config_methods != req_config_methods) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
- "our Provision Discovery Request");
+ "our Provision Discovery Request (received "
+ "config_methods 0x%x expected 0x%x",
+ msg.wps_config_methods, req_config_methods);
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
P2P_PROV_DISC_REJECTED);
@@ -311,10 +319,10 @@
goto out;
}
- report_config_methods = dev->req_config_methods;
+ report_config_methods = req_config_methods;
dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
P2P_DEV_PD_PEER_KEYPAD);
- if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
+ if (req_config_methods & WPS_CONFIG_DISPLAY) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
" accepted to show a PIN on display", MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 8a996f9..3ba4496 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -498,6 +498,9 @@
hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags;
hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
+ hapd_iface->extended_capa = wpa_s->extended_capa;
+ hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
+ hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
if (conf == NULL) {
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index c50de53..0e1576b 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -224,11 +224,27 @@
}
-static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
- struct os_time *fetch_time)
+static void calculate_update_time(const struct os_time *fetch_time,
+ unsigned int age_ms,
+ struct os_time *update_time)
{
os_time_t usec;
+ update_time->sec = fetch_time->sec;
+ update_time->usec = fetch_time->usec;
+ update_time->sec -= age_ms / 1000;
+ usec = (age_ms % 1000) * 1000;
+ if (update_time->usec < usec) {
+ update_time->sec--;
+ update_time->usec += 1000000;
+ }
+ update_time->usec -= usec;
+}
+
+
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
+ struct os_time *fetch_time)
+{
dst->flags = src->flags;
os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
dst->freq = src->freq;
@@ -239,15 +255,7 @@
dst->level = src->level;
dst->tsf = src->tsf;
- dst->last_update.sec = fetch_time->sec;
- dst->last_update.usec = fetch_time->usec;
- dst->last_update.sec -= src->age / 1000;
- usec = (src->age % 1000) * 1000;
- if (dst->last_update.usec < usec) {
- dst->last_update.sec--;
- dst->last_update.usec += 1000000;
- }
- dst->last_update.usec -= usec;
+ calculate_update_time(fetch_time, src->age, &dst->last_update);
}
@@ -567,6 +575,21 @@
const u8 *ssid, *p2p;
struct wpa_bss *bss;
+ if (wpa_s->conf->ignore_old_scan_res) {
+ struct os_time update;
+ calculate_update_time(fetch_time, res->age, &update);
+ if (os_time_before(&update, &wpa_s->scan_trigger_time)) {
+ struct os_time age;
+ os_time_sub(&wpa_s->scan_trigger_time, &update, &age);
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
+ "table entry that is %u.%06u seconds older "
+ "than our scan trigger",
+ (unsigned int) age.sec,
+ (unsigned int) age.usec);
+ return;
+ }
+ }
+
ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
if (ssid == NULL) {
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
@@ -829,6 +852,34 @@
}
+/**
+ * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
+ * find the entry that has the most recent update. This can help in finding the
+ * correct entry in cases where the SSID of the AP may have changed recently
+ * (e.g., in WPS reconfiguration cases).
+ */
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ struct wpa_bss *bss, *found = NULL;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
+ continue;
+ if (found == NULL ||
+ os_time_before(&found->last_update, &bss->last_update))
+ found = bss;
+ }
+ return found;
+}
+
+
#ifdef CONFIG_P2P
/**
* wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 9f14d0e..2b41948 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -109,6 +109,8 @@
const u8 *ssid, size_t ssid_len);
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid);
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 1b71ca7..0d98884 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -3089,6 +3089,7 @@
{ INT(dtim_period), 0 },
{ INT(beacon_int), 0 },
{ FUNC(ap_vendor_elements), 0 },
+ { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 00990cb..1315e7b 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -844,6 +844,16 @@
* elements (id+len+payload for one or more elements).
*/
struct wpabuf *ap_vendor_elements;
+
+ /**
+ * ignore_old_scan_res - Ignore scan results older than request
+ *
+ * The driver may have a cache of scan results that makes it return
+ * information that is older than our scan trigger. This parameter can
+ * be used to configure such old information to be ignored instead of
+ * allowing it to update the internal BSS table.
+ */
+ int ignore_old_scan_res;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index d5de030..5ca6bf2 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1004,6 +1004,10 @@
fprintf(f, "\n");
}
}
+
+ if (config->ignore_old_scan_res)
+ fprintf(f, "ignore_old_scan_res=%d\n",
+ config->ignore_old_scan_res);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a8c57eb..6d2b3b1 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -3532,7 +3532,13 @@
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
+ "configuration known for the target AP");
+ return -1;
+ }
+
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
if (!bss) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
"from BSS table");
@@ -3544,12 +3550,6 @@
* allow roaming to other networks
*/
- if (!ssid) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
- "configuration known for the target AP");
- return -1;
- }
-
wpa_s->reassociate = 1;
wpa_supplicant_connect(wpa_s, bss, ssid);
@@ -4509,6 +4509,15 @@
}
+static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
+{
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ wpa_s->force_long_sd = 0;
+ if (wpa_s->global->p2p)
+ p2p_flush(wpa_s->global->p2p);
+}
+
+
static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos, *pos2;
@@ -4979,6 +4988,54 @@
#endif
+static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
+
+#ifdef CONFIG_P2P
+ wpas_p2p_stop_find(wpa_s);
+ p2p_ctrl_flush(wpa_s);
+ wpas_p2p_group_remove(wpa_s, "*");
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS_TESTING
+ wps_version_number = 0x20;
+ wps_testing_dummy_cred = 0;
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_WPS
+ wpas_wps_cancel(wpa_s);
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_TDLS_TESTING
+ extern unsigned int tdls_testing;
+ tdls_testing = 0;
+#endif /* CONFIG_TDLS_TESTING */
+#ifdef CONFIG_TDLS
+ wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
+ wpa_tdls_enable(wpa_s->wpa, 1);
+#endif /* CONFIG_TDLS */
+
+ wpa_s->no_keep_alive = 0;
+
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = NULL;
+ wpa_s->disallow_aps_bssid_count = 0;
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = NULL;
+ wpa_s->disallow_aps_ssid_count = 0;
+
+ wpa_s->set_sta_uapsd = 0;
+ wpa_s->sta_uapsd = 0;
+
+ wpa_drv_radio_disable(wpa_s, 0);
+
+ wpa_bss_flush(wpa_s);
+ wpa_blacklist_clear(wpa_s);
+ wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
+ wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -5260,10 +5317,7 @@
if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
- os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
- wpa_s->force_long_sd = 0;
- if (wpa_s->global->p2p)
- p2p_flush(wpa_s->global->p2p);
+ p2p_ctrl_flush(wpa_s);
} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
reply_len = -1;
@@ -5516,6 +5570,8 @@
if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
reply_len = -1;
#endif /* CONFIG_WNM */
+ } else if (os_strcmp(buf, "FLUSH") == 0) {
+ wpa_supplicant_ctrl_iface_flush(wpa_s);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index b117b62..6c0a246 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -854,9 +854,8 @@
}
-static struct wpa_bss *
-wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
- struct wpa_ssid **selected_ssid)
+struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **selected_ssid)
{
struct wpa_bss *selected = NULL;
int prio;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 6fe762f..b59dd6a 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -187,6 +187,7 @@
wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
MAC2STR(bss->bssid));
+ wpa_s->interworking_gas_bss = bss;
info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
if (all) {
@@ -1809,11 +1810,11 @@
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, u16 info_id,
+ struct wpa_bss *bss, const u8 *sa,
+ u16 info_id,
const u8 *data, size_t slen)
{
const u8 *pos = data;
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
#ifdef CONFIG_HS20
u8 type;
@@ -1949,6 +1950,7 @@
const u8 *end;
u16 info_id;
u16 slen;
+ struct wpa_bss *bss = NULL, *tmp;
if (result != GAS_QUERY_SUCCESS)
return;
@@ -1961,6 +1963,21 @@
return;
}
+ /*
+ * If possible, select the BSS entry based on which BSS entry was used
+ * for the request. This can help in cases where multiple BSS entries
+ * may exist for the same AP.
+ */
+ dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
+ if (tmp == wpa_s->interworking_gas_bss &&
+ os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
+ bss = tmp;
+ break;
+ }
+ }
+ if (bss == NULL)
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+
pos = wpabuf_head(resp);
end = pos + wpabuf_len(resp);
@@ -1978,7 +1995,7 @@
"for Info ID %u", info_id);
break;
}
- interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+ interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
slen);
pos += slen;
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index c6856e2..fc311e9 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -228,8 +228,10 @@
break;
}
}
- } else
+ } else {
+ os_get_time(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ }
return ret;
}
@@ -994,6 +996,7 @@
d->persistent_reconnect = s->persistent_reconnect;
d->max_num_sta = s->max_num_sta;
d->pbc_in_m1 = s->pbc_in_m1;
+ d->ignore_old_scan_res = s->ignore_old_scan_res;
}
@@ -3422,8 +3425,8 @@
if (join == 0 &&
wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) {
wpa_s->auto_pd_scan_retry++;
- bss = wpa_bss_get_bssid(wpa_s,
- wpa_s->pending_join_dev_addr);
+ bss = wpa_bss_get_bssid_latest(
+ wpa_s, wpa_s->pending_join_dev_addr);
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for "
@@ -3503,7 +3506,7 @@
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from P2P peer table: %d MHz", freq);
}
- bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+ bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
@@ -3638,8 +3641,10 @@
* the new scan results become available.
*/
ret = wpa_drv_scan(wpa_s, ¶ms);
- if (!ret)
+ if (!ret) {
+ os_get_time(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+ }
wpabuf_free(ies);
@@ -3715,7 +3720,7 @@
os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
ETH_ALEN);
res.wps_method = wpa_s->pending_join_wps_method;
- bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+ bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
if (bss) {
res.freq = bss->freq;
res.ssid_len = bss->ssid_len;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 825e90b..db73a18 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -227,6 +227,7 @@
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
} else {
+ os_get_time(&wpa_s->scan_trigger_time);
wpa_s->scan_runs++;
wpa_s->normal_scans++;
}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 90e4169..cdbe011 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2323,6 +2323,12 @@
#endif
+static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "FLUSH");
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2770,6 +2776,8 @@
#endif /* CONFIG_WNM */
{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
"<params..> = Sent unprocessed command" },
+ { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
+ "= flush wpa_supplicant state" },
#ifdef ANDROID
{ "driver", wpa_cli_cmd_driver, NULL,
cli_cmd_flag_none,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6fb1cae..a6478b6 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1184,30 +1184,67 @@
}
+static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
+{
+ *pos = 0x00;
+
+ switch (idx) {
+ case 0: /* Bits 0-7 */
+ break;
+ case 1: /* Bits 8-15 */
+ break;
+ case 2: /* Bits 16-23 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+#endif /* CONFIG_WNM */
+ break;
+ case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+#endif /* CONFIG_INTERWORKING */
+ break;
+ case 4: /* Bits 32-39 */
+ break;
+ case 5: /* Bits 40-47 */
+ break;
+ case 6: /* Bits 48-55 */
+ break;
+ }
+}
+
+
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
{
- u32 ext_capab = 0;
u8 *pos = buf;
+ u8 len = 4, i;
-#ifdef CONFIG_INTERWORKING
- if (wpa_s->conf->interworking)
- ext_capab |= BIT(31); /* Interworking */
-#endif /* CONFIG_INTERWORKING */
-
-#ifdef CONFIG_WNM
- ext_capab |= BIT(17); /* WNM-Sleep Mode */
- ext_capab |= BIT(19); /* BSS Transition */
-#endif /* CONFIG_WNM */
-
- if (!ext_capab)
- return 0;
+ if (len < wpa_s->extended_capa_len)
+ len = wpa_s->extended_capa_len;
*pos++ = WLAN_EID_EXT_CAPAB;
- *pos++ = 4;
- WPA_PUT_LE32(pos, ext_capab);
- pos += 4;
+ *pos++ = len;
+ for (i = 0; i < len; i++, pos++) {
+ wpas_ext_capab_byte(wpa_s, pos, i);
- return pos - buf;
+ if (i < wpa_s->extended_capa_len) {
+ *pos &= ~wpa_s->extended_capa_mask[i];
+ *pos |= wpa_s->extended_capa[i];
+ }
+ }
+
+ while (len > 0 && buf[1 + len] == 0) {
+ len--;
+ buf[1] = len;
+ }
+ if (len == 0)
+ return 0;
+
+ return 2 + len;
}
@@ -2925,6 +2962,9 @@
wpa_s->max_match_sets = capa.max_match_sets;
wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
wpa_s->max_stations = capa.max_stations;
+ wpa_s->extended_capa = capa.extended_capa;
+ wpa_s->extended_capa_mask = capa.extended_capa_mask;
+ wpa_s->extended_capa_len = capa.extended_capa_len;
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index b407060..0935a06 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -302,6 +302,15 @@
# one or more elements). This is used in AP and P2P GO modes.
#ap_vendor_elements=dd0411223301
+# Ignore scan results older than request
+#
+# The driver may have a cache of scan results that makes it return
+# information that is older than our scan trigger. This parameter can
+# be used to configure such old information to be ignored instead of
+# allowing it to update the internal BSS table.
+#ignore_old_scan_res=0
+
+
# Interworking (IEEE 802.11u)
# Enable Interworking
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 5465c4f..0308806 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -444,6 +444,7 @@
*/
MANUAL_SCAN_REQ
} scan_req;
+ struct os_time scan_trigger_time;
int scan_runs; /* number of scan runs since WPS was started */
int *next_scan_freqs;
int scan_interval; /* time in sec between scans to find suitable AP */
@@ -460,6 +461,10 @@
*/
unsigned int probe_resp_offloads;
+ /* extended capabilities supported by the driver */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+
int max_scan_ssids;
int max_sched_scan_ssids;
int sched_scan_supported;
@@ -654,6 +659,7 @@
unsigned int auto_select:1;
unsigned int auto_network_select:1;
unsigned int fetch_all_anqp:1;
+ struct wpa_bss *interworking_gas_bss;
#endif /* CONFIG_INTERWORKING */
unsigned int drv_capa_known;
@@ -790,6 +796,8 @@
void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
+struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **selected_ssid);
/* eap_register.c */
int eap_register_methods(void);
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 1b1b5f7..603ce91 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -84,6 +84,10 @@
!(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
int disabled = wpa_s->current_ssid->disabled;
unsigned int freq = wpa_s->assoc_freq;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = NULL;
+ int use_fast_assoc = 0;
+
wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
"try to associate with the received credential "
"(freq=%u)", freq);
@@ -98,7 +102,26 @@
wpa_s->wps_freq = freq;
wpa_s->normal_scans = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
+ "without a new scan can be used");
+ bss = wpa_supplicant_pick_network(wpa_s, &ssid);
+ if (bss) {
+ struct wpabuf *wps;
+ struct wps_parse_attr attr;
+
+ wps = wpa_bss_get_vendor_ie_multi(bss,
+ WPS_IE_VENDOR_TYPE);
+ if (wps && wps_parse_msg(wps, &attr) == 0 &&
+ attr.wps_state &&
+ *attr.wps_state == WPS_STATE_CONFIGURED)
+ use_fast_assoc = 1;
+ wpabuf_free(wps);
+ }
+
+ if (!use_fast_assoc ||
+ wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
return 1;
}
@@ -871,9 +894,10 @@
struct wpa_ssid *ssid;
struct wpa_bss *bss;
+ wpa_s->after_wps = 0;
wpa_s->known_wps_freq = 0;
if (bssid) {
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
if (bss && bss->freq > 0) {
wpa_s->known_wps_freq = 1;
wpa_s->wps_freq = bss->freq;