18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Wi-Fi Direct - P2P group operations 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_common.h" 142e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt#include "common/wpa_ctrl.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps/wps_defs.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps/wps_i.h" 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p_i.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct p2p_group_member { 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *next; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 addr[ETH_ALEN]; /* P2P Interface Address */ 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 dev_addr[ETH_ALEN]; /* P2P Device Address */ 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *p2p_ie; 2661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *wfd_ie; 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *client_info; 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 dev_capab; 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct p2p_group - Internal P2P module per-group data 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct p2p_group { 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_data *p2p; 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_config *cfg; 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *members; 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned int num_members; 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int group_formation; 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int beacon_update; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *noa; 4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *wfd_ie; 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct p2p_group * p2p_group_init(struct p2p_data *p2p, 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_config *config) 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group *group, **groups; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group = os_zalloc(sizeof(*group)); 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group == NULL) 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt groups = os_realloc_array(p2p->groups, p2p->num_groups + 1, 5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt sizeof(struct p2p_group *)); 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (groups == NULL) { 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(group); 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt groups[p2p->num_groups++] = group; 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p->groups = groups; 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->p2p = p2p; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->cfg = config; 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->group_formation = 1; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->beacon_update = 1; 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_update_ies(group); 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->cfg->idle_update(group->cfg->cb_ctx, 1); 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return group; 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void p2p_group_free_member(struct p2p_group_member *m) 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_free(m->wfd_ie); 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(m->p2p_ie); 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(m->client_info); 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(m); 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void p2p_group_free_members(struct p2p_group *group) 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *m, *prev; 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m = group->members; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->members = NULL; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->num_members = 0; 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (m) { 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev = m; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m = m->next; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_free_member(prev); 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid p2p_group_deinit(struct p2p_group *group) 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t g; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_data *p2p; 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group == NULL) 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p = group->p2p; 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (g = 0; g < p2p->num_groups; g++) { 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p2p->groups[g] == group) { 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (g + 1 < p2p->num_groups) { 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p->groups[g] = p2p->groups[g + 1]; 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt g++; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p->num_groups--; 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_free_members(group); 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(group->cfg); 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(group->noa); 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_free(group->wfd_ie); 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(group); 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m) 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (m->client_info == NULL) 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_tailroom(ie) < wpabuf_len(m->client_info) + 1) 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_buf(ie, m->client_info); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void p2p_group_add_common_ies(struct p2p_group *group, 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *ie) 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 dev_capab = group->p2p->dev_capab, group_capab = 0; 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* P2P Capability */ 14304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; 1451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (group->cfg->persistent_group) { 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; 1471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (group->cfg->persistent_group == 2) 1481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN; 1491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->p2p->cfg->p2p_intra_bss) 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->group_formation) 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group_capab |= P2P_GROUP_CAPAB_GROUP_FORMATION; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->p2p->cross_connect) 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->num_members >= group->cfg->max_clients) 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT; 158cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_buf_add_capability(ie, dev_capab, group_capab); 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa) 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (noa == NULL) 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Notice of Absence */ 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(ie, P2P_ATTR_NOTICE_OF_ABSENCE); 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_le16(ie, wpabuf_len(noa)); 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_buf(ie, noa); 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 174a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems) 175a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 176a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct wpabuf *ie; 177a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, *end; 178a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt size_t len; 179a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 180a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (subelems == NULL) 181a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return NULL; 182a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt len = wpabuf_len(subelems) + 100; 184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 185a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ie = wpabuf_alloc(len); 186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ie == NULL) 187a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return NULL; 188a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 189a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos = wpabuf_head(subelems); 190a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt end = pos + wpabuf_len(subelems); 191a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 192a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt while (end > pos) { 193a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt size_t frag_len = end - pos; 194a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (frag_len > 251) 195a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt frag_len = 251; 196a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 197a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpabuf_put_u8(ie, 4 + frag_len); 198a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE); 199a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpabuf_put_data(ie, pos, frag_len); 200a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += frag_len; 201a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 202a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 203a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return ie; 204a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 205a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 206a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *ie; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *len; 21161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t extra = 0; 21261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 21361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_WIFI_DISPLAY 21461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (group->p2p->wfd_ie_beacon) 21561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt extra = wpabuf_len(group->p2p->wfd_ie_beacon); 21661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_WIFI_DISPLAY */ 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2182e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt if (group->p2p->vendor_elem && 2192e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) 2202e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); 2212e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt 22261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ie = wpabuf_alloc(257 + extra); 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ie == NULL) 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 22661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_WIFI_DISPLAY 22761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (group->p2p->wfd_ie_beacon) 22861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon); 22961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_WIFI_DISPLAY */ 23061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2312e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt if (group->p2p->vendor_elem && 2322e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) 2332e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt wpabuf_put_buf(ie, 2342e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); 2352e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = p2p_buf_add_ie_hdr(ie); 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_add_common_ies(group, ie); 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_add_noa(ie, group->noa); 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_buf_update_ie_hdr(ie, len); 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ie; 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_WIFI_DISPLAY 24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 24861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstruct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g) 24961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 25061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return g->wfd_ie; 25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 25261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 25361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 25461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstruct wpabuf * wifi_display_encaps(struct wpabuf *subelems) 25561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 25661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *ie; 25761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *pos, *end; 25861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 25961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (subelems == NULL) 26061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return NULL; 26161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 26261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ie = wpabuf_alloc(wpabuf_len(subelems) + 100); 26361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (ie == NULL) 26461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return NULL; 26561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos = wpabuf_head(subelems); 26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt end = pos + wpabuf_len(subelems); 26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 26961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (end > pos) { 27061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t frag_len = end - pos; 27161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (frag_len > 251) 27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt frag_len = 251; 27361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 27461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(ie, 4 + frag_len); 27561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_be32(ie, WFD_IE_VENDOR_TYPE); 27661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(ie, pos, frag_len); 27761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += frag_len; 27861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return ie; 28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 28261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 28361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 28461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int wifi_display_add_dev_info_descr(struct wpabuf *buf, 28561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct p2p_group_member *m) 28661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 28761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *pos, *end; 28861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *dev_info = NULL; 28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *assoc_bssid = NULL; 29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *coupled_sink = NULL; 29161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 zero_addr[ETH_ALEN]; 29261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (m->wfd_ie == NULL) 29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return 0; 29561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memset(zero_addr, 0, ETH_ALEN); 29761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos = wpabuf_head_u8(m->wfd_ie); 29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt end = pos + wpabuf_len(m->wfd_ie); 29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (pos + 1 < end) { 30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 id; 30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 len; 30261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 30361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt id = *pos++; 30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = WPA_GET_BE16(pos); 30561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += 2; 30661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (pos + len > end) 30761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 30861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 30961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (id) { 31061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case WFD_SUBELEM_DEVICE_INFO: 31161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (len < 6) 31261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 31361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt dev_info = pos; 31461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 31561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case WFD_SUBELEM_ASSOCIATED_BSSID: 31661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (len < ETH_ALEN) 31761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 31861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt assoc_bssid = pos; 31961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 32061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case WFD_SUBELEM_COUPLED_SINK: 32161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (len < 1 + ETH_ALEN) 32261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 32361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt coupled_sink = pos; 32461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 32561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 32661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 32761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += len; 32861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 32961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 33061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (dev_info == NULL) 33161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return 0; 33261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 33361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 23); 33461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, m->dev_addr, ETH_ALEN); 33561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (assoc_bssid) 33661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, assoc_bssid, ETH_ALEN); 33761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt else 33861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, zero_addr, ETH_ALEN); 33961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, dev_info, 2); /* WFD Device Info */ 34061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, dev_info + 4, 2); /* WFD Device Max Throughput */ 34161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (coupled_sink) { 34261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, coupled_sink, 1 + ETH_ALEN); 34361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 34461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(buf, 0); 34561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_data(buf, zero_addr, ETH_ALEN); 34661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 34761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 34861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return 1; 34961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 35061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 35161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 35261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic struct wpabuf * 35361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtwifi_display_build_go_ie(struct p2p_group *group) 35461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 35561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wpabuf *wfd_subelems, *wfd_ie; 35661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct p2p_group_member *m; 35761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *len; 35861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt unsigned int count = 0; 35961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 36061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!group->p2p->wfd_ie_probe_resp) 36161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return NULL; 36261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 36361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) + 36461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt group->num_members * 24 + 100); 36561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wfd_subelems == NULL) 36661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return NULL; 36761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (group->p2p->wfd_dev_info) 36861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info); 36961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (group->p2p->wfd_assoc_bssid) 37061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_buf(wfd_subelems, 37161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt group->p2p->wfd_assoc_bssid); 37261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (group->p2p->wfd_coupled_sink_info) 37361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_buf(wfd_subelems, 37461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt group->p2p->wfd_coupled_sink_info); 37561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 37661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* Build WFD Session Info */ 37761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO); 37861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = wpabuf_put(wfd_subelems, 2); 37961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt m = group->members; 38061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (m) { 38161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wifi_display_add_dev_info_descr(wfd_subelems, m)) 38261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt count++; 38361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt m = m->next; 38461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 38561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 38661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (count == 0) { 38761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* No Wi-Fi Display clients - do not include subelement */ 38861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wfd_subelems->used -= 3; 38961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 39061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len - 39161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2); 392b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "WFD: WFD Session Info: %u descriptors", 393b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt count); 39461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 39561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 39661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wfd_ie = wifi_display_encaps(wfd_subelems); 39761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_free(wfd_subelems); 39861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 39961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return wfd_ie; 40061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 40161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 40261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void wifi_display_group_update(struct p2p_group *group) 40361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 40461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_free(group->wfd_ie); 40561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt group->wfd_ie = wifi_display_build_go_ie(group); 40661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 40761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 40861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_WIFI_DISPLAY */ 40961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 41061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 411cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtvoid p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf, 412cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt int max_clients) 413cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{ 414cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt u8 *group_info; 415cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt int count = 0; 416cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt struct p2p_group_member *m; 417cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 418cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt p2p_dbg(group->p2p, "* P2P Group Info"); 419cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt group_info = wpabuf_put(buf, 0); 420cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt wpabuf_put_u8(buf, P2P_ATTR_GROUP_INFO); 421cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt wpabuf_put_le16(buf, 0); /* Length to be filled */ 422cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt for (m = group->members; m; m = m->next) { 423cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt p2p_client_info(buf, m); 424cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt count++; 425cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (max_clients >= 0 && count >= max_clients) 426cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt break; 427cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt } 428cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt WPA_PUT_LE16(group_info + 1, 429cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt (u8 *) wpabuf_put(buf, 0) - group_info - 3); 430cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt} 431cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 432cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 433cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtvoid p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf) 434cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{ 435cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt p2p_buf_add_group_id(buf, group->p2p->cfg->dev_addr, group->cfg->ssid, 436cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt group->cfg->ssid_len); 437cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt} 438cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 439cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 442a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct wpabuf *p2p_subelems, *ie; 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 44433077b18208aab987e14cd26f0f501c7666a89ffJouni Malinen p2p_subelems = wpabuf_alloc(500); 445a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (p2p_subelems == NULL) 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 448a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt p2p_group_add_common_ies(group, p2p_subelems); 449a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt p2p_group_add_noa(p2p_subelems, group->noa); 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* P2P Device Info */ 452a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL); 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 454444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt /* P2P Group Info: Only when at least one P2P Client is connected */ 455cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (group->members) 456cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt p2p_buf_add_group_info(group, p2p_subelems, -1); 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 458a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ie = p2p_group_encaps_probe_resp(p2p_subelems); 459a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpabuf_free(p2p_subelems); 46061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4612e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt if (group->p2p->vendor_elem && 4622e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]) { 4632e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt struct wpabuf *extra; 4642e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt extra = wpabuf_dup(group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]); 4652e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt ie = wpabuf_concat(extra, ie); 4662e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt } 4672e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt 46833077b18208aab987e14cd26f0f501c7666a89ffJouni Malinen#ifdef CONFIG_WIFI_DISPLAY 46933077b18208aab987e14cd26f0f501c7666a89ffJouni Malinen if (group->wfd_ie) { 47033077b18208aab987e14cd26f0f501c7666a89ffJouni Malinen struct wpabuf *wfd = wpabuf_dup(group->wfd_ie); 47133077b18208aab987e14cd26f0f501c7666a89ffJouni Malinen ie = wpabuf_concat(wfd, ie); 47233077b18208aab987e14cd26f0f501c7666a89ffJouni Malinen } 47333077b18208aab987e14cd26f0f501c7666a89ffJouni Malinen#endif /* CONFIG_WIFI_DISPLAY */ 47433077b18208aab987e14cd26f0f501c7666a89ffJouni Malinen 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ie; 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 47961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid p2p_group_update_ies(struct p2p_group *group) 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *beacon_ie; 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *probe_resp_ie; 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 48461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_WIFI_DISPLAY 48561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wifi_display_group_update(group); 48661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_WIFI_DISPLAY */ 48761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt probe_resp_ie = p2p_group_build_probe_resp_ie(group); 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (probe_resp_ie == NULL) 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Probe Response P2P IE", 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt probe_resp_ie); 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->beacon_update) { 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt beacon_ie = p2p_group_build_beacon_ie(group); 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (beacon_ie) 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->beacon_update = 0; 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Beacon P2P IE", 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt beacon_ie); 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt beacon_ie = NULL; 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->cfg->ie_update(group->cfg->cb_ctx, beacon_ie, probe_resp_ie); 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_build_client_info - Build P2P Client Info Descriptor 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @addr: MAC address of the peer device 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @p2p_ie: P2P IE from (Re)Association Request 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @dev_capab: Buffer for returning Device Capability 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @dev_addr: Buffer for returning P2P Device Address 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: P2P Client Info Descriptor or %NULL on failure 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function builds P2P Client Info Descriptor based on the information 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * available from (Re)Association Request frame. Group owner can use this to 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * build the P2P Group Info attribute for Probe Response frames. 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * p2p_build_client_info(const u8 *addr, 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *p2p_ie, 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *dev_capab, u8 *dev_addr) 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *spos; 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_message msg; 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *len_pos; 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *buf; 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p2p_ie == NULL) 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&msg, 0, sizeof(msg)); 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p2p_parse_p2p_ie(p2p_ie, &msg) || 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.capability == NULL || msg.p2p_device_info == NULL) 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = wpabuf_alloc(ETH_ALEN + 1 + 1 + msg.p2p_device_info_len); 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *dev_capab = msg.capability[0]; 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN); 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt spos = msg.p2p_device_info; /* P2P Device address */ 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* P2P Client Info Descriptor */ 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Length to be set */ 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len_pos = wpabuf_put(buf, 1); 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* P2P Device address */ 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(buf, spos, ETH_ALEN); 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* P2P Interface address */ 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(buf, addr, ETH_ALEN); 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Device Capability Bitmap */ 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(buf, msg.capability[0]); 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Config Methods, Primary Device Type, Number of Secondary Device 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Types, Secondary Device Type List, Device Name copied from 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Device Info 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(buf, spos + ETH_ALEN, 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.p2p_device_info_len - ETH_ALEN); 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *len_pos = wpabuf_len(buf) - 1; 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return buf; 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int p2p_group_remove_member(struct p2p_group *group, const u8 *addr) 5701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{ 5711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt struct p2p_group_member *m, *prev; 5721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (group == NULL) 5741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt m = group->members; 5771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt prev = NULL; 5781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (m) { 5791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (os_memcmp(m->addr, addr, ETH_ALEN) == 0) 5801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt break; 5811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt prev = m; 5821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt m = m->next; 5831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 5841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (m == NULL) 5861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 0; 5871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (prev) 5891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt prev->next = m->next; 5901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt else 5911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt group->members = m->next; 5921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt p2p_group_free_member(m); 5931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt group->num_members--; 5941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return 1; 5961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 5971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *ie, size_t len) 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *m; 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group == NULL) 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6072f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt p2p_add_device(group->p2p, addr, 0, NULL, 0, ie, len, 0); 6082f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m = os_zalloc(sizeof(*m)); 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (m == NULL) 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(m->addr, addr, ETH_ALEN); 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m->p2p_ie = ieee802_11_vendor_ie_concat(ie, len, P2P_IE_VENDOR_TYPE); 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (m->p2p_ie) { 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m->client_info = p2p_build_client_info(addr, m->p2p_ie, 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &m->dev_capab, 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m->dev_addr); 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 61961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_WIFI_DISPLAY 62061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt m->wfd_ie = ieee802_11_vendor_ie_concat(ie, len, WFD_IE_VENDOR_TYPE); 62161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_WIFI_DISPLAY */ 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt p2p_group_remove_member(group, addr); 6241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m->next = group->members; 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->members = m; 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->num_members++; 628b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "Add client " MACSTR 62961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt " to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u", 63061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0, 63161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt m->client_info ? 1 : 0, 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->num_members, group->cfg->max_clients); 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->num_members == group->cfg->max_clients) 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->beacon_update = 1; 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_update_ies(group); 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->num_members == 1) 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->cfg->idle_update(group->cfg->cb_ctx, 0); 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *resp; 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *rlen; 64761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t extra = 0; 64861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 64961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_WIFI_DISPLAY 65061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (group->wfd_ie) 65161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt extra = wpabuf_len(group->wfd_ie); 65261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_WIFI_DISPLAY */ 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6542e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt if (group->p2p->vendor_elem && 6552e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]) 6562e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]); 6572e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (Re)Association Response - P2P IE 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Status attribute (shall be present when association request is 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * denied) 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Extended Listen Timing (may be present) 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 66461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt resp = wpabuf_alloc(20 + extra); 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (resp == NULL) 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 66761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 66861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_WIFI_DISPLAY 66961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (group->wfd_ie) 67061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpabuf_put_buf(resp, group->wfd_ie); 67161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_WIFI_DISPLAY */ 67261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 6732e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt if (group->p2p->vendor_elem && 6742e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]) 6752e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt wpabuf_put_buf(resp, 6762e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]); 6772e67f06149ff649fb6f8782bad041d3d9124685eDmitry Shmidt 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rlen = p2p_buf_add_ie_hdr(resp); 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (status != P2P_SC_SUCCESS) 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_buf_add_status(resp, status); 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_buf_update_ie_hdr(resp, rlen); 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return resp; 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr) 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (p2p_group_remove_member(group, addr)) { 690b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "Remove client " MACSTR 691b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt " from group; num_members=%u/%u", 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(addr), group->num_members, 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->cfg->max_clients); 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->num_members == group->cfg->max_clients - 1) 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->beacon_update = 1; 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_update_ies(group); 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->num_members == 0) 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->cfg->idle_update(group->cfg->cb_ctx, 1); 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * p2p_match_dev_type_member - Match client device type with requested type 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @m: Group member 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs) 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 1 on match, 0 on mismatch 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function can be used to match the Requested Device Type attribute in 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPS IE with the device types of a group member for deciding whether a GO 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * should reply to a Probe Request frame. 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int p2p_match_dev_type_member(struct p2p_group_member *m, 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *wps) 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wps_parse_attr attr; 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 num_sec; 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (m->client_info == NULL || wps == NULL) 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = wpabuf_head(m->client_info); 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = pos + wpabuf_len(m->client_info); 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 1 + 2 * ETH_ALEN + 1 + 2; 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - pos < WPS_DEV_TYPE_LEN + 1) 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wps_parse_msg(wps, &attr)) 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* assume no Requested Device Type attributes */ 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (attr.num_req_dev_type == 0) 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* no Requested Device Type attributes -> match */ 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dev_type_list_match(pos, attr.req_dev_type, attr.num_req_dev_type)) 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* Match with client Primary Device Type */ 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += WPS_DEV_TYPE_LEN; 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt num_sec = *pos++; 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - pos < num_sec * WPS_DEV_TYPE_LEN) 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (num_sec > 0) { 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt num_sec--; 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dev_type_list_match(pos, attr.req_dev_type, 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt attr.num_req_dev_type)) 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* Match with client Secondary Device Type */ 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += WPS_DEV_TYPE_LEN; 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* No matching device type found */ 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps) 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *m; 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p2p_match_dev_type(group->p2p, wps)) 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* Match with own device type */ 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (m = group->members; m; m = m->next) { 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p2p_match_dev_type_member(m, wps)) 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; /* Match with group client device type */ 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* No match with Requested Device Type */ 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 773c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtint p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p) 774c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{ 775c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt struct p2p_group_member *m; 776c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt struct p2p_message msg; 777c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 778c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt os_memset(&msg, 0, sizeof(msg)); 779c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt if (p2p_parse_p2p_ie(p2p, &msg)) 780c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt return 1; /* Failed to parse - assume no filter on Device ID */ 781c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 782c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt if (!msg.device_id) 783c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt return 1; /* No filter on Device ID */ 784c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 785c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt if (os_memcmp(msg.device_id, group->p2p->cfg->dev_addr, ETH_ALEN) == 0) 786c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt return 1; /* Match with our P2P Device Address */ 787c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 788c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt for (m = group->members; m; m = m->next) { 789c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt if (os_memcmp(msg.device_id, m->dev_addr, ETH_ALEN) == 0) 790c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt return 1; /* Match with group client P2P Device Address */ 791c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt } 792c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 793c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt /* No match with Device ID */ 794c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt return 0; 795c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt} 796c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 797c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid p2p_group_notif_formation_done(struct p2p_group *group) 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group == NULL) 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->group_formation = 0; 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->beacon_update = 1; 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_update_ies(group); 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_group_notif_noa(struct p2p_group *group, const u8 *noa, 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t noa_len) 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (noa == NULL) { 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(group->noa); 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->noa = NULL; 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->noa) { 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_size(group->noa) >= noa_len) { 817fc41cadcff448cdd2b60e376fc6e7378e2e57b5eDmitry Shmidt group->noa->used = 0; 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(group->noa, noa, noa_len); 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(group->noa); 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->noa = NULL; 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!group->noa) { 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->noa = wpabuf_alloc_copy(noa, noa_len); 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->noa == NULL) 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->beacon_update = 1; 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_group_update_ies(group); 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct p2p_group_member * p2p_group_get_client(struct p2p_group *group, 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *dev_id) 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *m; 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (m = group->members; m; m = m->next) { 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(dev_id, m->dev_addr, ETH_ALEN) == 0) 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return m; 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct p2p_group_member * p2p_group_get_client_iface( 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group *group, const u8 *interface_addr) 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *m; 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (m = group->members; m; m = m->next) { 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(interface_addr, m->addr, ETH_ALEN) == 0) 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return m; 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 8661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtconst u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr) 867dca3979ccdf869f140f096b83df322a0efc84f22Dmitry Shmidt{ 868dca3979ccdf869f140f096b83df322a0efc84f22Dmitry Shmidt struct p2p_group_member *m; 869dca3979ccdf869f140f096b83df322a0efc84f22Dmitry Shmidt 8701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (group == NULL) 8711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return NULL; 872dca3979ccdf869f140f096b83df322a0efc84f22Dmitry Shmidt m = p2p_group_get_client_iface(group, addr); 8731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (m && !is_zero_ether_addr(m->dev_addr)) 874dca3979ccdf869f140f096b83df322a0efc84f22Dmitry Shmidt return m->dev_addr; 8751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return NULL; 876dca3979ccdf869f140f096b83df322a0efc84f22Dmitry Shmidt} 8771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * p2p_build_go_disc_req(void) 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *buf; 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = wpabuf_alloc(100); 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p_buf_add_action_hdr(buf, P2P_GO_DISC_REQ, 0); 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return buf; 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id, 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *searching_dev, int rx_freq) 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *m; 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *req; 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_data *p2p = group->p2p; 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int freq; 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m = p2p_group_get_client(group, dev_id); 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (m == NULL || m->client_info == NULL) { 903b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "Requested client was not in this group " 904b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt MACSTR, MAC2STR(group->cfg->interface_addr)); 9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { 909b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "Requested client does not support client discoverability"); 9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 913b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "Schedule GO Discoverability Request to be sent to " 914b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt MACSTR, MAC2STR(dev_id)); 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req = p2p_build_go_disc_req(); 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req == NULL) 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: Should really use group operating frequency here */ 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt freq = rx_freq; 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p2p->pending_action_state = P2P_PENDING_GO_DISC_REQ; 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr, 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->cfg->interface_addr, 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->cfg->interface_addr, 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_head(req), wpabuf_len(req), 200) < 0) 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 929b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(p2p, "Failed to send Action frame"); 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(req); 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * p2p_group_get_interface_addr(struct p2p_group *group) 9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return group->cfg->interface_addr; 9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 p2p_group_presence_req(struct p2p_group *group, 9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *client_interface_addr, 9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *noa, size_t noa_len) 9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *m; 9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 curr_noa[50]; 9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int curr_noa_len; 9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt m = p2p_group_get_client_iface(group, client_interface_addr); 9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (m == NULL || m->client_info == NULL) { 954b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "Client was not in this group"); 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "P2P: Presence Request NoA", noa, noa_len); 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group->p2p->cfg->get_noa) 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt curr_noa_len = group->p2p->cfg->get_noa( 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group->p2p->cfg->cb_ctx, group->cfg->interface_addr, 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt curr_noa, sizeof(curr_noa)); 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt curr_noa_len = -1; 9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (curr_noa_len < 0) 967b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "Failed to fetch current NoA"); 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (curr_noa_len == 0) 969b6e9aaf735990dc64cdb6efccc03d076768eabf3Dmitry Shmidt p2p_dbg(group->p2p, "No NoA being advertized"); 9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa, 9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt curr_noa_len); 9731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: properly process request and store copy */ 9751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (curr_noa_len > 0 || curr_noa_len == -1) 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; 9771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return P2P_SC_SUCCESS; 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int p2p_get_group_num_members(struct p2p_group *group) 9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return group->num_members; 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * p2p_iterate_group_members(struct p2p_group *group, void **next) 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct p2p_group_member *iter = *next; 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iter) 9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iter = group->members; 9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iter = iter->next; 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *next = iter; 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iter) 10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1002d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt return iter->dev_addr; 10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1004c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 1005c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 1006c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidtint p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr) 1007c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt{ 1008c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt struct p2p_group_member *m; 1009c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 1010c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt for (m = group->members; m; m = m->next) { 1011c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt if (os_memcmp(m->dev_addr, dev_addr, ETH_ALEN) == 0) 1012c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt return 1; 1013c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt } 1014c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 1015c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt return 0; 1016c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt} 101704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 101804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 101904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id, 102004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t group_id_len) 102104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 102204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (group_id_len != ETH_ALEN + group->cfg->ssid_len) 102304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 102404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0) 102504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return 0; 102604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid, 102704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt group->cfg->ssid_len) == 0; 102804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 1029b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt 1030b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt 1031b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidtvoid p2p_group_force_beacon_update_ies(struct p2p_group *group) 1032b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt{ 1033b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt group->beacon_update = 1; 1034b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt p2p_group_update_ies(group); 1035b96dad47218788efffa3db0fe7f1b54a7d19e366Dmitry Shmidt} 1036cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1037cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1038cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint p2p_group_get_freq(struct p2p_group *group) 1039cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{ 1040cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return group->cfg->freq; 1041cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt} 1042d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 1043d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 1044d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidtconst struct p2p_group_config * p2p_group_get_config(struct p2p_group *group) 1045d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt{ 1046d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt return group->cfg; 1047d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt} 1048d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 1049d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 1050d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidtvoid p2p_loop_on_all_groups(struct p2p_data *p2p, 1051d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt int (*group_callback)(struct p2p_group *group, 1052d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt void *user_data), 1053d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt void *user_data) 1054d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt{ 1055d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt unsigned int i; 1056d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt 1057d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt for (i = 0; i < p2p->num_groups; i++) { 1058d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt if (!group_callback(p2p->groups[i], user_data)) 1059d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt break; 1060d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt } 1061d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt} 1062