]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/bluetooth/sdpd/ssar.c
MFC r343905:
[FreeBSD/stable/10.git] / usr.sbin / bluetooth / sdpd / ssar.c
1 /*
2  * ssar.c
3  *
4  * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
29  * $FreeBSD$
30  */
31
32 #include <sys/queue.h>
33 #include <bluetooth.h>
34 #include <sdp.h>
35 #include <string.h>
36 #include "profile.h"
37 #include "provider.h"
38 #include "server.h"
39 #include "uuid-private.h"
40
41 /* from sar.c */
42 int32_t server_prepare_attr_list(provider_p const provider,
43                 uint8_t const *req, uint8_t const * const req_end,
44                 uint8_t *rsp, uint8_t const * const rsp_end);
45
46 /*
47  * Scan an attribute for matching UUID.
48  */
49 static int
50 server_search_uuid_sub(uint8_t *buf, uint8_t const * const eob, const uint128_t *uuid)
51 {
52         int128_t duuid;
53         uint32_t value;
54         uint8_t type;
55
56         while (buf < eob) {
57
58                 SDP_GET8(type, buf);
59
60                 switch (type) {
61                 case SDP_DATA_UUID16:
62                         if (buf + 2 > eob)
63                                 continue;
64                         SDP_GET16(value, buf);
65
66                         memcpy(&duuid, &uuid_base, sizeof(duuid));
67                         duuid.b[2] = value >> 8 & 0xff;
68                         duuid.b[3] = value & 0xff;
69
70                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
71                                 return (0);
72                         break;
73                 case SDP_DATA_UUID32:
74                         if (buf + 4 > eob)
75                                 continue;
76                         SDP_GET32(value, buf);
77                         memcpy(&duuid, &uuid_base, sizeof(duuid));
78                         duuid.b[0] = value >> 24 & 0xff;
79                         duuid.b[1] = value >> 16 & 0xff;
80                         duuid.b[2] = value >> 8 & 0xff;
81                         duuid.b[3] = value & 0xff;
82
83                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
84                                 return (0);
85                         break;
86                 case SDP_DATA_UUID128:
87                         if (buf + 16 > eob)
88                                 continue;
89                         SDP_GET_UUID128(&duuid, buf);
90
91                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
92                                 return (0);
93                         break;
94                 case SDP_DATA_UINT8:
95                 case SDP_DATA_INT8:
96                 case SDP_DATA_SEQ8:
97                         buf++;
98                         break;
99                 case SDP_DATA_UINT16:
100                 case SDP_DATA_INT16:
101                 case SDP_DATA_SEQ16:
102                         buf += 2;
103                         break;
104                 case SDP_DATA_UINT32:
105                 case SDP_DATA_INT32:
106                 case SDP_DATA_SEQ32:
107                         buf += 4;
108                         break;
109                 case SDP_DATA_UINT64:
110                 case SDP_DATA_INT64:
111                         buf += 8;
112                         break;
113                 case SDP_DATA_UINT128:
114                 case SDP_DATA_INT128:
115                         buf += 16;
116                         break;
117                 case SDP_DATA_STR8:
118                         if (buf + 1 > eob)
119                                 continue;
120                         SDP_GET8(value, buf);
121                         buf += value;
122                         break;
123                 case SDP_DATA_STR16:
124                         if (buf + 2 > eob)
125                                 continue;
126                         SDP_GET16(value, buf);
127                         if (value > (eob - buf))
128                                 return (1);
129                         buf += value;
130                         break;
131                 case SDP_DATA_STR32:
132                         if (buf + 4 > eob)
133                                 continue;
134                         SDP_GET32(value, buf);
135                         if (value > (eob - buf))
136                                 return (1);
137                         buf += value;
138                         break;
139                 case SDP_DATA_BOOL:
140                         buf += 1;
141                         break;
142                 default:
143                         return (1);
144                 }
145         }
146         return (1);
147 }
148
149 /*
150  * Search a provider for matching UUID in its attributes.
151  */
152 static int
153 server_search_uuid(provider_p const provider, const uint128_t *uuid)
154 {
155         uint8_t buffer[256];
156         const attr_t *attr;
157         int len;
158
159         for (attr = provider->profile->attrs; attr->create != NULL; attr++) {
160
161                 len = attr->create(buffer, buffer + sizeof(buffer),
162                     (const uint8_t *)provider->profile, sizeof(*provider->profile));
163                 if (len < 0)
164                         continue;
165                 if (server_search_uuid_sub(buffer, buffer + len, uuid) == 0)
166                         return (0);
167         }
168         return (1);
169 }
170
171 /*
172  * Prepare SDP Service Search Attribute Response
173  */
174
175 int32_t
176 server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
177 {
178         uint8_t const   *req = srv->req + sizeof(sdp_pdu_t);
179         uint8_t const   *req_end = req + ((sdp_pdu_p)(srv->req))->len;
180         uint8_t         *rsp = srv->fdidx[fd].rsp;
181         uint8_t const   *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
182
183         uint8_t const   *sspptr = NULL, *aidptr = NULL;
184         uint8_t         *ptr = NULL;
185
186         provider_t      *provider = NULL;
187         int32_t          type, rsp_limit, ssplen, aidlen, cslen, cs;
188         uint128_t        uuid, puuid;
189
190         /*
191          * Minimal Service Search Attribute Request request
192          *
193          * seq8 len8            - 2 bytes
194          *      uuid16 value16  - 3 bytes ServiceSearchPattern
195          * value16              - 2 bytes MaximumAttributeByteCount
196          * seq8 len8            - 2 bytes
197          *      uint16 value16  - 3 bytes AttributeIDList
198          * value8               - 1 byte  ContinuationState
199          */
200
201         if (req_end - req < 13)
202                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
203
204         /* Get size of ServiceSearchPattern */
205         ssplen = 0;
206         SDP_GET8(type, req);
207         switch (type) {
208         case SDP_DATA_SEQ8:
209                 SDP_GET8(ssplen, req);
210                 break;
211
212         case SDP_DATA_SEQ16:
213                 SDP_GET16(ssplen, req);
214                 break;
215
216         case SDP_DATA_SEQ32:
217                 SDP_GET32(ssplen, req);
218                 break;
219         }
220         if (ssplen <= 0)
221                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
222
223         sspptr = req;
224         req += ssplen;
225
226         /* Get MaximumAttributeByteCount */
227         if (req + 2 > req_end)
228                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
229
230         SDP_GET16(rsp_limit, req);
231         if (rsp_limit <= 0)
232                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
233
234         /* Get size of AttributeIDList */
235         if (req + 1 > req_end)
236                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
237
238         aidlen = 0;
239         SDP_GET8(type, req);
240         switch (type) {
241         case SDP_DATA_SEQ8:
242                 if (req + 1 > req_end)
243                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
244
245                 SDP_GET8(aidlen, req);
246                 break;
247
248         case SDP_DATA_SEQ16:
249                 if (req + 2 > req_end)
250                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
251
252                 SDP_GET16(aidlen, req);
253                 break;
254
255         case SDP_DATA_SEQ32:
256                 if (req + 4 > req_end)
257                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
258
259                 SDP_GET32(aidlen, req);
260                 break;
261         }
262         if (aidlen <= 0)
263                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
264
265         aidptr = req;
266         req += aidlen;
267
268         /* Get ContinuationState */
269         if (req + 1 > req_end)
270                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
271
272         SDP_GET8(cslen, req);
273         if (cslen != 0) {
274                 if (cslen != 2 || req_end - req != 2)
275                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
276
277                 SDP_GET16(cs, req);
278         } else
279                 cs = 0;
280
281         /* Process the request. First, check continuation state */
282         if (srv->fdidx[fd].rsp_cs != cs)
283                 return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
284         if (srv->fdidx[fd].rsp_size > 0)
285                 return (0);
286
287         /*
288          * Service Search Attribute Response format
289          *
290          * value16              - 2 bytes  AttributeListByteCount (not incl.)
291          * seq8 len16           - 3 bytes
292          *      attr list       - 3+ bytes AttributeLists
293          *      [ attr list ]
294          */
295
296         ptr = rsp + 3;
297
298         while (ssplen > 0) {
299                 SDP_GET8(type, sspptr);
300                 ssplen --;
301
302                 switch (type) {
303                 case SDP_DATA_UUID16:
304                         if (ssplen < 2)
305                                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
306
307                         memcpy(&uuid, &uuid_base, sizeof(uuid));
308                         uuid.b[2] = *sspptr ++;
309                         uuid.b[3] = *sspptr ++;
310                         ssplen -= 2;
311                         break;
312
313                 case SDP_DATA_UUID32:
314                         if (ssplen < 4)
315                                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
316
317                         memcpy(&uuid, &uuid_base, sizeof(uuid));
318                         uuid.b[0] = *sspptr ++;
319                         uuid.b[1] = *sspptr ++;
320                         uuid.b[2] = *sspptr ++;
321                         uuid.b[3] = *sspptr ++;
322                         ssplen -= 4;
323                         break;
324
325                 case SDP_DATA_UUID128:
326                         if (ssplen < 16)
327                                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
328
329                         memcpy(uuid.b, sspptr, 16);
330                         sspptr += 16;   
331                         ssplen -= 16; 
332                         break;
333
334                 default:
335                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
336                         /* NOT REACHED */
337                 }
338
339                 for (provider = provider_get_first();
340                      provider != NULL;
341                      provider = provider_get_next(provider)) {
342                         if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
343                                 continue;
344
345                         memcpy(&puuid, &uuid_base, sizeof(puuid));
346                         puuid.b[2] = provider->profile->uuid >> 8;
347                         puuid.b[3] = provider->profile->uuid;
348
349                         if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 &&
350                             memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0 &&
351                             server_search_uuid(provider, &uuid) != 0)
352                                 continue;
353
354                         cs = server_prepare_attr_list(provider,
355                                 aidptr, aidptr + aidlen, ptr, rsp_end);
356                         if (cs < 0)
357                                 return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
358
359                         ptr += cs;
360                 }
361         }
362
363         /* Set reply size (not counting PDU header and continuation state) */
364         srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
365         if (srv->fdidx[fd].rsp_limit > rsp_limit)
366                 srv->fdidx[fd].rsp_limit = rsp_limit;
367
368         srv->fdidx[fd].rsp_size = ptr - rsp;
369         srv->fdidx[fd].rsp_cs = 0;
370
371         /* Fix AttributeLists sequence header */
372         ptr = rsp;
373         SDP_PUT8(SDP_DATA_SEQ16, ptr);
374         SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
375
376         return (0);
377 }
378