diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2013-10-28 17:59:21 -0700 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2013-10-29 10:40:54 -0700 |
commit | 68d0e3ed07847339aedfac8e02f50db68c702e52 (patch) | |
tree | 4a9c95bbf8f9ef933218ea0b674a6fb78c2e59db /src/p2p | |
parent | fc01fd207990a3ea0e0bc2f4d98746e559474c9f (diff) | |
download | android_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.c | 85 | ||||
-rw-r--r-- | src/p2p/p2p.h | 45 | ||||
-rw-r--r-- | src/p2p/p2p_build.c | 64 | ||||
-rw-r--r-- | src/p2p/p2p_go_neg.c | 40 | ||||
-rw-r--r-- | src/p2p/p2p_i.h | 14 | ||||
-rw-r--r-- | src/p2p/p2p_invitation.c | 3 | ||||
-rw-r--r-- | src/p2p/p2p_utils.c | 126 |
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) { |