Home | History | Annotate | Download | only in p2p
      1 /*
      2  * Wi-Fi Direct - P2P Device Discoverability procedure
      3  * Copyright (c) 2010, Atheros Communications
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "common/ieee802_11_defs.h"
     13 #include "p2p_i.h"
     14 #include "p2p.h"
     15 
     16 
     17 static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p,
     18 					      struct p2p_device *go,
     19 					      const u8 *dev_id)
     20 {
     21 	struct wpabuf *buf;
     22 	u8 *len;
     23 
     24 	buf = wpabuf_alloc(100);
     25 	if (buf == NULL)
     26 		return NULL;
     27 
     28 	go->dialog_token++;
     29 	if (go->dialog_token == 0)
     30 		go->dialog_token = 1;
     31 	p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_REQ, go->dialog_token);
     32 
     33 	len = p2p_buf_add_ie_hdr(buf);
     34 	p2p_buf_add_device_id(buf, dev_id);
     35 	p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid,
     36 			     go->oper_ssid_len);
     37 	p2p_buf_update_ie_hdr(buf, len);
     38 
     39 	return buf;
     40 }
     41 
     42 
     43 void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
     44 {
     45 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
     46 		"P2P: Device Discoverability Request TX callback: success=%d",
     47 		success);
     48 
     49 	if (!success) {
     50 		/*
     51 		 * Use P2P find, if needed, to find the other device or to
     52 		 * retry device discoverability.
     53 		 */
     54 		p2p_set_state(p2p, P2P_CONNECT);
     55 		p2p_set_timeout(p2p, 0, 100000);
     56 		return;
     57 	}
     58 
     59 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
     60 		"P2P: GO acknowledged Device Discoverability Request - wait "
     61 		"for response");
     62 	/*
     63 	 * TODO: is the remain-on-channel from Action frame TX long enough for
     64 	 * most cases or should we try to increase its duration and/or start
     65 	 * another remain-on-channel if needed once the previous one expires?
     66 	 */
     67 }
     68 
     69 
     70 int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
     71 {
     72 	struct p2p_device *go;
     73 	struct wpabuf *req;
     74 
     75 	go = p2p_get_device(p2p, dev->member_in_go_dev);
     76 	if (go == NULL || dev->oper_freq <= 0) {
     77 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
     78 			"P2P: Could not find peer entry for GO and frequency "
     79 			"to send Device Discoverability Request");
     80 		return -1;
     81 	}
     82 
     83 	req = p2p_build_dev_disc_req(p2p, go, dev->info.p2p_device_addr);
     84 	if (req == NULL)
     85 		return -1;
     86 
     87 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
     88 		"P2P: Sending Device Discoverability Request to GO " MACSTR
     89 		" for client " MACSTR,
     90 		MAC2STR(go->info.p2p_device_addr),
     91 		MAC2STR(dev->info.p2p_device_addr));
     92 
     93 	p2p->pending_client_disc_go = go;
     94 	os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr,
     95 		  ETH_ALEN);
     96 	p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST;
     97 	if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr,
     98 			    p2p->cfg->dev_addr, go->info.p2p_device_addr,
     99 			    wpabuf_head(req), wpabuf_len(req), 1000) < 0) {
    100 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    101 			"P2P: Failed to send Action frame");
    102 		wpabuf_free(req);
    103 		/* TODO: how to recover from failure? */
    104 		return -1;
    105 	}
    106 
    107 	wpabuf_free(req);
    108 
    109 	return 0;
    110 }
    111 
    112 
    113 static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status)
    114 {
    115 	struct wpabuf *buf;
    116 	u8 *len;
    117 
    118 	buf = wpabuf_alloc(100);
    119 	if (buf == NULL)
    120 		return NULL;
    121 
    122 	p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_RESP, dialog_token);
    123 
    124 	len = p2p_buf_add_ie_hdr(buf);
    125 	p2p_buf_add_status(buf, status);
    126 	p2p_buf_update_ie_hdr(buf, len);
    127 
    128 	return buf;
    129 }
    130 
    131 
    132 void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success)
    133 {
    134 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    135 		"P2P: Device Discoverability Response TX callback: success=%d",
    136 		success);
    137 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
    138 }
    139 
    140 
    141 static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
    142 				   const u8 *addr, int freq, u8 status)
    143 {
    144 	struct wpabuf *resp;
    145 
    146 	resp = p2p_build_dev_disc_resp(dialog_token, status);
    147 	if (resp == NULL)
    148 		return;
    149 
    150 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    151 		"P2P: Sending Device Discoverability Response to " MACSTR
    152 		" (status %u freq %d)",
    153 		MAC2STR(addr), status, freq);
    154 
    155 	p2p->pending_action_state = P2P_PENDING_DEV_DISC_RESPONSE;
    156 	if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr,
    157 			    p2p->cfg->dev_addr,
    158 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
    159 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    160 			"P2P: Failed to send Action frame");
    161 	}
    162 
    163 	wpabuf_free(resp);
    164 }
    165 
    166 
    167 void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
    168 			      const u8 *data, size_t len, int rx_freq)
    169 {
    170 	struct p2p_message msg;
    171 	size_t g;
    172 
    173 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    174 		"P2P: Received Device Discoverability Request from " MACSTR
    175 		" (freq=%d)", MAC2STR(sa), rx_freq);
    176 
    177 	if (p2p_parse(data, len, &msg))
    178 		return;
    179 
    180 	if (msg.dialog_token == 0) {
    181 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    182 			"P2P: Invalid Dialog Token 0 (must be nonzero) in "
    183 			"Device Discoverability Request");
    184 		p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
    185 				       P2P_SC_FAIL_INVALID_PARAMS);
    186 		p2p_parse_free(&msg);
    187 		return;
    188 	}
    189 
    190 	if (msg.device_id == NULL) {
    191 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    192 			"P2P: P2P Device ID attribute missing from Device "
    193 			"Discoverability Request");
    194 		p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
    195 				       P2P_SC_FAIL_INVALID_PARAMS);
    196 		p2p_parse_free(&msg);
    197 		return;
    198 	}
    199 
    200 	for (g = 0; g < p2p->num_groups; g++) {
    201 		if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa,
    202 					  rx_freq) == 0) {
    203 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scheduled "
    204 				"GO Discoverability Request for the target "
    205 				"device");
    206 			/*
    207 			 * P2P group code will use a callback to indicate TX
    208 			 * status, so that we can reply to the request once the
    209 			 * target client has acknowledged the request or it has
    210 			 * timed out.
    211 			 */
    212 			p2p->pending_dev_disc_dialog_token = msg.dialog_token;
    213 			os_memcpy(p2p->pending_dev_disc_addr, sa, ETH_ALEN);
    214 			p2p->pending_dev_disc_freq = rx_freq;
    215 			p2p_parse_free(&msg);
    216 			return;
    217 		}
    218 	}
    219 
    220 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Requested client "
    221 		"was not found in any group or did not support client "
    222 		"discoverability");
    223 	p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
    224 			       P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
    225 	p2p_parse_free(&msg);
    226 }
    227 
    228 
    229 void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
    230 			       const u8 *data, size_t len)
    231 {
    232 	struct p2p_message msg;
    233 	struct p2p_device *go;
    234 	u8 status;
    235 
    236 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    237 		"P2P: Received Device Discoverability Response from " MACSTR,
    238 		MAC2STR(sa));
    239 
    240 	go = p2p->pending_client_disc_go;
    241 	if (go == NULL ||
    242 	    os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) {
    243 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected "
    244 			"Device Discoverability Response");
    245 		return;
    246 	}
    247 
    248 	if (p2p_parse(data, len, &msg))
    249 		return;
    250 
    251 	if (msg.status == NULL) {
    252 		p2p_parse_free(&msg);
    253 		return;
    254 	}
    255 
    256 	if (msg.dialog_token != go->dialog_token) {
    257 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore Device "
    258 			"Discoverability Response with unexpected dialog "
    259 			"token %u (expected %u)",
    260 			msg.dialog_token, go->dialog_token);
    261 		p2p_parse_free(&msg);
    262 		return;
    263 	}
    264 
    265 	status = *msg.status;
    266 	p2p_parse_free(&msg);
    267 
    268 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    269 		"P2P: Device Discoverability Response status %u", status);
    270 
    271 	if (p2p->go_neg_peer == NULL ||
    272 	    os_memcmp(p2p->pending_client_disc_addr,
    273 		      p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 ||
    274 	    os_memcmp(p2p->go_neg_peer->member_in_go_dev,
    275 		      go->info.p2p_device_addr, ETH_ALEN) != 0) {
    276 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending "
    277 			"operation with the client discoverability peer "
    278 			"anymore");
    279 		return;
    280 	}
    281 
    282 	if (status == 0) {
    283 		/*
    284 		 * Peer is expected to be awake for at least 100 TU; try to
    285 		 * connect immediately.
    286 		 */
    287 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    288 			"P2P: Client discoverability request succeeded");
    289 		if (p2p->state == P2P_CONNECT) {
    290 			/*
    291 			 * Change state to force the timeout to start in
    292 			 * P2P_CONNECT again without going through the short
    293 			 * Listen state.
    294 			 */
    295 			p2p_set_state(p2p, P2P_CONNECT_LISTEN);
    296 			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
    297 		}
    298 		p2p_set_timeout(p2p, 0, 0);
    299 	} else {
    300 		/*
    301 		 * Client discoverability request failed; try to connect from
    302 		 * timeout.
    303 		 */
    304 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    305 			"P2P: Client discoverability request failed");
    306 		p2p_set_timeout(p2p, 0, 500000);
    307 	}
    308 
    309 }
    310 
    311 
    312 void p2p_go_disc_req_cb(struct p2p_data *p2p, int success)
    313 {
    314 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    315 		"P2P: GO Discoverability Request TX callback: success=%d",
    316 		success);
    317 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
    318 
    319 	if (p2p->pending_dev_disc_dialog_token == 0) {
    320 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending Device "
    321 			"Discoverability Request");
    322 		return;
    323 	}
    324 
    325 	p2p_send_dev_disc_resp(p2p, p2p->pending_dev_disc_dialog_token,
    326 			       p2p->pending_dev_disc_addr,
    327 			       p2p->pending_dev_disc_freq,
    328 			       success ? P2P_SC_SUCCESS :
    329 			       P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
    330 
    331 	p2p->pending_dev_disc_dialog_token = 0;
    332 }
    333 
    334 
    335 void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
    336 			     const u8 *data, size_t len, int rx_freq)
    337 {
    338 	unsigned int tu;
    339 	struct wpabuf *ies;
    340 
    341 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    342 		"P2P: Received GO Discoverability Request - remain awake for "
    343 		"100 TU");
    344 
    345 	ies = p2p_build_probe_resp_ies(p2p);
    346 	if (ies == NULL)
    347 		return;
    348 
    349 	/* Remain awake 100 TU on operating channel */
    350 	p2p->pending_client_disc_freq = rx_freq;
    351 	tu = 100;
    352 	if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000,
    353 		    ies) < 0) {
    354 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
    355 			"P2P: Failed to start listen mode for client "
    356 			"discoverability");
    357 	}
    358 	wpabuf_free(ies);
    359 }
    360