Home | History | Annotate | Download | only in p2p
      1 /*
      2  * Wi-Fi Direct - P2P provision discovery
      3  * Copyright (c) 2009-2010, Atheros Communications
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "common/ieee802_11_defs.h"
     19 #include "wps/wps_defs.h"
     20 #include "p2p_i.h"
     21 #include "p2p.h"
     22 
     23 
     24 /*
     25  * Number of retries to attempt for provision discovery requests during IDLE
     26  * state in case the peer is not listening.
     27  */
     28 #define MAX_PROV_DISC_REQ_RETRIES 10
     29 
     30 
     31 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
     32 					    u16 config_methods)
     33 {
     34 	u8 *len;
     35 	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
     36 	len = wpabuf_put(buf, 1);
     37 	wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
     38 
     39 	/* Config Methods */
     40 	wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
     41 	wpabuf_put_be16(buf, 2);
     42 	wpabuf_put_be16(buf, config_methods);
     43 
     44 	p2p_buf_update_ie_hdr(buf, len);
     45 }
     46 
     47 
     48 static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
     49 					       u8 dialog_token,
     50 					       u16 config_methods,
     51 					       struct p2p_device *go)
     52 {
     53 	struct wpabuf *buf;
     54 	u8 *len;
     55 
     56 	buf = wpabuf_alloc(1000);
     57 	if (buf == NULL)
     58 		return NULL;
     59 
     60 	p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
     61 
     62 	len = p2p_buf_add_ie_hdr(buf);
     63 	p2p_buf_add_capability(buf, p2p->dev_capab, 0);
     64 	p2p_buf_add_device_info(buf, p2p, NULL);
     65 	if (go) {
     66 		p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
     67 				     go->oper_ssid, go->oper_ssid_len);
     68 	}
     69 	p2p_buf_update_ie_hdr(buf, len);
     70 
     71 	/* WPS IE with Config Methods attribute */
     72 	p2p_build_wps_ie_config_methods(buf, config_methods);
     73 
     74 	return buf;
     75 }
     76 
     77 
     78 static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
     79 						u8 dialog_token,
     80 						u16 config_methods)
     81 {
     82 	struct wpabuf *buf;
     83 
     84 	buf = wpabuf_alloc(100);
     85 	if (buf == NULL)
     86 		return NULL;
     87 
     88 	p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
     89 
     90 	/* WPS IE with Config Methods attribute */
     91 	p2p_build_wps_ie_config_methods(buf, config_methods);
     92 
     93 	return buf;
     94 }
     95 
     96 
     97 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
     98 			       const u8 *data, size_t len, int rx_freq)
     99 {
    100 	struct p2p_message msg;
    101 	struct p2p_device *dev;
    102 	int freq;
    103 	int reject = 1;
    104 	struct wpabuf *resp;
    105 
    106 	if (p2p_parse(data, len, &msg))
    107 		return;
    108 
    109 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    110 		"P2P: Received Provision Discovery Request from " MACSTR
    111 		" with config methods 0x%x (freq=%d)",
    112 		MAC2STR(sa), msg.wps_config_methods, rx_freq);
    113 
    114 	dev = p2p_get_device(p2p, sa);
    115 	if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
    116 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    117 			"P2P: Provision Discovery Request from "
    118 			"unknown peer " MACSTR, MAC2STR(sa));
    119 		if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
    120 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    121 			        "P2P: Provision Discovery Request add device "
    122 				"failed " MACSTR, MAC2STR(sa));
    123 		}
    124 	}
    125 
    126 	if (!(msg.wps_config_methods &
    127 	      (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
    128 	       WPS_CONFIG_PUSHBUTTON))) {
    129 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported "
    130 			"Config Methods in Provision Discovery Request");
    131 		goto out;
    132 	}
    133 
    134 	if (dev)
    135 		dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
    136 				P2P_DEV_PD_PEER_KEYPAD);
    137 	if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
    138 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
    139 			" requested us to show a PIN on display", MAC2STR(sa));
    140 		if (dev)
    141 			dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
    142 	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
    143 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
    144 			" requested us to write its PIN using keypad",
    145 			MAC2STR(sa));
    146 		if (dev)
    147 			dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
    148 	}
    149 
    150 	reject = 0;
    151 
    152 out:
    153 	resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
    154 					reject ? 0 : msg.wps_config_methods);
    155 	if (resp == NULL) {
    156 		p2p_parse_free(&msg);
    157 		return;
    158 	}
    159 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    160 		"P2P: Sending Provision Discovery Response");
    161 	if (rx_freq > 0)
    162 		freq = rx_freq;
    163 	else
    164 		freq = p2p_channel_to_freq(p2p->cfg->country,
    165 					   p2p->cfg->reg_class,
    166 					   p2p->cfg->channel);
    167 	if (freq < 0) {
    168 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    169 			"P2P: Unknown regulatory class/channel");
    170 		wpabuf_free(resp);
    171 		p2p_parse_free(&msg);
    172 		return;
    173 	}
    174 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
    175 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
    176 			    p2p->cfg->dev_addr,
    177 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
    178 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    179 			"P2P: Failed to send Action frame");
    180 	}
    181 
    182 	wpabuf_free(resp);
    183 
    184 	if (!reject && p2p->cfg->prov_disc_req) {
    185 		const u8 *dev_addr = sa;
    186 		if (msg.p2p_device_addr)
    187 			dev_addr = msg.p2p_device_addr;
    188 		p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
    189 					msg.wps_config_methods,
    190 					dev_addr, msg.pri_dev_type,
    191 					msg.device_name, msg.config_methods,
    192 					msg.capability ? msg.capability[0] : 0,
    193 					msg.capability ? msg.capability[1] :
    194 					0);
    195 
    196 	}
    197 	p2p_parse_free(&msg);
    198 }
    199 
    200 
    201 void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
    202 				const u8 *data, size_t len)
    203 {
    204 	struct p2p_message msg;
    205 	struct p2p_device *dev;
    206 	u16 report_config_methods = 0;
    207 
    208 	if (p2p_parse(data, len, &msg))
    209 		return;
    210 
    211 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    212 		"P2P: Received Provisioning Discovery Response from " MACSTR
    213 		" with config methods 0x%x",
    214 		MAC2STR(sa), msg.wps_config_methods);
    215 
    216 	dev = p2p_get_device(p2p, sa);
    217 	if (dev == NULL || !dev->req_config_methods) {
    218 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    219 			"P2P: Ignore Provisioning Discovery Response from "
    220 			MACSTR " with no pending request", MAC2STR(sa));
    221 		p2p_parse_free(&msg);
    222 		return;
    223 	}
    224 
    225 	if (p2p->pending_action_state == P2P_PENDING_PD) {
    226 		os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
    227 		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
    228 	}
    229 
    230 	if (dev->dialog_token != msg.dialog_token) {
    231 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    232 			"P2P: Ignore Provisioning Discovery Response with "
    233 			"unexpected Dialog Token %u (expected %u)",
    234 			msg.dialog_token, dev->dialog_token);
    235 		p2p_parse_free(&msg);
    236 		return;
    237 	}
    238 
    239 	/*
    240 	 * If the response is from the peer to whom a user initiated request
    241 	 * was sent earlier, we reset that state info here.
    242 	 */
    243 	if (p2p->user_initiated_pd &&
    244 	    os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
    245 		p2p_reset_pending_pd(p2p);
    246 
    247 	if (msg.wps_config_methods != dev->req_config_methods) {
    248 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
    249 			"our Provisioning Discovery Request");
    250 		if (p2p->cfg->prov_disc_fail)
    251 			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
    252 						 P2P_PROV_DISC_REJECTED);
    253 		p2p_parse_free(&msg);
    254 		goto out;
    255 	}
    256 
    257 	report_config_methods = dev->req_config_methods;
    258 	dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
    259 			P2P_DEV_PD_PEER_KEYPAD);
    260 	if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
    261 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
    262 			" accepted to show a PIN on display", MAC2STR(sa));
    263 		dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
    264 	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
    265 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
    266 			" accepted to write our PIN using keypad",
    267 			MAC2STR(sa));
    268 		dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
    269 	}
    270 	p2p_parse_free(&msg);
    271 
    272 out:
    273 	dev->req_config_methods = 0;
    274 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
    275 	if (p2p->cfg->prov_disc_resp)
    276 		p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
    277 					 report_config_methods);
    278 }
    279 
    280 
    281 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
    282 			   int join)
    283 {
    284 	struct wpabuf *req;
    285 	int freq;
    286 #ifdef ANDROID_BRCM_P2P_PATCH
    287 	if(dev->go_state == REMOTE_GO) {
    288 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    289 			"P2P: GO Sending it to oper_freq %d", dev->oper_freq);
    290 		freq= dev->oper_freq;
    291 	}
    292 	else {
    293 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    294 			"P2P: NOT GO oper_freq %d listen_freq %d", dev->oper_freq, dev->listen_freq);
    295 		freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
    296 	}
    297 #else
    298 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
    299 #endif
    300 
    301 	if (freq <= 0) {
    302 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    303 			"P2P: No Listen/Operating frequency known for the "
    304 			"peer " MACSTR " to send Provision Discovery Request",
    305 			MAC2STR(dev->info.p2p_device_addr));
    306 		return -1;
    307 	}
    308 
    309 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
    310 		if (!(dev->info.dev_capab &
    311 		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
    312 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    313 				"P2P: Cannot use PD with P2P Device " MACSTR
    314 				" that is in a group and is not discoverable",
    315 				MAC2STR(dev->info.p2p_device_addr));
    316 			return -1;
    317 		}
    318 		/* TODO: use device discoverability request through GO */
    319 	}
    320 
    321 	dev->dialog_token++;
    322 	if (dev->dialog_token == 0)
    323 		dev->dialog_token = 1;
    324 	req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
    325 				      dev->req_config_methods,
    326 				      join ? dev : NULL);
    327 	if (req == NULL)
    328 		return -1;
    329 
    330 	p2p->pending_action_state = P2P_PENDING_PD;
    331 	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
    332 			    p2p->cfg->dev_addr, dev->info.p2p_device_addr,
    333 			    wpabuf_head(req), wpabuf_len(req), 200) < 0) {
    334 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    335 			"P2P: Failed to send Action frame");
    336 		wpabuf_free(req);
    337 		return -1;
    338 	}
    339 
    340 	os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
    341 
    342 	wpabuf_free(req);
    343 	return 0;
    344 }
    345 
    346 
    347 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
    348 		      u16 config_methods, int join)
    349 {
    350 	struct p2p_device *dev;
    351 
    352 	dev = p2p_get_device(p2p, peer_addr);
    353 	if (dev == NULL)
    354 		dev = p2p_get_device_interface(p2p, peer_addr);
    355 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
    356 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision "
    357 			"Discovery Request destination " MACSTR
    358 			" not yet known", MAC2STR(peer_addr));
    359 		return -1;
    360 	}
    361 
    362 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery "
    363 		"Request with " MACSTR " (config methods 0x%x)",
    364 		MAC2STR(peer_addr), config_methods);
    365 	if (config_methods == 0)
    366 		return -1;
    367 
    368 	dev->req_config_methods = config_methods;
    369 	if (join)
    370 		dev->flags |= P2P_DEV_PD_FOR_JOIN;
    371 	else
    372 		dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
    373 
    374 	if (p2p->go_neg_peer ||
    375 	    (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
    376 	     p2p->state != P2P_LISTEN_ONLY)) {
    377 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
    378 			"operations; postpone Provision Discovery Request "
    379 			"with " MACSTR " (config methods 0x%x)",
    380 			MAC2STR(peer_addr), config_methods);
    381 		return 0;
    382 	}
    383 
    384 	/*
    385 	 * We use the join param as a cue to differentiate between user
    386 	 * initiated PD request and one issued during finds (internal).
    387 	 */
    388 	p2p->user_initiated_pd = !join;
    389 
    390 	/* Also set some retries to attempt in case of IDLE state */
    391 	if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
    392 		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
    393 
    394 	return p2p_send_prov_disc_req(p2p, dev, join);
    395 }
    396 
    397 
    398 void p2p_reset_pending_pd(struct p2p_data *p2p)
    399 {
    400 	p2p->user_initiated_pd = 0;
    401 	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
    402 	p2p->pd_retries = 0;
    403 }
    404