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