aboutsummaryrefslogtreecommitdiff
path: root/contrib/wpa/wpa_supplicant/p2p_supplicant.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa/wpa_supplicant/p2p_supplicant.c')
-rw-r--r--contrib/wpa/wpa_supplicant/p2p_supplicant.c667
1 files changed, 565 insertions, 102 deletions
diff --git a/contrib/wpa/wpa_supplicant/p2p_supplicant.c b/contrib/wpa/wpa_supplicant/p2p_supplicant.c
index 55b3b08efe50..62c9a26a3490 100644
--- a/contrib/wpa/wpa_supplicant/p2p_supplicant.c
+++ b/contrib/wpa/wpa_supplicant/p2p_supplicant.c
@@ -242,6 +242,22 @@ static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
}
+static void wpas_p2p_scan_res_handled(struct wpa_supplicant *wpa_s)
+{
+ unsigned int delay = wpas_p2p_search_delay(wpa_s);
+
+ /* In case of concurrent P2P and external scans, delay P2P search. */
+ if (external_scan_running(wpa_s->radio)) {
+ delay = wpa_s->conf->p2p_search_delay;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Delay next P2P search by %d ms to let externally triggered scan complete",
+ delay);
+ }
+
+ p2p_scan_res_handled(wpa_s->global->p2p, delay);
+}
+
+
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
@@ -287,7 +303,25 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
break;
}
- p2p_scan_res_handled(wpa_s->global->p2p);
+ wpas_p2p_scan_res_handled(wpa_s);
+}
+
+
+static void wpas_p2p_scan_res_fail_handler(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
+ if (wpa_s->global->p2p_disabled || !wpa_s->global->p2p)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to get scan results - try to continue");
+ wpas_p2p_scan_res_handled(wpa_s);
}
@@ -312,6 +346,15 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
"Request driver to clear scan cache due to local BSS flush");
params->only_new_results = 1;
}
+
+ if (!params->p2p_include_6ghz && !params->freqs) {
+ wpa_printf(MSG_DEBUG,
+ "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,
+ 0);
+ }
ret = wpa_drv_scan(wpa_s, params);
if (ret == 0)
wpa_s->curr_scan_cookie = params->scan_cookie;
@@ -326,6 +369,7 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ wpa_s->scan_res_fail_handler = wpas_p2p_scan_res_fail_handler;
wpa_s->own_scan_requested = 1;
wpa_s->clear_driver_scan_cache = 0;
wpa_s->p2p_scan_work = work;
@@ -350,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;
@@ -388,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,
@@ -522,7 +568,7 @@ static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s,
/*
* The calling wpa_s instance is going to be removed. Do that
* from an eloop callback to keep the instance available until
- * the caller has returned. This my be needed, e.g., to provide
+ * the caller has returned. This may be needed, e.g., to provide
* control interface responses on the per-interface socket.
*/
if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
@@ -1063,9 +1109,9 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
"group is persistent - BSS " MACSTR
" did not include P2P IE", MAC2STR(bssid));
wpa_hexdump(MSG_DEBUG, "P2P: Probe Response IEs",
- (u8 *) (bss + 1), bss->ie_len);
+ wpa_bss_ie_ptr(bss), bss->ie_len);
wpa_hexdump(MSG_DEBUG, "P2P: Beacon IEs",
- ((u8 *) bss + 1) + bss->ie_len,
+ wpa_bss_ie_ptr(bss) + bss->ie_len,
bss->beacon_ie_len);
return 0;
}
@@ -1885,6 +1931,83 @@ static void p2p_go_configured(void *ctx, void *data)
}
+/**
+ * wpas_p2p_freq_to_edmg_channel - Convert frequency into EDMG channel
+ * @freq: Frequency (MHz) to convert
+ * @op_class: Buffer for returning operating class
+ * @op_edmg_channel: Buffer for returning channel number
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to find the highest channel bonding which includes the
+ * specified frequency.
+ */
+static int wpas_p2p_freq_to_edmg_channel(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ u8 *op_class, u8 *op_edmg_channel)
+{
+ struct hostapd_hw_modes *hwmode;
+ struct ieee80211_edmg_config edmg;
+ unsigned int i;
+ enum chan_width chanwidth[] = {
+ CHAN_WIDTH_8640,
+ CHAN_WIDTH_6480,
+ CHAN_WIDTH_4320,
+ };
+
+ if (!wpa_s->hw.modes)
+ return -1;
+
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211AD, false);
+ if (!hwmode) {
+ wpa_printf(MSG_ERROR,
+ "Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD");
+ return -1;
+ }
+
+ /* Find the highest EDMG channel bandwidth to start the P2P GO */
+ for (i = 0; i < ARRAY_SIZE(chanwidth); i++) {
+ if (ieee80211_chaninfo_to_channel(freq, chanwidth[i], 0,
+ op_class,
+ op_edmg_channel) < 0)
+ continue;
+
+ hostapd_encode_edmg_chan(1, *op_edmg_channel, 0, &edmg);
+ if (edmg.channels &&
+ ieee802_edmg_is_allowed(hwmode->edmg, edmg)) {
+ wpa_printf(MSG_DEBUG,
+ "Freq %u to EDMG channel %u at opclass %u",
+ freq, *op_edmg_channel, *op_class);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params)
+{
+ u8 op_channel, op_class;
+ int freq;
+
+ /* Try social channel as primary channel frequency */
+ freq = (!params->freq) ? 58320 + 1 * 2160 : params->freq;
+
+ if (wpas_p2p_freq_to_edmg_channel(wpa_s, freq, &op_class,
+ &op_channel) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Freq %d will be used to set an EDMG connection (channel=%u opclass=%u)",
+ freq, op_channel, op_class);
+ params->freq = freq;
+ return 0;
+ }
+
+ return -1;
+}
+
+
static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int group_formation)
@@ -1921,6 +2044,20 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
ssid->max_oper_chwidth = params->max_oper_chwidth;
ssid->vht_center_freq2 = params->vht_center_freq2;
ssid->he = params->he;
+ if (params->edmg) {
+ u8 op_channel, op_class;
+
+ if (!wpas_p2p_freq_to_edmg_channel(wpa_s, params->freq,
+ &op_class, &op_channel)) {
+ ssid->edmg_channel = op_channel;
+ ssid->enable_edmg = params->edmg;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Could not match EDMG channel, freq %d, for GO",
+ params->freq);
+ }
+ }
+
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -1928,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;
@@ -2026,6 +2171,7 @@ do { \
d->go_internet = s->go_internet;
d->go_venue_group = s->go_venue_group;
d->go_venue_type = s->go_venue_type;
+ d->p2p_add_cli_chan = s->p2p_add_cli_chan;
}
@@ -2270,6 +2416,8 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
res->vht = 1;
if (wpa_s->p2p_go_he)
res->he = 1;
+ if (wpa_s->p2p_go_edmg)
+ res->edmg = 1;
res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
@@ -2329,7 +2477,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpas_start_wps_enrollee(group_wpa_s, res);
}
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
@@ -2598,7 +2746,7 @@ static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf,
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
- freq);
+ freq, 0);
}
@@ -3089,9 +3237,14 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
MAC2STR(sa), s->id);
}
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0,
+ wpa_s->conf->p2p_go_ht40,
+ wpa_s->conf->p2p_go_vht,
+ 0,
+ 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,
@@ -3316,10 +3469,12 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
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));
}
@@ -3401,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 &
@@ -3432,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 };
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.
@@ -3453,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)
@@ -3493,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 };
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.
@@ -3514,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. */
@@ -3531,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;
@@ -3560,26 +3748,46 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
}
+static enum chan_allowed wpas_p2p_verify_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ struct ieee80211_edmg_config edmg;
+
+ hostapd_encode_edmg_chan(1, channel, 0, &edmg);
+ if (edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+ return ALLOWED;
+
+ return NOT_ALLOWED;
+}
+
+
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);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3592,7 +3800,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
struct p2p_channels *chan,
- struct p2p_channels *cli_chan)
+ struct p2p_channels *cli_chan,
+ bool p2p_disable_6ghz)
{
struct hostapd_hw_modes *mode;
int cla, op, cli_cla;
@@ -3611,36 +3820,55 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
u8 ch;
struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
- if (o->p2p == NO_P2P_SUPP)
+ if (o->p2p == NO_P2P_SUPP ||
+ (is_6ghz_op_class(o->op_class) && p2p_disable_6ghz))
continue;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
+ is_6ghz_op_class(o->op_class));
if (mode == NULL)
continue;
if (mode->mode == HOSTAPD_MODE_IEEE80211G)
wpa_s->global->p2p_24ghz_social_channels = 1;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
enum chan_allowed res;
- res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+
+ /* Check for non-continuous jump in channel index
+ * incrementation */
+ if ((o->op_class >= 128 && o->op_class <= 130) &&
+ ch < 149 && ch + o->inc > 149)
+ ch = 149;
+
+ 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)
+ continue;
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
o->op_class);
reg = &chan->reg_class[cla];
cla++;
reg->reg_class = o->op_class;
}
+ if (reg->channels == P2P_MAX_REG_CLASS_CHANNELS)
+ continue;
reg->channel[reg->channels] = ch;
reg->channels++;
} else if (res == NO_IR &&
wpa_s->conf->p2p_add_cli_chan) {
if (cli_reg == NULL) {
+ if (cli_cla == P2P_MAX_REG_CLASSES)
+ continue;
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
o->op_class);
cli_reg = &cli_chan->reg_class[cli_cla];
cli_cla++;
cli_reg->reg_class = o->op_class;
}
+ if (cli_reg->channels ==
+ P2P_MAX_REG_CLASS_CHANNELS)
+ continue;
cli_reg->channel[cli_reg->channels] = ch;
cli_reg->channels++;
}
@@ -3672,7 +3900,9 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
const struct oper_class_map *o = &global_op_class[op];
u8 ch;
- if (o->p2p == NO_P2P_SUPP)
+ if (o->p2p == NO_P2P_SUPP ||
+ (is_6ghz_op_class(o->op_class) &&
+ wpa_s->conf->p2p_6ghz_disable))
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
@@ -3680,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;
}
@@ -3690,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);
}
@@ -3799,14 +4054,24 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
char ifname[100];
char force_name[100];
int ret;
+ const u8 *if_addr = NULL;
ret = os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
wpa_s->ifname);
if (os_snprintf_error(sizeof(ifname), ret))
return -1;
+ /* Cut length at the maximum size. Note that we don't need to ensure
+ * collision free names here as the created interface is not a netdev.
+ */
+ ifname[IFNAMSIZ - 1] = '\0';
force_name[0] = '\0';
wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
- ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
+
+ if (wpa_s->conf->p2p_device_random_mac_addr == 2 &&
+ !is_zero_ether_addr(wpa_s->conf->p2p_device_persistent_mac_addr))
+ if_addr = wpa_s->conf->p2p_device_persistent_mac_addr;
+
+ ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, if_addr, NULL,
force_name, wpa_s->pending_interface_addr, NULL);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
@@ -4230,14 +4495,14 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, freq, 0, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 0, 0, 0, 0, 0, NULL,
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, false);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -4353,11 +4618,14 @@ static int wpas_prov_disc_resp_cb(void *ctx)
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
+ 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);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0,
+ is_p2p_allow_6ghz(wpa_s->global->p2p));
}
return 1;
@@ -4382,6 +4650,16 @@ int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->p2p_device_random_mac_addr == 0)
return 0;
+ if (wpa_s->conf->p2p_device_random_mac_addr == 2) {
+ if (is_zero_ether_addr(
+ wpa_s->conf->p2p_device_persistent_mac_addr) &&
+ !is_zero_ether_addr(wpa_s->own_addr)) {
+ os_memcpy(wpa_s->conf->p2p_device_persistent_mac_addr,
+ wpa_s->own_addr, ETH_ALEN);
+ }
+ return 0;
+ }
+
if (!wpa_s->conf->ssid) {
if (random_mac_addr(addr) < 0) {
wpa_msg(wpa_s, MSG_INFO,
@@ -4483,6 +4761,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.prov_disc_resp_cb = wpas_prov_disc_resp_cb;
p2p.p2ps_group_capability = p2ps_group_capability;
p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list;
+ p2p.p2p_6ghz_disable = wpa_s->conf->p2p_6ghz_disable;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -4496,7 +4775,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.config_methods = wpa_s->wps->config_methods;
}
- if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
+ if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels,
+ p2p.p2p_6ghz_disable)) {
wpa_printf(MSG_ERROR,
"P2P: Failed to configure supported channel list");
return -1;
@@ -4638,11 +4918,12 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_p2p_reconsider_moving_go, wpa_s, NULL);
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->p2p_send_action_work) {
os_free(wpa_s->p2p_send_action_work->ctx);
@@ -4791,6 +5072,15 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
MAC2STR(wpa_s->pending_join_dev_addr));
return;
}
+ if (wpa_s->p2p_fallback_to_go_neg) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Join operation failed - fall back to GO Negotiation");
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
+ P2P_EVENT_FALLBACK_TO_GO_NEG
+ "reason=join-failed");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
+ }
wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
wpas_notify_p2p_group_formation_failure(wpa_s, "");
@@ -4942,7 +5232,9 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
- NULL, 0);
+ wpa_s->p2p_go_edmg,
+ NULL, 0,
+ is_p2p_allow_6ghz(wpa_s->global->p2p));
return;
}
@@ -5001,7 +5293,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from BSS table: %d MHz (SSID %s)", freq,
wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+ if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len,
dev_addr) == 0 &&
os_memcmp(wpa_s->pending_join_dev_addr,
wpa_s->pending_join_iface_addr, ETH_ALEN) == 0 &&
@@ -5140,6 +5432,14 @@ 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 ||
+ !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, &params,
+ 0);
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, &params,
+ 0);
}
ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
@@ -5170,6 +5470,8 @@ 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, &params);
+ if (params.freqs != freqs)
+ os_free(params.freqs);
if (!ret) {
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
@@ -5398,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;
@@ -5457,6 +5763,40 @@ exit_free:
}
+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()
@@ -5481,6 +5821,7 @@ exit_free:
* (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
@@ -5490,8 +5831,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int persistent_group, int auto_join, int join, int auth,
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, const u8 *group_ssid,
- size_t group_ssid_len)
+ unsigned int vht_chwidth, int he, int edmg,
+ const u8 *group_ssid, size_t group_ssid_len,
+ bool allow_6ghz)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -5510,6 +5852,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return -1;
}
+ if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq))
+ return -2;
+
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
@@ -5522,7 +5867,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
go_intent = wpa_s->conf->p2p_go_intent;
if (!auth)
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
wpa_s->p2p_wps_method = wps_method;
wpa_s->p2p_persistent_group = !!persistent_group;
@@ -5536,6 +5881,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
wpa_s->p2p_go_he = !!he;
+ wpa_s->p2p_go_edmg = !!edmg;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -5691,19 +6037,20 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
{
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
- wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+ wpa_s->global->p2p_long_listen,
+ offchannel_pending_action_tx(wpa_s));
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->p2p_long_listen > 0)
- wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
+ if (wpa_s->global->p2p_long_listen > 0)
+ wpa_s->global->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
if (offchannel_pending_action_tx(wpa_s))
return;
- if (wpa_s->p2p_long_listen > 0) {
+ if (wpa_s->global->p2p_long_listen > 0) {
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
- wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
} else {
/*
* When listen duration is over, stop listen & update p2p_state
@@ -5734,6 +6081,8 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
if (os_strcmp(ifname, "*") == 0) {
struct wpa_supplicant *prev;
+ bool calling_wpa_s_group_removed = false;
+
wpa_s = global->ifaces;
while (wpa_s) {
prev = wpa_s;
@@ -5741,9 +6090,23 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
if (prev->p2p_group_interface !=
NOT_P2P_GROUP_INTERFACE ||
(prev->current_ssid &&
- prev->current_ssid->p2p_group))
+ prev->current_ssid->p2p_group)) {
wpas_p2p_disconnect_safely(prev, calling_wpa_s);
+ if (prev == calling_wpa_s)
+ calling_wpa_s_group_removed = true;
+ }
}
+
+ if (!calling_wpa_s_group_removed &&
+ (calling_wpa_s->p2p_group_interface !=
+ NOT_P2P_GROUP_INTERFACE ||
+ (calling_wpa_s->current_ssid &&
+ calling_wpa_s->current_ssid->p2p_group))) {
+ wpa_printf(MSG_DEBUG, "Remove calling_wpa_s P2P group");
+ wpas_p2p_disconnect_safely(calling_wpa_s,
+ calling_wpa_s);
+ }
+
return 0;
}
@@ -5767,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 &&
@@ -5822,10 +6188,32 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
"channel: %d MHz", freq);
} else {
+ const int freqs[] = {
+ /* operating class 115 */
+ 5180, 5200, 5220, 5240,
+ /* operating class 124 */
+ 5745, 5765, 5785, 5805,
+ };
+ unsigned int i, num_freqs = ARRAY_SIZE(freqs);
+
if (os_get_random((u8 *) &r, sizeof(r)) < 0)
return -1;
- freq = 5180 + (r % 4) * 20;
- if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+
+ /*
+ * Most of the 5 GHz channels require DFS. Only
+ * operating classes 115 and 124 are available possibly
+ * without that requirement. Check these for
+ * availability starting from a randomly picked
+ * position.
+ */
+ for (i = 0; i < num_freqs; i++, r++) {
+ freq = freqs[r % num_freqs];
+ if (p2p_supported_freq_go(wpa_s->global->p2p,
+ freq))
+ break;
+ }
+
+ if (i >= num_freqs) {
wpa_printf(MSG_DEBUG, "P2P: Could not select "
"5 GHz channel for P2P group");
return -1;
@@ -5960,6 +6348,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int vht_center_freq2, int ht40,
int vht, int max_oper_chwidth, int he,
+ int edmg,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
@@ -5975,6 +6364,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
params->he = he;
params->max_oper_chwidth = max_oper_chwidth;
params->vht_center_freq2 = vht_center_freq2;
+ params->edmg = edmg;
freqs = os_calloc(wpa_s->num_multichan_concurrent,
sizeof(struct wpa_used_freq_data));
@@ -6005,6 +6395,13 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
}
}
+ /* Try to use EDMG channel */
+ if (params->edmg) {
+ if (wpas_p2p_try_edmg_channel(wpa_s, params) == 0)
+ goto success;
+ params->edmg = 0;
+ }
+
/* try using the forced freq */
if (freq) {
if (wpas_p2p_disallowed_freq(wpa_s->global, freq) ||
@@ -6163,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);
+ 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;
@@ -6189,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);
+ 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,
@@ -6322,6 +6745,8 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
* @ht40: Start GO with 40 MHz channel width
* @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,
@@ -6329,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 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;
@@ -6350,7 +6778,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
}
if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, he, NULL))
+ ht40, vht, max_oper_chwidth, he, edmg,
+ NULL))
return -1;
p2p_go_params(wpa_s->global->p2p, &params);
@@ -6430,8 +6859,10 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
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_go_neg_results params;
int go = 0, freq;
@@ -6505,7 +6936,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
}
if (wpas_p2p_init_go_params(wpa_s, &params, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, he, channels))
+ ht40, vht, max_oper_chwidth, he, edmg,
+ channels))
return -1;
params.role_go = 1;
@@ -6822,10 +7254,11 @@ 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->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
wpa_s->p2p_in_provisioning) {
@@ -6841,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);
}
@@ -6863,14 +7297,14 @@ static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s,
* Indicate that results have been processed so that the P2P module can
* continue pending tasks.
*/
- p2p_scan_res_handled(wpa_s->global->p2p);
+ wpas_p2p_scan_res_handled(wpa_s);
}
static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
@@ -6896,7 +7330,7 @@ void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
}
@@ -6925,7 +7359,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
timeout = 3600;
}
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
/*
* Stop previous find/listen operation to avoid trying to request a new
@@ -6937,7 +7371,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
- wpa_s->p2p_long_listen = timeout * 1000;
+ wpa_s->global->p2p_long_listen = timeout * 1000;
eloop_register_timeout(timeout, 0,
wpas_p2p_long_listen_timeout,
wpa_s, NULL);
@@ -7044,7 +7478,7 @@ static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -7057,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 pref_freq, int he, int edmg, bool allow_6ghz)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -7066,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);
@@ -7078,6 +7515,7 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_go_he = !!he;
wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
+ wpa_s->p2p_go_edmg = !!edmg;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -7139,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;
@@ -7155,6 +7594,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
wpa_s->p2p_go_vht = 0;
wpa_s->p2p_go_vht_center_freq2 = 0;
wpa_s->p2p_go_max_oper_chwidth = 0;
+ wpa_s->p2p_go_edmg = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -7201,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,
@@ -7776,7 +8218,8 @@ void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s,
os_memset(&chan, 0, sizeof(chan));
os_memset(&cli_chan, 0, sizeof(cli_chan));
- if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
+ if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan,
+ is_p2p_6ghz_disabled(wpa_s->global->p2p))) {
wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
"channel list");
return;
@@ -8100,7 +8543,9 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
+ NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p));
return ret;
}
@@ -8636,9 +9081,9 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
params->go_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_he, wpa_s->p2p_go_edmg,
params->go_ssid_len ? params->go_ssid : NULL,
- params->go_ssid_len);
+ params->go_ssid_len, false);
}
@@ -8716,7 +9161,8 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
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, NULL, 0);
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+ NULL, 0, false);
}
@@ -8732,7 +9178,8 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
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, NULL, 0);
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+ NULL, 0, false);
if (res)
return res;
@@ -9117,7 +9564,8 @@ static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s)
* TODO: This function may not always work correctly. For example,
* when we have a running GO and a BSS on a DFS channel.
*/
- if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, 0,
+ NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P CSA: Failed to select new frequency for GO");
return -1;
@@ -9217,6 +9665,8 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
{
struct p2p_go_neg_results params;
struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+ void (*ap_configured_cb)(void *ctx, void *data);
+ void *ap_configured_cb_ctx, *ap_configured_cb_data;
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
@@ -9226,10 +9676,18 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
/* Stop the AP functionality */
/* TODO: Should do this in a way that does not indicated to possible
* P2P Clients in the group that the group is terminated. */
+ /* If this action occurs before a group is started, the callback should
+ * be preserved, or GROUP-STARTED event would be lost. If this action
+ * occurs after a group is started, these pointers are all NULL and
+ * harmless. */
+ ap_configured_cb = wpa_s->ap_configured_cb;
+ ap_configured_cb_ctx = wpa_s->ap_configured_cb_ctx;
+ ap_configured_cb_data = wpa_s->ap_configured_cb_data;
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, &params, 0, 0, 0, 0, 0, 0, 0,
+ NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
@@ -9248,6 +9706,11 @@ static void wpas_p2p_move_go_no_csa(struct wpa_supplicant *wpa_s)
return;
}
+ /* Restore preserved callback parameters */
+ wpa_s->ap_configured_cb = ap_configured_cb;
+ wpa_s->ap_configured_cb_ctx = ap_configured_cb_ctx;
+ wpa_s->ap_configured_cb_data = ap_configured_cb_data;
+
/* Update the frequency */
current_ssid->frequency = params.freq;
wpa_s->connect_without_scan = current_ssid;