diff --git a/src/ap/dfs.c b/src/ap/dfs.c index b990fb342388..03c99b175215 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -1228,7 +1228,9 @@ int hostapd_is_dfs_required(struct hostapd_iface *iface) { int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res; - if (!iface->conf->ieee80211h || !iface->current_mode || + if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && + !iface->conf->ieee80211h) || + !iface->current_mode || iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) return 0; @@ -1279,6 +1281,8 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, */ int hostapd_handle_dfs_offload(struct hostapd_iface *iface) { + int dfs_res; + wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d", __func__, iface->cac_started); @@ -1294,10 +1298,11 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface) return 1; } - if (ieee80211_is_dfs(iface->freq, iface->hw_features, - iface->num_hw_features)) { - wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS", - __func__, iface->freq); + dfs_res = hostapd_is_dfs_required(iface); + if (dfs_res > 0) { + wpa_printf(MSG_DEBUG, + "%s: freq %d MHz requires DFS for %d chans", + __func__, iface->freq, dfs_res); return 0; } diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index b404e84affe5..22cce961063e 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -3943,8 +3943,10 @@ static void handle_auth(struct hostapd_data *hapd, fail: reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg, - auth_transaction + 1, resp, resp_ies, - resp_ies_len, "handle-auth"); + auth_alg == WLAN_AUTH_SAE ? + auth_transaction : auth_transaction + 1, + resp, resp_ies, resp_ies_len, + "handle-auth"); if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS || reply_res != WLAN_STATUS_SUCCESS)) { diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 7ca292530dc1..3e992155395e 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -1553,7 +1553,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) return -1; } - hapd->ptksa = ptksa_cache_init(); + if (!hapd->ptksa) + hapd->ptksa = ptksa_cache_init(); if (!hapd->ptksa) { wpa_printf(MSG_ERROR, "Failed to allocate PTKSA cache"); return -1; diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index e97dbf996749..9f22e39a2e6a 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -1172,6 +1172,8 @@ int hostapd_init_wps(struct hostapd_data *hapd, wps->auth_types |= WPS_AUTH_WPA2PSK; if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) wps->auth_types |= WPS_AUTH_WPA2; + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) + wps->auth_types |= WPS_AUTH_WPA2PSK; if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_CCMP_256 | @@ -1328,6 +1330,11 @@ int hostapd_init_wps(struct hostapd_data *hapd, hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd); +#ifdef CONFIG_P2P + if ((hapd->conf->p2p & P2P_ENABLED) && + is_6ghz_op_class(hapd->iconf->op_class)) + wps->use_passphrase = true; +#endif /* CONFIG_P2P */ hapd->wps = wps; bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN); diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 96681843e258..3e5cfb01d565 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1894,7 +1894,7 @@ const struct oper_class_map global_op_class[] = { */ { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP }, diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 7d2f36b8f1e6..519a13b1d064 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1657,6 +1657,7 @@ enum p2p_attr_id { #define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3) #define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4) #define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5) +#define P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE BIT(6) /* P2P Capability - Group Capability bitmap */ #define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0) diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index ce588cc00a59..47666f04ae7c 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -1730,11 +1730,22 @@ enum qca_vendor_attr_tsf_cmd { * @QCA_TSF_CAPTURE: Initiate TSF Capture * @QCA_TSF_GET: Get TSF capture value * @QCA_TSF_SYNC_GET: Initiate TSF capture and return with captured value + * @QCA_TSF_AUTO_REPORT_ENABLE: Used in STA mode only. Once set, the target + * will automatically send TSF report to the host. To query + * QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY, this operation needs to be + * initiated first. + * @QCA_TSF_AUTO_REPORT_DISABLE: Used in STA mode only. Once set, the target + * will not automatically send TSF report to the host. If + * QCA_TSF_AUTO_REPORT_ENABLE is initiated and + * QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY is not queried anymore, this + * operation needs to be initiated. */ enum qca_tsf_cmd { QCA_TSF_CAPTURE, QCA_TSF_GET, QCA_TSF_SYNC_GET, + QCA_TSF_AUTO_REPORT_ENABLE, + QCA_TSF_AUTO_REPORT_DISABLE, }; /** @@ -3867,6 +3878,10 @@ enum qca_wlan_vendor_attr_ll_stats_results { * QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME = 85, + /* u8 value representing the channel load percentage. Possible values + * are 0-100. + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE = 86, /* keep last */ QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX = @@ -8120,6 +8135,29 @@ enum qca_wlan_vendor_attr_wifi_test_config { */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_KEEP_ALIVE_FRAME_TYPE = 53, + /* 8-bit unsigned value to configure the driver to use scan request + * BSSID value in Probe Request frame RA(A1) during the scan. The + * driver saves this configuration and applies this setting to all user + * space scan requests until the setting is cleared. If this + * configuration is set, the driver uses the BSSID value from the scan + * request to set the RA(A1) in the Probe Request frames during the + * scan. + * + * 0 - Default behavior uses the broadcast RA in Probe Request frames. + * 1 - Uses the scan request BSSID in RA in Probe Request frames. + * This attribute is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_USE_BSSID_IN_PROBE_REQ_RA = 54, + + /* 8-bit unsigned value to configure the driver to enable/disable the + * BSS max idle period support. + * + * 0 - Disable the BSS max idle support. + * 1 - Enable the BSS max idle support. + * This attribute is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD_ENABLE = 55, + /* keep last */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX = @@ -10369,6 +10407,11 @@ enum qca_vendor_wlan_sta_guard_interval { * failed roam invoke. Different roam invoke failure reason codes * are specified in enum qca_vendor_roam_invoke_fail_reasons. This can be * queried either in connected state or disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY: u32, used in STA mode only. + * This represents the average congestion duration of uplink frames in MAC + * queue in unit of ms. This can be queried either in connected state or + * disconnected state. */ enum qca_wlan_vendor_attr_get_sta_info { QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0, @@ -10421,6 +10464,7 @@ enum qca_wlan_vendor_attr_get_sta_info { QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_TRIGGER_REASON = 47, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON = 48, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON = 49, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY = 50, /* keep last */ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST, diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 561882d0d024..804ac6806f61 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -645,6 +645,12 @@ struct wpa_driver_scan_params { */ unsigned int oce_scan:1; + /** + * p2p_include_6ghz - Include 6 GHz channels for P2P full scan + * + */ + unsigned int p2p_include_6ghz:1; + /* * NOTE: Whenever adding new parameters here, please make sure * wpa_scan_clone_params() and wpa_scan_free_params() get updated with diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index d19586f06ead..0f0a01d0180b 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -1329,7 +1329,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, struct nlattr *nl; int rem; struct scan_info *info; -#define MAX_REPORT_FREQS 50 +#define MAX_REPORT_FREQS 100 int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; @@ -1361,7 +1361,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, } } if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { - char msg[300], *pos, *end; + char msg[500], *pos, *end; int res; pos = msg; @@ -2273,7 +2273,7 @@ static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv, } if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { - char msg[300], *pos, *end; + char msg[500], *pos, *end; int res; pos = msg; diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c index fc70cf1962db..a162deb9ef6b 100644 --- a/src/eap_server/eap_server_wsc.c +++ b/src/eap_server/eap_server_wsc.c @@ -132,9 +132,11 @@ static void * eap_wsc_init(struct eap_sm *sm) cfg.peer_addr = sm->peer_addr; #ifdef CONFIG_P2P if (sm->assoc_p2p_ie) { - wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P " - "client"); - cfg.use_psk_key = 1; + if (!sm->cfg->wps->use_passphrase) { + wpa_printf(MSG_DEBUG, + "EAP-WSC: Prefer PSK format for non-6 GHz P2P client"); + cfg.use_psk_key = 1; + } cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie); } #endif /* CONFIG_P2P */ diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 1aa98f1a877a..9ac505735cbb 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1035,7 +1035,7 @@ static void p2p_search(struct p2p_data *p2p) res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, p2p->num_req_dev_types, p2p->req_dev_types, - p2p->find_dev_id, pw_id); + p2p->find_dev_id, pw_id, p2p->include_6ghz); if (res < 0) { p2p_dbg(p2p, "Scan request schedule failed"); p2p_continue_find(p2p); @@ -1159,7 +1159,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, unsigned int search_delay, - u8 seek_count, const char **seek, int freq) + u8 seek_count, const char **seek, int freq, bool include_6ghz) { int res; struct os_reltime start; @@ -1184,7 +1184,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, p2p->find_dev_id = p2p->find_dev_id_buf; } else p2p->find_dev_id = NULL; - + p2p->include_6ghz = p2p_wfd_enabled(p2p) && include_6ghz; if (seek_count == 0 || !seek) { /* Not an ASP search */ p2p->p2ps_seek = 0; @@ -1260,7 +1260,8 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, P2P_SCAN_SPECIFIC, freq, p2p->num_req_dev_types, p2p->req_dev_types, dev_id, - DEV_PW_DEFAULT); + DEV_PW_DEFAULT, + p2p->include_6ghz); break; } /* fall through */ @@ -1268,13 +1269,13 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0, p2p->num_req_dev_types, p2p->req_dev_types, dev_id, - DEV_PW_DEFAULT); + DEV_PW_DEFAULT, p2p->include_6ghz); break; case P2P_FIND_ONLY_SOCIAL: res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0, p2p->num_req_dev_types, p2p->req_dev_types, dev_id, - DEV_PW_DEFAULT); + DEV_PW_DEFAULT, p2p->include_6ghz); break; default: return -1; @@ -1396,8 +1397,8 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p, p2p->channels.reg_class[0].reg_class = p2p->op_reg_class; p2p->channels.reg_class[0].channel[0] = p2p->op_channel; } else { - os_memcpy(&p2p->channels, &p2p->cfg->channels, - sizeof(struct p2p_channels)); + p2p_copy_channels(&p2p->channels, &p2p->cfg->channels, + p2p->allow_6ghz); } return 0; @@ -1411,6 +1412,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) const int op_classes_ht40[] = { 126, 127, 116, 117, 0 }; const int op_classes_vht[] = { 128, 0 }; const int op_classes_edmg[] = { 181, 182, 183, 0 }; + const int op_classes_6ghz[] = { 131, 0 }; p2p_dbg(p2p, "Prepare channel best"); @@ -1447,6 +1449,12 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) 0) { p2p_dbg(p2p, "Select possible EDMG channel (op_class %u channel %u) as operating channel preference", p2p->op_reg_class, p2p->op_channel); + } else if (p2p->allow_6ghz && + (p2p_channel_select(&p2p->cfg->channels, op_classes_6ghz, + &p2p->op_reg_class, &p2p->op_channel) == + 0)) { + p2p_dbg(p2p, "Select possible 6 GHz channel (op_class %u channel %u) as operating channel preference", + p2p->op_reg_class, p2p->op_channel); } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht, &p2p->op_reg_class, &p2p->op_channel) == 0) { @@ -1484,8 +1492,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) p2p->op_channel, p2p->op_reg_class); } - os_memcpy(&p2p->channels, &p2p->cfg->channels, - sizeof(struct p2p_channels)); + p2p_copy_channels(&p2p->channels, &p2p->cfg->channels, p2p->allow_6ghz); } @@ -1568,9 +1575,10 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR " GO Intent=%d Intended Interface Address=" MACSTR " wps_method=%d persistent_group=%d pd_before_go_neg=%d " - "oob_pw_id=%u", + "oob_pw_id=%u allow_6ghz=%d", MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr), - wps_method, persistent_group, pd_before_go_neg, oob_pw_id); + wps_method, persistent_group, pd_before_go_neg, oob_pw_id, + p2p->allow_6ghz); dev = p2p_get_device(p2p, peer_addr); if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { @@ -1668,9 +1676,9 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR " GO Intent=%d Intended Interface Address=" MACSTR - " wps_method=%d persistent_group=%d oob_pw_id=%u", + " wps_method=%d persistent_group=%d oob_pw_id=%u allow_6ghz=%d", MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr), - wps_method, persistent_group, oob_pw_id); + wps_method, persistent_group, oob_pw_id, p2p->allow_6ghz); dev = p2p_get_device(p2p, peer_addr); if (dev == NULL) { @@ -5575,3 +5583,69 @@ struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p, return buf; } + + +bool p2p_is_peer_6ghz_capab(struct p2p_data *p2p, const u8 *addr) +{ + struct p2p_device *dev; + + dev = p2p_get_device(p2p, addr); + if (!dev) + return false; + + return !!(dev->info.dev_capab & P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE); +} + + +void p2p_set_6ghz_dev_capab(struct p2p_data *p2p, bool allow_6ghz) +{ + p2p->p2p_6ghz_capable = allow_6ghz; + p2p->allow_6ghz = allow_6ghz; + p2p_dbg(p2p, "Set 6 GHz capability to %d", allow_6ghz); + + if (allow_6ghz) + p2p->dev_capab |= P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE; + else + p2p->dev_capab &= ~P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE; +} + + +bool is_p2p_6ghz_capable(struct p2p_data *p2p) +{ + return p2p->p2p_6ghz_capable; +} + + +bool p2p_wfd_enabled(struct p2p_data *p2p) +{ +#ifdef CONFIG_WIFI_DISPLAY + return p2p->wfd_ie_probe_req != NULL; +#else /* CONFIG_WIFI_DISPLAY */ + return false; +#endif /* CONFIG_WIFI_DISPLAY */ +} + + +bool p2p_peer_wfd_enabled(struct p2p_data *p2p, const u8 *peer_addr) +{ +#ifdef CONFIG_WIFI_DISPLAY + struct p2p_device *dev; + + dev = p2p_get_device(p2p, peer_addr); + return dev && dev->info.wfd_subelems != NULL; +#else /* CONFIG_WIFI_DISPLAY */ + return false; +#endif /* CONFIG_WIFI_DISPLAY */ +} + + +bool is_p2p_allow_6ghz(struct p2p_data *p2p) +{ + return p2p->allow_6ghz; +} + + +void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value) +{ + p2p->allow_6ghz = value; +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 762bd40bea8b..f606fbb14a81 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -612,6 +612,7 @@ struct p2p_config { * @req_dev_types: Array containing requested device types * @dev_id: Device ID to search for or %NULL to find all devices * @pw_id: Device Password ID + * @include_6ghz: Include 6 GHz channels in P2P scan * Returns: 0 on success, -1 on failure * * This callback function is used to request a P2P scan or search @@ -635,7 +636,8 @@ struct p2p_config { */ int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq, unsigned int num_req_dev_types, - const u8 *req_dev_types, const u8 *dev_id, u16 pw_id); + const u8 *req_dev_types, const u8 *dev_id, u16 pw_id, + bool include_6ghz); /** * send_probe_resp - Transmit a Probe Response frame @@ -1243,13 +1245,15 @@ enum p2p_discovery_type { * P2P_FIND_START_WITH_FULL behavior. 0 = Use normal full scan. * If p2p_find is already in progress, this parameter is ignored and full * scan will be executed. + * @include_6ghz: Include 6 GHz channels in P2P find * Returns: 0 on success, -1 on failure */ int p2p_find(struct p2p_data *p2p, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, unsigned int search_delay, - u8 seek_count, const char **seek_string, int freq); + u8 seek_count, const char **seek_string, int freq, + bool include_6ghz); /** * p2p_notify_scan_trigger_status - Indicate scan trigger status @@ -2411,4 +2415,13 @@ int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs, struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p, unsigned int freq); +void p2p_set_6ghz_dev_capab(struct p2p_data *p2p, bool allow_6ghz); +bool is_p2p_6ghz_capable(struct p2p_data *p2p); +bool p2p_is_peer_6ghz_capab(struct p2p_data *p2p, const u8 *addr); +bool p2p_peer_wfd_enabled(struct p2p_data *p2p, const u8 *peer_addr); +bool p2p_wfd_enabled(struct p2p_data *p2p); +bool is_p2p_allow_6ghz(struct p2p_data *p2p); +void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value); +int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 4195c5f07dd1..8220e85506a3 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -548,6 +548,9 @@ struct p2p_data { /* Override option for preferred operating channel in GO Negotiation */ u8 override_pref_op_class; u8 override_pref_channel; + bool p2p_6ghz_capable; + bool include_6ghz; + bool allow_6ghz; }; /** @@ -698,6 +701,8 @@ int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class, u8 *op_channel, struct wpa_freq_range_list *avoid_list, struct wpa_freq_range_list *disallow_list); +void p2p_copy_channels(struct p2p_channels *dst, const struct p2p_channels *src, + bool allow_6ghz); /* p2p_parse.c */ void p2p_copy_filter_devname(char *dst, size_t dst_len, diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 77d662a47ae2..ab0072219d2e 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -653,8 +653,9 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, struct p2p_device *dev; p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d " - "force_freq=%u", - MAC2STR(peer), role, persistent_group, force_freq); + "force_freq=%u allow_6ghz=%d", + MAC2STR(peer), role, persistent_group, force_freq, + p2p->allow_6ghz); if (bssid) p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid)); if (go_dev_addr) { diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index 1a62a44a2df3..7d21f68819c7 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -496,3 +496,42 @@ int p2p_channels_to_freqs(const struct p2p_channels *channels, int *freq_list, return idx; } + + +void p2p_copy_channels(struct p2p_channels *dst, + const struct p2p_channels *src, bool allow_6ghz) +{ + size_t i, j; + + if (allow_6ghz) { + os_memcpy(dst, src, sizeof(struct p2p_channels)); + return; + } + + for (i = 0, j = 0; i < P2P_MAX_REG_CLASSES; i++) { + if (is_6ghz_op_class(src->reg_class[i].reg_class)) + continue; + os_memcpy(&dst->reg_class[j], &src->reg_class[i], + sizeof(struct p2p_reg_class)); + j++; + } + dst->reg_classes = j; +} + + +int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (is_6ghz_freq(pref_freq_list[i])) { + wpa_printf(MSG_DEBUG, "P2P: Remove 6 GHz channel %d", + pref_freq_list[i]); + size--; + os_memmove(&pref_freq_list[i], &pref_freq_list[i + 1], + (size - i) * sizeof(pref_freq_list[0])); + i--; + } + } + return i; +} diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index cb2a8674a81b..97a01a2f81e8 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -212,7 +212,8 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, "that was based on the old PMK"); if (!pos->opportunistic) pmksa_cache_flush(pmksa, entry->network_ctx, - pos->pmk, pos->pmk_len); + pos->pmk, pos->pmk_len, + false); pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE); break; } @@ -282,9 +283,11 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, * @network_ctx: Network configuration context or %NULL to flush all entries * @pmk: PMK to match for or %NULL to match all PMKs * @pmk_len: PMK length + * @external_only: Flush only PMKSA cache entries configured by external + * applications */ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *pmk, size_t pmk_len) + const u8 *pmk, size_t pmk_len, bool external_only) { struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; int removed = 0; @@ -295,7 +298,8 @@ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, network_ctx == NULL) && (pmk == NULL || (pmk_len == entry->pmk_len && - os_memcmp(pmk, entry->pmk, pmk_len) == 0))) { + os_memcmp(pmk, entry->pmk, pmk_len) == 0)) && + (!external_only || entry->external)) { wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " "for " MACSTR, MAC2STR(entry->aa)); if (prev) diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index 83faa05844d6..ae7bc13fa118 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -43,6 +43,7 @@ struct rsn_pmksa_cache_entry { */ void *network_ctx; int opportunistic; + bool external; }; struct rsn_pmksa_cache; @@ -84,7 +85,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, const u8 *aa, int akmp); void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *pmk, size_t pmk_len); + const u8 *pmk, size_t pmk_len, bool external_only); #else /* IEEE8021X_EAPOL */ @@ -157,7 +158,8 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *pmk, size_t pmk_len) + const u8 *pmk, size_t pmk_len, + bool external_only) { } diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 78e2380b15e8..e01cd52177d2 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2345,6 +2345,16 @@ void wpa_sm_aborted_cached(struct wpa_sm *sm) } +void wpa_sm_aborted_external_cached(struct wpa_sm *sm) +{ + if (sm && sm->cur_pmksa && sm->cur_pmksa->external) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Cancelling external PMKSA caching attempt"); + sm->cur_pmksa = NULL; + } +} + + static void wpa_eapol_key_dump(struct wpa_sm *sm, const struct wpa_eapol_key *key, unsigned int key_data_len, @@ -3865,7 +3875,13 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr) void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx) { - pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0); + pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0, false); +} + + +void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx) +{ + pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0, true); } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index f377acba2f23..ff8a85b6e29b 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -180,6 +180,7 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data); void wpa_sm_aborted_cached(struct wpa_sm *sm); +void wpa_sm_aborted_external_cached(struct wpa_sm *sm); int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len); int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data); @@ -205,6 +206,7 @@ int wpa_sm_has_ptk_installed(struct wpa_sm *sm); void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr); void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx); +void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx); int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf); @@ -353,6 +355,10 @@ static inline void wpa_sm_aborted_cached(struct wpa_sm *sm) { } +static inline void wpa_sm_aborted_external_cached(struct wpa_sm *sm) +{ +} + static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len) { @@ -392,6 +398,11 @@ static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm, { } +static inline void wpa_sm_external_pmksa_cache_flush(struct wpa_sm *sm, + void *network_ctx) +{ +} + static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx) { diff --git a/src/wps/wps.h b/src/wps/wps.h index 6a12255c8a68..fed3e284895f 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -841,6 +841,10 @@ struct wps_context { struct wpabuf *ap_nfc_dh_pubkey; struct wpabuf *ap_nfc_dh_privkey; struct wpabuf *ap_nfc_dev_pw; + + /* Whether to send WPA2-PSK passphrase as a passphrase instead of PSK + * for WPA3-Personal transition mode needs. */ + bool use_passphrase; }; struct wps_registrar * diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 45f7e947e0fd..173fbbd68aa0 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -1753,8 +1753,10 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN); os_memcpy(wps->cred.key, hex, PMK_LEN * 2); wps->cred.key_len = PMK_LEN * 2; - } else if (!wps->wps->registrar->force_per_enrollee_psk && - wps->wps->network_key) { + } else if ((!wps->wps->registrar->force_per_enrollee_psk || + wps->wps->use_passphrase) && wps->wps->network_key) { + wpa_printf(MSG_DEBUG, + "WPS: Use passphrase format for Network key"); os_memcpy(wps->cred.key, wps->wps->network_key, wps->wps->network_key_len); wps->cred.key_len = wps->wps->network_key_len; diff --git a/tests/hwsim/test_multi_ap.py b/tests/hwsim/test_multi_ap.py index ca8ea3a31f90..99db14ebfae9 100644 --- a/tests/hwsim/test_multi_ap.py +++ b/tests/hwsim/test_multi_ap.py @@ -100,6 +100,11 @@ def test_multi_ap_fronthaul_on_ap(dev, apdev): if "CTRL-EVENT-DISCONNECTED" not in ev: raise Exception("Unexpected connection result") +def remove_apdev(dev, ifname): + hglobal = hostapd.HostapdGlobal() + hglobal.remove(ifname) + dev.cmd_execute(['iw', ifname, 'del']) + def run_multi_ap_wps(dev, apdev, params, params_backhaul=None, add_apdev=False, run_csa=False, allow_csa_fail=False): """Helper for running Multi-AP WPS tests @@ -219,10 +224,10 @@ def run_multi_ap_wps(dev, apdev, params, params_backhaul=None, add_apdev=False, raise Exception("Received disconnection event instead of channel switch event") if add_apdev: - dev[0].cmd_execute(['iw', wpas_apdev['ifname'], 'del']) + remove_apdev(dev[0], wpas_apdev['ifname']) except: if wpas_apdev: - dev[0].cmd_execute(['iw', wpas_apdev['ifname'], 'del']) + remove_apdev(dev[0], wpas_apdev['ifname']) raise return hapd diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py index c8bcd63f6ac7..6f7a806f5c46 100644 --- a/tests/hwsim/test_pasn.py +++ b/tests/hwsim/test_pasn.py @@ -680,6 +680,8 @@ def test_pasn_ft_eap_sha384(dev, apdev): def test_pasn_sta_mic_error(dev, apdev): """PASN authentication with WPA2/CCMP AP with corrupted MIC on station""" + check_pasn_capab(dev[0]) + params = pasn_ap_params("PASN", "CCMP", "19") hapd = hostapd.add_ap(apdev[0], params) @@ -697,6 +699,8 @@ def test_pasn_sta_mic_error(dev, apdev): def test_pasn_ap_mic_error(dev, apdev): """PASN authentication with WPA2/CCMP AP with corrupted MIC on AP""" + check_pasn_capab(dev[0]) + params = pasn_ap_params("PASN", "CCMP", "19") hapd0 = hostapd.add_ap(apdev[0], params) diff --git a/tests/hwsim/test_sae.py b/tests/hwsim/test_sae.py index 159678e0c7be..9925d98f3a7c 100644 --- a/tests/hwsim/test_sae.py +++ b/tests/hwsim/test_sae.py @@ -2775,3 +2775,19 @@ def test_sae_ocv_pmk_failure(dev, apdev): raise Exception("hostapd did not report correct PMK after disconnection") if pmk_w2 != pmk_w: raise Exception("wpa_supplicant did not report correct PMK after disconnection") + +def test_sae_reject(dev, apdev): + """SAE and AP rejecting connection""" + check_sae_capab(dev[0]) + params = hostapd.wpa2_params(ssid="test-sae", + passphrase="12345678") + params['wpa_key_mgmt'] = 'SAE' + params['max_num_sta'] = '0' + hapd = hostapd.add_ap(apdev[0], params) + dev[0].set("sae_groups", "") + id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", + scan_freq="2412", wait_connect=False) + if not dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10): + raise Exception("Authentication rejection not reported") + dev[0].request("REMOVE_NETWORK all") + dev[0].dump_monitor() diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index cfefa48d443e..cdf0ed5c7b5f 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -109,13 +109,15 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, switch (hostapd_get_oper_chwidth(conf)) { case CHANWIDTH_80MHZ: case CHANWIDTH_80P80MHZ: - center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel); + center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel, + conf->op_class); wpa_printf(MSG_DEBUG, "VHT center channel %u for 80 or 80+80 MHz bandwidth", center_chan); break; case CHANWIDTH_160MHZ: - center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel); + center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel, + conf->op_class); wpa_printf(MSG_DEBUG, "VHT center channel %u for 160 MHz bandwidth", center_chan); @@ -127,15 +129,25 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, * not supported. */ hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ); - center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel); + ieee80211_freq_to_channel_ext(ssid->frequency, 0, + conf->vht_oper_chwidth, + &conf->op_class, + &conf->channel); + center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel, + conf->op_class); if (center_chan && is_chanwidth160_supported(mode, conf)) { wpa_printf(MSG_DEBUG, "VHT center channel %u for auto-selected 160 MHz bandwidth", center_chan); } else { hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ); + ieee80211_freq_to_channel_ext(ssid->frequency, 0, + conf->vht_oper_chwidth, + &conf->op_class, + &conf->channel); center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, - channel); + channel, + conf->op_class); wpa_printf(MSG_DEBUG, "VHT center channel %u for auto-selected 80 MHz bandwidth", center_chan); @@ -183,9 +195,15 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct hostapd_config *conf) { - conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, - &conf->channel); - + conf->hw_mode = ieee80211_freq_to_channel_ext(ssid->frequency, 0, + ssid->max_oper_chwidth, + &conf->op_class, + &conf->channel); + /* ssid->max_oper_chwidth is not valid in all cases, so fall back to the + * less specific mechanism, if needed, at least for now */ + if (conf->hw_mode == NUM_HOSTAPD_MODES) + conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, + &conf->channel); if (conf->hw_mode == NUM_HOSTAPD_MODES) { wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz", ssid->frequency); @@ -874,6 +892,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, params.wpa_proto = ssid->proto; if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) wpa_s->key_mgmt = WPA_KEY_MGMT_PSK; + else if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) + wpa_s->key_mgmt = WPA_KEY_MGMT_SAE; else wpa_s->key_mgmt = WPA_KEY_MGMT_NONE; params.key_mgmt_suite = wpa_s->key_mgmt; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index ba91cfb11d14..8a6a829b6665 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -5723,12 +5723,16 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL; u8 seek_count = 0; int freq = 0; + bool include_6ghz = false; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_INFO, "Reject P2P_FIND since interface is disabled"); return -1; } + + if (os_strstr(cmd, " include_6ghz")) + include_6ghz = true; if (os_strstr(cmd, "type=social")) type = P2P_FIND_ONLY_SOCIAL; else if (os_strstr(cmd, "type=progressive")) @@ -5788,7 +5792,8 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) } return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type, - _dev_id, search_delay, seek_count, seek, freq); + _dev_id, search_delay, seek_count, seek, freq, + include_6ghz); } @@ -6041,6 +6046,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL; size_t group_ssid_len = 0; int he; + bool allow_6ghz; if (!wpa_s->global->p2p_init_wpa_s) return -1; @@ -6078,6 +6084,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, } } join = os_strstr(pos, " join") != NULL; + allow_6ghz = os_strstr(pos, " allow_6ghz") != NULL; auth = os_strstr(pos, " auth") != NULL; automatic = os_strstr(pos, " auto") != NULL; pd = os_strstr(pos, " provdisc") != NULL; @@ -6157,7 +6164,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, persistent_group, automatic, join, auth, go_intent, freq, freq2, persistent_id, pd, ht40, vht, max_oper_chwidth, he, edmg, - group_ssid, group_ssid_len); + group_ssid, group_ssid_len, allow_6ghz); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); return 25; @@ -6714,6 +6721,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) int freq = 0, pref_freq = 0; int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0; int edmg; + bool allow_6ghz; id = atoi(cmd); pos = os_strstr(cmd, " peer="); @@ -6765,8 +6773,11 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) if (max_oper_chwidth < 0) return -1; + allow_6ghz = os_strstr(cmd, " allow_6ghz") != NULL; + return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, - max_oper_chwidth, pref_freq, he, edmg); + max_oper_chwidth, pref_freq, he, edmg, + allow_6ghz); } @@ -6774,6 +6785,7 @@ static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL; + bool allow_6ghz; pos = os_strstr(cmd, " peer="); if (!pos) @@ -6786,6 +6798,8 @@ static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd) return -1; } + allow_6ghz = os_strstr(pos, " allow_6ghz") != NULL; + pos = os_strstr(pos, " go_dev_addr="); if (pos) { pos += 13; @@ -6797,7 +6811,7 @@ static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd) go_dev = go_dev_addr; } - return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev); + return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev, allow_6ghz); } @@ -6815,7 +6829,7 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, int id, int freq, int vht_center_freq2, int ht40, int vht, int vht_chwidth, - int he, int edmg) + int he, int edmg, bool allow_6ghz) { struct wpa_ssid *ssid; @@ -6830,13 +6844,14 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, vht_center_freq2, 0, ht40, vht, vht_chwidth, he, edmg, - NULL, 0, 0); + NULL, 0, 0, allow_6ghz); } static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) { int freq = 0, persistent = 0, group_id = -1; + bool allow_6ghz = false; int vht = wpa_s->conf->p2p_go_vht; int ht40 = wpa_s->conf->p2p_go_ht40 || vht; int he = wpa_s->conf->p2p_go_he; @@ -6869,6 +6884,8 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) edmg = 1; } else if (os_strcmp(token, "persistent") == 0) { persistent = 1; + } else if (os_strcmp(token, "allow_6ghz") == 0) { + allow_6ghz = true; } else { wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'", @@ -6905,10 +6922,10 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) return p2p_ctrl_group_add_persistent(wpa_s, group_id, freq, freq2, ht40, vht, max_oper_chwidth, he, - edmg); + edmg, allow_6ghz); return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht, - max_oper_chwidth, he, edmg); + max_oper_chwidth, he, edmg, allow_6ghz); } @@ -10606,6 +10623,8 @@ static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s, entry->network_ctx = ssid; + entry->external = true; + wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry); entry = NULL; ret = 0; diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 7a6567330407..565ced0fd7e2 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -175,7 +175,7 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message, } if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, - req_dev_types, NULL, 0, 0, NULL, freq)) + req_dev_types, NULL, 0, 0, NULL, freq, false)) reply = wpas_dbus_error_unknown_error( message, "Could not start P2P find"); @@ -425,14 +425,15 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, goto inv_args; if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0, - 0, 0, 0, 0, NULL, 0, 0)) { + 0, 0, 0, 0, NULL, 0, 0, + false)) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); goto out; } } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0, - 0, 0, 0)) + 0, 0, 0, false)) goto inv_args; out: @@ -653,7 +654,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, 0, join, authorize_only, go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0, - NULL, 0); + NULL, 0, false); if (new_pin >= 0) { char npin[9]; @@ -810,7 +811,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, goto err; if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0, - 0, 0, 0) < 0) { + 0, 0, 0, false) < 0) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); @@ -821,7 +822,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, * No group ID means propose to a peer to join my active group */ if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname, - peer_addr, NULL)) { + peer_addr, NULL, false)) { reply = wpas_dbus_error_unknown_error( message, "Failed to join to an active group"); goto out; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index b511d1cc1457..a565e658f33d 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -4621,6 +4621,7 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, #ifdef CONFIG_FILS /* Update ERP next sequence number */ if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) { + fils_pmksa_cache_flush(wpa_s); eapol_sm_update_erp_next_seq_num( wpa_s->eapol, data->assoc_reject.fils_erp_next_seq_num); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index e3d3c1d71029..62c9a26a3490 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -347,9 +347,9 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit) params->only_new_results = 1; } - if (wpa_s->conf->p2p_6ghz_disable && !params->freqs) { + if (!params->p2p_include_6ghz && !params->freqs) { wpa_printf(MSG_DEBUG, - "P2P: 6 GHz disabled - update the scan frequency list"); + "P2P: Exclude 6 GHz channels - update the scan frequency list"); wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params, 0); wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params, @@ -394,7 +394,8 @@ static int wpas_p2p_search_social_channel(struct wpa_supplicant *wpa_s, static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, unsigned int num_req_dev_types, - const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) + const u8 *req_dev_types, const u8 *dev_id, u16 pw_id, + bool include_6ghz) { struct wpa_supplicant *wpa_s = ctx; struct wpa_driver_scan_params *params = NULL; @@ -432,7 +433,8 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, num_req_dev_types, req_dev_types); if (wps_ie == NULL) goto fail; - + if (!wpa_s->conf->p2p_6ghz_disable) + params->p2p_include_6ghz = include_6ghz; switch (type) { case P2P_SCAN_SOCIAL: params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 1, @@ -2063,6 +2065,14 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, } ssid->auth_alg = WPA_AUTH_ALG_OPEN; ssid->key_mgmt = WPA_KEY_MGMT_PSK; + if (is_6ghz_freq(ssid->frequency) && + is_p2p_6ghz_capable(wpa_s->global->p2p)) { + ssid->auth_alg |= WPA_AUTH_ALG_SAE; + ssid->key_mgmt = WPA_KEY_MGMT_SAE; + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use SAE auth_alg and key_mgmt"); + } else { + p2p_set_6ghz_dev_capab(wpa_s->global->p2p, false); + } ssid->proto = WPA_PROTO_RSN; ssid->pairwise_cipher = WPA_CIPHER_CCMP; ssid->group_cipher = WPA_CIPHER_CCMP; @@ -3234,7 +3244,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, wpa_s->conf->p2p_go_he, wpa_s->conf->p2p_go_edmg, NULL, go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, - 1); + 1, is_p2p_allow_6ghz(wpa_s->global->p2p)); } else if (bssid) { wpa_s->user_initiated_pd = 0; wpa_msg_global(wpa_s, MSG_INFO, @@ -3463,7 +3473,8 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, channels, ssid->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : - 0, 1); + 0, 1, + is_p2p_allow_6ghz(wpa_s->global->p2p)); } @@ -3545,19 +3556,19 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s, } -static int has_channel(struct wpa_global *global, - struct hostapd_hw_modes *mode, u8 chan, int *flags) +static enum chan_allowed has_channel(struct wpa_global *global, + struct hostapd_hw_modes *mode, u8 op_class, + u8 chan, int *flags) { int i; unsigned int freq; - freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) + - chan * 5; + freq = ieee80211_chan_to_freq(NULL, op_class, chan); if (wpas_p2p_disallowed_freq(global, freq)) return NOT_ALLOWED; for (i = 0; i < mode->num_channels; i++) { - if (mode->channels[i].chan == chan) { + if ((unsigned int) mode->channels[i].freq == freq) { if (flags) *flags = mode->channels[i].flag; if (mode->channels[i].flag & @@ -3576,15 +3587,15 @@ static int has_channel(struct wpa_global *global, static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, - u8 channel) + u8 channel, const u8 *center_channels, + size_t num_chan) { - u8 center_channels[] = { 42, 58, 106, 122, 138, 155, 171 }; size_t i; if (mode->mode != HOSTAPD_MODE_IEEE80211A) return 0; - for (i = 0; i < ARRAY_SIZE(center_channels); i++) + for (i = 0; i < num_chan; i++) /* * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48), * so the center channel is 6 channels away from the start/end. @@ -3597,25 +3608,43 @@ static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s, } +static const u8 center_channels_5ghz_80mhz[] = { 42, 58, 106, 122, 138, + 155, 171 }; +static const u8 center_channels_6ghz_80mhz[] = { 7, 23, 39, 55, 71, 87, 103, + 119, 135, 151, 167, 183, 199, + 215 }; + static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, - u8 channel, u8 bw) + u8 op_class, u8 channel, u8 bw) { u8 center_chan; int i, flags; enum chan_allowed res, ret = ALLOWED; + const u8 *chans; + size_t num_chans; + bool is_6ghz = is_6ghz_op_class(op_class); - center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel); + if (is_6ghz) { + chans = center_channels_6ghz_80mhz; + num_chans = ARRAY_SIZE(center_channels_6ghz_80mhz); + } else { + chans = center_channels_5ghz_80mhz; + num_chans = ARRAY_SIZE(center_channels_5ghz_80mhz); + } + center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel, + chans, num_chans); if (!center_chan) return NOT_ALLOWED; - if (center_chan >= 58 && center_chan <= 138) + if (!is_6ghz && center_chan >= 58 && center_chan <= 138) return NOT_ALLOWED; /* Do not allow DFS channels for P2P */ /* check all the channels are available */ for (i = 0; i < 4; i++) { int adj_chan = center_chan - 6 + i * 4; - res = has_channel(wpa_s->global, mode, adj_chan, &flags); + res = has_channel(wpa_s->global, mode, op_class, adj_chan, + &flags); if (res == NOT_ALLOWED) return NOT_ALLOWED; if (res == NO_IR) @@ -3637,15 +3666,15 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, - u8 channel) + u8 channel, const u8 *center_channels, + size_t num_chan) { - u8 center_channels[] = { 50, 114, 163 }; unsigned int i; if (mode->mode != HOSTAPD_MODE_IEEE80211A) return 0; - for (i = 0; i < ARRAY_SIZE(center_channels); i++) + for (i = 0; i < num_chan; i++) /* * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64), * so the center channel is 14 channels away from the start/end. @@ -3658,15 +3687,29 @@ static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s, } +static const u8 center_channels_5ghz_160mhz[] = { 50, 114, 163 }; +static const u8 center_channels_6ghz_160mhz[] = { 15, 47, 79, 111, 143, 175, + 207 }; + static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, - u8 channel, u8 bw) + u8 op_class, u8 channel, u8 bw) { u8 center_chan; int i, flags; enum chan_allowed res, ret = ALLOWED; + const u8 *chans; + size_t num_chans; - center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel); + if (is_6ghz_op_class(op_class)) { + chans = center_channels_6ghz_160mhz; + num_chans = ARRAY_SIZE(center_channels_6ghz_160mhz); + } else { + chans = center_channels_5ghz_160mhz; + num_chans = ARRAY_SIZE(center_channels_5ghz_160mhz); + } + center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel, + chans, num_chans); if (!center_chan) return NOT_ALLOWED; /* VHT 160 MHz uses DFS channels in most countries. */ @@ -3675,7 +3718,8 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s, for (i = 0; i < 8; i++) { int adj_chan = center_chan - 14 + i * 4; - res = has_channel(wpa_s->global, mode, adj_chan, &flags); + res = has_channel(wpa_s->global, mode, op_class, adj_chan, + &flags); if (res == NOT_ALLOWED) return NOT_ALLOWED; @@ -3720,24 +3764,28 @@ static enum chan_allowed wpas_p2p_verify_edmg(struct wpa_supplicant *wpa_s, static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, - u8 channel, u8 bw) + u8 op_class, u8 channel, u8 bw) { int flag = 0; enum chan_allowed res, res2; - res2 = res = has_channel(wpa_s->global, mode, channel, &flag); + res2 = res = has_channel(wpa_s->global, mode, op_class, channel, &flag); if (bw == BW40MINUS) { if (!(flag & HOSTAPD_CHAN_HT40MINUS)) return NOT_ALLOWED; - res2 = has_channel(wpa_s->global, mode, channel - 4, NULL); + res2 = has_channel(wpa_s->global, mode, op_class, channel - 4, + NULL); } else if (bw == BW40PLUS) { if (!(flag & HOSTAPD_CHAN_HT40PLUS)) return NOT_ALLOWED; - res2 = has_channel(wpa_s->global, mode, channel + 4, NULL); + res2 = has_channel(wpa_s->global, mode, op_class, channel + 4, + NULL); } else if (bw == BW80) { - res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw); + res2 = wpas_p2p_verify_80mhz(wpa_s, mode, op_class, channel, + bw); } else if (bw == BW160) { - res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw); + res2 = wpas_p2p_verify_160mhz(wpa_s, mode, op_class, channel, + bw); } else if (bw == BW4320 || bw == BW6480 || bw == BW8640) { return wpas_p2p_verify_edmg(wpa_s, mode, channel); } @@ -3791,7 +3839,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, ch < 149 && ch + o->inc > 149) ch = 149; - res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw); + res = wpas_p2p_verify_channel(wpa_s, mode, o->op_class, + ch, o->bw); if (res == ALLOWED) { if (reg == NULL) { if (cla == P2P_MAX_REG_CLASSES) @@ -3861,7 +3910,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, (o->bw != BW40PLUS && o->bw != BW40MINUS) || ch != channel) continue; - ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw); + ret = wpas_p2p_verify_channel(wpa_s, mode, o->op_class, + ch, o->bw); if (ret == ALLOWED) return (o->bw == BW40MINUS) ? -1 : 1; } @@ -3871,21 +3921,45 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, - struct hostapd_hw_modes *mode, u8 channel) + struct hostapd_hw_modes *mode, u8 channel, + u8 op_class) { - if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80)) + const u8 *chans; + size_t num_chans; + + if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80)) return 0; - return wpas_p2p_get_center_80mhz(wpa_s, mode, channel); + if (is_6ghz_op_class(op_class)) { + chans = center_channels_6ghz_80mhz; + num_chans = ARRAY_SIZE(center_channels_6ghz_80mhz); + } else { + chans = center_channels_5ghz_80mhz; + num_chans = ARRAY_SIZE(center_channels_5ghz_80mhz); + } + return wpas_p2p_get_center_80mhz(wpa_s, mode, channel, + chans, num_chans); } int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s, - struct hostapd_hw_modes *mode, u8 channel) + struct hostapd_hw_modes *mode, u8 channel, + u8 op_class) { - if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160)) + const u8 *chans; + size_t num_chans; + + if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160)) return 0; - return wpas_p2p_get_center_160mhz(wpa_s, mode, channel); + if (is_6ghz_op_class(op_class)) { + chans = center_channels_6ghz_160mhz; + num_chans = ARRAY_SIZE(center_channels_6ghz_160mhz); + } else { + chans = center_channels_5ghz_160mhz; + num_chans = ARRAY_SIZE(center_channels_5ghz_160mhz); + } + return wpas_p2p_get_center_160mhz(wpa_s, mode, channel, + chans, num_chans); } @@ -4425,10 +4499,10 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : - 0, 0); + 0, 0, false); } else if (response_done) { wpas_p2p_group_add(wpa_s, 1, freq, - 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0, 0, 0, false); } if (passwd_id == DEV_PW_P2PS_DEFAULT) { @@ -4547,9 +4621,11 @@ static int wpas_prov_disc_resp_cb(void *ctx) wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, persistent_go->mode == WPAS_MODE_P2P_GO ? - P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0); + P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0, + is_p2p_allow_6ghz(wpa_s->global->p2p)); } else { - wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0); + wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0, + is_p2p_allow_6ghz(wpa_s->global->p2p)); } return 1; @@ -5157,7 +5233,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0); + NULL, 0, + is_p2p_allow_6ghz(wpa_s->global->p2p)); return; } @@ -5355,7 +5432,8 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, if (freq > 0) { freqs[0] = freq; params.freqs = freqs; - } else if (wpa_s->conf->p2p_6ghz_disable) { + } else if (wpa_s->conf->p2p_6ghz_disable || + !is_p2p_allow_6ghz(wpa_s->global->p2p)) { wpa_printf(MSG_DEBUG, "P2P: 6 GHz disabled - update the scan frequency list"); wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, ¶ms, @@ -5392,7 +5470,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, * the new scan results become available. */ ret = wpa_drv_scan(wpa_s, ¶ms); - if (wpa_s->conf->p2p_6ghz_disable && params.freqs != freqs) + if (params.freqs != freqs) os_free(params.freqs); if (!ret) { os_get_reltime(&wpa_s->scan_trigger_time); @@ -5622,6 +5700,10 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, res = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &max_pref_freq, pref_freq_list); + if (!is_p2p_allow_6ghz(wpa_s->global->p2p)) + max_pref_freq = p2p_remove_6ghz_channels(pref_freq_list, + max_pref_freq); + if (!res && max_pref_freq > 0) { *num_pref_freq = max_pref_freq; i = 0; @@ -5681,6 +5763,40 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, } +static bool is_p2p_6ghz_supported(struct wpa_supplicant *wpa_s, + const u8 *peer_addr) +{ + if (wpa_s->conf->p2p_6ghz_disable || + !get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, + HOSTAPD_MODE_IEEE80211A, true)) + return false; + + if (!p2p_wfd_enabled(wpa_s->global->p2p)) + return false; + if (peer_addr && !p2p_peer_wfd_enabled(wpa_s->global->p2p, peer_addr)) + return false; + + return true; +} + + +static int wpas_p2p_check_6ghz(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, bool allow_6ghz, int freq) +{ + if (allow_6ghz && is_p2p_6ghz_supported(wpa_s, peer_addr)) { + wpa_printf(MSG_DEBUG, + "P2P: Allow connection on 6 GHz channels"); + p2p_set_6ghz_dev_capab(wpa_s->global->p2p, true); + } else { + if (is_6ghz_freq(freq)) + return -2; + p2p_set_6ghz_dev_capab(wpa_s->global->p2p, false); + } + + return 0; +} + + /** * wpas_p2p_connect - Request P2P Group Formation to be started * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() @@ -5705,6 +5821,7 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, * (CHANWIDTH_*). * @group_ssid: Specific Group SSID for join or %NULL if not set * @group_ssid_len: Length of @group_ssid in octets + * @allow_6ghz: Allow P2P connection on 6 GHz channels * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified * failure, -2 on failure due to channel not currently available, * -3 if forced channel is not supported @@ -5715,7 +5832,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int go_intent, int freq, unsigned int vht_center_freq2, int persistent_id, int pd, int ht40, int vht, unsigned int vht_chwidth, int he, int edmg, - const u8 *group_ssid, size_t group_ssid_len) + const u8 *group_ssid, size_t group_ssid_len, + bool allow_6ghz) { int force_freq = 0, pref_freq = 0; int ret = 0, res; @@ -5734,7 +5852,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return -1; } - if (is_6ghz_freq(freq) && wpa_s->conf->p2p_6ghz_disable) + if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq)) return -2; os_free(wpa_s->global->add_psk); @@ -6012,6 +6130,9 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) res = wpa_drv_get_pref_freq_list(wpa_s, WPA_IF_P2P_GO, &size, pref_freq_list); + if (!is_p2p_allow_6ghz(wpa_s->global->p2p)) + size = p2p_remove_6ghz_channels(pref_freq_list, size); + if (!res && size > 0) { i = 0; while (i < size && @@ -6439,14 +6560,16 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, enum hostapd_hw_mode mode; struct hostapd_hw_modes *hwmode; u8 chan; + u8 op_class; cand = wpa_s->p2p_group_common_freqs[i]; + op_class = is_6ghz_freq(cand) ? 133 : 128; mode = ieee80211_freq_to_chan(cand, &chan); hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, mode, is_6ghz_freq(cand)); if (!hwmode || - wpas_p2p_verify_channel(wpa_s, hwmode, chan, - BW80) != ALLOWED) + wpas_p2p_verify_channel(wpa_s, hwmode, op_class, + chan, BW80) != ALLOWED) continue; if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) { params->freq = cand; @@ -6465,20 +6588,44 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) { enum hostapd_hw_mode mode; struct hostapd_hw_modes *hwmode; - u8 chan; + u8 chan, op_class; + bool is_6ghz, supported = false; + is_6ghz = is_6ghz_freq(cand); cand = wpa_s->p2p_group_common_freqs[i]; mode = ieee80211_freq_to_chan(cand, &chan); hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, - mode, is_6ghz_freq(cand)); + mode, is_6ghz); if (!wpas_same_band(wpa_s->current_ssid->frequency, cand) || - !hwmode || - (wpas_p2p_verify_channel(wpa_s, hwmode, chan, - BW40MINUS) != ALLOWED && - wpas_p2p_verify_channel(wpa_s, hwmode, chan, - BW40PLUS) != ALLOWED)) + !hwmode) continue; + if (is_6ghz && + wpas_p2p_verify_channel(wpa_s, hwmode, 132, chan, + BW40) == ALLOWED) + supported = true; + + if (!is_6ghz && + ieee80211_freq_to_channel_ext( + cand, -1, CHANWIDTH_USE_HT, &op_class, + &chan) != NUM_HOSTAPD_MODES && + wpas_p2p_verify_channel( + wpa_s, hwmode, op_class, chan, + BW40MINUS) == ALLOWED) + supported = true; + + if (!supported && !is_6ghz && + ieee80211_freq_to_channel_ext( + cand, 1, CHANWIDTH_USE_HT, &op_class, + &chan) != NUM_HOSTAPD_MODES && + wpas_p2p_verify_channel( + wpa_s, hwmode, op_class, chan, + BW40PLUS) == ALLOWED) + supported = true; + + if (!supported) + continue; + if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) { params->freq = cand; wpa_printf(MSG_DEBUG, @@ -6599,6 +6746,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, * @vht: Start GO with VHT support * @vht_chwidth: channel bandwidth for GO operating with VHT support * @edmg: Start GO with EDMG support + * @allow_6ghz: Allow P2P group creation on a 6 GHz channel * Returns: 0 on success, -1 on failure * * This function creates a new P2P group with the local end as the Group Owner, @@ -6606,12 +6754,15 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, */ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq, int vht_center_freq2, int ht40, int vht, - int max_oper_chwidth, int he, int edmg) + int max_oper_chwidth, int he, int edmg, + bool allow_6ghz) { struct p2p_go_neg_results params; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + if (wpas_p2p_check_6ghz(wpa_s, NULL, allow_6ghz, freq)) + return -1; os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; @@ -6710,7 +6861,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, int vht, int max_oper_chwidth, int he, int edmg, const struct p2p_channels *channels, - int connection_timeout, int force_scan) + int connection_timeout, int force_scan, + bool allow_6ghz) { struct p2p_go_neg_results params; int go = 0, freq; @@ -7102,7 +7254,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, unsigned int search_delay, - u8 seek_cnt, const char **seek_string, int freq) + u8 seek_cnt, const char **seek_string, int freq, + bool include_6ghz) { wpas_p2p_clear_pending_action_tx(wpa_s); wpa_s->global->p2p_long_listen = 0; @@ -7121,7 +7274,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, return p2p_find(wpa_s->global->p2p, timeout, type, num_req_dev_types, req_dev_types, dev_id, - search_delay, seek_cnt, seek_string, freq); + search_delay, seek_cnt, seek_string, freq, + include_6ghz); } @@ -7337,7 +7491,7 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, int vht_center_freq2, int ht40, int vht, int max_chwidth, - int pref_freq, int he, int edmg) + int pref_freq, int he, int edmg, bool allow_6ghz) { enum p2p_invite_role role; u8 *bssid = NULL; @@ -7346,6 +7500,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int no_pref_freq_given = pref_freq == 0; unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + if (wpas_p2p_check_6ghz(wpa_s, NULL, allow_6ghz, freq)) + return -1; + wpa_s->global->p2p_invite_group = NULL; if (peer_addr) os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN); @@ -7420,7 +7577,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, /* Invite to join an active group */ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, - const u8 *peer_addr, const u8 *go_dev_addr) + const u8 *peer_addr, const u8 *go_dev_addr, + bool allow_6ghz) { struct wpa_global *global = wpa_s->global; enum p2p_invite_role role; @@ -7483,6 +7641,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq)) + return -1; size = P2P_MAX_PREF_CHANNELS; res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq, @@ -8385,7 +8545,7 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0); + NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p)); return ret; } @@ -8923,7 +9083,7 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, params->go_ssid_len ? params->go_ssid : NULL, - params->go_ssid_len); + params->go_ssid_len, false); } @@ -9002,7 +9162,7 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s, forced_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0); + NULL, 0, false); } @@ -9019,7 +9179,7 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s, forced_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0); + NULL, 0, false); if (res) return res; diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 941198e3afb0..dee9c1bcc1e1 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -38,19 +38,21 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int go_intent, int freq, unsigned int vht_center_freq2, int persistent_id, int pd, int ht40, int vht, unsigned int vht_chwidth, int he, int edmg, - const u8 *group_ssid, size_t group_ssid_len); + const u8 *group_ssid, size_t group_ssid_len, + bool allow_6ghz); int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq, struct wpa_ssid *ssid); int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq, int vht_center_freq2, int ht40, int vht, - int max_oper_chwidth, int he, int edmg); + int max_oper_chwidth, int he, int edmg, bool allow_6ghz); int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int addr_allocated, int force_freq, int neg_freq, int vht_center_freq2, int ht40, int vht, int max_oper_chwidth, int he, int edmg, const struct p2p_channels *channels, - int connection_timeout, int force_scan); + int connection_timeout, int force_scan, + bool allow_6ghz); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); enum wpas_p2p_prov_disc_use { @@ -73,7 +75,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, unsigned int search_delay, - u8 seek_cnt, const char **seek_string, int freq); + u8 seek_cnt, const char **seek_string, int freq, + bool include_6ghz); void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s); int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout); int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout); @@ -117,9 +120,10 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr); int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, int vht_center_freq2, int ht40, int vht, int max_chwidth, - int pref_freq, int he, int edmg); + int pref_freq, int he, int edmg, bool allow_6ghz); int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, - const u8 *peer_addr, const u8 *go_dev_addr); + const u8 *peer_addr, const u8 *go_dev_addr, + bool allow_6ghz); int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, u32 interval1, u32 duration2, u32 interval2); int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period, @@ -145,9 +149,11 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s); int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, - struct hostapd_hw_modes *mode, u8 channel); + struct hostapd_hw_modes *mode, u8 channel, + u8 op_class); int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s, - struct hostapd_hw_modes *mode, u8 channel); + struct hostapd_hw_modes *mode, u8 channel, + u8 op_class); unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s); void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, const u8 *p2p_dev_addr, diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index c194806cd7f2..97a8d9a638d6 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -2850,6 +2850,7 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->relative_rssi = src->relative_rssi; params->relative_adjust_band = src->relative_adjust_band; params->relative_adjust_rssi = src->relative_adjust_rssi; + params->p2p_include_6ghz = src->p2p_include_6ghz; return params; failed: diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 72aa9b5b8f18..f2c42ff354e7 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1340,8 +1340,15 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if (status_code != WLAN_STATUS_SUCCESS && status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT && - status_code != WLAN_STATUS_SAE_PK) + status_code != WLAN_STATUS_SAE_PK) { + const u8 *bssid = sa ? sa : wpa_s->pending_bssid; + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AUTH_REJECT MACSTR + " auth_type=%u auth_transaction=%u status_code=%u", + MAC2STR(bssid), WLAN_AUTH_SAE, + auth_transaction, status_code); return -1; + } if (auth_transaction == 1) { u16 res; @@ -1542,7 +1549,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) int res; res = sme_sae_auth(wpa_s, data->auth.auth_transaction, data->auth.status_code, data->auth.ies, - data->auth.ies_len, 0, NULL); + data->auth.ies_len, 0, data->auth.peer); if (res < 0) { wpas_connection_failed(wpa_s, wpa_s->pending_bssid); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index c4c6651d42e6..8a1a44690ba5 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -1343,11 +1343,11 @@ static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) continue; bss = wpa_s->current_bss; ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); - if (bss && ssid_ie && + if (bss && ssid_ie && ssid_ie[1] && (bss->ssid_len != ssid_ie[1] || os_memcmp(bss->ssid, ssid_ie + 2, bss->ssid_len) != 0)) - continue; + continue; /* Skip entries for other ESSs */ /* Potential candidate found */ found = 1; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 0d9b9caa5906..cc184dba5feb 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -7537,6 +7537,46 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) #ifdef CONFIG_FILS + +void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + const u8 *realm, *username, *rrk; + size_t realm_len, username_len, rrk_len; + u16 next_seq_num; + + /* Clear the PMKSA cache entry if FILS authentication was rejected. + * Check for ERP keys existing to limit when this can be done since + * the rejection response is not protected and such triggers should + * really not allow internal state to be modified unless required to + * avoid significant issues in functionality. In addition, drop + * externally configure PMKSA entries even without ERP keys since it + * is possible for an external component to add PMKSA entries for FILS + * authentication without restoring previously generated ERP keys. + * + * In this case, this is needed to allow recovery from cases where the + * AP or authentication server has dropped PMKSAs and ERP keys. */ + if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt)) + return; + + if (eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, + &username, &username_len, + &realm, &realm_len, &next_seq_num, + &rrk, &rrk_len) != 0 || + !realm) { + wpa_dbg(wpa_s, MSG_DEBUG, + "FILS: Drop external PMKSA cache entry"); + wpa_sm_aborted_external_cached(wpa_s->wpa); + wpa_sm_external_pmksa_cache_flush(wpa_s->wpa, ssid); + return; + } + + wpa_dbg(wpa_s, MSG_DEBUG, "FILS: Drop PMKSA cache entry"); + wpa_sm_aborted_cached(wpa_s->wpa); + wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); +} + + void fils_connection_failure(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid = wpa_s->current_ssid; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 6877f5a9960d..60acb53c5c38 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1501,6 +1501,7 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s); void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s); void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid); void fils_connection_failure(struct wpa_supplicant *wpa_s); +void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s); int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s); int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s); void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason); diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 029349b08d20..5633f3d1ecaf 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -372,6 +372,7 @@ static int wpa_supplicant_wps_cred(void *ctx, #ifdef CONFIG_WPS_REG_DISABLE_OPEN int registrar = 0; #endif /* CONFIG_WPS_REG_DISABLE_OPEN */ + bool add_sae; if ((wpa_s->conf->wps_cred_processing == 1 || wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) { @@ -534,8 +535,12 @@ static int wpa_supplicant_wps_cred(void *ctx, 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) { + add_sae = wpa_s->conf->wps_cred_add_sae; +#ifdef CONFIG_P2P + if (ssid->p2p_group && is_p2p_6ghz_capable(wpa_s->global->p2p)) + add_sae = true; +#endif /* CONFIG_P2P */ + if (add_sae && cred->key_len != 2 * PMK_LEN) { ssid->auth_alg = 0; ssid->key_mgmt |= WPA_KEY_MGMT_SAE; ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;