diff options
author | Andrew Shadura <andrewsh@debian.org> | 2016-07-20 19:07:58 +0200 |
---|---|---|
committer | Andrew Shadura <andrewsh@debian.org> | 2016-07-20 19:07:58 +0200 |
commit | 379fee4d2cb49ebda46d4546dc697dee4a9d9352 (patch) | |
tree | 1cc5c21d2a82caaa0ad0c3f88870479ddccbf67e /src/p2p | |
parent | 4442ea526434508f455e85290eabc0cc4523b5dd (diff) |
Imported Upstream version 1.0~rc3
Diffstat (limited to 'src/p2p')
-rw-r--r-- | src/p2p/p2p.c | 122 | ||||
-rw-r--r-- | src/p2p/p2p.h | 59 | ||||
-rw-r--r-- | src/p2p/p2p_go_neg.c | 16 | ||||
-rw-r--r-- | src/p2p/p2p_i.h | 11 | ||||
-rw-r--r-- | src/p2p/p2p_invitation.c | 2 | ||||
-rw-r--r-- | src/p2p/p2p_pd.c | 14 |
6 files changed, 212 insertions, 12 deletions
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index caff7d7..3bcbea6 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -142,6 +142,34 @@ static const char * p2p_state_txt(int state) } +u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr) +{ + struct p2p_device *dev = NULL; + + if (!addr || !p2p) + return 0; + + dev = p2p_get_device(p2p, addr); + if (dev) + return dev->wps_prov_info; + else + return 0; +} + + +void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr) +{ + struct p2p_device *dev = NULL; + + if (!addr || !p2p) + return; + + dev = p2p_get_device(p2p, addr); + if (dev) + dev->wps_prov_info = 0; +} + + void p2p_set_state(struct p2p_data *p2p, int new_state) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s", @@ -796,7 +824,7 @@ static void p2p_search(struct p2p_data *p2p) if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, p2p->num_req_dev_types, p2p->req_dev_types, - p2p->find_dev_id) < 0) { + p2p->find_dev_id)) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scan request failed"); p2p_continue_find(p2p); @@ -1002,11 +1030,21 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) p2p->go_neg_peer = NULL; p2p->sd_peer = NULL; p2p->invite_peer = NULL; + p2p_stop_listen_for_freq(p2p, freq); +} + + +void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq) +{ if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen " "since we are on correct channel for response"); return; } + if (p2p->in_listen) { + p2p->in_listen = 0; + p2p_clear_timeout(p2p); + } if (p2p->drv_in_listen) { /* * The driver may not deliver callback to p2p_listen_end() @@ -2068,6 +2106,35 @@ int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end) } +int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr) +{ + struct wpabuf *p2p_ie; + struct p2p_message msg; + int ret = -1; + + p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, + P2P_IE_VENDOR_TYPE); + if (p2p_ie == NULL) + return -1; + os_memset(&msg, 0, sizeof(msg)); + if (p2p_parse_p2p_ie(p2p_ie, &msg)) { + wpabuf_free(p2p_ie); + return -1; + } + + if (msg.p2p_device_addr) { + os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN); + ret = 0; + } else if (msg.device_id) { + os_memcpy(dev_addr, msg.device_id, ETH_ALEN); + ret = 0; + } + + wpabuf_free(p2p_ie); + return ret; +} + + static void p2p_clear_go_neg(struct p2p_data *p2p) { p2p->go_neg_peer = NULL; @@ -2142,6 +2209,16 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) p2p->cfg->model_number = os_strdup(cfg->model_number); if (cfg->serial_number) p2p->cfg->serial_number = os_strdup(cfg->serial_number); + if (cfg->pref_chan) { + p2p->cfg->pref_chan = os_malloc(cfg->num_pref_chan * + sizeof(struct p2p_channel)); + if (p2p->cfg->pref_chan) { + os_memcpy(p2p->cfg->pref_chan, cfg->pref_chan, + cfg->num_pref_chan * + sizeof(struct p2p_channel)); + } else + p2p->cfg->num_pref_chan = 0; + } p2p->min_disc_int = 1; p2p->max_disc_int = 3; @@ -2176,6 +2253,7 @@ void p2p_deinit(struct p2p_data *p2p) os_free(p2p->cfg->model_name); os_free(p2p->cfg->model_number); os_free(p2p->cfg->serial_number); + os_free(p2p->cfg->pref_chan); os_free(p2p->groups); wpabuf_free(p2p->sd_resp); os_free(p2p->after_scan_tx); @@ -2187,11 +2265,7 @@ void p2p_deinit(struct p2p_data *p2p) void p2p_flush(struct p2p_data *p2p) { struct p2p_device *dev, *prev; - p2p_clear_timeout(p2p); - p2p_set_state(p2p, P2P_IDLE); - p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; - p2p->go_neg_peer = NULL; - eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); + p2p_stop_find(p2p); dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device, list) { dl_list_del(&dev->list); @@ -2797,6 +2871,20 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq) p2p_connect_send(p2p, p2p->go_neg_peer); return 1; } else if (p2p->state == P2P_SEARCH) { + if (p2p->p2p_scan_running) { + /* + * Search is already in progress. This can happen if + * an Action frame RX is reported immediately after + * the end of a remain-on-channel operation and the + * response frame to that is sent using an offchannel + * operation while in p2p_find. Avoid an attempt to + * restart a scan here. + */ + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan " + "already in progress - do not try to start a " + "new one"); + return 1; + } p2p_search(p2p); return 1; } @@ -3621,6 +3709,28 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel, } +int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan, + const struct p2p_channel *pref_chan) +{ + struct p2p_channel *n; + + if (pref_chan) { + n = os_malloc(num_pref_chan * sizeof(struct p2p_channel)); + if (n == NULL) + return -1; + os_memcpy(n, pref_chan, + num_pref_chan * sizeof(struct p2p_channel)); + } else + n = NULL; + + os_free(p2p->cfg->pref_chan); + p2p->cfg->pref_chan = n; + p2p->cfg->num_pref_chan = num_pref_chan; + + return 0; +} + + int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, u8 *iface_addr) { diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index ace69c3..75d4739 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -224,6 +224,11 @@ enum p2p_prov_disc_status { P2P_PROV_DISC_REJECTED, }; +struct p2p_channel { + u8 op_class; + u8 chan; +}; + /** * struct p2p_config - P2P configuration * @@ -271,6 +276,16 @@ struct p2p_config { struct p2p_channels channels; /** + * num_pref_chan - Number of pref_chan entries + */ + unsigned int num_pref_chan; + + /** + * pref_chan - Preferred channels for GO Negotiation + */ + struct p2p_channel *pref_chan; + + /** * pri_dev_type - Primary Device Type (see WPS) */ u8 pri_dev_type[8]; @@ -1051,6 +1066,28 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr); */ void p2p_group_formation_failed(struct p2p_data *p2p); +/** + * p2p_get_provisioning_info - Get any stored provisioning info + * @p2p: P2P module context from p2p_init() + * @addr: Peer P2P Device Address + * Returns: WPS provisioning information (WPS config method) or 0 if no + * information is available + * + * This function is used to retrieve stored WPS provisioning info for the given + * peer. + */ +u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr); + +/** + * p2p_clear_provisioning_info - Clear any stored provisioning info + * @p2p: P2P module context from p2p_init() + * @iface_addr: Peer P2P Device Address + * + * This function is used to clear stored WPS provisioning info for the given + * peer. + */ +void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr); + /* Event notifications from lower layer driver operations */ @@ -1355,6 +1392,15 @@ int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end); int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end); /** + * p2p_parse_dev_addr - Parse P2P Device Address from P2P IE(s) + * @ies: Information elements from scan results + * @ies_len: ies buffer length in octets + * @dev_addr: Buffer for returning P2P Device Address + * Returns: 0 on success or -1 if P2P Device Address could not be parsed + */ +int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr); + +/** * p2p_assoc_req_ie - Build P2P IE for (Re)Association Request frame * @p2p: P2P module context from p2p_init() * @bssid: BSSID @@ -1481,9 +1527,6 @@ void p2p_set_cross_connect(struct p2p_data *p2p, int enabled); int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr); -int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, - const u8 *ies, size_t ies_len); - /** * p2p_set_intra_bss_dist - Set intra BSS distribution * @p2p: P2P module context from p2p_init() @@ -1586,6 +1629,16 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel, int cfg_op_channel); /** + * p2p_set_pref_chan - Set P2P preferred channel list + * @p2p: P2P module context from p2p_init() + * @num_pref_chan: Number of entries in pref_chan list + * @pref_chan: Preferred channels or %NULL to remove preferences + * Returns: 0 on success, -1 on failure + */ +int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan, + const struct p2p_channel *pref_chan); + +/** * 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_go_neg.c b/src/p2p/p2p_go_neg.c index eb85f51..f83d3de 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -302,6 +302,7 @@ static void p2p_reselect_channel(struct p2p_data *p2p, struct p2p_reg_class *cl; int freq; u8 op_reg_class, op_channel; + unsigned int i; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating " "channel (reg_class %u channel %u) not acceptable to the " @@ -334,6 +335,21 @@ static void p2p_reselect_channel(struct p2p_data *p2p, return; } + /* Select channel with highest preference if the peer supports it */ + for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) { + if (p2p_channels_includes(intersection, + p2p->cfg->pref_chan[i].op_class, + p2p->cfg->pref_chan[i].chan)) { + p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class; + p2p->op_channel = p2p->cfg->pref_chan[i].chan; + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick " + "highest preferred chnnel (op_class %u " + "channel %u) from intersection", + p2p->op_reg_class, p2p->op_channel); + return; + } + } + /* * Fall back to whatever is included in the channel intersection since * no better options seems to be available. diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 82df24e..d052a03 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -71,6 +71,14 @@ struct p2p_device { */ u16 req_config_methods; + /** + * wps_prov_info - Stored provisioning WPS config method + * + * This is used to store pending WPS config method between Provisioning + * Discovery and connection to a running group. + */ + u16 wps_prov_info; + #define P2P_DEV_PROBE_REQ_ONLY BIT(0) #define P2P_DEV_REPORTED BIT(1) #define P2P_DEV_NOT_YET_READY BIT(2) @@ -649,6 +657,8 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, struct p2p_message *msg); void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, struct p2p_device *dev, struct p2p_message *msg); +int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, + const u8 *ies, size_t ies_len); struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr); struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p, const u8 *addr); @@ -663,5 +673,6 @@ void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len); int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time); +void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq); #endif /* P2P_I_H */ diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index bb2767d..016c572 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -350,6 +350,8 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, req = p2p_build_invitation_req(p2p, dev, go_dev_addr); if (req == NULL) return -1; + if (p2p->state != P2P_IDLE) + p2p_stop_listen_for_freq(p2p, freq); wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Sending Invitation Request"); p2p_set_state(p2p, P2P_INVITE); diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index 0f06cbd..8eced26 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -267,6 +267,10 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_KEYPAD; } + + /* Store the provisioning info */ + dev->wps_prov_info = msg.wps_config_methods; + p2p_parse_free(&msg); out: @@ -318,6 +322,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, if (req == NULL) return -1; + if (p2p->state != P2P_IDLE) + p2p_stop_listen_for_freq(p2p, freq); p2p->pending_action_state = P2P_PENDING_PD; if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, p2p->cfg->dev_addr, dev->info.p2p_device_addr, @@ -356,15 +362,17 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, if (config_methods == 0) return -1; + /* Reset provisioning info */ + dev->wps_prov_info = 0; + dev->req_config_methods = config_methods; if (join) dev->flags |= P2P_DEV_PD_FOR_JOIN; else dev->flags &= ~P2P_DEV_PD_FOR_JOIN; - if (p2p->go_neg_peer || - (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH && - p2p->state != P2P_LISTEN_ONLY)) { + if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH && + p2p->state != P2P_LISTEN_ONLY) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other " "operations; postpone Provision Discovery Request " "with " MACSTR " (config methods 0x%x)", |