]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libsdp/search.c
Merge llvm-project release/17.x llvmorg-17.0.2-0-gb2417f51dbbd
[FreeBSD/FreeBSD.git] / lib / libsdp / search.c
1 /*-
2  * search.c
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the 
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $Id: search.c,v 1.2 2003/09/04 22:12:13 max Exp $
31  */
32
33 #include <sys/uio.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #define L2CAP_SOCKET_CHECKED
37 #include <bluetooth.h>
38 #include <errno.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 #include <sdp-int.h>
45 #include <sdp.h>
46
47 int32_t
48 sdp_search(void *xss,
49                 uint32_t plen, uint16_t const *pp,
50                 uint32_t alen, uint32_t const *ap,
51                 uint32_t vlen, sdp_attr_t *vp)
52 {
53         struct sdp_xpdu {
54                 sdp_pdu_t                pdu;
55                 uint16_t                 len;
56         } __attribute__ ((packed))       xpdu;
57
58         sdp_session_p                    ss = (sdp_session_p) xss;
59         uint8_t                         *req = NULL, *rsp = NULL, *rsp_tmp = NULL;
60         int32_t                          t, len;
61         uint16_t                         lo, hi;
62
63         if (ss == NULL)
64                 return (-1);
65
66         if (ss->req == NULL || ss->rsp == NULL ||
67             plen == 0 || pp == NULL || alen == 0 || ap == NULL) {
68                 ss->error = EINVAL;
69                 return (-1);
70         }
71
72         req = ss->req;
73
74         /* Calculate ServiceSearchPattern length */
75         plen = plen * (sizeof(pp[0]) + 1);
76
77         /* Calculate AttributeIDList length */
78         for (len = 0, t = 0; t < alen; t ++) {
79                 lo = (uint16_t) (ap[t] >> 16);
80                 hi = (uint16_t) (ap[t]);
81
82                 if (lo > hi) {
83                         ss->error = EINVAL;
84                         return (-1);
85                 }
86
87                 if (lo != hi)
88                         len += (sizeof(ap[t]) + 1);
89                 else
90                         len += (sizeof(lo) + 1);
91         }
92         alen = len;
93
94         /* Calculate length of the request */
95         len =   plen + sizeof(uint8_t) + sizeof(uint16_t) +
96                         /* ServiceSearchPattern */
97                 sizeof(uint16_t) +
98                         /* MaximumAttributeByteCount */
99                 alen + sizeof(uint8_t) + sizeof(uint16_t);
100                         /* AttributeIDList */
101
102         if (ss->req_e - req < len) {
103                 ss->error = ENOBUFS;
104                 return (-1);
105         }
106                 
107         /* Put ServiceSearchPattern */
108         SDP_PUT8(SDP_DATA_SEQ16, req);
109         SDP_PUT16(plen, req);
110         for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) {
111                 SDP_PUT8(SDP_DATA_UUID16, req);
112                 SDP_PUT16(*pp, req);
113         }
114
115         /* Put MaximumAttributeByteCount */
116         SDP_PUT16(0xffff, req);
117
118         /* Put AttributeIDList */
119         SDP_PUT8(SDP_DATA_SEQ16, req);
120         SDP_PUT16(alen, req);
121         for (; alen > 0; ap ++) {
122                 lo = (uint16_t) (*ap >> 16);
123                 hi = (uint16_t) (*ap);
124
125                 if (lo != hi) {
126                         /* Put attribute range */
127                         SDP_PUT8(SDP_DATA_UINT32, req);
128                         SDP_PUT32(*ap, req);
129                         alen -= (sizeof(ap[0]) + 1);
130                 } else {
131                         /* Put attribute */
132                         SDP_PUT8(SDP_DATA_UINT16, req);
133                         SDP_PUT16(lo, req);
134                         alen -= (sizeof(lo) + 1);
135                 }
136         }
137
138         /* Submit ServiceSearchAttributeRequest and wait for response */
139         ss->cslen = 0;
140         rsp = ss->rsp;
141
142         do {
143                 struct iovec     iov[2];
144                 uint8_t         *req_cs = req;
145
146                 /* Add continuation state (if any) */
147                 if (ss->req_e - req_cs < ss->cslen + 1) {
148                         ss->error = ENOBUFS;
149                         return (-1);
150                 }
151
152                 SDP_PUT8(ss->cslen, req_cs);
153                 if (ss->cslen > 0) {
154                         memcpy(req_cs, ss->cs, ss->cslen);
155                         req_cs += ss->cslen;
156                 }
157
158                 /* Prepare SDP PDU header */
159                 xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
160                 xpdu.pdu.tid = htons(ss->tid);
161                 xpdu.pdu.len = htons(req_cs - ss->req);
162
163                 /* Submit request */
164                 iov[0].iov_base = (void *) &xpdu;
165                 iov[0].iov_len = sizeof(xpdu.pdu);
166                 iov[1].iov_base = (void *) ss->req;
167                 iov[1].iov_len = req_cs - ss->req;
168
169                 do {
170                         len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
171                 } while (len < 0 && errno == EINTR);
172
173                 if (len < 0) {
174                         ss->error = errno;
175                         return (-1);
176                 }
177
178                 /* Read response */
179                 iov[0].iov_base = (void *) &xpdu;
180                 iov[0].iov_len = sizeof(xpdu);
181                 iov[1].iov_base = (void *) rsp;
182                 iov[1].iov_len = ss->imtu;
183
184                 do {
185                         len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
186                 } while (len < 0 && errno == EINTR);
187
188                 if (len < 0) {
189                         ss->error = errno;
190                         return (-1);
191                 }
192                 if (len < sizeof(xpdu)) {
193                         ss->error = ENOMSG;
194                         return (-1);
195                 }
196
197                 xpdu.pdu.tid = ntohs(xpdu.pdu.tid);
198                 xpdu.pdu.len = ntohs(xpdu.pdu.len);
199                 xpdu.len = ntohs(xpdu.len);
200
201                 if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE ||
202                     xpdu.pdu.tid != ss->tid ||
203                     xpdu.pdu.len > len ||
204                     xpdu.len > xpdu.pdu.len) {
205                         ss->error = EIO;
206                         return (-1);
207                 }
208
209                 rsp += xpdu.len;
210                 ss->tid ++;
211
212                 /* Save continuation state (if any) */
213                 ss->cslen = rsp[0];
214                 if (ss->cslen > 0) {
215                         if (ss->cslen > sizeof(ss->cs)) {
216                                 ss->error = ENOBUFS;
217                                 return (-1);
218                         }
219
220                         memcpy(ss->cs, rsp + 1, ss->cslen);
221
222                         /*
223                          * Ensure that we always have ss->imtu bytes
224                          * available in the ss->rsp buffer
225                          */
226
227                         if (ss->rsp_e - rsp <= ss->imtu) {
228                                 uint32_t         size, offset;
229
230                                 size = ss->rsp_e - ss->rsp + ss->imtu;
231                                 offset = rsp - ss->rsp;
232                 
233                                 rsp_tmp = realloc(ss->rsp, size);
234                                 if (rsp_tmp == NULL) {
235                                         ss->error = ENOMEM;
236                                         return (-1);
237                                 }
238
239                                 ss->rsp = rsp_tmp;
240                                 ss->rsp_e = ss->rsp + size;
241                                 rsp = ss->rsp + offset;
242                         }
243                 }
244         } while (ss->cslen > 0);
245
246         /*
247          * If we got here then we have completed SDP transaction and now
248          * we must populate attribute values into vp array. At this point
249          * ss->rsp points to the beginning of the response and rsp points
250          * to the end of the response.
251          * 
252          * From Bluetooth v1.1 spec page 364
253          * 
254          * The AttributeLists is a data element sequence where each element
255          * in turn is a data element sequence representing an attribute list.
256          * Each attribute list contains attribute IDs and attribute values 
257          * from one service record. The first element in each attribute list
258          * contains the attribute ID of the first attribute to be returned for
259          * that service record. The second element in each attribute list
260          * contains the corresponding attribute value. Successive pairs of
261          * elements in each attribute list contain additional attribute ID
262          * and value pairs. Only attributes that have non-null values within
263          * the service record and whose attribute IDs were specified in the
264          * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
265          * Neither an attribute ID nor attribute value is placed in 
266          * AttributeLists for attributes in the service record that have no 
267          * value. Within each attribute list, the attributes are listed in 
268          * ascending order of attribute ID value.
269          */
270
271         if (vp == NULL)
272                 goto done;
273
274         rsp_tmp = ss->rsp;
275
276         /* Skip the first SEQ */
277         SDP_GET8(t, rsp_tmp);
278         switch (t) {
279         case SDP_DATA_SEQ8:
280                 SDP_GET8(len, rsp_tmp);
281                 break;
282
283         case SDP_DATA_SEQ16:
284                 SDP_GET16(len, rsp_tmp);
285                 break;
286
287         case SDP_DATA_SEQ32:
288                 SDP_GET32(len, rsp_tmp);
289                 break;
290
291         default:
292                 ss->error = ENOATTR;
293                 return (-1);
294                 /* NOT REACHED */
295         }
296
297         for (; rsp_tmp < rsp && vlen > 0; ) {
298                 /* Get set of attributes for the next record */
299                 SDP_GET8(t, rsp_tmp);
300                 switch (t) {
301                 case SDP_DATA_SEQ8:
302                         SDP_GET8(len, rsp_tmp);
303                         break;
304
305                 case SDP_DATA_SEQ16:
306                         SDP_GET16(len, rsp_tmp);
307                         break;
308
309                 case SDP_DATA_SEQ32:
310                         SDP_GET32(len, rsp_tmp);
311                         break;
312
313                 default:
314                         ss->error = ENOATTR;
315                         return (-1);
316                         /* NOT REACHED */
317                 }
318
319                 /* Now rsp_tmp points to list of (attr,value) pairs */
320                 for (; len > 0 && vlen > 0; vp ++, vlen --) {
321                         /* Attribute */
322                         SDP_GET8(t, rsp_tmp);
323                         if (t != SDP_DATA_UINT16) {
324                                 ss->error = ENOATTR;
325                                 return (-1);
326                         }
327                         SDP_GET16(vp->attr, rsp_tmp);
328
329                         /* Attribute value */
330                         switch (rsp_tmp[0]) {
331                         case SDP_DATA_NIL:
332                                 alen = 0;
333                                 break;
334
335                         case SDP_DATA_UINT8:
336                         case SDP_DATA_INT8:
337                         case SDP_DATA_BOOL:
338                                 alen = sizeof(uint8_t);
339                                 break;
340
341                         case SDP_DATA_UINT16:
342                         case SDP_DATA_INT16:
343                         case SDP_DATA_UUID16:
344                                 alen = sizeof(uint16_t);
345                                 break;
346
347                         case SDP_DATA_UINT32:
348                         case SDP_DATA_INT32:
349                         case SDP_DATA_UUID32:
350                                 alen = sizeof(uint32_t);
351                                 break;
352
353                         case SDP_DATA_UINT64:
354                         case SDP_DATA_INT64:
355                                 alen = sizeof(uint64_t);
356                                 break;
357
358                         case SDP_DATA_UINT128:
359                         case SDP_DATA_INT128:
360                         case SDP_DATA_UUID128:
361                                 alen = sizeof(uint128_t);
362                                 break;
363
364                         case SDP_DATA_STR8:
365                         case SDP_DATA_URL8:
366                         case SDP_DATA_SEQ8:
367                         case SDP_DATA_ALT8:
368                                 alen = rsp_tmp[1] + sizeof(uint8_t);
369                                 break;
370
371                         case SDP_DATA_STR16:
372                         case SDP_DATA_URL16:
373                         case SDP_DATA_SEQ16:
374                         case SDP_DATA_ALT16:
375                                 alen =    ((uint16_t)rsp_tmp[1] << 8)
376                                         | ((uint16_t)rsp_tmp[2]);
377                                 alen += sizeof(uint16_t);
378                                 break;
379
380                         case SDP_DATA_STR32:
381                         case SDP_DATA_URL32:
382                         case SDP_DATA_SEQ32:
383                         case SDP_DATA_ALT32:
384                                 alen =    ((uint32_t)rsp_tmp[1] << 24)
385                                         | ((uint32_t)rsp_tmp[2] << 16)
386                                         | ((uint32_t)rsp_tmp[3] <<  8)
387                                         | ((uint32_t)rsp_tmp[4]);
388                                 alen += sizeof(uint32_t);
389                                 break;
390
391                         default:
392                                 ss->error = ENOATTR;
393                                 return (-1);
394                                 /* NOT REACHED */
395                         }
396
397                         alen += sizeof(uint8_t);
398
399                         if (vp->value != NULL) {
400                                 if (alen <= vp->vlen) {
401                                         vp->flags = SDP_ATTR_OK;
402                                         vp->vlen = alen;
403                                 } else
404                                         vp->flags = SDP_ATTR_TRUNCATED;
405
406                                 memcpy(vp->value, rsp_tmp, vp->vlen);
407                         } else
408                                 vp->flags = SDP_ATTR_INVALID;
409
410                         len -=  (
411                                 sizeof(uint8_t) + sizeof(uint16_t) +
412                                 alen
413                                 );
414
415                         rsp_tmp += alen;
416                 }
417         }
418 done:
419         ss->error = 0;
420
421         return (0);
422 }
423