aboutsummaryrefslogtreecommitdiffstats
path: root/src/p2p
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2013-10-28 17:59:21 -0700
committerDmitry Shmidt <dimitrysh@google.com>2013-10-29 10:40:54 -0700
commit68d0e3ed07847339aedfac8e02f50db68c702e52 (patch)
tree4a9c95bbf8f9ef933218ea0b674a6fb78c2e59db /src/p2p
parentfc01fd207990a3ea0e0bc2f4d98746e559474c9f (diff)
downloadandroid_external_wpa_supplicant_8-68d0e3ed07847339aedfac8e02f50db68c702e52.tar.gz
android_external_wpa_supplicant_8-68d0e3ed07847339aedfac8e02f50db68c702e52.tar.bz2
android_external_wpa_supplicant_8-68d0e3ed07847339aedfac8e02f50db68c702e52.zip
Cumulative patch from commit 32b62704fac6af74f60b2effb173474e11ff089d
32b6270 Android: Fix ARRAY_SIZE() compilation 7617388 Interworking: Report STATUS:sp_type even if domain is not configured c20bc9d P2P: Remove compiler warning without CONFIG_IEEE80211N ca9bc5b P2P: Add VHT support 20ea1ca P2P: Add VHT parameter to P2P operations 53cfad4 nl80211: Mark VHT 80 MHz channels f2112b2 wpa_supplicant: Add CONFIG_IEEE80211AC 6b02335 hostapd: Mask out not-supported VHT capabilities 7f0303d hostapd: Verify VHT 160/80+80 MHz driver support c781eb8 hostapd: Verify VHT capabilities are supported by driver b29b012 Fix some VHT Capabilities definitions 7066a8e hostapd: Fix wrong VHT configuration capabilities flags 6651f1f nl80211: Use max tx power from regulatory domain 7ac3616 nl80211: Replace perror() and printf() calls with wpa_printf() 4d9fb08 WPS: Clear known_wps_freq in addition to after_wps d20c340 Interworking: Clear known_wps_freq for network selection f3be6ee tests: Allow test case descriptions to be written into database 1bd05d0 Interworking: Force normal scan for network selection 51e9f22 P2P: Add option to allow additional client channels 556b30d P2P: Add option to remove channels from GO use e7ecab4 Use ARRAY_SIZE() macro 39044a7 Introduce ARRAY_SIZE() macro 2e94624 DFS: Handle radar event when CAC actived correctly 5eaf240 DFS: Fix overlapped() function to check only DFS channels 345276a DFS: Adjust center freq correctly for VHT20/VHT40 1dc17db DFS: Fix available channels list for VHT80 34068ac nl80211: Add debug prints on nl_recvmsgs() failure 10b8592 nl80211: Make eloop sockets non-blocking 5f65e9f nl80211: Abstract handling of sockets on eloop e8d1168 nl80211: Register for IBSS auth frames before eloop 03610ad Clean up get_seqnum() use for IPN 29179b8 Stop ctrl_iface monitor send loop on reinit failure a2a535f Remove unnecessary wpa_s->conf checks 3318376 Add explicit buffer length checks for p2p_build_wps_ie() 0f01201 Verify that readlink() did not truncate result f5eb9da nl80211: Clean up if_add() for hostapd use a288da6 OpenSSL: Fix memory leak on error path 6cb4f11 nl80211: Fix strerror() value in P2P Dev debug messages 35f8363 DFS: Add forgotten break statement 2f243b8 Remove os_strncpy() 24f051e Replace remainining strncpy() uses with strlcpy() 41c526f P2P: Fix snprintf buffer length for group ifname backup Change-Id: I2e1506cb9219a5a37efbb2ae0dc180fb081c809f Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src/p2p')
-rw-r--r--src/p2p/p2p.c85
-rw-r--r--src/p2p/p2p.h45
-rw-r--r--src/p2p/p2p_build.c64
-rw-r--r--src/p2p/p2p_go_neg.c40
-rw-r--r--src/p2p/p2p_i.h14
-rw-r--r--src/p2p/p2p_invitation.c3
-rw-r--r--src/p2p/p2p_utils.c126
7 files changed, 335 insertions, 42 deletions
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 64ca006d..723e4002 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1208,19 +1208,21 @@ void p2p_stop_find(struct p2p_data *p2p)
static int p2p_prepare_channel_pref(struct p2p_data *p2p,
unsigned int force_freq,
- unsigned int pref_freq)
+ unsigned int pref_freq, int go)
{
u8 op_class, op_channel;
unsigned int freq = force_freq ? force_freq : pref_freq;
- p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u",
- force_freq, pref_freq);
+ p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d",
+ force_freq, pref_freq, go);
if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
return -1;
}
- if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+ if (!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, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
freq, op_class, op_channel);
return -1;
@@ -1294,6 +1296,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* @dev: Selected peer device
* @force_freq: Forced frequency in MHz or 0 if not forced
* @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * @go: Whether the local end will be forced to be GO
* Returns: 0 on success, -1 on failure (channel not supported for P2P)
*
* This function is used to do initial operating channel selection for GO
@@ -1302,16 +1305,25 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* is available.
*/
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
- unsigned int force_freq, unsigned int pref_freq)
+ unsigned int force_freq, unsigned int pref_freq, int go)
{
- p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u",
- force_freq, pref_freq);
+ p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
+ force_freq, pref_freq, go);
if (force_freq || pref_freq) {
- if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
+ 0)
return -1;
} else {
p2p_prepare_channel_best(p2p);
}
+ p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
+ if (go)
+ p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
+ else if (!force_freq)
+ p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
+ &p2p->channels);
+ p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
+
p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
p2p->op_reg_class, p2p->op_channel,
force_freq ? " (forced)" : "");
@@ -1367,7 +1379,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+ go_intent == 15) < 0)
return -1;
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
@@ -1477,7 +1490,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent ==
+ 15) < 0)
return -1;
p2p->ssid_set = 0;
@@ -1618,8 +1632,15 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
}
}
+ p2p_channels_dump(p2p, "own channels", &p2p->channels);
+ p2p_channels_dump(p2p, "peer channels", &peer->channels);
p2p_channels_intersect(&p2p->channels, &peer->channels,
&intersection);
+ if (go) {
+ p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
+ p2p_channels_dump(p2p, "intersection after no-GO removal",
+ &intersection);
+ }
freqs = 0;
for (i = 0; i < intersection.reg_classes; i++) {
struct p2p_reg_class *c = &intersection.reg_class[i];
@@ -1979,7 +2000,11 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
}
- p2p_build_wps_ie(p2p, buf, pw_id, 1);
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 1) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for Probe Response");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_probe_resp)
@@ -2439,6 +2464,10 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
p2p->go_timeout = 100;
p2p->client_timeout = 20;
+ p2p_dbg(p2p, "initialized");
+ p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+ p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
+
return p2p;
}
@@ -2475,6 +2504,7 @@ void p2p_deinit(struct p2p_data *p2p)
wpabuf_free(p2p->sd_resp);
os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
+ os_free(p2p->no_go_freq.range);
os_free(p2p);
}
@@ -4047,6 +4077,31 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
}
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+ const struct wpa_freq_range_list *list)
+{
+ struct wpa_freq_range *tmp;
+
+ if (list == NULL || list->num == 0) {
+ os_free(p2p->no_go_freq.range);
+ p2p->no_go_freq.range = NULL;
+ p2p->no_go_freq.num = 0;
+ return 0;
+ }
+
+ tmp = os_calloc(list->num, sizeof(struct wpa_freq_range));
+ if (tmp == NULL)
+ return -1;
+ os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range));
+ os_free(p2p->no_go_freq.range);
+ p2p->no_go_freq.range = tmp;
+ p2p->no_go_freq.num = list->num;
+ p2p_dbg(p2p, "Updated no GO chan list");
+
+ return 0;
+}
+
+
int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
u8 *iface_addr)
{
@@ -4109,10 +4164,16 @@ void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
}
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
+void p2p_update_channel_list(struct p2p_data *p2p,
+ const struct p2p_channels *chan,
+ const struct p2p_channels *cli_chan)
{
p2p_dbg(p2p, "Update channel list");
os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
+ p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+ os_memcpy(&p2p->cfg->cli_channels, cli_chan,
+ sizeof(struct p2p_channels));
+ p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 7f845b23..cb3991bf 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -77,6 +77,8 @@ struct p2p_go_neg_results {
int ht40;
+ int vht;
+
/**
* ssid - SSID of the group
*/
@@ -287,6 +289,20 @@ struct p2p_config {
struct p2p_channels channels;
/**
+ * cli_channels - Additional client channels
+ *
+ * This list of channels (if any) will be used when advertising local
+ * channels during GO Negotiation or Invitation for the cases where the
+ * local end may become the client. This may allow the peer to become a
+ * GO on additional channels if it supports these options. The main use
+ * case for this is to include passive-scan channels on devices that may
+ * not know their current location and have configured most channels to
+ * not allow initiation of radition (i.e., another device needs to take
+ * master responsibilities).
+ */
+ struct p2p_channels cli_channels;
+
+ /**
* num_pref_chan - Number of pref_chan entries
*/
unsigned int num_pref_chan;
@@ -1649,6 +1665,22 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels,
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
/**
+ * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
+
+/**
+ * p2p_supported_freq_cli - Check whether channel is supported for P2P client operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq);
+
+/**
* p2p_get_pref_freq - Get channel from preferred channel list
* @p2p: P2P module context from p2p_init()
* @channels: List of channels
@@ -1657,7 +1689,9 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
const struct p2p_channels *channels);
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
+void p2p_update_channel_list(struct p2p_data *p2p,
+ const struct p2p_channels *chan,
+ const struct p2p_channels *cli_chan);
/**
* p2p_set_best_channels - Update best channel information
@@ -1765,6 +1799,15 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
const struct p2p_channel *pref_chan);
/**
+ * p2p_set_no_go_freq - Set no GO channel ranges
+ * @p2p: P2P module context from p2p_init()
+ * @list: Channel ranges or %NULL to remove restriction
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+ const struct wpa_freq_range_list *list);
+
+/**
* p2p_in_progress - Check whether a P2P operation is progress
* @p2p: P2P module context from p2p_init()
* Returns: 0 if P2P module is idle or 1 if an operation is in progress
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 5838d35e..3c819ff4 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -327,13 +327,15 @@ void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p)
}
-static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
- const char *val)
+static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
+ const char *val)
{
size_t len;
- wpabuf_put_be16(buf, attr);
len = val ? os_strlen(val) : 0;
+ if (wpabuf_tailroom(buf) < 4 + len)
+ return -1;
+ wpabuf_put_be16(buf, attr);
#ifndef CONFIG_WPS_STRICT
if (len == 0) {
/*
@@ -341,36 +343,46 @@ static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
* attributes. As a workaround, send a space character if the
* device attribute string is empty.
*/
+ if (wpabuf_tailroom(buf) < 3)
+ return -1;
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, ' ');
- return;
+ return 0;
}
#endif /* CONFIG_WPS_STRICT */
wpabuf_put_be16(buf, len);
if (val)
wpabuf_put_data(buf, val, len);
+ return 0;
}
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
- int all_attr)
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+ int all_attr)
{
u8 *len;
int i;
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
len = wpabuf_put(buf, 1);
wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
- wps_build_version(buf);
+ if (wps_build_version(buf) < 0)
+ return -1;
if (all_attr) {
+ if (wpabuf_tailroom(buf) < 5)
+ return -1;
wpabuf_put_be16(buf, ATTR_WPS_STATE);
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
}
if (pw_id >= 0) {
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
/* Device Password ID */
wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
wpabuf_put_be16(buf, 2);
@@ -380,33 +392,47 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
}
if (all_attr) {
+ if (wpabuf_tailroom(buf) < 5)
+ return -1;
wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
- wps_build_uuid_e(buf, p2p->cfg->uuid);
- p2p_add_wps_string(buf, ATTR_MANUFACTURER,
- p2p->cfg->manufacturer);
- p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name);
- p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
- p2p->cfg->model_number);
- p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
- p2p->cfg->serial_number);
-
+ if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MANUFACTURER,
+ p2p->cfg->manufacturer) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MODEL_NAME,
+ p2p->cfg->model_name) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
+ p2p->cfg->model_number) < 0 ||
+ p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
+ p2p->cfg->serial_number) < 0)
+ return -1;
+
+ if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
+ return -1;
wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
- p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name);
+ if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
+ < 0)
+ return -1;
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
wpabuf_put_be16(buf, 2);
wpabuf_put_be16(buf, p2p->cfg->config_methods);
}
- wps_build_wfa_ext(buf, 0, NULL, 0);
+ if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+ return -1;
if (all_attr && p2p->cfg->num_sec_dev_types) {
+ if (wpabuf_tailroom(buf) <
+ 4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
+ return -1;
wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
p2p->cfg->num_sec_dev_types);
@@ -428,4 +454,6 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
}
p2p_buf_update_ie_hdr(buf, len);
+
+ return 0;
}
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index eea946fa..5faab07c 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -172,7 +172,12 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+ if (p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method),
+ 0) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
@@ -307,9 +312,13 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- p2p_build_wps_ie(p2p, buf,
- p2p_wps_method_pw_id(peer ? peer->wps_method :
- WPS_NOT_READY), 0);
+ if (p2p_build_wps_ie(p2p, buf,
+ p2p_wps_method_pw_id(peer ? peer->wps_method :
+ WPS_NOT_READY), 0) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
@@ -403,6 +412,18 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
}
+ /* Try a channel where we might be able to use VHT */
+ for (i = 0; i < intersection->reg_classes; i++) {
+ struct p2p_reg_class *c = &intersection->reg_class[i];
+ if (c->reg_class == 128) {
+ p2p_dbg(p2p, "Pick possible VHT channel (reg_class %u channel %u) from intersection",
+ c->reg_class, c->channel[0]);
+ p2p->op_reg_class = c->reg_class;
+ p2p->op_channel = c->channel[0];
+ return;
+ }
+ }
+
/* Try a channel where we might be able to use HT40 */
for (i = 0; i < intersection->reg_classes; i++) {
struct p2p_reg_class *c = &intersection->reg_class[i];
@@ -470,12 +491,17 @@ void p2p_reselect_channel(struct p2p_data *p2p,
static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
u8 *status)
{
- struct p2p_channels intersection;
+ struct p2p_channels tmp, intersection;
p2p_channels_dump(p2p, "own channels", &p2p->channels);
p2p_channels_dump(p2p, "peer channels", &dev->channels);
- p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
- p2p_channels_dump(p2p, "intersection", &intersection);
+ p2p_channels_intersect(&p2p->channels, &dev->channels, &tmp);
+ p2p_channels_dump(p2p, "intersection", &tmp);
+ p2p_channels_remove_freqs(&tmp, &p2p->no_go_freq);
+ p2p_channels_dump(p2p, "intersection after no-GO removal", &tmp);
+ p2p_channels_intersect(&tmp, &p2p->cfg->channels, &intersection);
+ p2p_channels_dump(p2p, "intersection with local channel list",
+ &intersection);
if (intersection.reg_classes == 0 ||
intersection.reg_class[0].channels == 0) {
*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index f9b1e686..276dfd07 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -324,6 +324,8 @@ struct p2p_data {
*/
struct p2p_channels channels;
+ struct wpa_freq_range_list no_go_freq;
+
enum p2p_pending_action_state {
P2P_NO_PENDING_ACTION,
P2P_PENDING_GO_NEG_REQUEST,
@@ -578,6 +580,11 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
void p2p_channels_intersect(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res);
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+ const struct wpa_freq_range_list *list);
int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
u8 channel);
void p2p_channels_dump(struct p2p_data *p2p, const char *title,
@@ -644,8 +651,8 @@ void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
u16 interval);
void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
- int all_attr);
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+ int all_attr);
/* p2p_sd.c */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -737,7 +744,8 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
size_t len, unsigned int wait_time);
void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
- unsigned int force_freq, unsigned int pref_freq);
+ unsigned int force_freq, unsigned int pref_freq,
+ int 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_invitation.c b/src/p2p/p2p_invitation.c
index 4e4593e0..203445ba 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -548,7 +548,8 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+ role != P2P_INVITE_ROLE_CLIENT) < 0)
return -1;
if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 8c2d2de2..06ebc606 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -94,6 +94,10 @@ int p2p_channel_to_freq(int op_class, int channel)
if (channel < 149 || channel > 161)
return -1;
return 5000 + 5 * channel;
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ if (channel < 36 || channel > 161)
+ return -1;
+ return 5000 + 5 * channel;
}
return -1;
}
@@ -204,6 +208,105 @@ void p2p_channels_intersect(const struct p2p_channels *a,
}
+static void p2p_op_class_union(struct p2p_reg_class *cl,
+ const struct p2p_reg_class *b_cl)
+{
+ size_t i, j;
+
+ for (i = 0; i < b_cl->channels; i++) {
+ for (j = 0; j < cl->channels; j++) {
+ if (b_cl->channel[i] == cl->channel[j])
+ break;
+ }
+ if (j == cl->channels) {
+ if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
+ return;
+ cl->channel[cl->channels++] = b_cl->channel[i];
+ }
+ }
+}
+
+
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res)
+{
+ size_t i, j;
+
+ if (a != res)
+ os_memcpy(res, a, sizeof(*res));
+
+ for (i = 0; i < res->reg_classes; i++) {
+ struct p2p_reg_class *cl = &res->reg_class[i];
+ for (j = 0; j < b->reg_classes; j++) {
+ const struct p2p_reg_class *b_cl = &b->reg_class[j];
+ if (cl->reg_class != b_cl->reg_class)
+ continue;
+ p2p_op_class_union(cl, b_cl);
+ }
+ }
+
+ for (j = 0; j < b->reg_classes; j++) {
+ const struct p2p_reg_class *b_cl = &b->reg_class[j];
+
+ for (i = 0; i < res->reg_classes; i++) {
+ struct p2p_reg_class *cl = &res->reg_class[i];
+ if (cl->reg_class == b_cl->reg_class)
+ break;
+ }
+
+ if (i == res->reg_classes) {
+ if (res->reg_classes == P2P_MAX_REG_CLASSES)
+ return;
+ os_memcpy(&res->reg_class[res->reg_classes++],
+ b_cl, sizeof(struct p2p_reg_class));
+ }
+ }
+}
+
+
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+ const struct wpa_freq_range_list *list)
+{
+ size_t o, c;
+
+ if (list == NULL)
+ return;
+
+ o = 0;
+ while (o < chan->reg_classes) {
+ struct p2p_reg_class *op = &chan->reg_class[o];
+
+ c = 0;
+ while (c < op->channels) {
+ int freq = p2p_channel_to_freq(op->reg_class,
+ op->channel[c]);
+ if (freq > 0 && freq_range_list_includes(list, freq)) {
+ op->channels--;
+ os_memmove(&op->channel[c],
+ &op->channel[c + 1],
+ op->channels - c);
+ } else
+ c++;
+ }
+
+ if (op->channels == 0) {
+ chan->reg_classes--;
+ os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1],
+ (chan->reg_classes - o) *
+ sizeof(struct p2p_reg_class));
+ } else
+ o++;
+ }
+}
+
+
/**
* p2p_channels_includes - Check whether a channel is included in the list
* @channels: List of supported channels
@@ -284,6 +387,29 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
}
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
+{
+ u8 op_reg_class, op_channel;
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+ return 0;
+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+ op_channel) &&
+ !freq_range_list_includes(&p2p->no_go_freq, freq);
+}
+
+
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
+{
+ u8 op_reg_class, op_channel;
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+ return 0;
+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+ op_channel) ||
+ p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
+ op_channel);
+}
+
+
unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
const struct p2p_channels *channels)
{