X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=libeap%2Fsrc%2Fp2p%2Fp2p_group.c;h=0d66993465686e9d350a4ee861e75b8d7f188d70;hb=4f319dde67a76fe0aaf33f6d2788968012584ada;hp=4ee84cdedf051ae375801bb632fc36f4057ba43f;hpb=32c7cb5841cb87eb434b1a802f0032b2b71c7d17;p=mech_eap.git diff --git a/libeap/src/p2p/p2p_group.c b/libeap/src/p2p/p2p_group.c index 4ee84cd..0d66993 100644 --- a/libeap/src/p2p/p2p_group.c +++ b/libeap/src/p2p/p2p_group.c @@ -2,14 +2,8 @@ * Wi-Fi Direct - P2P group operations * Copyright (c) 2009-2010, Atheros Communications * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -17,6 +11,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "wps/wps_i.h" #include "p2p_i.h" @@ -28,6 +23,7 @@ struct p2p_group_member { u8 addr[ETH_ALEN]; /* P2P Interface Address */ u8 dev_addr[ETH_ALEN]; /* P2P Device Address */ struct wpabuf *p2p_ie; + struct wpabuf *wfd_ie; struct wpabuf *client_info; u8 dev_capab; }; @@ -39,15 +35,14 @@ struct p2p_group { struct p2p_data *p2p; struct p2p_group_config *cfg; struct p2p_group_member *members; + unsigned int num_members; int group_formation; int beacon_update; struct wpabuf *noa; + struct wpabuf *wfd_ie; }; -static void p2p_group_update_ies(struct p2p_group *group); - - struct p2p_group * p2p_group_init(struct p2p_data *p2p, struct p2p_group_config *config) { @@ -57,8 +52,8 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p, if (group == NULL) return NULL; - groups = os_realloc(p2p->groups, (p2p->num_groups + 1) * - sizeof(struct p2p_group *)); + groups = os_realloc_array(p2p->groups, p2p->num_groups + 1, + sizeof(struct p2p_group *)); if (groups == NULL) { os_free(group); return NULL; @@ -71,6 +66,7 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p, group->group_formation = 1; group->beacon_update = 1; p2p_group_update_ies(group); + group->cfg->idle_update(group->cfg->cb_ctx, 1); return group; } @@ -78,6 +74,7 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p, static void p2p_group_free_member(struct p2p_group_member *m) { + wpabuf_free(m->wfd_ie); wpabuf_free(m->p2p_ie); wpabuf_free(m->client_info); os_free(m); @@ -89,6 +86,7 @@ static void p2p_group_free_members(struct p2p_group *group) struct p2p_group_member *m, *prev; m = group->members; group->members = NULL; + group->num_members = 0; while (m) { prev = m; m = m->next; @@ -121,12 +119,15 @@ void p2p_group_deinit(struct p2p_group *group) p2p_group_free_members(group); os_free(group->cfg); wpabuf_free(group->noa); + wpabuf_free(group->wfd_ie); os_free(group); } static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m) { + if (m->client_info == NULL) + return; if (wpabuf_tailroom(ie) < wpabuf_len(m->client_info) + 1) return; wpabuf_put_buf(ie, m->client_info); @@ -136,20 +137,25 @@ static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m) static void p2p_group_add_common_ies(struct p2p_group *group, struct wpabuf *ie) { - u8 dev_capab = 0, group_capab = 0; + u8 dev_capab = group->p2p->dev_capab, group_capab = 0; /* P2P Capability */ - dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY; - dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE; + dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; - if (group->cfg->persistent_group) + if (group->cfg->persistent_group) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (group->cfg->persistent_group == 2) + group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (group->p2p->cfg->p2p_intra_bss) group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; if (group->group_formation) group_capab |= P2P_GROUP_CAPAB_GROUP_FORMATION; if (group->p2p->cross_connect) group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; + if (group->num_members >= group->cfg->max_clients) + group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT; + group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION; p2p_buf_add_capability(ie, dev_capab, group_capab); } @@ -165,15 +171,68 @@ static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa) } +static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems) +{ + struct wpabuf *ie; + const u8 *pos, *end; + size_t len; + + if (subelems == NULL) + return NULL; + + len = wpabuf_len(subelems) + 100; + + ie = wpabuf_alloc(len); + if (ie == NULL) + return NULL; + + pos = wpabuf_head(subelems); + end = pos + wpabuf_len(subelems); + + while (end > pos) { + size_t frag_len = end - pos; + if (frag_len > 251) + frag_len = 251; + wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(ie, 4 + frag_len); + wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE); + wpabuf_put_data(ie, pos, frag_len); + pos += frag_len; + } + + return ie; +} + + static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) { struct wpabuf *ie; u8 *len; + size_t extra = 0; - ie = wpabuf_alloc(257); +#ifdef CONFIG_WIFI_DISPLAY + if (group->p2p->wfd_ie_beacon) + extra = wpabuf_len(group->p2p->wfd_ie_beacon); +#endif /* CONFIG_WIFI_DISPLAY */ + + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) + extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); + + ie = wpabuf_alloc(257 + extra); if (ie == NULL) return NULL; +#ifdef CONFIG_WIFI_DISPLAY + if (group->p2p->wfd_ie_beacon) + wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon); +#endif /* CONFIG_WIFI_DISPLAY */ + + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) + wpabuf_put_buf(ie, + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); + len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); @@ -184,44 +243,248 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) } -static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) +#ifdef CONFIG_WIFI_DISPLAY + +struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g) +{ + return g->wfd_ie; +} + + +struct wpabuf * wifi_display_encaps(struct wpabuf *subelems) { - u8 *group_info; struct wpabuf *ie; + const u8 *pos, *end; + + if (subelems == NULL) + return NULL; + + ie = wpabuf_alloc(wpabuf_len(subelems) + 100); + if (ie == NULL) + return NULL; + + pos = wpabuf_head(subelems); + end = pos + wpabuf_len(subelems); + + while (end > pos) { + size_t frag_len = end - pos; + if (frag_len > 251) + frag_len = 251; + wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(ie, 4 + frag_len); + wpabuf_put_be32(ie, WFD_IE_VENDOR_TYPE); + wpabuf_put_data(ie, pos, frag_len); + pos += frag_len; + } + + return ie; +} + + +static int wifi_display_add_dev_info_descr(struct wpabuf *buf, + struct p2p_group_member *m) +{ + const u8 *pos, *end; + const u8 *dev_info = NULL; + const u8 *assoc_bssid = NULL; + const u8 *coupled_sink = NULL; + u8 zero_addr[ETH_ALEN]; + + if (m->wfd_ie == NULL) + return 0; + + os_memset(zero_addr, 0, ETH_ALEN); + pos = wpabuf_head_u8(m->wfd_ie); + end = pos + wpabuf_len(m->wfd_ie); + while (pos + 1 < end) { + u8 id; + u16 len; + + id = *pos++; + len = WPA_GET_BE16(pos); + pos += 2; + if (pos + len > end) + break; + + switch (id) { + case WFD_SUBELEM_DEVICE_INFO: + if (len < 6) + break; + dev_info = pos; + break; + case WFD_SUBELEM_ASSOCIATED_BSSID: + if (len < ETH_ALEN) + break; + assoc_bssid = pos; + break; + case WFD_SUBELEM_COUPLED_SINK: + if (len < 1 + ETH_ALEN) + break; + coupled_sink = pos; + break; + } + + pos += len; + } + + if (dev_info == NULL) + return 0; + + wpabuf_put_u8(buf, 23); + wpabuf_put_data(buf, m->dev_addr, ETH_ALEN); + if (assoc_bssid) + wpabuf_put_data(buf, assoc_bssid, ETH_ALEN); + else + wpabuf_put_data(buf, zero_addr, ETH_ALEN); + wpabuf_put_data(buf, dev_info, 2); /* WFD Device Info */ + wpabuf_put_data(buf, dev_info + 4, 2); /* WFD Device Max Throughput */ + if (coupled_sink) { + wpabuf_put_data(buf, coupled_sink, 1 + ETH_ALEN); + } else { + wpabuf_put_u8(buf, 0); + wpabuf_put_data(buf, zero_addr, ETH_ALEN); + } + + return 1; +} + + +static struct wpabuf * +wifi_display_build_go_ie(struct p2p_group *group) +{ + struct wpabuf *wfd_subelems, *wfd_ie; struct p2p_group_member *m; u8 *len; + unsigned int count = 0; - ie = wpabuf_alloc(257); - if (ie == NULL) + if (!group->p2p->wfd_ie_probe_resp) return NULL; - len = p2p_buf_add_ie_hdr(ie); + wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) + + group->num_members * 24 + 100); + if (wfd_subelems == NULL) + return NULL; + if (group->p2p->wfd_dev_info) + wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info); + if (group->p2p->wfd_assoc_bssid) + wpabuf_put_buf(wfd_subelems, + group->p2p->wfd_assoc_bssid); + if (group->p2p->wfd_coupled_sink_info) + wpabuf_put_buf(wfd_subelems, + group->p2p->wfd_coupled_sink_info); + + /* Build WFD Session Info */ + wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO); + len = wpabuf_put(wfd_subelems, 2); + m = group->members; + while (m) { + if (wifi_display_add_dev_info_descr(wfd_subelems, m)) + count++; + m = m->next; + } - p2p_group_add_common_ies(group, ie); - p2p_group_add_noa(ie, group->noa); + if (count == 0) { + /* No Wi-Fi Display clients - do not include subelement */ + wfd_subelems->used -= 3; + } else { + WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len - + 2); + p2p_dbg(group->p2p, "WFD: WFD Session Info: %u descriptors", + count); + } - /* P2P Device Info */ - p2p_buf_add_device_info(ie, group->p2p, NULL); - - /* P2P Group Info */ - group_info = wpabuf_put(ie, 0); - wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO); - wpabuf_put_le16(ie, 0); /* Length to be filled */ - for (m = group->members; m; m = m->next) - p2p_client_info(ie, m); + wfd_ie = wifi_display_encaps(wfd_subelems); + wpabuf_free(wfd_subelems); + + return wfd_ie; +} + +static void wifi_display_group_update(struct p2p_group *group) +{ + wpabuf_free(group->wfd_ie); + group->wfd_ie = wifi_display_build_go_ie(group); +} + +#endif /* CONFIG_WIFI_DISPLAY */ + + +void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf, + int max_clients) +{ + u8 *group_info; + int count = 0; + struct p2p_group_member *m; + + p2p_dbg(group->p2p, "* P2P Group Info"); + group_info = wpabuf_put(buf, 0); + wpabuf_put_u8(buf, P2P_ATTR_GROUP_INFO); + wpabuf_put_le16(buf, 0); /* Length to be filled */ + for (m = group->members; m; m = m->next) { + p2p_client_info(buf, m); + count++; + if (max_clients >= 0 && count >= max_clients) + break; + } WPA_PUT_LE16(group_info + 1, - (u8 *) wpabuf_put(ie, 0) - group_info - 3); + (u8 *) wpabuf_put(buf, 0) - group_info - 3); +} + + +void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf) +{ + p2p_buf_add_group_id(buf, group->p2p->cfg->dev_addr, group->cfg->ssid, + group->cfg->ssid_len); +} + + +static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) +{ + struct wpabuf *p2p_subelems, *ie; + + p2p_subelems = wpabuf_alloc(500); + if (p2p_subelems == NULL) + return NULL; + + p2p_group_add_common_ies(group, p2p_subelems); + p2p_group_add_noa(p2p_subelems, group->noa); + + /* P2P Device Info */ + p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL); + + /* P2P Group Info: Only when at least one P2P Client is connected */ + if (group->members) + p2p_buf_add_group_info(group, p2p_subelems, -1); + + ie = p2p_group_encaps_probe_resp(p2p_subelems); + wpabuf_free(p2p_subelems); + + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]) { + struct wpabuf *extra; + extra = wpabuf_dup(group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]); + ie = wpabuf_concat(extra, ie); + } + +#ifdef CONFIG_WIFI_DISPLAY + if (group->wfd_ie) { + struct wpabuf *wfd = wpabuf_dup(group->wfd_ie); + ie = wpabuf_concat(wfd, ie); + } +#endif /* CONFIG_WIFI_DISPLAY */ - p2p_buf_update_ie_hdr(ie, len); return ie; } -static void p2p_group_update_ies(struct p2p_group *group) +void p2p_group_update_ies(struct p2p_group *group) { struct wpabuf *beacon_ie; struct wpabuf *probe_resp_ie; +#ifdef CONFIG_WIFI_DISPLAY + wifi_display_group_update(group); +#endif /* CONFIG_WIFI_DISPLAY */ + probe_resp_ie = p2p_group_build_probe_resp_ie(group); if (probe_resp_ie == NULL) return; @@ -303,6 +566,36 @@ static struct wpabuf * p2p_build_client_info(const u8 *addr, } +static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr) +{ + struct p2p_group_member *m, *prev; + + if (group == NULL) + return 0; + + m = group->members; + prev = NULL; + while (m) { + if (os_memcmp(m->addr, addr, ETH_ALEN) == 0) + break; + prev = m; + m = m->next; + } + + if (m == NULL) + return 0; + + if (prev) + prev->next = m->next; + else + group->members = m->next; + p2p_group_free_member(m); + group->num_members--; + + return 1; +} + + int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, const u8 *ie, size_t len) { @@ -311,37 +604,37 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, if (group == NULL) return -1; + p2p_add_device(group->p2p, addr, 0, NULL, 0, ie, len, 0); + m = os_zalloc(sizeof(*m)); if (m == NULL) return -1; os_memcpy(m->addr, addr, ETH_ALEN); m->p2p_ie = ieee802_11_vendor_ie_concat(ie, len, P2P_IE_VENDOR_TYPE); - if (m->p2p_ie == NULL) { - p2p_group_free_member(m); - return -1; + if (m->p2p_ie) { + m->client_info = p2p_build_client_info(addr, m->p2p_ie, + &m->dev_capab, + m->dev_addr); } +#ifdef CONFIG_WIFI_DISPLAY + m->wfd_ie = ieee802_11_vendor_ie_concat(ie, len, WFD_IE_VENDOR_TYPE); +#endif /* CONFIG_WIFI_DISPLAY */ - m->client_info = p2p_build_client_info(addr, m->p2p_ie, &m->dev_capab, - m->dev_addr); - if (m->client_info == NULL) { - /* - * This can happen, e.g., when a P2P client connects to a P2P - * group using the infrastructure WLAN interface instead of - * P2P group interface. In that case, the P2P client may behave - * as if the GO would be a P2P Manager WLAN AP. - */ - wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Could not build Client Info from P2P IE - " - "assume " MACSTR " is not a P2P client", - MAC2STR(addr)); - p2p_group_free_member(m); - return 0; - } + p2p_group_remove_member(group, addr); m->next = group->members; group->members = m; - + group->num_members++; + p2p_dbg(group->p2p, "Add client " MACSTR + " to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u", + MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0, + m->client_info ? 1 : 0, + group->num_members, group->cfg->max_clients); + if (group->num_members == group->cfg->max_clients) + group->beacon_update = 1; p2p_group_update_ies(group); + if (group->num_members == 1) + group->cfg->idle_update(group->cfg->cb_ctx, 0); return 0; } @@ -351,6 +644,16 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) { struct wpabuf *resp; u8 *rlen; + size_t extra = 0; + +#ifdef CONFIG_WIFI_DISPLAY + if (group->wfd_ie) + extra = wpabuf_len(group->wfd_ie); +#endif /* CONFIG_WIFI_DISPLAY */ + + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]) + extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]); /* * (Re)Association Response - P2P IE @@ -358,9 +661,20 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) * denied) * Extended Listen Timing (may be present) */ - resp = wpabuf_alloc(20); + resp = wpabuf_alloc(20 + extra); if (resp == NULL) return NULL; + +#ifdef CONFIG_WIFI_DISPLAY + if (group->wfd_ie) + wpabuf_put_buf(resp, group->wfd_ie); +#endif /* CONFIG_WIFI_DISPLAY */ + + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]) + wpabuf_put_buf(resp, + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]); + rlen = p2p_buf_add_ie_hdr(resp); if (status != P2P_SC_SUCCESS) p2p_buf_add_status(resp, status); @@ -372,27 +686,16 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr) { - struct p2p_group_member *m, *prev; - - if (group == NULL) - return; - - m = group->members; - prev = NULL; - while (m) { - if (os_memcmp(m->addr, addr, ETH_ALEN) == 0) - break; - prev = m; - m = m->next; - } - - if (m) { - if (prev) - prev->next = m->next; - else - group->members = m->next; - p2p_group_free_member(m); + if (p2p_group_remove_member(group, addr)) { + p2p_dbg(group->p2p, "Remove client " MACSTR + " from group; num_members=%u/%u", + MAC2STR(addr), group->num_members, + group->cfg->max_clients); + if (group->num_members == group->cfg->max_clients - 1) + group->beacon_update = 1; p2p_group_update_ies(group); + if (group->num_members == 0) + group->cfg->idle_update(group->cfg->cb_ctx, 1); } } @@ -467,6 +770,31 @@ int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps) } +int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p) +{ + struct p2p_group_member *m; + struct p2p_message msg; + + os_memset(&msg, 0, sizeof(msg)); + if (p2p_parse_p2p_ie(p2p, &msg)) + return 1; /* Failed to parse - assume no filter on Device ID */ + + if (!msg.device_id) + return 1; /* No filter on Device ID */ + + if (os_memcmp(msg.device_id, group->p2p->cfg->dev_addr, ETH_ALEN) == 0) + return 1; /* Match with our P2P Device Address */ + + for (m = group->members; m; m = m->next) { + if (os_memcmp(msg.device_id, m->dev_addr, ETH_ALEN) == 0) + return 1; /* Match with group client P2P Device Address */ + } + + /* No match with Device ID */ + return 0; +} + + void p2p_group_notif_formation_done(struct p2p_group *group) { if (group == NULL) @@ -486,7 +814,7 @@ int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa, } else { if (group->noa) { if (wpabuf_size(group->noa) >= noa_len) { - group->noa->size = 0; + group->noa->used = 0; wpabuf_put_data(group->noa, noa, noa_len); } else { wpabuf_free(group->noa); @@ -535,6 +863,19 @@ static struct p2p_group_member * p2p_group_get_client_iface( } +const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr) +{ + struct p2p_group_member *m; + + if (group == NULL) + return NULL; + m = p2p_group_get_client_iface(group, addr); + if (m && !is_zero_ether_addr(m->dev_addr)) + return m->dev_addr; + return NULL; +} + + static struct wpabuf * p2p_build_go_disc_req(void) { struct wpabuf *buf; @@ -558,21 +899,19 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id, int freq; m = p2p_group_get_client(group, dev_id); - if (m == NULL) { - wpa_printf(MSG_DEBUG, "P2P: Requested client was not in this " - "group " MACSTR, - MAC2STR(group->cfg->interface_addr)); + if (m == NULL || m->client_info == NULL) { + p2p_dbg(group->p2p, "Requested client was not in this group " + MACSTR, MAC2STR(group->cfg->interface_addr)); return -1; } if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { - wpa_printf(MSG_DEBUG, "P2P: Requested client does not support " - "client discoverability"); + p2p_dbg(group->p2p, "Requested client does not support client discoverability"); return -1; } - wpa_printf(MSG_DEBUG, "P2P: Schedule GO Discoverability Request to be " - "sent to " MACSTR, MAC2STR(dev_id)); + p2p_dbg(group->p2p, "Schedule GO Discoverability Request to be sent to " + MACSTR, MAC2STR(dev_id)); req = p2p_build_go_disc_req(); if (req == NULL) @@ -587,8 +926,7 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id, group->cfg->interface_addr, wpabuf_head(req), wpabuf_len(req), 200) < 0) { - wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, - "P2P: Failed to send Action frame"); + p2p_dbg(p2p, "Failed to send Action frame"); } wpabuf_free(req); @@ -612,8 +950,8 @@ u8 p2p_group_presence_req(struct p2p_group *group, int curr_noa_len; m = p2p_group_get_client_iface(group, client_interface_addr); - if (m == NULL) { - wpa_printf(MSG_DEBUG, "P2P: Client was not in this group"); + if (m == NULL || m->client_info == NULL) { + p2p_dbg(group->p2p, "Client was not in this group"); return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; } @@ -626,16 +964,150 @@ u8 p2p_group_presence_req(struct p2p_group *group, else curr_noa_len = -1; if (curr_noa_len < 0) - wpa_printf(MSG_DEBUG, "P2P: Failed to fetch current NoA"); + p2p_dbg(group->p2p, "Failed to fetch current NoA"); else if (curr_noa_len == 0) - wpa_printf(MSG_DEBUG, "P2P: No NoA being advertized"); + p2p_dbg(group->p2p, "No NoA being advertized"); else wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa, curr_noa_len); /* TODO: properly process request and store copy */ - if (curr_noa_len > 0) + if (curr_noa_len > 0 || curr_noa_len == -1) return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; return P2P_SC_SUCCESS; } + + +unsigned int p2p_get_group_num_members(struct p2p_group *group) +{ + if (!group) + return 0; + + return group->num_members; +} + + +int p2p_client_limit_reached(struct p2p_group *group) +{ + if (!group || !group->cfg) + return 1; + + return group->num_members >= group->cfg->max_clients; +} + + +const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next) +{ + struct p2p_group_member *iter = *next; + + if (!iter) + iter = group->members; + else + iter = iter->next; + + *next = iter; + + if (!iter) + return NULL; + + return iter->dev_addr; +} + + +int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr) +{ + struct p2p_group_member *m; + + for (m = group->members; m; m = m->next) { + if (os_memcmp(m->dev_addr, dev_addr, ETH_ALEN) == 0) + return 1; + } + + return 0; +} + + +int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id, + size_t group_id_len) +{ + if (group_id_len != ETH_ALEN + group->cfg->ssid_len) + return 0; + if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0) + return 0; + return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid, + group->cfg->ssid_len) == 0; +} + + +void p2p_group_force_beacon_update_ies(struct p2p_group *group) +{ + group->beacon_update = 1; + p2p_group_update_ies(group); +} + + +int p2p_group_get_freq(struct p2p_group *group) +{ + return group->cfg->freq; +} + + +const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group) +{ + return group->cfg; +} + + +void p2p_loop_on_all_groups(struct p2p_data *p2p, + int (*group_callback)(struct p2p_group *group, + void *user_data), + void *user_data) +{ + unsigned int i; + + for (i = 0; i < p2p->num_groups; i++) { + if (!group_callback(p2p->groups[i], user_data)) + break; + } +} + + +int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs, + unsigned int *num) + +{ + struct p2p_channels intersect, res; + struct p2p_group_member *m; + + if (!group || !common_freqs || !num) + return -1; + + os_memset(&intersect, 0, sizeof(intersect)); + os_memset(&res, 0, sizeof(res)); + + p2p_channels_union(&intersect, &group->p2p->cfg->channels, + &intersect); + + p2p_channels_dump(group->p2p, + "Group common freqs before iterating members", + &intersect); + + for (m = group->members; m; m = m->next) { + struct p2p_device *dev; + + dev = p2p_get_device(group->p2p, m->dev_addr); + if (!dev) + continue; + + p2p_channels_intersect(&intersect, &dev->channels, &res); + intersect = res; + } + + p2p_channels_dump(group->p2p, "Group common channels", &intersect); + + os_memset(common_freqs, 0, *num * sizeof(int)); + *num = p2p_channels_to_freqs(&intersect, common_freqs, *num); + + return 0; +}