* 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"
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;
group->group_formation = 1;
group->beacon_update = 1;
p2p_group_update_ies(group);
+ group->cfg->idle_update(group->cfg->cb_ctx, 1);
return group;
}
struct p2p_group_member *m, *prev;
m = group->members;
group->members = NULL;
+ group->num_members = 0;
while (m) {
prev = m;
m = m->next;
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);
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;
- group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
+ 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;
p2p_buf_add_capability(ie, dev_capab, group_capab);
}
}
+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)
{
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);
}
- m->client_info = p2p_build_client_info(addr, m->p2p_ie, &m->dev_capab,
- m->dev_addr);
- if (m->client_info == NULL) {
- p2p_group_free_member(m);
- return -1;
- }
+ p2p_group_remove_member(group, addr);
m->next = group->members;
group->members = m;
-
+ group->num_members++;
+ wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
+ " to group (p2p=%d client_info=%d); num_members=%u/%u",
+ MAC2STR(addr), m->p2p_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;
}
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)) {
+ wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "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);
}
}
}
+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)
} 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);
}
+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;
int freq;
m = p2p_group_get_client(group, dev_id);
- if (m == NULL) {
+ if (m == NULL || m->client_info == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Requested client was not in this "
"group " MACSTR,
MAC2STR(group->cfg->interface_addr));
int curr_noa_len;
m = p2p_group_get_client_iface(group, client_interface_addr);
- if (m == NULL) {
+ if (m == NULL || m->client_info == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Client was not in this group");
return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
}
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)
+{
+ return group->num_members;
+}
+
+
+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->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;
+}