]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bluetooth/sdpd/ssar.c
bluetooth: Fix a mandoc related issues
[FreeBSD/FreeBSD.git] / usr.sbin / bluetooth / sdpd / ssar.c
1 /*-
2  * ssar.c
3  *
4  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5  *
6  * Copyright (c) 2004 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: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
31  * $FreeBSD$
32  */
33
34 #include <sys/queue.h>
35 #define L2CAP_SOCKET_CHECKED
36 #include <bluetooth.h>
37 #include <sdp.h>
38 #include <string.h>
39 #include "profile.h"
40 #include "provider.h"
41 #include "server.h"
42 #include "uuid-private.h"
43
44 /* from sar.c */
45 int32_t server_prepare_attr_list(provider_p const provider,
46                 uint8_t const *req, uint8_t const * const req_end,
47                 uint8_t *rsp, uint8_t const * const rsp_end);
48
49 /*
50  * Scan an attribute for matching UUID.
51  */
52 static int
53 server_search_uuid_sub(uint8_t *buf, uint8_t const * const eob, const uint128_t *uuid)
54 {
55         int128_t duuid;
56         uint32_t value;
57         uint8_t type;
58
59         while (buf < eob) {
60
61                 SDP_GET8(type, buf);
62
63                 switch (type) {
64                 case SDP_DATA_UUID16:
65                         if (buf + 2 > eob)
66                                 continue;
67                         SDP_GET16(value, buf);
68
69                         memcpy(&duuid, &uuid_base, sizeof(duuid));
70                         duuid.b[2] = value >> 8 & 0xff;
71                         duuid.b[3] = value & 0xff;
72
73                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
74                                 return (0);
75                         break;
76                 case SDP_DATA_UUID32:
77                         if (buf + 4 > eob)
78                                 continue;
79                         SDP_GET32(value, buf);
80                         memcpy(&duuid, &uuid_base, sizeof(duuid));
81                         duuid.b[0] = value >> 24 & 0xff;
82                         duuid.b[1] = value >> 16 & 0xff;
83                         duuid.b[2] = value >> 8 & 0xff;
84                         duuid.b[3] = value & 0xff;
85
86                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
87                                 return (0);
88                         break;
89                 case SDP_DATA_UUID128:
90                         if (buf + 16 > eob)
91                                 continue;
92                         SDP_GET_UUID128(&duuid, buf);
93
94                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
95                                 return (0);
96                         break;
97                 case SDP_DATA_UINT8:
98                 case SDP_DATA_INT8:
99                 case SDP_DATA_SEQ8:
100                         buf++;
101                         break;
102                 case SDP_DATA_UINT16:
103                 case SDP_DATA_INT16:
104                 case SDP_DATA_SEQ16:
105                         buf += 2;
106                         break;
107                 case SDP_DATA_UINT32:
108                 case SDP_DATA_INT32:
109                 case SDP_DATA_SEQ32:
110                         buf += 4;
111                         break;
112                 case SDP_DATA_UINT64:
113                 case SDP_DATA_INT64:
114                         buf += 8;
115                         break;
116                 case SDP_DATA_UINT128:
117                 case SDP_DATA_INT128:
118                         buf += 16;
119                         break;
120                 case SDP_DATA_STR8:
121                         if (buf + 1 > eob)
122                                 continue;
123                         SDP_GET8(value, buf);
124                         buf += value;
125                         break;
126                 case SDP_DATA_STR16:
127                         if (buf + 2 > eob)
128                                 continue;
129                         SDP_GET16(value, buf);
130                         if (value > (eob - buf))
131                                 return (1);
132                         buf += value;
133                         break;
134                 case SDP_DATA_STR32:
135                         if (buf + 4 > eob)
136                                 continue;
137                         SDP_GET32(value, buf);
138                         if (value > (eob - buf))
139                                 return (1);
140                         buf += value;
141                         break;
142                 case SDP_DATA_BOOL:
143                         buf += 1;
144                         break;
145                 default:
146                         return (1);
147                 }
148         }
149         return (1);
150 }
151
152 /*
153  * Search a provider for matching UUID in its attributes.
154  */
155 static int
156 server_search_uuid(provider_p const provider, const uint128_t *uuid)
157 {
158         uint8_t buffer[256];
159         const attr_t *attr;
160         int len;
161
162         for (attr = provider->profile->attrs; attr->create != NULL; attr++) {
163
164                 len = attr->create(buffer, buffer + sizeof(buffer),
165                     (const uint8_t *)provider->profile, sizeof(*provider->profile));
166                 if (len < 0)
167                         continue;
168                 if (server_search_uuid_sub(buffer, buffer + len, uuid) == 0)
169                         return (0);
170         }
171         return (1);
172 }
173
174 /*
175  * Prepare SDP Service Search Attribute Response
176  */
177
178 int32_t
179 server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
180 {
181         uint8_t const   *req = srv->req + sizeof(sdp_pdu_t);
182         uint8_t const   *req_end = req + ((sdp_pdu_p)(srv->req))->len;
183         uint8_t         *rsp = srv->fdidx[fd].rsp;
184         uint8_t const   *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
185
186         uint8_t const   *sspptr = NULL, *aidptr = NULL;
187         uint8_t         *ptr = NULL;
188
189         provider_t      *provider = NULL;
190         int32_t          type, rsp_limit, ssplen, aidlen, cslen, cs;
191         uint128_t        uuid, puuid;
192
193         /*
194          * Minimal Service Search Attribute Request request
195          *
196          * seq8 len8            - 2 bytes
197          *      uuid16 value16  - 3 bytes ServiceSearchPattern
198          * value16              - 2 bytes MaximumAttributeByteCount
199          * seq8 len8            - 2 bytes
200          *      uint16 value16  - 3 bytes AttributeIDList
201          * value8               - 1 byte  ContinuationState
202          */
203
204         if (req_end - req < 13)
205                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
206
207         /* Get size of ServiceSearchPattern */
208         ssplen = 0;
209         SDP_GET8(type, req);
210         switch (type) {
211         case SDP_DATA_SEQ8:
212                 SDP_GET8(ssplen, req);
213                 break;
214
215         case SDP_DATA_SEQ16:
216                 SDP_GET16(ssplen, req);
217                 break;
218
219         case SDP_DATA_SEQ32:
220                 SDP_GET32(ssplen, req);
221                 break;
222         }
223         if (ssplen <= 0)
224                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
225
226         sspptr = req;
227         req += ssplen;
228
229         /* Get MaximumAttributeByteCount */
230         if (req + 2 > req_end)
231                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
232
233         SDP_GET16(rsp_limit, req);
234         if (rsp_limit <= 0)
235                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
236
237         /* Get size of AttributeIDList */
238         if (req + 1 > req_end)
239                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
240
241         aidlen = 0;
242         SDP_GET8(type, req);
243         switch (type) {
244         case SDP_DATA_SEQ8:
245                 if (req + 1 > req_end)
246                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
247
248                 SDP_GET8(aidlen, req);
249                 break;
250
251         case SDP_DATA_SEQ16:
252                 if (req + 2 > req_end)
253                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
254
255                 SDP_GET16(aidlen, req);
256                 break;
257
258         case SDP_DATA_SEQ32:
259                 if (req + 4 > req_end)
260                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
261
262                 SDP_GET32(aidlen, req);
263                 break;
264         }
265         if (aidlen <= 0)
266                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
267
268         aidptr = req;
269         req += aidlen;
270
271         /* Get ContinuationState */
272         if (req + 1 > req_end)
273                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
274
275         SDP_GET8(cslen, req);
276         if (cslen != 0) {
277                 if (cslen != 2 || req_end - req != 2)
278                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
279
280                 SDP_GET16(cs, req);
281         } else
282                 cs = 0;
283
284         /* Process the request. First, check continuation state */
285         if (srv->fdidx[fd].rsp_cs != cs)
286                 return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
287         if (srv->fdidx[fd].rsp_size > 0)
288                 return (0);
289
290         /*
291          * Service Search Attribute Response format
292          *
293          * value16              - 2 bytes  AttributeListByteCount (not incl.)
294          * seq8 len16           - 3 bytes
295          *      attr list       - 3+ bytes AttributeLists
296          *      [ attr list ]
297          */
298
299         ptr = rsp + 3;
300
301         while (ssplen > 0) {
302                 SDP_GET8(type, sspptr);
303                 ssplen --;
304
305                 switch (type) {
306                 case SDP_DATA_UUID16:
307                         if (ssplen < 2)
308                                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
309
310                         memcpy(&uuid, &uuid_base, sizeof(uuid));
311                         uuid.b[2] = *sspptr ++;
312                         uuid.b[3] = *sspptr ++;
313                         ssplen -= 2;
314                         break;
315
316                 case SDP_DATA_UUID32:
317                         if (ssplen < 4)
318                                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
319
320                         memcpy(&uuid, &uuid_base, sizeof(uuid));
321                         uuid.b[0] = *sspptr ++;
322                         uuid.b[1] = *sspptr ++;
323                         uuid.b[2] = *sspptr ++;
324                         uuid.b[3] = *sspptr ++;
325                         ssplen -= 4;
326                         break;
327
328                 case SDP_DATA_UUID128:
329                         if (ssplen < 16)
330                                 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
331
332                         memcpy(uuid.b, sspptr, 16);
333                         sspptr += 16;   
334                         ssplen -= 16; 
335                         break;
336
337                 default:
338                         return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
339                         /* NOT REACHED */
340                 }
341
342                 for (provider = provider_get_first();
343                      provider != NULL;
344                      provider = provider_get_next(provider)) {
345                         if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
346                                 continue;
347
348                         memcpy(&puuid, &uuid_base, sizeof(puuid));
349                         puuid.b[2] = provider->profile->uuid >> 8;
350                         puuid.b[3] = provider->profile->uuid;
351
352                         if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 &&
353                             memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0 &&
354                             server_search_uuid(provider, &uuid) != 0)
355                                 continue;
356
357                         cs = server_prepare_attr_list(provider,
358                                 aidptr, aidptr + aidlen, ptr, rsp_end);
359                         if (cs < 0)
360                                 return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
361
362                         ptr += cs;
363                 }
364         }
365
366         /* Set reply size (not counting PDU header and continuation state) */
367         srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
368         if (srv->fdidx[fd].rsp_limit > rsp_limit)
369                 srv->fdidx[fd].rsp_limit = rsp_limit;
370
371         srv->fdidx[fd].rsp_size = ptr - rsp;
372         srv->fdidx[fd].rsp_cs = 0;
373
374         /* Fix AttributeLists sequence header */
375         ptr = rsp;
376         SDP_PUT8(SDP_DATA_SEQ16, ptr);
377         SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
378
379         return (0);
380 }
381