LCOV - code coverage report
Current view: top level - wpa_supplicant - p2p_supplicant_sd.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 558 642 86.9 %
Date: 2015-09-27 Functions: 38 40 95.0 %

          Line data    Source code
       1             : /*
       2             :  * wpa_supplicant - P2P service discovery
       3             :  * Copyright (c) 2009-2010, Atheros Communications
       4             :  * Copyright (c) 2010-2014, Jouni Malinen <j@w1.fi>
       5             :  *
       6             :  * This software may be distributed under the terms of the BSD license.
       7             :  * See README for more details.
       8             :  */
       9             : 
      10             : #include "utils/includes.h"
      11             : 
      12             : #include "utils/common.h"
      13             : #include "p2p/p2p.h"
      14             : #include "wpa_supplicant_i.h"
      15             : #include "notify.h"
      16             : #include "p2p_supplicant.h"
      17             : 
      18             : 
      19             : /*
      20             :  * DNS Header section is used only to calculate compression pointers, so the
      21             :  * contents of this data does not matter, but the length needs to be reserved
      22             :  * in the virtual packet.
      23             :  */
      24             : #define DNS_HEADER_LEN 12
      25             : 
      26             : /*
      27             :  * 27-octet in-memory packet from P2P specification containing two implied
      28             :  * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
      29             :  */
      30             : #define P2P_SD_IN_MEMORY_LEN 27
      31             : 
      32           4 : static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
      33             :                                        u8 **spos, const u8 *end)
      34             : {
      35          14 :         while (*spos < end) {
      36          10 :                 u8 val = ((*spos)[0] & 0xc0) >> 6;
      37             :                 int len;
      38             : 
      39          10 :                 if (val == 1 || val == 2) {
      40             :                         /* These are reserved values in RFC 1035 */
      41           0 :                         wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
      42             :                                    "sequence starting with 0x%x", val);
      43           0 :                         return -1;
      44             :                 }
      45             : 
      46          10 :                 if (val == 3) {
      47             :                         u16 offset;
      48             :                         u8 *spos_tmp;
      49             : 
      50             :                         /* Offset */
      51           2 :                         if (*spos + 2 > end) {
      52           0 :                                 wpa_printf(MSG_DEBUG, "P2P: No room for full "
      53             :                                            "DNS offset field");
      54           0 :                                 return -1;
      55             :                         }
      56             : 
      57           2 :                         offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
      58           2 :                         if (offset >= *spos - start) {
      59           0 :                                 wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
      60             :                                            "pointer offset %u", offset);
      61           0 :                                 return -1;
      62             :                         }
      63             : 
      64           2 :                         (*spos) += 2;
      65           2 :                         spos_tmp = start + offset;
      66           2 :                         return p2p_sd_dns_uncompress_label(upos, uend, start,
      67             :                                                            &spos_tmp,
      68           2 :                                                            *spos - 2);
      69             :                 }
      70             : 
      71             :                 /* Label */
      72           8 :                 len = (*spos)[0] & 0x3f;
      73           8 :                 if (len == 0)
      74           2 :                         return 0;
      75             : 
      76           6 :                 (*spos)++;
      77           6 :                 if (*spos + len > end) {
      78           0 :                         wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
      79             :                                    "sequence - no room for label with length "
      80             :                                    "%u", len);
      81           0 :                         return -1;
      82             :                 }
      83             : 
      84           6 :                 if (*upos + len + 2 > uend)
      85           0 :                         return -2;
      86             : 
      87           6 :                 os_memcpy(*upos, *spos, len);
      88           6 :                 *spos += len;
      89           6 :                 *upos += len;
      90           6 :                 (*upos)[0] = '.';
      91           6 :                 (*upos)++;
      92           6 :                 (*upos)[0] = '\0';
      93             :         }
      94             : 
      95           0 :         return 0;
      96             : }
      97             : 
      98             : 
      99             : /* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
     100             :  * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
     101             :  * not large enough */
     102           2 : static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
     103             :                                  size_t msg_len, size_t offset)
     104             : {
     105             :         /* 27-octet in-memory packet from P2P specification */
     106           2 :         const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
     107             :                 "\x04_udp\xC0\x11\x00\x0C\x00\x01";
     108             :         u8 *tmp, *end, *spos;
     109             :         char *upos, *uend;
     110           2 :         int ret = 0;
     111             : 
     112           2 :         if (buf_len < 2)
     113           0 :                 return -1;
     114           2 :         if (offset > msg_len)
     115           0 :                 return -1;
     116             : 
     117           2 :         tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
     118           2 :         if (tmp == NULL)
     119           0 :                 return -1;
     120           2 :         spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
     121           2 :         end = spos + msg_len;
     122           2 :         spos += offset;
     123             : 
     124           2 :         os_memset(tmp, 0, DNS_HEADER_LEN);
     125           2 :         os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
     126           2 :         os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
     127             : 
     128           2 :         upos = buf;
     129           2 :         uend = buf + buf_len;
     130             : 
     131           2 :         ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
     132           2 :         if (ret) {
     133           0 :                 os_free(tmp);
     134           0 :                 return ret;
     135             :         }
     136             : 
     137           2 :         if (upos == buf) {
     138           0 :                 upos[0] = '.';
     139           0 :                 upos[1] = '\0';
     140           2 :         } else if (upos[-1] == '.')
     141           2 :                 upos[-1] = '\0';
     142             : 
     143           2 :         os_free(tmp);
     144           2 :         return 0;
     145             : }
     146             : 
     147             : 
     148             : static struct p2p_srv_bonjour *
     149          40 : wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
     150             :                              const struct wpabuf *query)
     151             : {
     152             :         struct p2p_srv_bonjour *bsrv;
     153             :         size_t len;
     154             : 
     155          40 :         len = wpabuf_len(query);
     156         172 :         dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
     157             :                          struct p2p_srv_bonjour, list) {
     158         172 :                 if (len == wpabuf_len(bsrv->query) &&
     159          20 :                     os_memcmp(wpabuf_head(query), wpabuf_head(bsrv->query),
     160             :                               len) == 0)
     161          20 :                         return bsrv;
     162             :         }
     163          20 :         return NULL;
     164             : }
     165             : 
     166             : 
     167             : static struct p2p_srv_upnp *
     168         581 : wpas_p2p_service_get_upnp(struct wpa_supplicant *wpa_s, u8 version,
     169             :                           const char *service)
     170             : {
     171             :         struct p2p_srv_upnp *usrv;
     172             : 
     173       33813 :         dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
     174             :                          struct p2p_srv_upnp, list) {
     175       66572 :                 if (version == usrv->version &&
     176       33286 :                     os_strcmp(service, usrv->service) == 0)
     177          54 :                         return usrv;
     178             :         }
     179         527 :         return NULL;
     180             : }
     181             : 
     182             : 
     183           8 : static void wpas_sd_add_empty(struct wpabuf *resp, u8 srv_proto,
     184             :                               u8 srv_trans_id, u8 status)
     185             : {
     186             :         u8 *len_pos;
     187             : 
     188           8 :         if (wpabuf_tailroom(resp) < 5)
     189           8 :                 return;
     190             : 
     191             :         /* Length (to be filled) */
     192           8 :         len_pos = wpabuf_put(resp, 2);
     193           8 :         wpabuf_put_u8(resp, srv_proto);
     194           8 :         wpabuf_put_u8(resp, srv_trans_id);
     195             :         /* Status Code */
     196           8 :         wpabuf_put_u8(resp, status);
     197             :         /* Response Data: empty */
     198           8 :         WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
     199             : }
     200             : 
     201             : 
     202           8 : static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
     203             :                                         u8 srv_trans_id)
     204             : {
     205           8 :         wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
     206             :                           P2P_SD_PROTO_NOT_AVAILABLE);
     207           8 : }
     208             : 
     209             : 
     210           0 : static void wpas_sd_add_bad_request(struct wpabuf *resp, u8 srv_proto,
     211             :                                     u8 srv_trans_id)
     212             : {
     213           0 :         wpas_sd_add_empty(resp, srv_proto, srv_trans_id, P2P_SD_BAD_REQUEST);
     214           0 : }
     215             : 
     216             : 
     217           0 : static void wpas_sd_add_not_found(struct wpabuf *resp, u8 srv_proto,
     218             :                                   u8 srv_trans_id)
     219             : {
     220           0 :         wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
     221             :                           P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
     222           0 : }
     223             : 
     224             : 
     225          15 : static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
     226             :                                 struct wpabuf *resp, u8 srv_trans_id)
     227             : {
     228             :         struct p2p_srv_bonjour *bsrv;
     229             :         u8 *len_pos;
     230             : 
     231          15 :         wpa_printf(MSG_DEBUG, "P2P: SD Request for all Bonjour services");
     232             : 
     233          15 :         if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
     234           0 :                 wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
     235           0 :                 return;
     236             :         }
     237             : 
     238          92 :         dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
     239             :                          struct p2p_srv_bonjour, list) {
     240         154 :                 if (wpabuf_tailroom(resp) <
     241          77 :                     5 + wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp))
     242           0 :                         return;
     243             :                 /* Length (to be filled) */
     244          77 :                 len_pos = wpabuf_put(resp, 2);
     245          77 :                 wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
     246          77 :                 wpabuf_put_u8(resp, srv_trans_id);
     247             :                 /* Status Code */
     248          77 :                 wpabuf_put_u8(resp, P2P_SD_SUCCESS);
     249         154 :                 wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
     250          77 :                                   wpabuf_head(bsrv->resp),
     251          77 :                                   wpabuf_len(bsrv->resp));
     252             :                 /* Response Data */
     253          77 :                 wpabuf_put_buf(resp, bsrv->query); /* Key */
     254          77 :                 wpabuf_put_buf(resp, bsrv->resp); /* Value */
     255          77 :                 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
     256             :                              2);
     257             :         }
     258             : }
     259             : 
     260             : 
     261           8 : static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
     262             :                                size_t query_len)
     263             : {
     264             :         char str_rx[256], str_srv[256];
     265             : 
     266           8 :         if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
     267           0 :                 return 0; /* Too short to include DNS Type and Version */
     268           8 :         if (os_memcmp(query + query_len - 3,
     269             :                       wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
     270             :                       3) != 0)
     271           6 :                 return 0; /* Mismatch in DNS Type or Version */
     272           3 :         if (query_len == wpabuf_len(bsrv->query) &&
     273           1 :             os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
     274           1 :                 return 1; /* Binary match */
     275             : 
     276           1 :         if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
     277             :                                   0))
     278           0 :                 return 0; /* Failed to uncompress query */
     279           2 :         if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
     280           1 :                                   wpabuf_head(bsrv->query),
     281           1 :                                   wpabuf_len(bsrv->query) - 3, 0))
     282           0 :                 return 0; /* Failed to uncompress service */
     283             : 
     284           1 :         return os_strcmp(str_rx, str_srv) == 0;
     285             : }
     286             : 
     287             : 
     288          11 : static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
     289             :                                 struct wpabuf *resp, u8 srv_trans_id,
     290             :                                 const u8 *query, size_t query_len)
     291             : {
     292             :         struct p2p_srv_bonjour *bsrv;
     293             :         u8 *len_pos;
     294          11 :         int matches = 0;
     295             : 
     296          11 :         wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
     297             :                           query, query_len);
     298          11 :         if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
     299           2 :                 wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
     300           2 :                 wpas_sd_add_proto_not_avail(resp, P2P_SERV_BONJOUR,
     301             :                                             srv_trans_id);
     302           2 :                 return;
     303             :         }
     304             : 
     305           9 :         if (query_len == 0) {
     306           7 :                 wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
     307           7 :                 return;
     308             :         }
     309             : 
     310          10 :         dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
     311             :                          struct p2p_srv_bonjour, list) {
     312           8 :                 if (!match_bonjour_query(bsrv, query, query_len))
     313           7 :                         continue;
     314             : 
     315           2 :                 if (wpabuf_tailroom(resp) <
     316           1 :                     5 + query_len + wpabuf_len(bsrv->resp))
     317           0 :                         return;
     318             : 
     319           1 :                 matches++;
     320             : 
     321             :                 /* Length (to be filled) */
     322           1 :                 len_pos = wpabuf_put(resp, 2);
     323           1 :                 wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
     324           1 :                 wpabuf_put_u8(resp, srv_trans_id);
     325             : 
     326             :                 /* Status Code */
     327           1 :                 wpabuf_put_u8(resp, P2P_SD_SUCCESS);
     328           2 :                 wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
     329           1 :                                   wpabuf_head(bsrv->resp),
     330           1 :                                   wpabuf_len(bsrv->resp));
     331             : 
     332             :                 /* Response Data */
     333           1 :                 wpabuf_put_data(resp, query, query_len); /* Key */
     334           1 :                 wpabuf_put_buf(resp, bsrv->resp); /* Value */
     335             : 
     336           1 :                 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
     337             :         }
     338             : 
     339           2 :         if (matches == 0) {
     340           1 :                 wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
     341             :                            "available");
     342           1 :                 if (wpabuf_tailroom(resp) < 5)
     343           0 :                         return;
     344             : 
     345             :                 /* Length (to be filled) */
     346           1 :                 len_pos = wpabuf_put(resp, 2);
     347           1 :                 wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
     348           1 :                 wpabuf_put_u8(resp, srv_trans_id);
     349             : 
     350             :                 /* Status Code */
     351           1 :                 wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
     352             :                 /* Response Data: empty */
     353           1 :                 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
     354             :                              2);
     355             :         }
     356             : }
     357             : 
     358             : 
     359          16 : static void wpas_sd_all_upnp(struct wpa_supplicant *wpa_s,
     360             :                              struct wpabuf *resp, u8 srv_trans_id)
     361             : {
     362             :         struct p2p_srv_upnp *usrv;
     363             :         u8 *len_pos;
     364             : 
     365          16 :         wpa_printf(MSG_DEBUG, "P2P: SD Request for all UPnP services");
     366             : 
     367          16 :         if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
     368           1 :                 wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
     369           1 :                 return;
     370             :         }
     371             : 
     372         437 :         dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
     373             :                          struct p2p_srv_upnp, list) {
     374         423 :                 if (wpabuf_tailroom(resp) < 5 + 1 + os_strlen(usrv->service))
     375           1 :                         return;
     376             : 
     377             :                 /* Length (to be filled) */
     378         422 :                 len_pos = wpabuf_put(resp, 2);
     379         422 :                 wpabuf_put_u8(resp, P2P_SERV_UPNP);
     380         422 :                 wpabuf_put_u8(resp, srv_trans_id);
     381             : 
     382             :                 /* Status Code */
     383         422 :                 wpabuf_put_u8(resp, P2P_SD_SUCCESS);
     384             :                 /* Response Data */
     385         422 :                 wpabuf_put_u8(resp, usrv->version);
     386         422 :                 wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
     387             :                            usrv->service);
     388         422 :                 wpabuf_put_str(resp, usrv->service);
     389         422 :                 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
     390             :                              2);
     391             :         }
     392             : }
     393             : 
     394             : 
     395          12 : static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
     396             :                              struct wpabuf *resp, u8 srv_trans_id,
     397             :                              const u8 *query, size_t query_len)
     398             : {
     399             :         struct p2p_srv_upnp *usrv;
     400             :         u8 *len_pos;
     401             :         u8 version;
     402             :         char *str;
     403          12 :         int count = 0;
     404             : 
     405          12 :         wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for UPnP",
     406             :                           query, query_len);
     407             : 
     408          12 :         if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
     409           2 :                 wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
     410           2 :                 wpas_sd_add_proto_not_avail(resp, P2P_SERV_UPNP,
     411             :                                             srv_trans_id);
     412           2 :                 return;
     413             :         }
     414             : 
     415          10 :         if (query_len == 0) {
     416           8 :                 wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
     417           8 :                 return;
     418             :         }
     419             : 
     420           2 :         if (wpabuf_tailroom(resp) < 5)
     421           0 :                 return;
     422             : 
     423             :         /* Length (to be filled) */
     424           2 :         len_pos = wpabuf_put(resp, 2);
     425           2 :         wpabuf_put_u8(resp, P2P_SERV_UPNP);
     426           2 :         wpabuf_put_u8(resp, srv_trans_id);
     427             : 
     428           2 :         version = query[0];
     429           2 :         str = os_malloc(query_len);
     430           2 :         if (str == NULL)
     431           0 :                 return;
     432           2 :         os_memcpy(str, query + 1, query_len - 1);
     433           2 :         str[query_len - 1] = '\0';
     434             : 
     435          12 :         dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
     436             :                          struct p2p_srv_upnp, list) {
     437          10 :                 if (version != usrv->version)
     438           0 :                         continue;
     439             : 
     440          15 :                 if (os_strcmp(str, "ssdp:all") != 0 &&
     441           5 :                     os_strstr(usrv->service, str) == NULL)
     442           5 :                         continue;
     443             : 
     444           5 :                 if (wpabuf_tailroom(resp) < 2)
     445           0 :                         break;
     446           5 :                 if (count == 0) {
     447             :                         /* Status Code */
     448           1 :                         wpabuf_put_u8(resp, P2P_SD_SUCCESS);
     449             :                         /* Response Data */
     450           1 :                         wpabuf_put_u8(resp, version);
     451             :                 } else
     452           4 :                         wpabuf_put_u8(resp, ',');
     453             : 
     454           5 :                 count++;
     455             : 
     456           5 :                 wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
     457             :                            usrv->service);
     458           5 :                 if (wpabuf_tailroom(resp) < os_strlen(usrv->service))
     459           0 :                         break;
     460           5 :                 wpabuf_put_str(resp, usrv->service);
     461             :         }
     462           2 :         os_free(str);
     463             : 
     464           2 :         if (count == 0) {
     465           1 :                 wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not "
     466             :                            "available");
     467             :                 /* Status Code */
     468           1 :                 wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
     469             :                 /* Response Data: empty */
     470             :         }
     471             : 
     472           2 :         WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
     473             : }
     474             : 
     475             : 
     476             : #ifdef CONFIG_WIFI_DISPLAY
     477           4 : static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
     478             :                             struct wpabuf *resp, u8 srv_trans_id,
     479             :                             const u8 *query, size_t query_len)
     480             : {
     481             :         const u8 *pos;
     482             :         u8 role;
     483             :         u8 *len_pos;
     484             : 
     485           4 :         wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len);
     486             : 
     487           4 :         if (!wpa_s->global->wifi_display) {
     488           1 :                 wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available");
     489           1 :                 wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY,
     490             :                                             srv_trans_id);
     491           1 :                 return;
     492             :         }
     493             : 
     494           3 :         if (query_len < 1) {
     495           1 :                 wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device "
     496             :                            "Role");
     497           1 :                 return;
     498             :         }
     499             : 
     500           2 :         if (wpabuf_tailroom(resp) < 5)
     501           0 :                 return;
     502             : 
     503           2 :         pos = query;
     504           2 :         role = *pos++;
     505           2 :         wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role);
     506             : 
     507             :         /* TODO: role specific handling */
     508             : 
     509             :         /* Length (to be filled) */
     510           2 :         len_pos = wpabuf_put(resp, 2);
     511           2 :         wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY);
     512           2 :         wpabuf_put_u8(resp, srv_trans_id);
     513           2 :         wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */
     514             : 
     515          12 :         while (pos < query + query_len) {
     516          16 :                 if (*pos < MAX_WFD_SUBELEMS &&
     517          16 :                     wpa_s->global->wfd_subelem[*pos] &&
     518           8 :                     wpabuf_tailroom(resp) >=
     519           8 :                     wpabuf_len(wpa_s->global->wfd_subelem[*pos])) {
     520           8 :                         wpa_printf(MSG_DEBUG, "P2P: Add WSD response "
     521           8 :                                    "subelement %u", *pos);
     522           8 :                         wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]);
     523             :                 }
     524           8 :                 pos++;
     525             :         }
     526             : 
     527           2 :         WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
     528             : }
     529             : #endif /* CONFIG_WIFI_DISPLAY */
     530             : 
     531             : 
     532          30 : static int find_p2ps_substr(struct p2ps_advertisement *adv_data,
     533             :                             const u8 *needle, size_t needle_len)
     534             : {
     535          30 :         const u8 *haystack = (const u8 *) adv_data->svc_info;
     536             :         size_t haystack_len, i;
     537             : 
     538             :         /* Allow search term to be empty */
     539          30 :         if (!needle || !needle_len)
     540           1 :                 return 1;
     541             : 
     542          29 :         if (!haystack)
     543           0 :                 return 0;
     544             : 
     545          29 :         haystack_len = os_strlen(adv_data->svc_info);
     546         860 :         for (i = 0; i < haystack_len; i++) {
     547         860 :                 if (haystack_len - i < needle_len)
     548           0 :                         break;
     549         860 :                 if (os_memcmp(haystack + i, needle, needle_len) == 0)
     550          29 :                         return 1;
     551             :         }
     552             : 
     553           0 :         return 0;
     554             : }
     555             : 
     556             : 
     557          29 : static void wpas_sd_req_asp(struct wpa_supplicant *wpa_s,
     558             :                             struct wpabuf *resp, u8 srv_trans_id,
     559             :                             const u8 *query, size_t query_len)
     560             : {
     561             :         struct p2ps_advertisement *adv_data;
     562          29 :         const u8 *svc = &query[1];
     563          29 :         const u8 *info = NULL;
     564          29 :         size_t svc_len = query[0];
     565          29 :         size_t info_len = 0;
     566          29 :         int prefix = 0;
     567          29 :         u8 *count_pos = NULL;
     568          29 :         u8 *len_pos = NULL;
     569             : 
     570          29 :         wpa_hexdump(MSG_DEBUG, "P2P: SD Request for ASP", query, query_len);
     571             : 
     572          29 :         if (!wpa_s->global->p2p) {
     573           0 :                 wpa_printf(MSG_DEBUG, "P2P: ASP protocol not available");
     574           0 :                 wpas_sd_add_proto_not_avail(resp, P2P_SERV_P2PS, srv_trans_id);
     575           0 :                 return;
     576             :         }
     577             : 
     578             :         /* Info block is optional */
     579          29 :         if (svc_len + 1 < query_len) {
     580          29 :                 info = &svc[svc_len];
     581          29 :                 info_len = *info++;
     582             :         }
     583             : 
     584             :         /* Range check length of svc string and info block */
     585          29 :         if (svc_len + (info_len ? info_len + 2 : 1) > query_len) {
     586           0 :                 wpa_printf(MSG_DEBUG, "P2P: ASP bad request");
     587           0 :                 wpas_sd_add_bad_request(resp, P2P_SERV_P2PS, srv_trans_id);
     588           0 :                 return;
     589             :         }
     590             : 
     591             :         /* Detect and correct for prefix search */
     592          29 :         if (svc_len && svc[svc_len - 1] == '*') {
     593           6 :                 prefix = 1;
     594           6 :                 svc_len--;
     595             :         }
     596             : 
     597          93 :         for (adv_data = p2p_get_p2ps_adv_list(wpa_s->global->p2p);
     598          35 :              adv_data; adv_data = adv_data->next) {
     599             :                 /* If not a prefix match, reject length mismatches */
     600          35 :                 if (!prefix && svc_len != os_strlen(adv_data->svc_name))
     601           2 :                         continue;
     602             : 
     603             :                 /* Search each service for request */
     604          63 :                 if (os_memcmp(adv_data->svc_name, svc, svc_len) == 0 &&
     605          30 :                     find_p2ps_substr(adv_data, info, info_len)) {
     606          30 :                         size_t len = os_strlen(adv_data->svc_name);
     607          30 :                         size_t svc_info_len = 0;
     608             : 
     609          30 :                         if (adv_data->svc_info)
     610          30 :                                 svc_info_len = os_strlen(adv_data->svc_info);
     611             : 
     612          30 :                         if (len > 0xff || svc_info_len > 0xffff)
     613           0 :                                 return;
     614             : 
     615             :                         /* Length & Count to be filled as we go */
     616          30 :                         if (!len_pos && !count_pos) {
     617          58 :                                 if (wpabuf_tailroom(resp) <
     618          29 :                                     len + svc_info_len + 16)
     619           0 :                                         return;
     620             : 
     621          29 :                                 len_pos = wpabuf_put(resp, 2);
     622          29 :                                 wpabuf_put_u8(resp, P2P_SERV_P2PS);
     623          29 :                                 wpabuf_put_u8(resp, srv_trans_id);
     624             :                                 /* Status Code */
     625          29 :                                 wpabuf_put_u8(resp, P2P_SD_SUCCESS);
     626          29 :                                 count_pos = wpabuf_put(resp, 1);
     627          29 :                                 *count_pos = 0;
     628           2 :                         } else if (wpabuf_tailroom(resp) <
     629           1 :                                    len + svc_info_len + 10)
     630           0 :                                 return;
     631             : 
     632          30 :                         if (svc_info_len) {
     633          60 :                                 wpa_printf(MSG_DEBUG,
     634             :                                            "P2P: Add Svc: %s info: %s",
     635          30 :                                            adv_data->svc_name,
     636             :                                            adv_data->svc_info);
     637             :                         } else {
     638           0 :                                 wpa_printf(MSG_DEBUG, "P2P: Add Svc: %s",
     639           0 :                                            adv_data->svc_name);
     640             :                         }
     641             : 
     642             :                         /* Advertisement ID */
     643          30 :                         wpabuf_put_le32(resp, adv_data->id);
     644             : 
     645             :                         /* Config Methods */
     646          30 :                         wpabuf_put_be16(resp, adv_data->config_methods);
     647             : 
     648             :                         /* Service Name */
     649          30 :                         wpabuf_put_u8(resp, (u8) len);
     650          30 :                         wpabuf_put_data(resp, adv_data->svc_name, len);
     651             : 
     652             :                         /* Service State */
     653          30 :                         wpabuf_put_u8(resp, adv_data->state);
     654             : 
     655             :                         /* Service Information */
     656          30 :                         wpabuf_put_le16(resp, (u16) svc_info_len);
     657          30 :                         wpabuf_put_data(resp, adv_data->svc_info, svc_info_len);
     658             : 
     659             :                         /* Update length and count */
     660          30 :                         (*count_pos)++;
     661          30 :                         WPA_PUT_LE16(len_pos,
     662          30 :                                      (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
     663             :                 }
     664             :         }
     665             : 
     666             :         /* Return error if no matching svc found */
     667          29 :         if (count_pos == NULL) {
     668           0 :                 wpa_printf(MSG_DEBUG, "P2P: ASP service not found");
     669           0 :                 wpas_sd_add_not_found(resp, P2P_SERV_P2PS, srv_trans_id);
     670             :         }
     671             : }
     672             : 
     673             : 
     674           8 : static void wpas_sd_all_asp(struct wpa_supplicant *wpa_s,
     675             :                             struct wpabuf *resp, u8 srv_trans_id)
     676             : {
     677             :         /* Query data to add all P2PS advertisements:
     678             :          *  - Service name length: 1
     679             :          *  - Service name: '*'
     680             :          *  - Service Information Request Length: 0
     681             :          */
     682           8 :         const u8 q[] = { 1, (const u8) '*', 0 };
     683             : 
     684           8 :         if (p2p_get_p2ps_adv_list(wpa_s->global->p2p))
     685           0 :                 wpas_sd_req_asp(wpa_s, resp, srv_trans_id, q, sizeof(q));
     686           8 : }
     687             : 
     688             : 
     689          69 : void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
     690             :                      u16 update_indic, const u8 *tlvs, size_t tlvs_len)
     691             : {
     692          69 :         struct wpa_supplicant *wpa_s = ctx;
     693          69 :         const u8 *pos = tlvs;
     694          69 :         const u8 *end = tlvs + tlvs_len;
     695             :         const u8 *tlv_end;
     696             :         u16 slen;
     697             :         struct wpabuf *resp;
     698             :         u8 srv_proto, srv_trans_id;
     699             :         size_t buf_len;
     700             :         char *buf;
     701             : 
     702          69 :         wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Request TLVs",
     703             :                     tlvs, tlvs_len);
     704          69 :         buf_len = 2 * tlvs_len + 1;
     705          69 :         buf = os_malloc(buf_len);
     706          69 :         if (buf) {
     707          69 :                 wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
     708         483 :                 wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_REQ "%d "
     709             :                              MACSTR " %u %u %s",
     710         414 :                              freq, MAC2STR(sa), dialog_token, update_indic,
     711             :                              buf);
     712          69 :                 os_free(buf);
     713             :         }
     714             : 
     715          69 :         if (wpa_s->p2p_sd_over_ctrl_iface) {
     716           3 :                 wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
     717             :                                            update_indic, tlvs, tlvs_len);
     718           3 :                 return; /* to be processed by an external program */
     719             :         }
     720             : 
     721          66 :         resp = wpabuf_alloc(10000);
     722          66 :         if (resp == NULL)
     723           0 :                 return;
     724             : 
     725         199 :         while (pos + 1 < end) {
     726          67 :                 wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
     727          67 :                 slen = WPA_GET_LE16(pos);
     728          67 :                 pos += 2;
     729          67 :                 if (pos + slen > end || slen < 2) {
     730           0 :                         wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
     731             :                                    "length");
     732           0 :                         wpabuf_free(resp);
     733           0 :                         return;
     734             :                 }
     735          67 :                 tlv_end = pos + slen;
     736             : 
     737          67 :                 srv_proto = *pos++;
     738          67 :                 wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
     739             :                            srv_proto);
     740          67 :                 srv_trans_id = *pos++;
     741          67 :                 wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
     742             :                            srv_trans_id);
     743             : 
     744          67 :                 wpa_hexdump(MSG_MSGDUMP, "P2P: Query Data",
     745          67 :                             pos, tlv_end - pos);
     746             : 
     747             : 
     748          67 :                 if (wpa_s->force_long_sd) {
     749           0 :                         wpa_printf(MSG_DEBUG, "P2P: SD test - force long "
     750             :                                    "response");
     751           0 :                         wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
     752           0 :                         wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
     753           0 :                         wpas_sd_all_asp(wpa_s, resp, srv_trans_id);
     754           0 :                         goto done;
     755             :                 }
     756             : 
     757          67 :                 switch (srv_proto) {
     758             :                 case P2P_SERV_ALL_SERVICES:
     759          10 :                         wpa_printf(MSG_DEBUG, "P2P: Service Discovery Request "
     760             :                                    "for all services");
     761          13 :                         if (dl_list_empty(&wpa_s->global->p2p_srv_upnp) &&
     762           5 :                             dl_list_empty(&wpa_s->global->p2p_srv_bonjour) &&
     763           2 :                             !p2p_get_p2ps_adv_list(wpa_s->global->p2p)) {
     764           2 :                                 wpa_printf(MSG_DEBUG, "P2P: No service "
     765             :                                            "discovery protocols available");
     766           2 :                                 wpas_sd_add_proto_not_avail(
     767             :                                         resp, P2P_SERV_ALL_SERVICES,
     768             :                                         srv_trans_id);
     769           2 :                                 break;
     770             :                         }
     771           8 :                         wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
     772           8 :                         wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
     773           8 :                         wpas_sd_all_asp(wpa_s, resp, srv_trans_id);
     774           8 :                         break;
     775             :                 case P2P_SERV_BONJOUR:
     776          11 :                         wpas_sd_req_bonjour(wpa_s, resp, srv_trans_id,
     777          11 :                                             pos, tlv_end - pos);
     778          11 :                         break;
     779             :                 case P2P_SERV_UPNP:
     780          12 :                         wpas_sd_req_upnp(wpa_s, resp, srv_trans_id,
     781          12 :                                          pos, tlv_end - pos);
     782          12 :                         break;
     783             : #ifdef CONFIG_WIFI_DISPLAY
     784             :                 case P2P_SERV_WIFI_DISPLAY:
     785           4 :                         wpas_sd_req_wfd(wpa_s, resp, srv_trans_id,
     786           4 :                                         pos, tlv_end - pos);
     787           4 :                         break;
     788             : #endif /* CONFIG_WIFI_DISPLAY */
     789             :                 case P2P_SERV_P2PS:
     790          29 :                         wpas_sd_req_asp(wpa_s, resp, srv_trans_id,
     791          29 :                                         pos, tlv_end - pos);
     792          29 :                         break;
     793             :                 default:
     794           1 :                         wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
     795             :                                    "protocol %u", srv_proto);
     796           1 :                         wpas_sd_add_proto_not_avail(resp, srv_proto,
     797             :                                                     srv_trans_id);
     798           1 :                         break;
     799             :                 }
     800             : 
     801          67 :                 pos = tlv_end;
     802             :         }
     803             : 
     804             : done:
     805          66 :         wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
     806             :                                    update_indic, tlvs, tlvs_len);
     807             : 
     808          66 :         wpas_p2p_sd_response(wpa_s, freq, sa, dialog_token, resp);
     809             : 
     810          66 :         wpabuf_free(resp);
     811             : }
     812             : 
     813             : 
     814          29 : static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
     815             :                                        const u8 *sa, u8 srv_trans_id,
     816             :                                        const u8 *pos, const u8 *tlv_end)
     817             : {
     818          29 :         u8 left = *pos++;
     819             :         u32 adv_id;
     820             :         u8 svc_status;
     821             :         u16 config_methods;
     822             :         char svc_str[256];
     823             : 
     824          88 :         while (left-- && pos < tlv_end) {
     825          30 :                 char *buf = NULL;
     826             :                 size_t buf_len;
     827             :                 u8 svc_len;
     828             : 
     829             :                 /* Sanity check fixed length+svc_str */
     830          30 :                 if (pos + 6 >= tlv_end)
     831           0 :                         break;
     832          30 :                 svc_len = pos[6];
     833          30 :                 if (pos + svc_len + 10 > tlv_end)
     834           0 :                         break;
     835             : 
     836             :                 /* Advertisement ID */
     837          30 :                 adv_id = WPA_GET_LE32(pos);
     838          30 :                 pos += sizeof(u32);
     839             : 
     840             :                 /* Config Methods */
     841          30 :                 config_methods = WPA_GET_BE16(pos);
     842          30 :                 pos += sizeof(u16);
     843             : 
     844             :                 /* Service Name */
     845          30 :                 pos++; /* svc_len */
     846          30 :                 os_memcpy(svc_str, pos, svc_len);
     847          30 :                 svc_str[svc_len] = '\0';
     848          30 :                 pos += svc_len;
     849             : 
     850             :                 /* Service Status */
     851          30 :                 svc_status = *pos++;
     852             : 
     853             :                 /* Service Information Length */
     854          30 :                 buf_len = WPA_GET_LE16(pos);
     855          30 :                 pos += sizeof(u16);
     856             : 
     857             :                 /* Sanity check buffer length */
     858          30 :                 if (buf_len > (unsigned int) (tlv_end - pos))
     859           0 :                         break;
     860             : 
     861          30 :                 if (buf_len) {
     862          30 :                         buf = os_zalloc(2 * buf_len + 1);
     863          30 :                         if (buf) {
     864          30 :                                 utf8_escape((const char *) pos, buf_len, buf,
     865          30 :                                             2 * buf_len + 1);
     866             :                         }
     867             :                 }
     868             : 
     869          30 :                 pos += buf_len;
     870             : 
     871          30 :                 if (buf) {
     872         210 :                         wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
     873             :                                        MACSTR " %x %x %x %x %s '%s'",
     874         180 :                                        MAC2STR(sa), srv_trans_id, adv_id,
     875             :                                        svc_status, config_methods, svc_str,
     876             :                                        buf);
     877          30 :                         os_free(buf);
     878             :                 } else {
     879           0 :                         wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
     880             :                                        MACSTR " %x %x %x %x %s",
     881           0 :                                        MAC2STR(sa), srv_trans_id, adv_id,
     882             :                                        svc_status, config_methods, svc_str);
     883             :                 }
     884             :         }
     885          29 : }
     886             : 
     887             : 
     888          69 : void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
     889             :                       const u8 *tlvs, size_t tlvs_len)
     890             : {
     891          69 :         struct wpa_supplicant *wpa_s = ctx;
     892          69 :         const u8 *pos = tlvs;
     893          69 :         const u8 *end = tlvs + tlvs_len;
     894             :         const u8 *tlv_end;
     895             :         u16 slen;
     896             :         size_t buf_len;
     897             :         char *buf;
     898             : 
     899          69 :         wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Response TLVs",
     900             :                     tlvs, tlvs_len);
     901          69 :         if (tlvs_len > 1500) {
     902             :                 /* TODO: better way for handling this */
     903          21 :                 wpa_msg_ctrl(wpa_s, MSG_INFO,
     904             :                              P2P_EVENT_SERV_DISC_RESP MACSTR
     905             :                              " %u <long response: %u bytes>",
     906          18 :                              MAC2STR(sa), update_indic,
     907             :                              (unsigned int) tlvs_len);
     908             :         } else {
     909          66 :                 buf_len = 2 * tlvs_len + 1;
     910          66 :                 buf = os_malloc(buf_len);
     911          66 :                 if (buf) {
     912          66 :                         wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
     913         462 :                         wpa_msg_ctrl(wpa_s, MSG_INFO,
     914             :                                      P2P_EVENT_SERV_DISC_RESP MACSTR " %u %s",
     915         396 :                                      MAC2STR(sa), update_indic, buf);
     916          66 :                         os_free(buf);
     917             :                 }
     918             :         }
     919             : 
     920         683 :         while (pos < end) {
     921             :                 u8 srv_proto, srv_trans_id, status;
     922             : 
     923         545 :                 wpa_printf(MSG_DEBUG, "P2P: Service Response TLV");
     924         545 :                 slen = WPA_GET_LE16(pos);
     925         545 :                 pos += 2;
     926         545 :                 if (pos + slen > end || slen < 3) {
     927           0 :                         wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
     928             :                                    "length");
     929          69 :                         return;
     930             :                 }
     931         545 :                 tlv_end = pos + slen;
     932             : 
     933         545 :                 srv_proto = *pos++;
     934         545 :                 wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
     935             :                            srv_proto);
     936         545 :                 srv_trans_id = *pos++;
     937         545 :                 wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
     938             :                            srv_trans_id);
     939         545 :                 status = *pos++;
     940         545 :                 wpa_printf(MSG_DEBUG, "P2P: Status Code ID %u",
     941             :                            status);
     942             : 
     943         545 :                 wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
     944         545 :                             pos, tlv_end - pos);
     945             : 
     946         545 :                 if (srv_proto == P2P_SERV_P2PS && pos < tlv_end) {
     947          29 :                         wpas_sd_p2ps_serv_response(wpa_s, sa, srv_trans_id,
     948             :                                                    pos, tlv_end);
     949             :                 }
     950             : 
     951         545 :                 pos = tlv_end;
     952             :         }
     953             : 
     954          69 :         wpas_notify_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len);
     955             : }
     956             : 
     957             : 
     958          73 : u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
     959             :                         const struct wpabuf *tlvs)
     960             : {
     961          73 :         if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
     962           0 :                 return 0;
     963          73 :         return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
     964             : }
     965             : 
     966             : 
     967           3 : u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
     968             :                              u8 version, const char *query)
     969             : {
     970             :         struct wpabuf *tlvs;
     971             :         u64 ret;
     972             : 
     973           3 :         tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
     974           3 :         if (tlvs == NULL)
     975           0 :                 return 0;
     976           3 :         wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
     977           3 :         wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
     978           3 :         wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
     979           3 :         wpabuf_put_u8(tlvs, version);
     980           3 :         wpabuf_put_str(tlvs, query);
     981           3 :         ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
     982           3 :         wpabuf_free(tlvs);
     983           3 :         return ret;
     984             : }
     985             : 
     986             : 
     987          29 : u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
     988             :                             const char *svc_str, const char *info_substr)
     989             : {
     990             :         struct wpabuf *tlvs;
     991          29 :         size_t plen, svc_len, substr_len = 0;
     992             :         u64 ret;
     993             : 
     994          29 :         svc_len = os_strlen(svc_str);
     995          29 :         if (info_substr)
     996          29 :                 substr_len = os_strlen(info_substr);
     997             : 
     998          29 :         if (svc_len > 0xff || substr_len > 0xff)
     999           0 :                 return 0;
    1000             : 
    1001          29 :         plen = 1 + 1 + 1 + svc_len + 1 + substr_len;
    1002          29 :         tlvs = wpabuf_alloc(2 + plen);
    1003          29 :         if (tlvs == NULL)
    1004           0 :                 return 0;
    1005             : 
    1006          29 :         wpabuf_put_le16(tlvs, plen);
    1007          29 :         wpabuf_put_u8(tlvs, P2P_SERV_P2PS);
    1008          29 :         wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
    1009          29 :         wpabuf_put_u8(tlvs, (u8) svc_len); /* Service String Length */
    1010          29 :         wpabuf_put_data(tlvs, svc_str, svc_len);
    1011          29 :         wpabuf_put_u8(tlvs, (u8) substr_len); /* Info Substring Length */
    1012          29 :         wpabuf_put_data(tlvs, info_substr, substr_len);
    1013          29 :         ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
    1014          29 :         wpabuf_free(tlvs);
    1015             : 
    1016          29 :         return ret;
    1017             : }
    1018             : 
    1019             : 
    1020             : #ifdef CONFIG_WIFI_DISPLAY
    1021             : 
    1022           1 : static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
    1023             :                                    const struct wpabuf *tlvs)
    1024             : {
    1025           1 :         if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
    1026           0 :                 return 0;
    1027           1 :         return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
    1028             : }
    1029             : 
    1030             : 
    1031             : #define MAX_WFD_SD_SUBELEMS 20
    1032             : 
    1033           2 : static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
    1034             :                                 const char *subelems)
    1035             : {
    1036             :         u8 *len;
    1037             :         const char *pos;
    1038             :         int val;
    1039           2 :         int count = 0;
    1040             : 
    1041           2 :         len = wpabuf_put(tlvs, 2);
    1042           2 :         wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
    1043           2 :         wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
    1044             : 
    1045           2 :         wpabuf_put_u8(tlvs, role);
    1046             : 
    1047           2 :         pos = subelems;
    1048          10 :         while (*pos) {
    1049           8 :                 val = atoi(pos);
    1050           8 :                 if (val >= 0 && val < 256) {
    1051           8 :                         wpabuf_put_u8(tlvs, val);
    1052           8 :                         count++;
    1053           8 :                         if (count == MAX_WFD_SD_SUBELEMS)
    1054           0 :                                 break;
    1055             :                 }
    1056           8 :                 pos = os_strchr(pos + 1, ',');
    1057           8 :                 if (pos == NULL)
    1058           2 :                         break;
    1059           6 :                 pos++;
    1060             :         }
    1061             : 
    1062           2 :         WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
    1063           2 : }
    1064             : 
    1065             : 
    1066           1 : u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
    1067             :                                      const u8 *dst, const char *role)
    1068             : {
    1069             :         struct wpabuf *tlvs;
    1070             :         u64 ret;
    1071             :         const char *subelems;
    1072           1 :         u8 id = 1;
    1073             : 
    1074           1 :         subelems = os_strchr(role, ' ');
    1075           1 :         if (subelems == NULL)
    1076           0 :                 return 0;
    1077           1 :         subelems++;
    1078             : 
    1079           1 :         tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
    1080           1 :         if (tlvs == NULL)
    1081           0 :                 return 0;
    1082             : 
    1083           1 :         if (os_strstr(role, "[source]"))
    1084           1 :                 wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
    1085           1 :         if (os_strstr(role, "[pri-sink]"))
    1086           1 :                 wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
    1087           1 :         if (os_strstr(role, "[sec-sink]"))
    1088           0 :                 wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
    1089           1 :         if (os_strstr(role, "[source+sink]"))
    1090           0 :                 wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
    1091             : 
    1092           1 :         ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
    1093           1 :         wpabuf_free(tlvs);
    1094           1 :         return ret;
    1095             : }
    1096             : 
    1097             : #endif /* CONFIG_WIFI_DISPLAY */
    1098             : 
    1099             : 
    1100          11 : int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
    1101             : {
    1102          11 :         if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
    1103           0 :                 return -1;
    1104          11 :         return p2p_sd_cancel_request(wpa_s->global->p2p,
    1105             :                                      (void *) (uintptr_t) req);
    1106             : }
    1107             : 
    1108             : 
    1109          69 : void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
    1110             :                           const u8 *dst, u8 dialog_token,
    1111             :                           const struct wpabuf *resp_tlvs)
    1112             : {
    1113          69 :         if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
    1114          69 :                 return;
    1115          69 :         p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
    1116             :                         resp_tlvs);
    1117             : }
    1118             : 
    1119             : 
    1120        5851 : void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
    1121             : {
    1122        5851 :         if (wpa_s->global->p2p)
    1123        5851 :                 p2p_sd_service_update(wpa_s->global->p2p);
    1124        5851 : }
    1125             : 
    1126             : 
    1127         115 : static void wpas_p2p_srv_bonjour_free(struct p2p_srv_bonjour *bsrv)
    1128             : {
    1129         115 :         dl_list_del(&bsrv->list);
    1130         115 :         wpabuf_free(bsrv->query);
    1131         115 :         wpabuf_free(bsrv->resp);
    1132         115 :         os_free(bsrv);
    1133         115 : }
    1134             : 
    1135             : 
    1136         507 : static void wpas_p2p_srv_upnp_free(struct p2p_srv_upnp *usrv)
    1137             : {
    1138         507 :         dl_list_del(&usrv->list);
    1139         507 :         os_free(usrv->service);
    1140         507 :         os_free(usrv);
    1141         507 : }
    1142             : 
    1143             : 
    1144        5110 : void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s)
    1145             : {
    1146             :         struct p2p_srv_bonjour *bsrv, *bn;
    1147             :         struct p2p_srv_upnp *usrv, *un;
    1148             : 
    1149        5205 :         dl_list_for_each_safe(bsrv, bn, &wpa_s->global->p2p_srv_bonjour,
    1150             :                               struct p2p_srv_bonjour, list)
    1151          95 :                 wpas_p2p_srv_bonjour_free(bsrv);
    1152             : 
    1153        5597 :         dl_list_for_each_safe(usrv, un, &wpa_s->global->p2p_srv_upnp,
    1154             :                               struct p2p_srv_upnp, list)
    1155         487 :                 wpas_p2p_srv_upnp_free(usrv);
    1156             : 
    1157        5110 :         wpas_p2p_service_flush_asp(wpa_s);
    1158        5110 :         wpas_p2p_sd_service_update(wpa_s);
    1159        5110 : }
    1160             : 
    1161             : 
    1162          45 : int wpas_p2p_service_p2ps_id_exists(struct wpa_supplicant *wpa_s, u32 adv_id)
    1163             : {
    1164          45 :         if (adv_id == 0)
    1165           0 :                 return 1;
    1166             : 
    1167          45 :         if (p2p_service_p2ps_id(wpa_s->global->p2p, adv_id))
    1168           2 :                 return 1;
    1169             : 
    1170          43 :         return 0;
    1171             : }
    1172             : 
    1173             : 
    1174          33 : int wpas_p2p_service_del_asp(struct wpa_supplicant *wpa_s, u32 adv_id)
    1175             : {
    1176             :         int ret;
    1177             : 
    1178          33 :         ret = p2p_service_del_asp(wpa_s->global->p2p, adv_id);
    1179          33 :         if (ret == 0)
    1180          33 :                 wpas_p2p_sd_service_update(wpa_s);
    1181          33 :         return ret;
    1182             : }
    1183             : 
    1184             : 
    1185          45 : int wpas_p2p_service_add_asp(struct wpa_supplicant *wpa_s,
    1186             :                              int auto_accept, u32 adv_id,
    1187             :                              const char *adv_str, u8 svc_state,
    1188             :                              u16 config_methods, const char *svc_info,
    1189             :                              const u8 *cpt_priority)
    1190             : {
    1191             :         int ret;
    1192             : 
    1193          45 :         ret = p2p_service_add_asp(wpa_s->global->p2p, auto_accept, adv_id,
    1194             :                                   adv_str, svc_state, config_methods,
    1195             :                                   svc_info, cpt_priority);
    1196          45 :         if (ret == 0)
    1197          44 :                 wpas_p2p_sd_service_update(wpa_s);
    1198          45 :         return ret;
    1199             : }
    1200             : 
    1201             : 
    1202        5111 : void wpas_p2p_service_flush_asp(struct wpa_supplicant *wpa_s)
    1203             : {
    1204        5111 :         p2p_service_flush_asp(wpa_s->global->p2p);
    1205        5111 : }
    1206             : 
    1207             : 
    1208         116 : int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
    1209             :                                  struct wpabuf *query, struct wpabuf *resp)
    1210             : {
    1211             :         struct p2p_srv_bonjour *bsrv;
    1212             : 
    1213         116 :         bsrv = os_zalloc(sizeof(*bsrv));
    1214         116 :         if (bsrv == NULL)
    1215           1 :                 return -1;
    1216         115 :         bsrv->query = query;
    1217         115 :         bsrv->resp = resp;
    1218         115 :         dl_list_add(&wpa_s->global->p2p_srv_bonjour, &bsrv->list);
    1219             : 
    1220         115 :         wpas_p2p_sd_service_update(wpa_s);
    1221         115 :         return 0;
    1222             : }
    1223             : 
    1224             : 
    1225          40 : int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
    1226             :                                  const struct wpabuf *query)
    1227             : {
    1228             :         struct p2p_srv_bonjour *bsrv;
    1229             : 
    1230          40 :         bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
    1231          40 :         if (bsrv == NULL)
    1232          20 :                 return -1;
    1233          20 :         wpas_p2p_srv_bonjour_free(bsrv);
    1234          20 :         wpas_p2p_sd_service_update(wpa_s);
    1235          20 :         return 0;
    1236             : }
    1237             : 
    1238             : 
    1239         541 : int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
    1240             :                               const char *service)
    1241             : {
    1242             :         struct p2p_srv_upnp *usrv;
    1243             : 
    1244         541 :         if (wpas_p2p_service_get_upnp(wpa_s, version, service))
    1245          34 :                 return 0; /* Already listed */
    1246         507 :         usrv = os_zalloc(sizeof(*usrv));
    1247         507 :         if (usrv == NULL)
    1248           0 :                 return -1;
    1249         507 :         usrv->version = version;
    1250         507 :         usrv->service = os_strdup(service);
    1251         507 :         if (usrv->service == NULL) {
    1252           0 :                 os_free(usrv);
    1253           0 :                 return -1;
    1254             :         }
    1255         507 :         dl_list_add(&wpa_s->global->p2p_srv_upnp, &usrv->list);
    1256             : 
    1257         507 :         wpas_p2p_sd_service_update(wpa_s);
    1258         507 :         return 0;
    1259             : }
    1260             : 
    1261             : 
    1262          40 : int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
    1263             :                               const char *service)
    1264             : {
    1265             :         struct p2p_srv_upnp *usrv;
    1266             : 
    1267          40 :         usrv = wpas_p2p_service_get_upnp(wpa_s, version, service);
    1268          40 :         if (usrv == NULL)
    1269          20 :                 return -1;
    1270          20 :         wpas_p2p_srv_upnp_free(usrv);
    1271          20 :         wpas_p2p_sd_service_update(wpa_s);
    1272          20 :         return 0;
    1273             : }

Generated by: LCOV version 1.10