if (ssid->ssid == NULL)
return;
bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
+ if (!bss)
+ bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+ ssid->ssid, ssid->ssid_len);
if (bss == NULL) {
wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
"table - use credential as-is");
ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
ssid->group_cipher |= WPA_CIPHER_GCMP;
}
+ if (wpa_s->drv_capa_known &&
+ (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256)) {
+ ssid->pairwise_cipher |= WPA_CIPHER_GCMP_256;
+ ssid->group_cipher |= WPA_CIPHER_GCMP_256;
+ }
+ if (wpa_s->drv_capa_known &&
+ (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256)) {
+ ssid->pairwise_cipher |= WPA_CIPHER_CCMP_256;
+ ssid->group_cipher |= WPA_CIPHER_CCMP_256;
+ }
break;
}
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+ if (wpa_s->conf->wps_cred_add_sae &&
+ cred->key_len != 2 * PMK_LEN) {
+ ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
+#ifdef CONFIG_IEEE80211W
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+#endif /* CONFIG_IEEE80211W */
+ }
ssid->proto = WPA_PROTO_RSN;
break;
}
- if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
if (cred->key_len == 2 * PMK_LEN) {
if (hexstr2bin((const char *) cred->key, ssid->psk,
PMK_LEN)) {
return -1;
}
}
+ ssid->priority = wpa_s->conf->wps_priority;
wpas_wps_security_workaround(wpa_s, ssid, cred);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
+ if (ssid->priority)
+ wpa_config_update_prio_list(wpa_s->conf);
+
/*
* Optimize the post-WPS scan based on the channel used during
* the provisioning in case EAP-Failure is not received.
m2d->dev_password_id, m2d->config_error);
wpas_notify_wps_event_m2d(wpa_s, m2d);
#ifdef CONFIG_P2P
- if (wpa_s->parent && wpa_s->parent != wpa_s) {
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) {
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D
"dev_password_id=%d config_error=%d",
m2d->dev_password_id, m2d->config_error);
}
WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error, fail->error_indication,
wps_ei_str(fail->error_indication));
- if (wpa_s->parent && wpa_s->parent != wpa_s)
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error,
fail->error_indication,
wpa_msg(wpa_s, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d",
fail->msg, fail->config_error);
- if (wpa_s->parent && wpa_s->parent != wpa_s)
- wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s)
+ wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d",
fail->msg, fail->config_error);
}
}
+int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s)
+{
+ return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb,
+ wpa_s, NULL);
+}
+
+
static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
{
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
+ union wps_event_data data;
+
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
"out");
+ os_memset(&data, 0, sizeof(data));
+ data.fail.config_error = WPS_CFG_MSG_TIMEOUT;
+ data.fail.error_indication = WPS_EI_NO_ERROR;
+ /*
+ * Call wpas_notify_wps_event_fail() directly instead of through
+ * wpa_supplicant_wps_event() which would end up registering unnecessary
+ * timeouts (those are only for the case where the failure happens
+ * during an EAP-WSC exchange).
+ */
+ wpas_notify_wps_event_fail(wpa_s, &data.fail);
wpas_clear_wps(wpa_s);
}
continue;
os_free(ssid->ssid);
- ssid->ssid = os_malloc(bss->ssid_len);
+ ssid->ssid = os_memdup(bss->ssid, bss->ssid_len);
if (ssid->ssid == NULL)
break;
- os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
ssid->ssid_len = bss->ssid_len;
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
"scan results",
int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
- int p2p_group)
+ int p2p_group, int multi_ap_backhaul_sta)
{
struct wpa_ssid *ssid;
+ char phase1[32];
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
return -1;
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ /*
+ * When starting a regular WPS process (not P2P group formation)
+ * the registrar/final station can be either AP or PCP
+ * so use a "don't care" value for the pbss flag.
+ */
+ if (!p2p_group)
+ ssid->pbss = 2;
#ifdef CONFIG_P2P
if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
ssid->ssid_len = wpa_s->go_params->ssid_len;
os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
ssid->ssid_len);
+ if (wpa_s->go_params->freq > 56160) {
+ /* P2P in 60 GHz uses PBSS */
+ ssid->pbss = 1;
+ }
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
}
#endif /* CONFIG_P2P */
- if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
+ os_snprintf(phase1, sizeof(phase1), "pbc=1%s",
+ multi_ap_backhaul_sta ? " multi_ap=1" : "");
+ if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0)
return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
+ if (multi_ap_backhaul_sta)
+ ssid->multi_ap_backhaul_sta = 1;
+ wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
wpas_wps_reassoc(wpa_s, ssid, bssid, 0);
}
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ /*
+ * When starting a regular WPS process (not P2P group formation)
+ * the registrar/final station can be either AP or PCP
+ * so use a "don't care" value for the pbss flag.
+ */
+ if (!p2p_group)
+ ssid->pbss = 2;
if (ssid_val) {
ssid->ssid = os_malloc(ssid_len);
if (ssid->ssid) {
}
#ifdef CONFIG_P2P
if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
+ os_free(ssid->ssid);
ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
if (ssid->ssid) {
ssid->ssid_len = wpa_s->go_params->ssid_len;
os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
ssid->ssid_len);
+ if (wpa_s->go_params->freq > 56160) {
+ /* P2P in 60 GHz uses PBSS */
+ ssid->pbss = 1;
+ }
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"",
dev_pw_id, hash);
} else {
- rpin = wps_generate_pin();
+ if (wps_generate_pin(&rpin) < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN");
+ return -1;
+ }
os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"",
rpin, dev_pw_id, hash);
}
}
+void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+ union wps_event_data data;
+
+ os_memset(&data, 0, sizeof(data));
+ data.fail.config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+ data.fail.error_indication = WPS_EI_NO_ERROR;
+ /*
+ * Call wpas_notify_wps_event_fail() directly instead of through
+ * wpa_supplicant_wps_event() which would end up registering unnecessary
+ * timeouts (those are only for the case where the failure happens
+ * during an EAP-WSC exchange).
+ */
+ wpas_notify_wps_event_fail(wpa_s, &data.fail);
+}
+
/* Cancel the wps pbc/pin requests */
int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
{
wpa_s->global->ifaces->wps->uuid,
WPS_UUID_LEN);
src = "from the first interface";
+ } else if (wpa_s->conf->auto_uuid == 1) {
+ uuid_random(wps->uuid);
+ src = "based on random data";
} else {
uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
src = "based on MAC address";
int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected, struct wpa_ssid *ssid)
{
- const u8 *sel_uuid, *uuid;
+ const u8 *sel_uuid;
struct wpabuf *wps_ie;
int ret = 0;
- struct wpa_bss *bss;
+ size_t i;
if (!eap_is_wps_pbc_enrollee(&ssid->eap))
return 0;
sel_uuid = NULL;
}
- dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- struct wpabuf *ie;
- if (bss == selected)
- continue;
- ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
- if (!ie)
- continue;
- if (!wps_is_selected_pbc_registrar(ie)) {
- wpabuf_free(ie);
+ for (i = 0; i < wpa_s->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+
+ if (!ap->pbc_active ||
+ os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
continue;
- }
+
wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
- MACSTR, MAC2STR(bss->bssid));
- uuid = wps_get_uuid_e(ie);
+ MACSTR, MAC2STR(ap->bssid));
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
- uuid, UUID_LEN);
- if (os_memcmp(selected->bssid, bss->bssid, ETH_ALEN) == 0) {
- wpabuf_free(ie);
- continue;
- }
- if (sel_uuid == NULL || uuid == NULL ||
- os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
+ ap->uuid, UUID_LEN);
+ if (sel_uuid == NULL ||
+ os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0) {
ret = 1; /* PBC overlap */
wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: "
MACSTR " and " MACSTR,
MAC2STR(selected->bssid),
- MAC2STR(bss->bssid));
- wpabuf_free(ie);
+ MAC2STR(ap->bssid));
break;
}
/* TODO: verify that this is reasonable dual-band situation */
-
- wpabuf_free(ie);
}
wpabuf_free(wps_ie);
struct wpabuf *wps;
enum wps_ap_info_type type;
struct wps_ap_info *ap;
- int r;
+ int r, pbc_active;
+ const u8 *uuid;
if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
return;
else
type = WPS_AP_NOT_SEL_REG;
- wpabuf_free(wps);
+ uuid = wps_get_uuid_e(wps);
+ pbc_active = wps_is_selected_pbc_registrar(wps);
ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
if (ap) {
if (type != WPS_AP_NOT_SEL_REG)
wpa_blacklist_del(wpa_s, ap->bssid);
}
- return;
+ ap->pbc_active = pbc_active;
+ if (uuid)
+ os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
+ goto out;
}
ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
sizeof(struct wps_ap_info));
if (ap == NULL)
- return;
+ goto out;
wpa_s->wps_ap = ap;
ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
os_memset(ap, 0, sizeof(*ap));
os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
ap->type = type;
+ ap->pbc_active = pbc_active;
+ if (uuid)
+ os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
MAC2STR(ap->bssid), ap->type);
+
+out:
+ wpabuf_free(wps);
}