LCOV - code coverage report
Current view: top level - src/p2p - p2p_group.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 388 509 76.2 %
Date: 2014-05-28 Functions: 35 41 85.4 %

          Line data    Source code
       1             : /*
       2             :  * Wi-Fi Direct - P2P group operations
       3             :  * Copyright (c) 2009-2010, Atheros Communications
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "common/ieee802_11_defs.h"
      13             : #include "common/ieee802_11_common.h"
      14             : #include "wps/wps_defs.h"
      15             : #include "wps/wps_i.h"
      16             : #include "p2p_i.h"
      17             : #include "p2p.h"
      18             : 
      19             : 
      20             : struct p2p_group_member {
      21             :         struct p2p_group_member *next;
      22             :         u8 addr[ETH_ALEN]; /* P2P Interface Address */
      23             :         u8 dev_addr[ETH_ALEN]; /* P2P Device Address */
      24             :         struct wpabuf *p2p_ie;
      25             :         struct wpabuf *wfd_ie;
      26             :         struct wpabuf *client_info;
      27             :         u8 dev_capab;
      28             : };
      29             : 
      30             : /**
      31             :  * struct p2p_group - Internal P2P module per-group data
      32             :  */
      33             : struct p2p_group {
      34             :         struct p2p_data *p2p;
      35             :         struct p2p_group_config *cfg;
      36             :         struct p2p_group_member *members;
      37             :         unsigned int num_members;
      38             :         int group_formation;
      39             :         int beacon_update;
      40             :         struct wpabuf *noa;
      41             :         struct wpabuf *wfd_ie;
      42             : };
      43             : 
      44             : 
      45         126 : struct p2p_group * p2p_group_init(struct p2p_data *p2p,
      46             :                                   struct p2p_group_config *config)
      47             : {
      48             :         struct p2p_group *group, **groups;
      49             : 
      50         126 :         group = os_zalloc(sizeof(*group));
      51         126 :         if (group == NULL)
      52           0 :                 return NULL;
      53             : 
      54         126 :         groups = os_realloc_array(p2p->groups, p2p->num_groups + 1,
      55             :                                   sizeof(struct p2p_group *));
      56         126 :         if (groups == NULL) {
      57           0 :                 os_free(group);
      58           0 :                 return NULL;
      59             :         }
      60         126 :         groups[p2p->num_groups++] = group;
      61         126 :         p2p->groups = groups;
      62             : 
      63         126 :         group->p2p = p2p;
      64         126 :         group->cfg = config;
      65         126 :         group->group_formation = 1;
      66         126 :         group->beacon_update = 1;
      67         126 :         p2p_group_update_ies(group);
      68         126 :         group->cfg->idle_update(group->cfg->cb_ctx, 1);
      69             : 
      70         126 :         return group;
      71             : }
      72             : 
      73             : 
      74         256 : static void p2p_group_free_member(struct p2p_group_member *m)
      75             : {
      76         256 :         wpabuf_free(m->wfd_ie);
      77         256 :         wpabuf_free(m->p2p_ie);
      78         256 :         wpabuf_free(m->client_info);
      79         256 :         os_free(m);
      80         256 : }
      81             : 
      82             : 
      83         126 : static void p2p_group_free_members(struct p2p_group *group)
      84             : {
      85             :         struct p2p_group_member *m, *prev;
      86         126 :         m = group->members;
      87         126 :         group->members = NULL;
      88         126 :         group->num_members = 0;
      89         338 :         while (m) {
      90          86 :                 prev = m;
      91          86 :                 m = m->next;
      92          86 :                 p2p_group_free_member(prev);
      93             :         }
      94         126 : }
      95             : 
      96             : 
      97         126 : void p2p_group_deinit(struct p2p_group *group)
      98             : {
      99             :         size_t g;
     100             :         struct p2p_data *p2p;
     101             : 
     102         126 :         if (group == NULL)
     103         126 :                 return;
     104             : 
     105         126 :         p2p = group->p2p;
     106             : 
     107         126 :         for (g = 0; g < p2p->num_groups; g++) {
     108         126 :                 if (p2p->groups[g] == group) {
     109         252 :                         while (g + 1 < p2p->num_groups) {
     110           0 :                                 p2p->groups[g] = p2p->groups[g + 1];
     111           0 :                                 g++;
     112             :                         }
     113         126 :                         p2p->num_groups--;
     114         126 :                         break;
     115             :                 }
     116             :         }
     117             : 
     118         126 :         p2p_group_free_members(group);
     119         126 :         os_free(group->cfg);
     120         126 :         wpabuf_free(group->noa);
     121         126 :         wpabuf_free(group->wfd_ie);
     122         126 :         os_free(group);
     123             : }
     124             : 
     125             : 
     126         379 : static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m)
     127             : {
     128         379 :         if (m->client_info == NULL)
     129          37 :                 return;
     130         342 :         if (wpabuf_tailroom(ie) < wpabuf_len(m->client_info) + 1)
     131           0 :                 return;
     132         342 :         wpabuf_put_buf(ie, m->client_info);
     133             : }
     134             : 
     135             : 
     136         922 : static void p2p_group_add_common_ies(struct p2p_group *group,
     137             :                                      struct wpabuf *ie)
     138             : {
     139         922 :         u8 dev_capab = group->p2p->dev_capab, group_capab = 0;
     140             : 
     141             :         /* P2P Capability */
     142         922 :         dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
     143         922 :         group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
     144         922 :         if (group->cfg->persistent_group) {
     145         202 :                 group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
     146         202 :                 if (group->cfg->persistent_group == 2)
     147         152 :                         group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
     148             :         }
     149         922 :         if (group->p2p->cfg->p2p_intra_bss)
     150         922 :                 group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
     151         922 :         if (group->group_formation)
     152         317 :                 group_capab |= P2P_GROUP_CAPAB_GROUP_FORMATION;
     153         922 :         if (group->p2p->cross_connect)
     154           0 :                 group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
     155         922 :         if (group->num_members >= group->cfg->max_clients)
     156           0 :                 group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT;
     157         922 :         group_capab |= P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION;
     158         922 :         p2p_buf_add_capability(ie, dev_capab, group_capab);
     159         922 : }
     160             : 
     161             : 
     162         922 : static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa)
     163             : {
     164         922 :         if (noa == NULL)
     165        1844 :                 return;
     166             :         /* Notice of Absence */
     167           0 :         wpabuf_put_u8(ie, P2P_ATTR_NOTICE_OF_ABSENCE);
     168           0 :         wpabuf_put_le16(ie, wpabuf_len(noa));
     169           0 :         wpabuf_put_buf(ie, noa);
     170             : }
     171             : 
     172             : 
     173         671 : static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems)
     174             : {
     175             :         struct wpabuf *ie;
     176             :         const u8 *pos, *end;
     177             :         size_t len;
     178             : 
     179         671 :         if (subelems == NULL)
     180           0 :                 return NULL;
     181             : 
     182         671 :         len = wpabuf_len(subelems) + 100;
     183             : 
     184         671 :         ie = wpabuf_alloc(len);
     185         671 :         if (ie == NULL)
     186           0 :                 return NULL;
     187             : 
     188         671 :         pos = wpabuf_head(subelems);
     189         671 :         end = pos + wpabuf_len(subelems);
     190             : 
     191        2013 :         while (end > pos) {
     192         671 :                 size_t frag_len = end - pos;
     193         671 :                 if (frag_len > 251)
     194           0 :                         frag_len = 251;
     195         671 :                 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
     196         671 :                 wpabuf_put_u8(ie, 4 + frag_len);
     197         671 :                 wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE);
     198         671 :                 wpabuf_put_data(ie, pos, frag_len);
     199         671 :                 pos += frag_len;
     200             :         }
     201             : 
     202         671 :         return ie;
     203             : }
     204             : 
     205             : 
     206         251 : static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
     207             : {
     208             :         struct wpabuf *ie;
     209             :         u8 *len;
     210         251 :         size_t extra = 0;
     211             : 
     212             : #ifdef CONFIG_WIFI_DISPLAY
     213         251 :         if (group->p2p->wfd_ie_beacon)
     214           2 :                 extra = wpabuf_len(group->p2p->wfd_ie_beacon);
     215             : #endif /* CONFIG_WIFI_DISPLAY */
     216             : 
     217         251 :         ie = wpabuf_alloc(257 + extra);
     218         251 :         if (ie == NULL)
     219           0 :                 return NULL;
     220             : 
     221             : #ifdef CONFIG_WIFI_DISPLAY
     222         251 :         if (group->p2p->wfd_ie_beacon)
     223           2 :                 wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon);
     224             : #endif /* CONFIG_WIFI_DISPLAY */
     225             : 
     226         251 :         len = p2p_buf_add_ie_hdr(ie);
     227         251 :         p2p_group_add_common_ies(group, ie);
     228         251 :         p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
     229         251 :         p2p_group_add_noa(ie, group->noa);
     230         251 :         p2p_buf_update_ie_hdr(ie, len);
     231             : 
     232         251 :         return ie;
     233             : }
     234             : 
     235             : 
     236             : #ifdef CONFIG_WIFI_DISPLAY
     237             : 
     238           0 : struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g)
     239             : {
     240           0 :         return g->wfd_ie;
     241             : }
     242             : 
     243             : 
     244         142 : struct wpabuf * wifi_display_encaps(struct wpabuf *subelems)
     245             : {
     246             :         struct wpabuf *ie;
     247             :         const u8 *pos, *end;
     248             : 
     249         142 :         if (subelems == NULL)
     250           0 :                 return NULL;
     251             : 
     252         142 :         ie = wpabuf_alloc(wpabuf_len(subelems) + 100);
     253         142 :         if (ie == NULL)
     254           0 :                 return NULL;
     255             : 
     256         142 :         pos = wpabuf_head(subelems);
     257         142 :         end = pos + wpabuf_len(subelems);
     258             : 
     259         394 :         while (end > pos) {
     260         110 :                 size_t frag_len = end - pos;
     261         110 :                 if (frag_len > 251)
     262           0 :                         frag_len = 251;
     263         110 :                 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
     264         110 :                 wpabuf_put_u8(ie, 4 + frag_len);
     265         110 :                 wpabuf_put_be32(ie, WFD_IE_VENDOR_TYPE);
     266         110 :                 wpabuf_put_data(ie, pos, frag_len);
     267         110 :                 pos += frag_len;
     268             :         }
     269             : 
     270         142 :         return ie;
     271             : }
     272             : 
     273             : 
     274           4 : static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
     275             :                                            struct p2p_group_member *m)
     276             : {
     277             :         const u8 *pos, *end;
     278           4 :         const u8 *dev_info = NULL;
     279           4 :         const u8 *assoc_bssid = NULL;
     280           4 :         const u8 *coupled_sink = NULL;
     281             :         u8 zero_addr[ETH_ALEN];
     282             : 
     283           4 :         if (m->wfd_ie == NULL)
     284           0 :                 return 0;
     285             : 
     286           4 :         os_memset(zero_addr, 0, ETH_ALEN);
     287           4 :         pos = wpabuf_head_u8(m->wfd_ie);
     288           4 :         end = pos + wpabuf_len(m->wfd_ie);
     289          20 :         while (pos + 1 < end) {
     290             :                 u8 id;
     291             :                 u16 len;
     292             : 
     293          12 :                 id = *pos++;
     294          12 :                 len = WPA_GET_BE16(pos);
     295          12 :                 pos += 2;
     296          12 :                 if (pos + len > end)
     297           0 :                         break;
     298             : 
     299          12 :                 switch (id) {
     300             :                 case WFD_SUBELEM_DEVICE_INFO:
     301           4 :                         if (len < 6)
     302           0 :                                 break;
     303           4 :                         dev_info = pos;
     304           4 :                         break;
     305             :                 case WFD_SUBELEM_ASSOCIATED_BSSID:
     306           4 :                         if (len < ETH_ALEN)
     307           0 :                                 break;
     308           4 :                         assoc_bssid = pos;
     309           4 :                         break;
     310             :                 case WFD_SUBELEM_COUPLED_SINK:
     311           4 :                         if (len < 1 + ETH_ALEN)
     312           0 :                                 break;
     313           4 :                         coupled_sink = pos;
     314           4 :                         break;
     315             :                 }
     316             : 
     317          12 :                 pos += len;
     318             :         }
     319             : 
     320           4 :         if (dev_info == NULL)
     321           0 :                 return 0;
     322             : 
     323           4 :         wpabuf_put_u8(buf, 23);
     324           4 :         wpabuf_put_data(buf, m->dev_addr, ETH_ALEN);
     325           4 :         if (assoc_bssid)
     326           4 :                 wpabuf_put_data(buf, assoc_bssid, ETH_ALEN);
     327             :         else
     328           0 :                 wpabuf_put_data(buf, zero_addr, ETH_ALEN);
     329           4 :         wpabuf_put_data(buf, dev_info, 2); /* WFD Device Info */
     330           4 :         wpabuf_put_data(buf, dev_info + 4, 2); /* WFD Device Max Throughput */
     331           4 :         if (coupled_sink) {
     332           4 :                 wpabuf_put_data(buf, coupled_sink, 1 + ETH_ALEN);
     333             :         } else {
     334           0 :                 wpabuf_put_u8(buf, 0);
     335           0 :                 wpabuf_put_data(buf, zero_addr, ETH_ALEN);
     336             :         }
     337             : 
     338           4 :         return 1;
     339             : }
     340             : 
     341             : 
     342             : static struct wpabuf *
     343         671 : wifi_display_build_go_ie(struct p2p_group *group)
     344             : {
     345             :         struct wpabuf *wfd_subelems, *wfd_ie;
     346             :         struct p2p_group_member *m;
     347             :         u8 *len;
     348         671 :         unsigned int count = 0;
     349             : 
     350         671 :         if (!group->p2p->wfd_ie_probe_resp)
     351         665 :                 return NULL;
     352             : 
     353          12 :         wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) +
     354           6 :                                     group->num_members * 24 + 100);
     355           6 :         if (wfd_subelems == NULL)
     356           0 :                 return NULL;
     357           6 :         if (group->p2p->wfd_dev_info)
     358           6 :                 wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info);
     359           6 :         if (group->p2p->wfd_assoc_bssid)
     360           0 :                 wpabuf_put_buf(wfd_subelems,
     361           0 :                                group->p2p->wfd_assoc_bssid);
     362           6 :         if (group->p2p->wfd_coupled_sink_info)
     363           0 :                 wpabuf_put_buf(wfd_subelems,
     364           0 :                                group->p2p->wfd_coupled_sink_info);
     365             : 
     366             :         /* Build WFD Session Info */
     367           6 :         wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO);
     368           6 :         len = wpabuf_put(wfd_subelems, 2);
     369           6 :         m = group->members;
     370          16 :         while (m) {
     371           4 :                 if (wifi_display_add_dev_info_descr(wfd_subelems, m))
     372           4 :                         count++;
     373           4 :                 m = m->next;
     374             :         }
     375             : 
     376           6 :         if (count == 0) {
     377             :                 /* No Wi-Fi Display clients - do not include subelement */
     378           2 :                 wfd_subelems->used -= 3;
     379             :         } else {
     380           4 :                 WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len -
     381             :                              2);
     382           4 :                 p2p_dbg(group->p2p, "WFD: WFD Session Info: %u descriptors",
     383             :                         count);
     384             :         }
     385             : 
     386           6 :         wfd_ie = wifi_display_encaps(wfd_subelems);
     387           6 :         wpabuf_free(wfd_subelems);
     388             : 
     389           6 :         return wfd_ie;
     390             : }
     391             : 
     392         671 : static void wifi_display_group_update(struct p2p_group *group)
     393             : {
     394         671 :         wpabuf_free(group->wfd_ie);
     395         671 :         group->wfd_ie = wifi_display_build_go_ie(group);
     396         671 : }
     397             : 
     398             : #endif /* CONFIG_WIFI_DISPLAY */
     399             : 
     400             : 
     401         350 : void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf,
     402             :                             int max_clients)
     403             : {
     404             :         u8 *group_info;
     405         350 :         int count = 0;
     406             :         struct p2p_group_member *m;
     407             : 
     408         350 :         p2p_dbg(group->p2p, "* P2P Group Info");
     409         350 :         group_info = wpabuf_put(buf, 0);
     410         350 :         wpabuf_put_u8(buf, P2P_ATTR_GROUP_INFO);
     411         350 :         wpabuf_put_le16(buf, 0); /* Length to be filled */
     412         729 :         for (m = group->members; m; m = m->next) {
     413         379 :                 p2p_client_info(buf, m);
     414         379 :                 count++;
     415         379 :                 if (max_clients >= 0 && count >= max_clients)
     416           0 :                         break;
     417             :         }
     418         350 :         WPA_PUT_LE16(group_info + 1,
     419         350 :                      (u8 *) wpabuf_put(buf, 0) - group_info - 3);
     420         350 : }
     421             : 
     422             : 
     423           5 : void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf)
     424             : {
     425           5 :         p2p_buf_add_group_id(buf, group->p2p->cfg->dev_addr, group->cfg->ssid,
     426           5 :                              group->cfg->ssid_len);
     427           5 : }
     428             : 
     429             : 
     430         671 : static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
     431             : {
     432             :         struct wpabuf *p2p_subelems, *ie;
     433             : 
     434         671 :         p2p_subelems = wpabuf_alloc(500);
     435         671 :         if (p2p_subelems == NULL)
     436           0 :                 return NULL;
     437             : 
     438         671 :         p2p_group_add_common_ies(group, p2p_subelems);
     439         671 :         p2p_group_add_noa(p2p_subelems, group->noa);
     440             : 
     441             :         /* P2P Device Info */
     442         671 :         p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
     443             : 
     444             :         /* P2P Group Info: Only when at least one P2P Client is connected */
     445         671 :         if (group->members)
     446         345 :                 p2p_buf_add_group_info(group, p2p_subelems, -1);
     447             : 
     448         671 :         ie = p2p_group_encaps_probe_resp(p2p_subelems);
     449         671 :         wpabuf_free(p2p_subelems);
     450             : 
     451             : #ifdef CONFIG_WIFI_DISPLAY
     452         671 :         if (group->wfd_ie) {
     453           6 :                 struct wpabuf *wfd = wpabuf_dup(group->wfd_ie);
     454           6 :                 ie = wpabuf_concat(wfd, ie);
     455             :         }
     456             : #endif /* CONFIG_WIFI_DISPLAY */
     457             : 
     458         671 :         return ie;
     459             : }
     460             : 
     461             : 
     462         671 : void p2p_group_update_ies(struct p2p_group *group)
     463             : {
     464             :         struct wpabuf *beacon_ie;
     465             :         struct wpabuf *probe_resp_ie;
     466             : 
     467             : #ifdef CONFIG_WIFI_DISPLAY
     468         671 :         wifi_display_group_update(group);
     469             : #endif /* CONFIG_WIFI_DISPLAY */
     470             : 
     471         671 :         probe_resp_ie = p2p_group_build_probe_resp_ie(group);
     472         671 :         if (probe_resp_ie == NULL)
     473         671 :                 return;
     474         671 :         wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Probe Response P2P IE",
     475             :                         probe_resp_ie);
     476             : 
     477         671 :         if (group->beacon_update) {
     478         251 :                 beacon_ie = p2p_group_build_beacon_ie(group);
     479         251 :                 if (beacon_ie)
     480         251 :                         group->beacon_update = 0;
     481         251 :                 wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Beacon P2P IE",
     482             :                                 beacon_ie);
     483             :         } else
     484         420 :                 beacon_ie = NULL;
     485             : 
     486         671 :         group->cfg->ie_update(group->cfg->cb_ctx, beacon_ie, probe_resp_ie);
     487             : }
     488             : 
     489             : 
     490             : /**
     491             :  * p2p_build_client_info - Build P2P Client Info Descriptor
     492             :  * @addr: MAC address of the peer device
     493             :  * @p2p_ie: P2P IE from (Re)Association Request
     494             :  * @dev_capab: Buffer for returning Device Capability
     495             :  * @dev_addr: Buffer for returning P2P Device Address
     496             :  * Returns: P2P Client Info Descriptor or %NULL on failure
     497             :  *
     498             :  * This function builds P2P Client Info Descriptor based on the information
     499             :  * available from (Re)Association Request frame. Group owner can use this to
     500             :  * build the P2P Group Info attribute for Probe Response frames.
     501             :  */
     502         232 : static struct wpabuf * p2p_build_client_info(const u8 *addr,
     503             :                                              struct wpabuf *p2p_ie,
     504             :                                              u8 *dev_capab, u8 *dev_addr)
     505             : {
     506             :         const u8 *spos;
     507             :         struct p2p_message msg;
     508             :         u8 *len_pos;
     509             :         struct wpabuf *buf;
     510             : 
     511         232 :         if (p2p_ie == NULL)
     512           0 :                 return NULL;
     513             : 
     514         232 :         os_memset(&msg, 0, sizeof(msg));
     515         464 :         if (p2p_parse_p2p_ie(p2p_ie, &msg) ||
     516         464 :             msg.capability == NULL || msg.p2p_device_info == NULL)
     517           5 :                 return NULL;
     518             : 
     519         227 :         buf = wpabuf_alloc(ETH_ALEN + 1 + 1 + msg.p2p_device_info_len);
     520         227 :         if (buf == NULL)
     521           0 :                 return NULL;
     522             : 
     523         227 :         *dev_capab = msg.capability[0];
     524         227 :         os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
     525             : 
     526         227 :         spos = msg.p2p_device_info; /* P2P Device address */
     527             : 
     528             :         /* P2P Client Info Descriptor */
     529             :         /* Length to be set */
     530         227 :         len_pos = wpabuf_put(buf, 1);
     531             :         /* P2P Device address */
     532         227 :         wpabuf_put_data(buf, spos, ETH_ALEN);
     533             :         /* P2P Interface address */
     534         227 :         wpabuf_put_data(buf, addr, ETH_ALEN);
     535             :         /* Device Capability Bitmap */
     536         227 :         wpabuf_put_u8(buf, msg.capability[0]);
     537             :         /*
     538             :          * Config Methods, Primary Device Type, Number of Secondary Device
     539             :          * Types, Secondary Device Type List, Device Name copied from
     540             :          * Device Info
     541             :          */
     542         227 :         wpabuf_put_data(buf, spos + ETH_ALEN,
     543         227 :                         msg.p2p_device_info_len - ETH_ALEN);
     544             : 
     545         227 :         *len_pos = wpabuf_len(buf) - 1;
     546             : 
     547             : 
     548         227 :         return buf;
     549             : }
     550             : 
     551             : 
     552         506 : static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr)
     553             : {
     554             :         struct p2p_group_member *m, *prev;
     555             : 
     556         506 :         if (group == NULL)
     557          86 :                 return 0;
     558             : 
     559         420 :         m = group->members;
     560         420 :         prev = NULL;
     561         879 :         while (m) {
     562         209 :                 if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
     563         170 :                         break;
     564          39 :                 prev = m;
     565          39 :                 m = m->next;
     566             :         }
     567             : 
     568         420 :         if (m == NULL)
     569         250 :                 return 0;
     570             : 
     571         170 :         if (prev)
     572           8 :                 prev->next = m->next;
     573             :         else
     574         162 :                 group->members = m->next;
     575         170 :         p2p_group_free_member(m);
     576         170 :         group->num_members--;
     577             : 
     578         170 :         return 1;
     579             : }
     580             : 
     581             : 
     582         256 : int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
     583             :                           const u8 *ie, size_t len)
     584             : {
     585             :         struct p2p_group_member *m;
     586             : 
     587         256 :         if (group == NULL)
     588           0 :                 return -1;
     589             : 
     590         256 :         p2p_add_device(group->p2p, addr, 0, NULL, 0, ie, len, 0);
     591             : 
     592         256 :         m = os_zalloc(sizeof(*m));
     593         256 :         if (m == NULL)
     594           0 :                 return -1;
     595         256 :         os_memcpy(m->addr, addr, ETH_ALEN);
     596         256 :         m->p2p_ie = ieee802_11_vendor_ie_concat(ie, len, P2P_IE_VENDOR_TYPE);
     597         256 :         if (m->p2p_ie) {
     598         232 :                 m->client_info = p2p_build_client_info(addr, m->p2p_ie,
     599             :                                                        &m->dev_capab,
     600         232 :                                                        m->dev_addr);
     601             :         }
     602             : #ifdef CONFIG_WIFI_DISPLAY
     603         256 :         m->wfd_ie = ieee802_11_vendor_ie_concat(ie, len, WFD_IE_VENDOR_TYPE);
     604             : #endif /* CONFIG_WIFI_DISPLAY */
     605             : 
     606         256 :         p2p_group_remove_member(group, addr);
     607             : 
     608         256 :         m->next = group->members;
     609         256 :         group->members = m;
     610         256 :         group->num_members++;
     611        2560 :         p2p_dbg(group->p2p,  "Add client " MACSTR
     612             :                 " to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u",
     613        2048 :                 MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0,
     614         256 :                 m->client_info ? 1 : 0,
     615         256 :                 group->num_members, group->cfg->max_clients);
     616         256 :         if (group->num_members == group->cfg->max_clients)
     617           0 :                 group->beacon_update = 1;
     618         256 :         p2p_group_update_ies(group);
     619         256 :         if (group->num_members == 1)
     620         222 :                 group->cfg->idle_update(group->cfg->cb_ctx, 0);
     621             : 
     622         256 :         return 0;
     623             : }
     624             : 
     625             : 
     626        1113 : struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
     627             : {
     628             :         struct wpabuf *resp;
     629             :         u8 *rlen;
     630        1113 :         size_t extra = 0;
     631             : 
     632             : #ifdef CONFIG_WIFI_DISPLAY
     633        1113 :         if (group->wfd_ie)
     634          11 :                 extra = wpabuf_len(group->wfd_ie);
     635             : #endif /* CONFIG_WIFI_DISPLAY */
     636             : 
     637             :         /*
     638             :          * (Re)Association Response - P2P IE
     639             :          * Status attribute (shall be present when association request is
     640             :          *      denied)
     641             :          * Extended Listen Timing (may be present)
     642             :          */
     643        1113 :         resp = wpabuf_alloc(20 + extra);
     644        1113 :         if (resp == NULL)
     645           0 :                 return NULL;
     646             : 
     647             : #ifdef CONFIG_WIFI_DISPLAY
     648        1113 :         if (group->wfd_ie)
     649          11 :                 wpabuf_put_buf(resp, group->wfd_ie);
     650             : #endif /* CONFIG_WIFI_DISPLAY */
     651             : 
     652        1113 :         rlen = p2p_buf_add_ie_hdr(resp);
     653        1113 :         if (status != P2P_SC_SUCCESS)
     654           0 :                 p2p_buf_add_status(resp, status);
     655        1113 :         p2p_buf_update_ie_hdr(resp, rlen);
     656             : 
     657        1113 :         return resp;
     658             : }
     659             : 
     660             : 
     661         250 : void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
     662             : {
     663         250 :         if (p2p_group_remove_member(group, addr)) {
     664        1148 :                 p2p_dbg(group->p2p, "Remove client " MACSTR
     665             :                         " from group; num_members=%u/%u",
     666         984 :                         MAC2STR(addr), group->num_members,
     667         164 :                         group->cfg->max_clients);
     668         164 :                 if (group->num_members == group->cfg->max_clients - 1)
     669           0 :                         group->beacon_update = 1;
     670         164 :                 p2p_group_update_ies(group);
     671         164 :                 if (group->num_members == 0)
     672         140 :                         group->cfg->idle_update(group->cfg->cb_ctx, 1);
     673             :         }
     674         250 : }
     675             : 
     676             : 
     677             : /**
     678             :  * p2p_match_dev_type_member - Match client device type with requested type
     679             :  * @m: Group member
     680             :  * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs)
     681             :  * Returns: 1 on match, 0 on mismatch
     682             :  *
     683             :  * This function can be used to match the Requested Device Type attribute in
     684             :  * WPS IE with the device types of a group member for deciding whether a GO
     685             :  * should reply to a Probe Request frame.
     686             :  */
     687           4 : static int p2p_match_dev_type_member(struct p2p_group_member *m,
     688             :                                      struct wpabuf *wps)
     689             : {
     690             :         const u8 *pos, *end;
     691             :         struct wps_parse_attr attr;
     692             :         u8 num_sec;
     693             : 
     694           4 :         if (m->client_info == NULL || wps == NULL)
     695           0 :                 return 0;
     696             : 
     697           4 :         pos = wpabuf_head(m->client_info);
     698           4 :         end = pos + wpabuf_len(m->client_info);
     699             : 
     700           4 :         pos += 1 + 2 * ETH_ALEN + 1 + 2;
     701           4 :         if (end - pos < WPS_DEV_TYPE_LEN + 1)
     702           0 :                 return 0;
     703             : 
     704           4 :         if (wps_parse_msg(wps, &attr))
     705           0 :                 return 1; /* assume no Requested Device Type attributes */
     706             : 
     707           4 :         if (attr.num_req_dev_type == 0)
     708           0 :                 return 1; /* no Requested Device Type attributes -> match */
     709             : 
     710           4 :         if (dev_type_list_match(pos, attr.req_dev_type, attr.num_req_dev_type))
     711           0 :                 return 1; /* Match with client Primary Device Type */
     712             : 
     713           4 :         pos += WPS_DEV_TYPE_LEN;
     714           4 :         num_sec = *pos++;
     715           4 :         if (end - pos < num_sec * WPS_DEV_TYPE_LEN)
     716           0 :                 return 0;
     717          11 :         while (num_sec > 0) {
     718           4 :                 num_sec--;
     719           4 :                 if (dev_type_list_match(pos, attr.req_dev_type,
     720             :                                         attr.num_req_dev_type))
     721           1 :                         return 1; /* Match with client Secondary Device Type */
     722           3 :                 pos += WPS_DEV_TYPE_LEN;
     723             :         }
     724             : 
     725             :         /* No matching device type found */
     726           3 :         return 0;
     727             : }
     728             : 
     729             : 
     730         240 : int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps)
     731             : {
     732             :         struct p2p_group_member *m;
     733             : 
     734         240 :         if (p2p_match_dev_type(group->p2p, wps))
     735         236 :                 return 1; /* Match with own device type */
     736             : 
     737           7 :         for (m = group->members; m; m = m->next) {
     738           4 :                 if (p2p_match_dev_type_member(m, wps))
     739           1 :                         return 1; /* Match with group client device type */
     740             :         }
     741             : 
     742             :         /* No match with Requested Device Type */
     743           3 :         return 0;
     744             : }
     745             : 
     746             : 
     747         236 : int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p)
     748             : {
     749             :         struct p2p_group_member *m;
     750             :         struct p2p_message msg;
     751             : 
     752         236 :         os_memset(&msg, 0, sizeof(msg));
     753         236 :         if (p2p_parse_p2p_ie(p2p, &msg))
     754           0 :                 return 1; /* Failed to parse - assume no filter on Device ID */
     755             : 
     756         236 :         if (!msg.device_id)
     757         233 :                 return 1; /* No filter on Device ID */
     758             : 
     759           3 :         if (os_memcmp(msg.device_id, group->p2p->cfg->dev_addr, ETH_ALEN) == 0)
     760           0 :                 return 1; /* Match with our P2P Device Address */
     761             : 
     762           5 :         for (m = group->members; m; m = m->next) {
     763           3 :                 if (os_memcmp(msg.device_id, m->dev_addr, ETH_ALEN) == 0)
     764           1 :                         return 1; /* Match with group client P2P Device Address */
     765             :         }
     766             : 
     767             :         /* No match with Device ID */
     768           2 :         return 0;
     769             : }
     770             : 
     771             : 
     772         123 : void p2p_group_notif_formation_done(struct p2p_group *group)
     773             : {
     774         123 :         if (group == NULL)
     775         123 :                 return;
     776         123 :         group->group_formation = 0;
     777         123 :         group->beacon_update = 1;
     778         123 :         p2p_group_update_ies(group);
     779             : }
     780             : 
     781             : 
     782           0 : int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa,
     783             :                         size_t noa_len)
     784             : {
     785           0 :         if (noa == NULL) {
     786           0 :                 wpabuf_free(group->noa);
     787           0 :                 group->noa = NULL;
     788             :         } else {
     789           0 :                 if (group->noa) {
     790           0 :                         if (wpabuf_size(group->noa) >= noa_len) {
     791           0 :                                 group->noa->used = 0;
     792           0 :                                 wpabuf_put_data(group->noa, noa, noa_len);
     793             :                         } else {
     794           0 :                                 wpabuf_free(group->noa);
     795           0 :                                 group->noa = NULL;
     796             :                         }
     797             :                 }
     798             : 
     799           0 :                 if (!group->noa) {
     800           0 :                         group->noa = wpabuf_alloc_copy(noa, noa_len);
     801           0 :                         if (group->noa == NULL)
     802           0 :                                 return -1;
     803             :                 }
     804             :         }
     805             : 
     806           0 :         group->beacon_update = 1;
     807           0 :         p2p_group_update_ies(group);
     808           0 :         return 0;
     809             : }
     810             : 
     811             : 
     812           3 : static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group,
     813             :                                                       const u8 *dev_id)
     814             : {
     815             :         struct p2p_group_member *m;
     816             : 
     817           3 :         for (m = group->members; m; m = m->next) {
     818           0 :                 if (os_memcmp(dev_id, m->dev_addr, ETH_ALEN) == 0)
     819           0 :                         return m;
     820             :         }
     821             : 
     822           3 :         return NULL;
     823             : }
     824             : 
     825             : 
     826         188 : static struct p2p_group_member * p2p_group_get_client_iface(
     827             :         struct p2p_group *group, const u8 *interface_addr)
     828             : {
     829             :         struct p2p_group_member *m;
     830             : 
     831         197 :         for (m = group->members; m; m = m->next) {
     832         197 :                 if (os_memcmp(interface_addr, m->addr, ETH_ALEN) == 0)
     833         188 :                         return m;
     834             :         }
     835             : 
     836           0 :         return NULL;
     837             : }
     838             : 
     839             : 
     840         187 : const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
     841             : {
     842             :         struct p2p_group_member *m;
     843             : 
     844         187 :         if (group == NULL)
     845           0 :                 return NULL;
     846         187 :         m = p2p_group_get_client_iface(group, addr);
     847         187 :         if (m && !is_zero_ether_addr(m->dev_addr))
     848         152 :                 return m->dev_addr;
     849          35 :         return NULL;
     850             : }
     851             : 
     852             : 
     853           0 : static struct wpabuf * p2p_build_go_disc_req(void)
     854             : {
     855             :         struct wpabuf *buf;
     856             : 
     857           0 :         buf = wpabuf_alloc(100);
     858           0 :         if (buf == NULL)
     859           0 :                 return NULL;
     860             : 
     861           0 :         p2p_buf_add_action_hdr(buf, P2P_GO_DISC_REQ, 0);
     862             : 
     863           0 :         return buf;
     864             : }
     865             : 
     866             : 
     867           3 : int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id,
     868             :                           const u8 *searching_dev, int rx_freq)
     869             : {
     870             :         struct p2p_group_member *m;
     871             :         struct wpabuf *req;
     872           3 :         struct p2p_data *p2p = group->p2p;
     873             :         int freq;
     874             : 
     875           3 :         m = p2p_group_get_client(group, dev_id);
     876           3 :         if (m == NULL || m->client_info == NULL) {
     877          18 :                 p2p_dbg(group->p2p, "Requested client was not in this group "
     878          18 :                         MACSTR, MAC2STR(group->cfg->interface_addr));
     879           3 :                 return -1;
     880             :         }
     881             : 
     882           0 :         if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
     883           0 :                 p2p_dbg(group->p2p, "Requested client does not support client discoverability");
     884           0 :                 return -1;
     885             :         }
     886             : 
     887           0 :         p2p_dbg(group->p2p, "Schedule GO Discoverability Request to be sent to "
     888           0 :                 MACSTR, MAC2STR(dev_id));
     889             : 
     890           0 :         req = p2p_build_go_disc_req();
     891           0 :         if (req == NULL)
     892           0 :                 return -1;
     893             : 
     894             :         /* TODO: Should really use group operating frequency here */
     895           0 :         freq = rx_freq;
     896             : 
     897           0 :         p2p->pending_action_state = P2P_PENDING_GO_DISC_REQ;
     898           0 :         if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr,
     899           0 :                                   group->cfg->interface_addr,
     900           0 :                                   group->cfg->interface_addr,
     901           0 :                                   wpabuf_head(req), wpabuf_len(req), 200) < 0)
     902             :         {
     903           0 :                 p2p_dbg(p2p, "Failed to send Action frame");
     904             :         }
     905             : 
     906           0 :         wpabuf_free(req);
     907             : 
     908           0 :         return 0;
     909             : }
     910             : 
     911             : 
     912           1 : const u8 * p2p_group_get_interface_addr(struct p2p_group *group)
     913             : {
     914           1 :         return group->cfg->interface_addr;
     915             : }
     916             : 
     917             : 
     918           1 : u8 p2p_group_presence_req(struct p2p_group *group,
     919             :                           const u8 *client_interface_addr,
     920             :                           const u8 *noa, size_t noa_len)
     921             : {
     922             :         struct p2p_group_member *m;
     923             :         u8 curr_noa[50];
     924             :         int curr_noa_len;
     925             : 
     926           1 :         m = p2p_group_get_client_iface(group, client_interface_addr);
     927           1 :         if (m == NULL || m->client_info == NULL) {
     928           0 :                 p2p_dbg(group->p2p, "Client was not in this group");
     929           0 :                 return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
     930             :         }
     931             : 
     932           1 :         wpa_hexdump(MSG_DEBUG, "P2P: Presence Request NoA", noa, noa_len);
     933             : 
     934           1 :         if (group->p2p->cfg->get_noa)
     935           2 :                 curr_noa_len = group->p2p->cfg->get_noa(
     936           1 :                         group->p2p->cfg->cb_ctx, group->cfg->interface_addr,
     937             :                         curr_noa, sizeof(curr_noa));
     938             :         else
     939           0 :                 curr_noa_len = -1;
     940           1 :         if (curr_noa_len < 0)
     941           1 :                 p2p_dbg(group->p2p, "Failed to fetch current NoA");
     942           0 :         else if (curr_noa_len == 0)
     943           0 :                 p2p_dbg(group->p2p, "No NoA being advertized");
     944             :         else
     945           0 :                 wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
     946             :                             curr_noa_len);
     947             : 
     948             :         /* TODO: properly process request and store copy */
     949           1 :         if (curr_noa_len > 0 || curr_noa_len == -1)
     950           1 :                 return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
     951             : 
     952           0 :         return P2P_SC_SUCCESS;
     953             : }
     954             : 
     955             : 
     956           0 : unsigned int p2p_get_group_num_members(struct p2p_group *group)
     957             : {
     958           0 :         return group->num_members;
     959             : }
     960             : 
     961             : 
     962           0 : const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
     963             : {
     964           0 :         struct p2p_group_member *iter = *next;
     965             : 
     966           0 :         if (!iter)
     967           0 :                 iter = group->members;
     968             :         else
     969           0 :                 iter = iter->next;
     970             : 
     971           0 :         *next = iter;
     972             : 
     973           0 :         if (!iter)
     974           0 :                 return NULL;
     975             : 
     976           0 :         return iter->addr;
     977             : }
     978             : 
     979             : 
     980           0 : int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr)
     981             : {
     982             :         struct p2p_group_member *m;
     983             : 
     984           0 :         for (m = group->members; m; m = m->next) {
     985           0 :                 if (os_memcmp(m->dev_addr, dev_addr, ETH_ALEN) == 0)
     986           0 :                         return 1;
     987             :         }
     988             : 
     989           0 :         return 0;
     990             : }
     991             : 
     992             : 
     993          33 : int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
     994             :                                 size_t group_id_len)
     995             : {
     996          33 :         if (group_id_len != ETH_ALEN + group->cfg->ssid_len)
     997           0 :                 return 0;
     998          33 :         if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0)
     999           0 :                 return 0;
    1000          66 :         return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
    1001          33 :                          group->cfg->ssid_len) == 0;
    1002             : }
    1003             : 
    1004             : 
    1005           2 : void p2p_group_force_beacon_update_ies(struct p2p_group *group)
    1006             : {
    1007           2 :         group->beacon_update = 1;
    1008           2 :         p2p_group_update_ies(group);
    1009           2 : }
    1010             : 
    1011             : 
    1012           5 : int p2p_group_get_freq(struct p2p_group *group)
    1013             : {
    1014           5 :         return group->cfg->freq;
    1015             : }

Generated by: LCOV version 1.10