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