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