From 4383528e01955d995d3b3db201e4c0f9840e8236 Mon Sep 17 00:00:00 2001 From: Sreeramya Soratkal Date: Thu, 5 Nov 2020 21:55:55 +0530 Subject: [PATCH] P2P: Use weighted preferred channel list for channel selection Previously, the driver could optionally (using QCA vendor command) provide a preferred channel list to wpa_supplicant for channel selection during the GO negotiation. Channel selection process can be more efficient with the information of weights and flags of the preferred channel list that can be provided by the driver. Use a weighted preferred channel list provided by the driver for channel selection during GO negotiation if such a list is available. Signed-off-by: Sreeramya Soratkal --- src/drivers/driver.h | 27 +++++++- src/drivers/driver_nl80211.c | 111 ++++++++++++++++++++++++------ src/p2p/p2p.c | 7 +- src/p2p/p2p.h | 11 ++- src/p2p/p2p_build.c | 14 ++-- src/p2p/p2p_go_neg.c | 89 +++++++++++++++++------- src/p2p/p2p_i.h | 9 ++- src/p2p/p2p_utils.c | 82 +++++++++++++++++++++- wpa_supplicant/ctrl_iface.c | 10 +-- wpa_supplicant/driver_i.h | 2 +- wpa_supplicant/p2p_supplicant.c | 46 ++++++++----- wpa_supplicant/wpa_supplicant_i.h | 2 +- 12 files changed, 322 insertions(+), 88 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 677b729d5..f069b74e1 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2602,6 +2602,24 @@ enum nested_attr { NESTED_ATTR_UNSPECIFIED = 2, }; +/* Preferred channel list information */ + +/* GO role */ +#define WEIGHTED_PCL_GO BIT(0) +/* P2P Client role */ +#define WEIGHTED_PCL_CLI BIT(1) +/* Must be considered for operating channel */ +#define WEIGHTED_PCL_MUST_CONSIDER BIT(2) +/* Should be excluded in GO negotiation */ +#define WEIGHTED_PCL_EXCLUDE BIT(3) + +/* Preferred channel list with weight */ +struct weighted_pcl { + u32 freq; /* MHz */ + u8 weight; + u32 flag; /* bitmap for WEIGHTED_PCL_* */ +}; + /** * struct wpa_driver_ops - Driver interface API definition * @@ -4446,14 +4464,17 @@ struct wpa_driver_ops { * @priv: Private driver interface data * @if_type: Interface type * @num: Number of channels - * @freq_list: Preferred channel frequency list encoded in MHz values + * @freq_list: Weighted preferred channel list * Returns 0 on success, -1 on failure * * This command can be used to query the preferred frequency list from - * the driver specific to a particular interface type. + * the driver specific to a particular interface type. The freq_list + * array needs to have room for *num entries. *num will be updated to + * indicate the number of entries fetched from the driver. */ int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type, - unsigned int *num, unsigned int *freq_list); + unsigned int *num, + struct weighted_pcl *freq_list); /** * set_prob_oper_freq - Indicate probable P2P operating channel diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 0127a6be2..60e44a1a9 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -11258,9 +11258,33 @@ static int nl80211_set_band(void *priv, u32 band_mask) struct nl80211_pcl { unsigned int num; - unsigned int *freq_list; + struct weighted_pcl *freq_list; }; +static void get_pcl_attr_values(struct weighted_pcl *wpcl, struct nlattr *nl[]) +{ + if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ]) + wpcl->freq = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ]); + if (nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT]) + wpcl->weight = nla_get_u8(nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT]); + if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]) { + u32 flags = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]); + + wpcl->flag = 0; + if (flags & BIT(0)) + wpcl->flag |= WEIGHTED_PCL_GO; + if (flags & BIT(1)) + wpcl->flag |= WEIGHTED_PCL_CLI; + if (flags & BIT(2)) + wpcl->flag |= WEIGHTED_PCL_MUST_CONSIDER; + if (flags & BIT(3)) + wpcl->flag |= WEIGHTED_PCL_EXCLUDE; + } else { + wpcl->flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI; + } +} + + static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -11269,6 +11293,7 @@ static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) struct nlattr *nl_vend, *attr; enum qca_iface_type iface_type; struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *nl_pcl[QCA_WLAN_VENDOR_ATTR_PCL_MAX + 1]; unsigned int num, max_num; u32 *freqs; @@ -11294,26 +11319,69 @@ static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d", iface_type); - attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]; - if (!attr) { + attr = tb_vendor[ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL]; + if (attr) { + int rem; + struct nlattr *wpcl = attr; + unsigned int i; + + num = 0; + nla_for_each_nested(attr, wpcl, rem) { + if (num == param->num) + break; /* not enough room for all entries */ + if (nla_parse(nl_pcl, QCA_WLAN_VENDOR_ATTR_PCL_MAX, + nla_data(attr), nla_len(attr), NULL)) { + wpa_printf(MSG_ERROR, + "nl80211: Failed to parse PCL info"); + param->num = 0; + return NL_SKIP; + } + get_pcl_attr_values(¶m->freq_list[num], nl_pcl); + num++; + } + param->num = num; + + /* Sort frequencies based on their weight */ + for (i = 0; i < num; i++) { + unsigned int j; + + for (j = i + 1; j < num; j++) { + if (param->freq_list[i].weight < + param->freq_list[j].weight) { + struct weighted_pcl tmp; + + tmp = param->freq_list[i]; + param->freq_list[i] = + param->freq_list[j]; + param->freq_list[j] = tmp; + } + } + } + } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]) { + wpa_printf(MSG_DEBUG, + "nl80211: Driver does not provide weighted PCL; use the non-weighted variant"); + attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]; + /* + * param->num has the maximum number of entries for which there + * is room in the freq_list provided by the caller. + */ + freqs = nla_data(attr); + max_num = nla_len(attr) / sizeof(u32); + if (max_num > param->num) + max_num = param->num; + for (num = 0; num < max_num; num++) { + param->freq_list[num].freq = freqs[num]; + param->freq_list[num].flag = + WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI; + } + param->num = num; + } else { wpa_printf(MSG_ERROR, "nl80211: preferred_freq_list couldn't be found"); param->num = 0; return NL_SKIP; } - - /* - * param->num has the maximum number of entries for which there - * is room in the freq_list provided by the caller. - */ - freqs = nla_data(attr); - max_num = nla_len(attr) / sizeof(u32); - if (max_num > param->num) - max_num = param->num; - for (num = 0; num < max_num; num++) - param->freq_list[num] = freqs[num]; - param->num = num; - return NL_SKIP; } @@ -11321,7 +11389,7 @@ static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) static int nl80211_get_pref_freq_list(void *priv, enum wpa_driver_if_type if_type, unsigned int *num, - unsigned int *freq_list) + struct weighted_pcl *freq_list) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -11378,7 +11446,8 @@ static int nl80211_get_pref_freq_list(void *priv, } nla_nest_end(msg, params); - os_memset(freq_list, 0, *num * sizeof(freq_list[0])); + if (freq_list) + os_memset(freq_list, 0, *num * sizeof(struct weighted_pcl)); ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, ¶m, NULL, NULL); if (ret) { @@ -11390,8 +11459,10 @@ static int nl80211_get_pref_freq_list(void *priv, *num = param.num; for (i = 0; i < *num; i++) { - wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d", - i, freq_list[i]); + wpa_printf(MSG_DEBUG, + "nl80211: preferred_channel_list[%d]=%d[%d]:0x%x", + i, freq_list[i].freq, freq_list[i].weight, + freq_list[i].flag); } return 0; diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 14eacf946..a5e3c15c7 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -5534,7 +5534,7 @@ void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx) void p2p_set_own_pref_freq_list(struct p2p_data *p2p, - const unsigned int *pref_freq_list, + const struct weighted_pcl *pref_freq_list, unsigned int size) { unsigned int i; @@ -5542,10 +5542,11 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p, if (size > P2P_MAX_PREF_CHANNELS) size = P2P_MAX_PREF_CHANNELS; p2p->num_pref_freq = size; + os_memcpy(p2p->pref_freq_list, pref_freq_list, + size * sizeof(struct weighted_pcl)); for (i = 0; i < size; i++) { - p2p->pref_freq_list[i] = pref_freq_list[i]; p2p_dbg(p2p, "Own preferred frequency list[%u]=%u MHz", - i, p2p->pref_freq_list[i]); + i, p2p->pref_freq_list[i].freq); } } diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index f606fbb14..768fc106e 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -12,6 +12,8 @@ #include "common/ieee802_11_defs.h" #include "wps/wps.h" +struct weighted_pcl; + /* P2P ASP Setup Capability */ #define P2PS_SETUP_NONE 0 #define P2PS_SETUP_NEW BIT(0) @@ -1132,7 +1134,8 @@ struct p2p_config { * the driver specific to a particular interface type. */ int (*get_pref_freq_list)(void *ctx, int go, - unsigned int *len, unsigned int *freq_list); + unsigned int *len, + struct weighted_pcl *freq_list); }; @@ -2338,6 +2341,8 @@ struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p, const u8 *go_dev_addr, const u8 *ssid, size_t ssid_len); +bool p2p_pref_freq_allowed(const struct weighted_pcl *freq_list, bool go); + struct p2p_nfc_params { int sel; const u8 *wsc_attr; @@ -2397,7 +2402,7 @@ struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p); void p2p_expire_peers(struct p2p_data *p2p); void p2p_set_own_pref_freq_list(struct p2p_data *p2p, - const unsigned int *pref_freq_list, + const struct weighted_pcl *pref_freq_list, unsigned int size); void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class, u8 chan); @@ -2422,6 +2427,6 @@ 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); +int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size); #endif /* P2P_H */ diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index a484fb0b0..e4f40fe8f 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -112,7 +112,7 @@ void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, void p2p_buf_add_pref_channel_list(struct wpabuf *buf, - const unsigned int *preferred_freq_list, + const struct weighted_pcl *pref_freq_list, unsigned int size) { unsigned int i, count = 0; @@ -127,8 +127,9 @@ void p2p_buf_add_pref_channel_list(struct wpabuf *buf, * of the vendor IE size. */ for (i = 0; i < size; i++) { - if (p2p_freq_to_channel(preferred_freq_list[i], &op_class, - &op_channel) == 0) + if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class, + &op_channel) == 0 && + !(pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE)) count++; } @@ -137,10 +138,11 @@ void p2p_buf_add_pref_channel_list(struct wpabuf *buf, wpabuf_put_be24(buf, OUI_QCA); wpabuf_put_u8(buf, QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST); for (i = 0; i < size; i++) { - if (p2p_freq_to_channel(preferred_freq_list[i], &op_class, - &op_channel) < 0) { + if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class, + &op_channel) < 0 || + (pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE)) { wpa_printf(MSG_DEBUG, "Unsupported frequency %u MHz", - preferred_freq_list[i]); + pref_freq_list[i].freq); continue; } wpabuf_put_u8(buf, op_class); diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 303aa7dd2..e3d704b8e 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -182,8 +182,20 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, p2p_buf_add_intended_addr(buf, p2p->intended_addr); is_6ghz_capab = is_p2p_6ghz_capable(p2p) && p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels, - is_6ghz_capab); + if (p2p->num_pref_freq) { + bool go = p2p->go_intent == 15; + struct p2p_channels pref_chanlist; + + p2p_pref_channel_filter(&p2p->channels, p2p->pref_freq_list, + p2p->num_pref_freq, &pref_chanlist, go); + p2p_channels_dump(p2p, "channel list after filtering", + &pref_chanlist); + p2p_buf_add_channel_list(buf, p2p->cfg->country, + &pref_chanlist, is_6ghz_capab); + } else { + p2p_buf_add_channel_list(buf, p2p->cfg->country, + &p2p->channels, is_6ghz_capab); + } p2p_buf_add_device_info(buf, p2p, peer); p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); @@ -283,6 +295,7 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, size_t extra = 0; u16 pw_id; bool is_6ghz_capab; + struct p2p_channels pref_chanlist; p2p_dbg(p2p, "Building GO Negotiation Response"); @@ -333,20 +346,32 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, p2p->op_channel); } p2p_buf_add_intended_addr(buf, p2p->intended_addr); + if (p2p->num_pref_freq) { + bool go = (peer && peer->go_state == LOCAL_GO) || + p2p->go_intent == 15; + + p2p_pref_channel_filter(&p2p->channels, p2p->pref_freq_list, + p2p->num_pref_freq, &pref_chanlist, go); + p2p_channels_dump(p2p, "channel list after filtering", + &pref_chanlist); + } else { + p2p_copy_channels(&pref_chanlist, &p2p->channels, + p2p->allow_6ghz); + } if (status || peer == NULL) { p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->channels, false); + &pref_chanlist, false); } else if (peer->go_state == REMOTE_GO) { is_6ghz_capab = is_p2p_6ghz_capable(p2p) && p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->channels, is_6ghz_capab); + &pref_chanlist, is_6ghz_capab); } else { struct p2p_channels res; is_6ghz_capab = is_p2p_6ghz_capable(p2p) && p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); - p2p_channels_intersect(&p2p->channels, &peer->channels, + p2p_channels_intersect(&pref_chanlist, &peer->channels, &res); p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, is_6ghz_capab); @@ -573,7 +598,8 @@ int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go, struct p2p_device *dev, struct p2p_message *msg, - unsigned freq_list[], unsigned int size) + const struct weighted_pcl freq_list[], + unsigned int size) { u8 op_class, op_channel; unsigned int oper_freq = 0, i, j; @@ -588,10 +614,11 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go, */ for (i = 0; i < size && !found; i++) { /* Make sure that the common frequency is supported by peer. */ - oper_freq = freq_list[i]; + oper_freq = freq_list[i].freq; if (p2p_freq_to_channel(oper_freq, &op_class, - &op_channel) < 0) - continue; /* cannot happen due to earlier check */ + &op_channel) < 0 || + !p2p_pref_freq_allowed(&freq_list[i], go)) + continue; for (j = 0; j < msg->channel_list_len; j++) { if (!msg->channel_list || op_channel != msg->channel_list[j]) @@ -620,7 +647,8 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go, static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go, struct p2p_device *dev, struct p2p_message *msg, - unsigned freq_list[], unsigned int size) + const struct weighted_pcl freq_list[], + unsigned int size) { u8 op_class, op_channel; unsigned int oper_freq = 0, i, j; @@ -636,11 +664,13 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go, oper_freq = p2p_channel_to_freq( msg->pref_freq_list[2 * j], msg->pref_freq_list[2 * j + 1]); - if (freq_list[i] != oper_freq) + if (freq_list[i].freq != oper_freq) continue; if (p2p_freq_to_channel(oper_freq, &op_class, &op_channel) < 0) continue; /* cannot happen */ + if (!p2p_pref_freq_allowed(&freq_list[i], go)) + break; p2p->op_reg_class = op_class; p2p->op_channel = op_channel; os_memcpy(&p2p->channels, &p2p->cfg->channels, @@ -663,7 +693,7 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go, void p2p_check_pref_chan(struct p2p_data *p2p, int go, struct p2p_device *dev, struct p2p_message *msg) { - unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size; + unsigned int size; unsigned int i; u8 op_class, op_channel; char txt[100], *pos, *end; @@ -680,25 +710,30 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, /* Obtain our preferred frequency list from driver based on P2P role. */ size = P2P_MAX_PREF_CHANNELS; - if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size, - freq_list)) + if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, + &p2p->num_pref_freq, + p2p->pref_freq_list)) + return; + size = p2p->num_pref_freq; + if (!size) return; /* Filter out frequencies that are not acceptable for P2P use */ i = 0; while (i < size) { - if (p2p_freq_to_channel(freq_list[i], &op_class, - &op_channel) < 0 || + if (p2p_freq_to_channel(p2p->pref_freq_list[i].freq, + &op_class, &op_channel) < 0 || (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) && (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class, op_channel)))) { p2p_dbg(p2p, "Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)", - freq_list[i], go); + p2p->pref_freq_list[i].freq, go); if (size - i - 1 > 0) - os_memmove(&freq_list[i], &freq_list[i + 1], + os_memmove(&p2p->pref_freq_list[i], + &p2p->pref_freq_list[i + 1], (size - i - 1) * - sizeof(unsigned int)); + sizeof(struct weighted_pcl)); size--; continue; } @@ -710,7 +745,8 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, pos = txt; end = pos + sizeof(txt); for (i = 0; i < size; i++) { - res = os_snprintf(pos, end - pos, " %u", freq_list[i]); + res = os_snprintf(pos, end - pos, " %u", + p2p->pref_freq_list[i].freq); if (os_snprintf_error(end - pos, res)) break; pos += res; @@ -724,11 +760,14 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, * our preferred channel list. */ for (i = 0; i < size; i++) { - if (freq_list[i] == (unsigned int) dev->oper_freq) + if (p2p->pref_freq_list[i].freq == + (unsigned int) dev->oper_freq && + p2p_pref_freq_allowed(&p2p->pref_freq_list[i], go)) break; } if (i != size && - p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) { + p2p_freq_to_channel(p2p->pref_freq_list[i].freq, &op_class, + &op_channel) == 0) { /* Peer operating channel preference matches our preference */ p2p->op_reg_class = op_class; p2p->op_channel = op_channel; @@ -746,9 +785,11 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, * _not_ included in the GO Negotiation Request or Invitation Request. */ if (msg->pref_freq_list_len == 0) - p2p_check_pref_chan_no_recv(p2p, go, dev, msg, freq_list, size); + p2p_check_pref_chan_no_recv(p2p, go, dev, msg, + p2p->pref_freq_list, size); else - p2p_check_pref_chan_recv(p2p, go, dev, msg, freq_list, size); + p2p_check_pref_chan_recv(p2p, go, dev, msg, + p2p->pref_freq_list, size); } diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 59790de9c..6573783fa 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -10,6 +10,7 @@ #define P2P_I_H #include "utils/list.h" +#include "drivers/driver.h" #include "p2p.h" #define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1 @@ -542,7 +543,7 @@ struct p2p_data { struct wpabuf **vendor_elem; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS]; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; unsigned int num_pref_freq; /* Override option for preferred operating channel in GO Negotiation */ @@ -789,7 +790,7 @@ void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr, int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, int all_attr); void p2p_buf_add_pref_channel_list(struct wpabuf *buf, - const unsigned int *preferred_freq_list, + const struct weighted_pcl *pref_freq_list, unsigned int size); /* p2p_sd.c */ @@ -891,6 +892,10 @@ int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx); int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, u8 *status); +void p2p_pref_channel_filter(const struct p2p_channels *a, + const struct weighted_pcl *freq_list, + unsigned int num_channels, + struct p2p_channels *res, bool go); void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...) PRINTF_FORMAT(2, 3); void p2p_info(struct p2p_data *p2p, const char *fmt, ...) diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index a20360633..c1f0084b8 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -519,14 +519,14 @@ void p2p_copy_channels(struct p2p_channels *dst, } -int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size) +int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size) { int i; for (i = 0; i < size; i++) { - if (is_6ghz_freq(pref_freq_list[i])) { + if (is_6ghz_freq(pref_freq_list[i].freq)) { wpa_printf(MSG_DEBUG, "P2P: Remove 6 GHz channel %d", - pref_freq_list[i]); + pref_freq_list[i].freq); size--; os_memmove(&pref_freq_list[i], &pref_freq_list[i + 1], (size - i) * sizeof(pref_freq_list[0])); @@ -535,3 +535,79 @@ int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size) } return i; } + + +/** + * p2p_pref_freq_allowed - Based on the flags set, check if the preferred + * frequency is allowed + * @freq_list: Weighted preferred channel list + * @go: Whether the local device is the group owner + * Returns: Whether the preferred frequency is allowed + */ +bool p2p_pref_freq_allowed(const struct weighted_pcl *freq_list, bool go) +{ + if (freq_list->flag & WEIGHTED_PCL_EXCLUDE) + return false; + if (!(freq_list->flag & WEIGHTED_PCL_CLI) && !go) + return false; + if (!(freq_list->flag & WEIGHTED_PCL_GO) && go) + return false; + return true; +} + + +static int p2p_check_pref_channel(int channel, u8 op_class, + const struct weighted_pcl *freq_list, + unsigned int num_channels, bool go) +{ + unsigned int i; + + /* If the channel is present in the preferred channel list, check if it + * has appropriate flags for the role. + */ + for (i = 0; i < num_channels; i++) { + if (p2p_channel_to_freq(op_class, channel) != + (int) freq_list[i].freq) + continue; + if (!p2p_pref_freq_allowed(&freq_list[i], go)) + return -1; + break; + } + + return 0; +} + + +void p2p_pref_channel_filter(const struct p2p_channels *p2p_chan, + const struct weighted_pcl *freq_list, + unsigned int num_channels, + struct p2p_channels *res, bool go) +{ + size_t i, j; + + os_memset(res, 0, sizeof(*res)); + + for (i = 0; i < p2p_chan->reg_classes; i++) { + const struct p2p_reg_class *reg = &p2p_chan->reg_class[i]; + struct p2p_reg_class *res_reg = &res->reg_class[i]; + + if (num_channels > 0) { + for (j = 0; j < reg->channels; j++) { + if (p2p_check_pref_channel(reg->channel[j], + reg->reg_class, + freq_list, + num_channels, + go) < 0) + continue; + + res_reg->channel[res_reg->channels++] = + reg->channel[j]; + } + } + + if (res_reg->channels == 0) + continue; + res->reg_classes++; + res_reg->reg_class = reg->reg_class; + } +} diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 606c79bc2..499e6d3dd 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -8123,7 +8123,7 @@ static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s, int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type if_type, unsigned int *num, - unsigned int *freq_list) + struct weighted_pcl *freq_list) { char *pos = wpa_s->get_pref_freq_list_override; char *end; @@ -8147,7 +8147,8 @@ int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, pos++; end = os_strchr(pos, ' '); while (pos && (!end || pos < end) && count < *num) { - freq_list[count++] = atoi(pos); + freq_list[count].freq = atoi(pos); + freq_list[count++].flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI; pos = os_strchr(pos, ','); if (pos) pos++; @@ -8162,10 +8163,11 @@ int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, static int wpas_ctrl_iface_get_pref_freq_list( struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { - unsigned int freq_list[100], num = 100, i; + unsigned int num = 100, i; int ret; enum wpa_driver_if_type iface_type; char *pos, *end; + struct weighted_pcl freq_list[100]; pos = buf; end = buf + buflen; @@ -8196,7 +8198,7 @@ static int wpas_ctrl_iface_get_pref_freq_list( for (i = 0; i < num; i++) { ret = os_snprintf(pos, end - pos, "%s%u", - i > 0 ? "," : "", freq_list[i]); + i > 0 ? "," : "", freq_list[i].freq); if (os_snprintf_error(end - pos, ret)) return -1; pos += ret; diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 237f4e085..b0af1cd98 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -964,7 +964,7 @@ static inline int wpa_drv_setband(struct wpa_supplicant *wpa_s, static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type if_type, unsigned int *num, - unsigned int *freq_list) + struct weighted_pcl *freq_list) { #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->get_pref_freq_list_override) diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index a996b436b..6a23dd998 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -126,7 +126,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, int *force_freq, int *pref_freq, int go, - unsigned int *pref_freq_list, + struct weighted_pcl *pref_freq_list, unsigned int *num_pref_freq); static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); @@ -702,7 +702,8 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role, struct wpa_supplicant *go_wpa_s, *cli_wpa_s; struct wpa_ssid *persistent_go; int p2p_no_group_iface; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int size; wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role); @@ -4701,7 +4702,7 @@ static int wpas_prov_disc_resp_cb(void *ctx) static int wpas_p2p_get_pref_freq_list(void *ctx, int go, unsigned int *len, - unsigned int *freq_list) + struct weighted_pcl *freq_list) { struct wpa_supplicant *wpa_s = ctx; @@ -5679,7 +5680,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, int *force_freq, int *pref_freq, int go, - unsigned int *pref_freq_list, + struct weighted_pcl *pref_freq_list, unsigned int *num_pref_freq) { struct wpa_used_freq_data *freqs; @@ -5776,16 +5777,19 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, i = 0; while (i < *num_pref_freq && (!p2p_supported_freq(wpa_s->global->p2p, - pref_freq_list[i]) || - wpas_p2p_disallowed_freq(wpa_s->global, - pref_freq_list[i]))) { + pref_freq_list[i].freq) || + wpas_p2p_disallowed_freq( + wpa_s->global, + pref_freq_list[i].freq) || + !p2p_pref_freq_allowed(&pref_freq_list[i], + go))) { wpa_printf(MSG_DEBUG, "P2P: preferred_freq_list[%d]=%d is disallowed", - i, pref_freq_list[i]); + i, pref_freq_list[i].freq); i++; } if (i != *num_pref_freq) { - best_freq = pref_freq_list[i]; + best_freq = pref_freq_list[i].freq; wpa_printf(MSG_DEBUG, "P2P: Using preferred_freq_list[%d]=%d", i, best_freq); @@ -5907,7 +5911,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, enum wpa_driver_if_type iftype; const u8 *if_addr; struct wpa_ssid *ssid = NULL; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int size; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -6192,7 +6197,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) if (!wpa_s->conf->num_p2p_pref_chan && !freq) { unsigned int i, size = P2P_MAX_PREF_CHANNELS; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS]; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; int res; res = wpa_drv_get_pref_freq_list(wpa_s, WPA_IF_P2P_GO, @@ -6204,16 +6209,19 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) i = 0; while (i < size && (!p2p_supported_freq(wpa_s->global->p2p, - pref_freq_list[i]) || - wpas_p2p_disallowed_freq(wpa_s->global, - pref_freq_list[i]))) { + pref_freq_list[i].freq) || + wpas_p2p_disallowed_freq( + wpa_s->global, + pref_freq_list[i].freq) || + !p2p_pref_freq_allowed(&pref_freq_list[i], + true))) { wpa_printf(MSG_DEBUG, "P2P: preferred_freq_list[%d]=%d is disallowed", - i, pref_freq_list[i]); + i, pref_freq_list[i].freq); i++; } if (i != size) { - freq = pref_freq_list[i]; + freq = pref_freq_list[i].freq; wpa_printf(MSG_DEBUG, "P2P: Using preferred_freq_list[%d]=%d", i, freq); @@ -7562,7 +7570,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int force_freq = 0; int res; int no_pref_freq_given = pref_freq == 0; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int size; if (wpas_p2p_check_6ghz(wpa_s, NULL, allow_6ghz, freq)) return -1; @@ -7651,7 +7660,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, int persistent; int freq = 0, force_freq = 0, pref_freq = 0; int res; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int size; wpa_s->p2p_persistent_go_freq = 0; wpa_s->p2p_go_ht40 = 0; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index ec0360e70..301d5d56a 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1854,7 +1854,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type if_type, unsigned int *num, - unsigned int *freq_list); + struct weighted_pcl *freq_list); int wpa_is_fils_supported(struct wpa_supplicant *wpa_s); int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);