p2p_group.c revision 04949598a23f501be6eec21697465fd46a28840a
1/*
2 * Wi-Fi Direct - P2P group operations
3 * Copyright (c) 2009-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 "common/ieee802_11_common.h"
14#include "wps/wps_defs.h"
15#include "wps/wps_i.h"
16#include "p2p_i.h"
17#include "p2p.h"
18
19
20struct p2p_group_member {
21	struct p2p_group_member *next;
22	u8 addr[ETH_ALEN]; /* P2P Interface Address */
23	u8 dev_addr[ETH_ALEN]; /* P2P Device Address */
24	struct wpabuf *p2p_ie;
25	struct wpabuf *client_info;
26	u8 dev_capab;
27};
28
29/**
30 * struct p2p_group - Internal P2P module per-group data
31 */
32struct p2p_group {
33	struct p2p_data *p2p;
34	struct p2p_group_config *cfg;
35	struct p2p_group_member *members;
36	unsigned int num_members;
37	int group_formation;
38	int beacon_update;
39	struct wpabuf *noa;
40};
41
42
43static void p2p_group_update_ies(struct p2p_group *group);
44
45
46struct p2p_group * p2p_group_init(struct p2p_data *p2p,
47				  struct p2p_group_config *config)
48{
49	struct p2p_group *group, **groups;
50
51	group = os_zalloc(sizeof(*group));
52	if (group == NULL)
53		return NULL;
54
55	groups = os_realloc(p2p->groups, (p2p->num_groups + 1) *
56			    sizeof(struct p2p_group *));
57	if (groups == NULL) {
58		os_free(group);
59		return NULL;
60	}
61	groups[p2p->num_groups++] = group;
62	p2p->groups = groups;
63
64	group->p2p = p2p;
65	group->cfg = config;
66	group->group_formation = 1;
67	group->beacon_update = 1;
68	p2p_group_update_ies(group);
69	group->cfg->idle_update(group->cfg->cb_ctx, 1);
70
71	return group;
72}
73
74
75static void p2p_group_free_member(struct p2p_group_member *m)
76{
77	wpabuf_free(m->p2p_ie);
78	wpabuf_free(m->client_info);
79	os_free(m);
80}
81
82
83static void p2p_group_free_members(struct p2p_group *group)
84{
85	struct p2p_group_member *m, *prev;
86	m = group->members;
87	group->members = NULL;
88	group->num_members = 0;
89	while (m) {
90		prev = m;
91		m = m->next;
92		p2p_group_free_member(prev);
93	}
94}
95
96
97void p2p_group_deinit(struct p2p_group *group)
98{
99	size_t g;
100	struct p2p_data *p2p;
101
102	if (group == NULL)
103		return;
104
105	p2p = group->p2p;
106
107	for (g = 0; g < p2p->num_groups; g++) {
108		if (p2p->groups[g] == group) {
109			while (g + 1 < p2p->num_groups) {
110				p2p->groups[g] = p2p->groups[g + 1];
111				g++;
112			}
113			p2p->num_groups--;
114			break;
115		}
116	}
117
118	p2p_group_free_members(group);
119	os_free(group->cfg);
120	wpabuf_free(group->noa);
121	os_free(group);
122}
123
124
125static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m)
126{
127	if (m->client_info == NULL)
128		return;
129	if (wpabuf_tailroom(ie) < wpabuf_len(m->client_info) + 1)
130		return;
131	wpabuf_put_buf(ie, m->client_info);
132}
133
134
135static void p2p_group_add_common_ies(struct p2p_group *group,
136				     struct wpabuf *ie)
137{
138	u8 dev_capab = group->p2p->dev_capab, group_capab = 0;
139
140	/* P2P Capability */
141	dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
142	group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
143	if (group->cfg->persistent_group) {
144		group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
145		if (group->cfg->persistent_group == 2)
146			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
147	}
148	if (group->p2p->cfg->p2p_intra_bss)
149		group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
150	if (group->group_formation)
151		group_capab |= P2P_GROUP_CAPAB_GROUP_FORMATION;
152	if (group->p2p->cross_connect)
153		group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
154	if (group->num_members >= group->cfg->max_clients)
155		group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT;
156	p2p_buf_add_capability(ie, dev_capab, group_capab);
157}
158
159
160static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa)
161{
162	if (noa == NULL)
163		return;
164	/* Notice of Absence */
165	wpabuf_put_u8(ie, P2P_ATTR_NOTICE_OF_ABSENCE);
166	wpabuf_put_le16(ie, wpabuf_len(noa));
167	wpabuf_put_buf(ie, noa);
168}
169
170
171static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
172{
173	struct wpabuf *ie;
174	u8 *len;
175
176	ie = wpabuf_alloc(257);
177	if (ie == NULL)
178		return NULL;
179
180	len = p2p_buf_add_ie_hdr(ie);
181	p2p_group_add_common_ies(group, ie);
182	p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
183	p2p_group_add_noa(ie, group->noa);
184	p2p_buf_update_ie_hdr(ie, len);
185
186	return ie;
187}
188
189
190static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
191{
192	u8 *group_info;
193	struct wpabuf *ie;
194	struct p2p_group_member *m;
195	u8 *len;
196
197	ie = wpabuf_alloc(257);
198	if (ie == NULL)
199		return NULL;
200
201	len = p2p_buf_add_ie_hdr(ie);
202
203	p2p_group_add_common_ies(group, ie);
204	p2p_group_add_noa(ie, group->noa);
205
206	/* P2P Device Info */
207	p2p_buf_add_device_info(ie, group->p2p, NULL);
208
209	/* P2P Group Info */
210	group_info = wpabuf_put(ie, 0);
211	wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO);
212	wpabuf_put_le16(ie, 0); /* Length to be filled */
213	for (m = group->members; m; m = m->next)
214		p2p_client_info(ie, m);
215	WPA_PUT_LE16(group_info + 1,
216		     (u8 *) wpabuf_put(ie, 0) - group_info - 3);
217
218	p2p_buf_update_ie_hdr(ie, len);
219	return ie;
220}
221
222
223static void p2p_group_update_ies(struct p2p_group *group)
224{
225	struct wpabuf *beacon_ie;
226	struct wpabuf *probe_resp_ie;
227
228	probe_resp_ie = p2p_group_build_probe_resp_ie(group);
229	if (probe_resp_ie == NULL)
230		return;
231	wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Probe Response P2P IE",
232			probe_resp_ie);
233
234	if (group->beacon_update) {
235		beacon_ie = p2p_group_build_beacon_ie(group);
236		if (beacon_ie)
237			group->beacon_update = 0;
238		wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Beacon P2P IE",
239				beacon_ie);
240	} else
241		beacon_ie = NULL;
242
243	group->cfg->ie_update(group->cfg->cb_ctx, beacon_ie, probe_resp_ie);
244}
245
246
247/**
248 * p2p_build_client_info - Build P2P Client Info Descriptor
249 * @addr: MAC address of the peer device
250 * @p2p_ie: P2P IE from (Re)Association Request
251 * @dev_capab: Buffer for returning Device Capability
252 * @dev_addr: Buffer for returning P2P Device Address
253 * Returns: P2P Client Info Descriptor or %NULL on failure
254 *
255 * This function builds P2P Client Info Descriptor based on the information
256 * available from (Re)Association Request frame. Group owner can use this to
257 * build the P2P Group Info attribute for Probe Response frames.
258 */
259static struct wpabuf * p2p_build_client_info(const u8 *addr,
260					     struct wpabuf *p2p_ie,
261					     u8 *dev_capab, u8 *dev_addr)
262{
263	const u8 *spos;
264	struct p2p_message msg;
265	u8 *len_pos;
266	struct wpabuf *buf;
267
268	if (p2p_ie == NULL)
269		return NULL;
270
271	os_memset(&msg, 0, sizeof(msg));
272	if (p2p_parse_p2p_ie(p2p_ie, &msg) ||
273	    msg.capability == NULL || msg.p2p_device_info == NULL)
274		return NULL;
275
276	buf = wpabuf_alloc(ETH_ALEN + 1 + 1 + msg.p2p_device_info_len);
277	if (buf == NULL)
278		return NULL;
279
280	*dev_capab = msg.capability[0];
281	os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
282
283	spos = msg.p2p_device_info; /* P2P Device address */
284
285	/* P2P Client Info Descriptor */
286	/* Length to be set */
287	len_pos = wpabuf_put(buf, 1);
288	/* P2P Device address */
289	wpabuf_put_data(buf, spos, ETH_ALEN);
290	/* P2P Interface address */
291	wpabuf_put_data(buf, addr, ETH_ALEN);
292	/* Device Capability Bitmap */
293	wpabuf_put_u8(buf, msg.capability[0]);
294	/*
295	 * Config Methods, Primary Device Type, Number of Secondary Device
296	 * Types, Secondary Device Type List, Device Name copied from
297	 * Device Info
298	 */
299	wpabuf_put_data(buf, spos + ETH_ALEN,
300			msg.p2p_device_info_len - ETH_ALEN);
301
302	*len_pos = wpabuf_len(buf) - 1;
303
304
305	return buf;
306}
307
308
309static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr)
310{
311	struct p2p_group_member *m, *prev;
312
313	if (group == NULL)
314		return 0;
315
316	m = group->members;
317	prev = NULL;
318	while (m) {
319		if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
320			break;
321		prev = m;
322		m = m->next;
323	}
324
325	if (m == NULL)
326		return 0;
327
328	if (prev)
329		prev->next = m->next;
330	else
331		group->members = m->next;
332	p2p_group_free_member(m);
333	group->num_members--;
334
335	return 1;
336}
337
338
339int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
340			  const u8 *ie, size_t len)
341{
342	struct p2p_group_member *m;
343
344	if (group == NULL)
345		return -1;
346
347	m = os_zalloc(sizeof(*m));
348	if (m == NULL)
349		return -1;
350	os_memcpy(m->addr, addr, ETH_ALEN);
351	m->p2p_ie = ieee802_11_vendor_ie_concat(ie, len, P2P_IE_VENDOR_TYPE);
352	if (m->p2p_ie) {
353		m->client_info = p2p_build_client_info(addr, m->p2p_ie,
354						       &m->dev_capab,
355						       m->dev_addr);
356	}
357
358	p2p_group_remove_member(group, addr);
359
360	m->next = group->members;
361	group->members = m;
362	group->num_members++;
363	wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
364		" to group (p2p=%d client_info=%d); num_members=%u/%u",
365		MAC2STR(addr), m->p2p_ie ? 1 : 0, m->client_info ? 1 : 0,
366		group->num_members, group->cfg->max_clients);
367	if (group->num_members == group->cfg->max_clients)
368		group->beacon_update = 1;
369	p2p_group_update_ies(group);
370	if (group->num_members == 1)
371		group->cfg->idle_update(group->cfg->cb_ctx, 0);
372
373	return 0;
374}
375
376
377struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
378{
379	struct wpabuf *resp;
380	u8 *rlen;
381
382	/*
383	 * (Re)Association Response - P2P IE
384	 * Status attribute (shall be present when association request is
385	 *	denied)
386	 * Extended Listen Timing (may be present)
387	 */
388	resp = wpabuf_alloc(20);
389	if (resp == NULL)
390		return NULL;
391	rlen = p2p_buf_add_ie_hdr(resp);
392	if (status != P2P_SC_SUCCESS)
393		p2p_buf_add_status(resp, status);
394	p2p_buf_update_ie_hdr(resp, rlen);
395
396	return resp;
397}
398
399
400void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
401{
402	if (p2p_group_remove_member(group, addr)) {
403		wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove "
404			"client " MACSTR " from group; num_members=%u/%u",
405			MAC2STR(addr), group->num_members,
406			group->cfg->max_clients);
407		if (group->num_members == group->cfg->max_clients - 1)
408			group->beacon_update = 1;
409		p2p_group_update_ies(group);
410		if (group->num_members == 0)
411			group->cfg->idle_update(group->cfg->cb_ctx, 1);
412	}
413}
414
415
416/**
417 * p2p_match_dev_type_member - Match client device type with requested type
418 * @m: Group member
419 * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs)
420 * Returns: 1 on match, 0 on mismatch
421 *
422 * This function can be used to match the Requested Device Type attribute in
423 * WPS IE with the device types of a group member for deciding whether a GO
424 * should reply to a Probe Request frame.
425 */
426static int p2p_match_dev_type_member(struct p2p_group_member *m,
427				     struct wpabuf *wps)
428{
429	const u8 *pos, *end;
430	struct wps_parse_attr attr;
431	u8 num_sec;
432
433	if (m->client_info == NULL || wps == NULL)
434		return 0;
435
436	pos = wpabuf_head(m->client_info);
437	end = pos + wpabuf_len(m->client_info);
438
439	pos += 1 + 2 * ETH_ALEN + 1 + 2;
440	if (end - pos < WPS_DEV_TYPE_LEN + 1)
441		return 0;
442
443	if (wps_parse_msg(wps, &attr))
444		return 1; /* assume no Requested Device Type attributes */
445
446	if (attr.num_req_dev_type == 0)
447		return 1; /* no Requested Device Type attributes -> match */
448
449	if (dev_type_list_match(pos, attr.req_dev_type, attr.num_req_dev_type))
450		return 1; /* Match with client Primary Device Type */
451
452	pos += WPS_DEV_TYPE_LEN;
453	num_sec = *pos++;
454	if (end - pos < num_sec * WPS_DEV_TYPE_LEN)
455		return 0;
456	while (num_sec > 0) {
457		num_sec--;
458		if (dev_type_list_match(pos, attr.req_dev_type,
459					attr.num_req_dev_type))
460			return 1; /* Match with client Secondary Device Type */
461		pos += WPS_DEV_TYPE_LEN;
462	}
463
464	/* No matching device type found */
465	return 0;
466}
467
468
469int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps)
470{
471	struct p2p_group_member *m;
472
473	if (p2p_match_dev_type(group->p2p, wps))
474		return 1; /* Match with own device type */
475
476	for (m = group->members; m; m = m->next) {
477		if (p2p_match_dev_type_member(m, wps))
478			return 1; /* Match with group client device type */
479	}
480
481	/* No match with Requested Device Type */
482	return 0;
483}
484
485
486int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p)
487{
488	struct p2p_group_member *m;
489	struct p2p_message msg;
490
491	os_memset(&msg, 0, sizeof(msg));
492	if (p2p_parse_p2p_ie(p2p, &msg))
493		return 1; /* Failed to parse - assume no filter on Device ID */
494
495	if (!msg.device_id)
496		return 1; /* No filter on Device ID */
497
498	if (os_memcmp(msg.device_id, group->p2p->cfg->dev_addr, ETH_ALEN) == 0)
499		return 1; /* Match with our P2P Device Address */
500
501	for (m = group->members; m; m = m->next) {
502		if (os_memcmp(msg.device_id, m->dev_addr, ETH_ALEN) == 0)
503			return 1; /* Match with group client P2P Device Address */
504	}
505
506	/* No match with Device ID */
507	return 0;
508}
509
510
511void p2p_group_notif_formation_done(struct p2p_group *group)
512{
513	if (group == NULL)
514		return;
515	group->group_formation = 0;
516	group->beacon_update = 1;
517	p2p_group_update_ies(group);
518}
519
520
521int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa,
522			size_t noa_len)
523{
524	if (noa == NULL) {
525		wpabuf_free(group->noa);
526		group->noa = NULL;
527	} else {
528		if (group->noa) {
529			if (wpabuf_size(group->noa) >= noa_len) {
530				group->noa->used = 0;
531				wpabuf_put_data(group->noa, noa, noa_len);
532			} else {
533				wpabuf_free(group->noa);
534				group->noa = NULL;
535			}
536		}
537
538		if (!group->noa) {
539			group->noa = wpabuf_alloc_copy(noa, noa_len);
540			if (group->noa == NULL)
541				return -1;
542		}
543	}
544
545	group->beacon_update = 1;
546	p2p_group_update_ies(group);
547	return 0;
548}
549
550
551static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group,
552						      const u8 *dev_id)
553{
554	struct p2p_group_member *m;
555
556	for (m = group->members; m; m = m->next) {
557		if (os_memcmp(dev_id, m->dev_addr, ETH_ALEN) == 0)
558			return m;
559	}
560
561	return NULL;
562}
563
564
565static struct p2p_group_member * p2p_group_get_client_iface(
566	struct p2p_group *group, const u8 *interface_addr)
567{
568	struct p2p_group_member *m;
569
570	for (m = group->members; m; m = m->next) {
571		if (os_memcmp(interface_addr, m->addr, ETH_ALEN) == 0)
572			return m;
573	}
574
575	return NULL;
576}
577
578
579const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
580{
581	struct p2p_group_member *m;
582
583	if (group == NULL)
584		return NULL;
585	m = p2p_group_get_client_iface(group, addr);
586	if (m && !is_zero_ether_addr(m->dev_addr))
587		return m->dev_addr;
588	return NULL;
589}
590
591
592static struct wpabuf * p2p_build_go_disc_req(void)
593{
594	struct wpabuf *buf;
595
596	buf = wpabuf_alloc(100);
597	if (buf == NULL)
598		return NULL;
599
600	p2p_buf_add_action_hdr(buf, P2P_GO_DISC_REQ, 0);
601
602	return buf;
603}
604
605
606int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
607			  const u8 *searching_dev, int rx_freq)
608{
609	struct p2p_group_member *m;
610	struct wpabuf *req;
611	struct p2p_data *p2p = group->p2p;
612	int freq;
613
614	m = p2p_group_get_client(group, dev_id);
615	if (m == NULL || m->client_info == NULL) {
616		wpa_printf(MSG_DEBUG, "P2P: Requested client was not in this "
617			   "group " MACSTR,
618			   MAC2STR(group->cfg->interface_addr));
619		return -1;
620	}
621
622	if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
623		wpa_printf(MSG_DEBUG, "P2P: Requested client does not support "
624			   "client discoverability");
625		return -1;
626	}
627
628	wpa_printf(MSG_DEBUG, "P2P: Schedule GO Discoverability Request to be "
629		   "sent to " MACSTR, MAC2STR(dev_id));
630
631	req = p2p_build_go_disc_req();
632	if (req == NULL)
633		return -1;
634
635	/* TODO: Should really use group operating frequency here */
636	freq = rx_freq;
637
638	p2p->pending_action_state = P2P_PENDING_GO_DISC_REQ;
639	if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr,
640				  group->cfg->interface_addr,
641				  group->cfg->interface_addr,
642				  wpabuf_head(req), wpabuf_len(req), 200) < 0)
643	{
644		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
645			"P2P: Failed to send Action frame");
646	}
647
648	wpabuf_free(req);
649
650	return 0;
651}
652
653
654const u8 * p2p_group_get_interface_addr(struct p2p_group *group)
655{
656	return group->cfg->interface_addr;
657}
658
659
660u8 p2p_group_presence_req(struct p2p_group *group,
661			  const u8 *client_interface_addr,
662			  const u8 *noa, size_t noa_len)
663{
664	struct p2p_group_member *m;
665	u8 curr_noa[50];
666	int curr_noa_len;
667
668	m = p2p_group_get_client_iface(group, client_interface_addr);
669	if (m == NULL || m->client_info == NULL) {
670		wpa_printf(MSG_DEBUG, "P2P: Client was not in this group");
671		return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
672	}
673
674	wpa_hexdump(MSG_DEBUG, "P2P: Presence Request NoA", noa, noa_len);
675
676	if (group->p2p->cfg->get_noa)
677		curr_noa_len = group->p2p->cfg->get_noa(
678			group->p2p->cfg->cb_ctx, group->cfg->interface_addr,
679			curr_noa, sizeof(curr_noa));
680	else
681		curr_noa_len = -1;
682	if (curr_noa_len < 0)
683		wpa_printf(MSG_DEBUG, "P2P: Failed to fetch current NoA");
684	else if (curr_noa_len == 0)
685		wpa_printf(MSG_DEBUG, "P2P: No NoA being advertized");
686	else
687		wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
688			    curr_noa_len);
689
690	/* TODO: properly process request and store copy */
691	if (curr_noa_len > 0 || curr_noa_len == -1)
692		return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
693
694	return P2P_SC_SUCCESS;
695}
696
697
698unsigned int p2p_get_group_num_members(struct p2p_group *group)
699{
700	return group->num_members;
701}
702
703
704const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
705{
706	struct p2p_group_member *iter = *next;
707
708	if (!iter)
709		iter = group->members;
710	else
711		iter = iter->next;
712
713	*next = iter;
714
715	if (!iter)
716		return NULL;
717
718	return iter->addr;
719}
720
721
722int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr)
723{
724	struct p2p_group_member *m;
725
726	for (m = group->members; m; m = m->next) {
727		if (os_memcmp(m->dev_addr, dev_addr, ETH_ALEN) == 0)
728			return 1;
729	}
730
731	return 0;
732}
733
734
735int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
736				size_t group_id_len)
737{
738	if (group_id_len != ETH_ALEN + group->cfg->ssid_len)
739		return 0;
740	if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0)
741		return 0;
742	return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
743			 group->cfg->ssid_len) == 0;
744}
745