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