Add sdpd(8) (Bluetooth Service Discovery Protocol daemon) and sdpquery(1)
[dragonfly.git] / usr.sbin / sdpd / profile.c
1 /* $NetBSD: profile.c,v 1.4 2007/11/09 20:08:41 plunky Exp $ */
2 /* $DragonFly: src/usr.sbin/sdpd/profile.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
3
4 /*
5  * profile.c
6  *
7  * Copyright (c) 2004 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: profile.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
32  * $FreeBSD: src/usr.sbin/bluetooth/sdpd/profile.c,v 1.2 2004/07/28 07:15:44 kan Exp $
33  */
34
35 #include <sys/queue.h>
36 #include <sys/utsname.h>
37 #include <bluetooth.h>
38 #include <sdp.h>
39 #include <string.h>
40 #include "profile.h"
41 #include "provider.h"
42
43 /*
44  * Lookup profile descriptor
45  */
46
47 profile_p
48 profile_get_descriptor(uint16_t uuid)
49 {
50         extern  profile_t       dun_profile_descriptor;
51         extern  profile_t       ftrn_profile_descriptor;
52         extern  profile_t       hf_profile_descriptor;
53         extern  profile_t       hset_profile_descriptor;
54         extern  profile_t       irmc_profile_descriptor;
55         extern  profile_t       irmc_command_profile_descriptor;
56         extern  profile_t       lan_profile_descriptor;
57         extern  profile_t       opush_profile_descriptor;
58         extern  profile_t       sp_profile_descriptor;
59
60         static const profile_p  profiles[] = {
61                 &dun_profile_descriptor,
62                 &ftrn_profile_descriptor,
63                 &hf_profile_descriptor,
64                 &hset_profile_descriptor,
65                 &irmc_profile_descriptor,
66                 &irmc_command_profile_descriptor,
67                 &lan_profile_descriptor,
68                 &opush_profile_descriptor,
69                 &sp_profile_descriptor
70         };
71
72         int32_t                 i;
73
74         for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++)
75                 if (profiles[i]->uuid[0] == uuid)
76                         return (profiles[i]);
77
78         return (NULL);
79 }
80
81 /*
82  * Look attribute in the profile descripror
83  */
84
85 profile_attr_create_p
86 profile_get_attr(const profile_p profile, uint16_t attr)
87 {
88         attr_t const    *ad = (attr_t const *) profile->attrs;
89
90         for (; ad->create != NULL; ad ++)
91                 if (ad->attr == attr)
92                         return (ad->create);
93
94         return (NULL);
95 }
96
97 /*
98  * uint32 value32 - 5 bytes
99  */
100
101 int32_t
102 common_profile_create_service_record_handle(
103         uint8_t *buf, uint8_t const * const eob,
104         uint8_t const *data, uint32_t datalen)
105 {
106         if (buf + 5 > eob)
107                 return (-1);
108
109         SDP_PUT8(SDP_DATA_UINT32, buf);
110         SDP_PUT32(((provider_t const *) data)->handle, buf);
111
112         return (5);
113 }
114
115 /*
116  * seq8 len8                    - 2 bytes
117  *      uuid16 value16          - 3 bytes
118  *      [ uuid16 value ]
119  */
120
121 int32_t
122 common_profile_create_service_class_id_list(
123                 uint8_t *buf, uint8_t const * const eob,
124                 uint8_t const *data, uint32_t datalen)
125 {
126         int32_t len = 3 * (datalen >>= 1);
127
128         if (len <= 0 || len > 0xff || buf + 2 + len > eob)
129                 return (-1);
130
131         SDP_PUT8(SDP_DATA_SEQ8, buf);
132         SDP_PUT8(len, buf);
133
134         for (; datalen > 0; datalen --) {
135                 SDP_PUT8(SDP_DATA_UUID16, buf);
136                 SDP_PUT16(*((uint16_t const *)data), buf);
137                 data += sizeof(uint16_t);
138         }
139
140         return (2 + len);
141 }
142
143 /*
144  * seq8 len8                    - 2 bytes
145  *      seq 8 len8              - 2 bytes
146  *              uuid16 value16  - 3 bytes
147  *              uint16 value16  - 3 bytes
148  *      [ seq 8 len8
149  *              uuid16 value16
150  *              uint16 value16 ]
151  */
152
153 int32_t
154 common_profile_create_bluetooth_profile_descriptor_list(
155                 uint8_t *buf, uint8_t const * const eob,
156                 uint8_t const *data, uint32_t datalen)
157 {
158         int32_t len = 8 * (datalen >>= 2);
159
160         if (len <= 0 || len > 0xff || buf + 2 + len > eob)
161                 return (-1);
162
163         SDP_PUT8(SDP_DATA_SEQ8, buf);
164         SDP_PUT8(len, buf);
165
166         for (; datalen > 0; datalen --) {
167                 SDP_PUT8(SDP_DATA_SEQ8, buf);
168                 SDP_PUT8(6, buf);
169                 SDP_PUT8(SDP_DATA_UUID16, buf);
170                 SDP_PUT16(*((uint16_t const *)data), buf);
171                 data += sizeof(uint16_t);
172                 SDP_PUT8(SDP_DATA_UINT16, buf);
173                 SDP_PUT16(*((uint16_t const *)data), buf);
174                 data += sizeof(uint16_t);
175         }
176
177         return (2 + len);
178 }
179
180 /*
181  * seq8 len8            - 2 bytes
182  *      uint16 value16  - 3 bytes
183  *      uint16 value16  - 3 bytes
184  *      uint16 value16  - 3 bytes
185  */
186
187 int32_t
188 common_profile_create_language_base_attribute_id_list(
189                 uint8_t *buf, uint8_t const * const eob,
190                 uint8_t const *data, uint32_t datalen)
191 {
192         if (buf + 11 > eob)
193                 return (-1);
194
195         SDP_PUT8(SDP_DATA_SEQ8, buf);
196         SDP_PUT8(9, buf);
197
198         /*
199          * Language code per ISO 639:1988. Use "en".
200          */
201
202         SDP_PUT8(SDP_DATA_UINT16, buf);
203         SDP_PUT16(((0x65 << 8) | 0x6e), buf);
204
205         /*
206          * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106
207          * (http://www.iana.org/assignments/character-sets)
208          */
209
210         SDP_PUT8(SDP_DATA_UINT16, buf);
211         SDP_PUT16(106, buf);
212
213         /*
214          * Offset (Primary Language Base is 0x100)
215          */
216
217         SDP_PUT8(SDP_DATA_UINT16, buf);
218         SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf);
219
220         return (11);
221 }
222
223 /*
224  * Use Operating System name as provider name
225  */
226
227 int32_t
228 common_profile_create_service_provider_name(
229                 uint8_t *buf, uint8_t const * const eob,
230                 uint8_t const *data, uint32_t datalen)
231 {
232         struct utsname u;
233         char const *name;
234
235         if (uname(&u) < 0)
236                 name = "Unknown";
237         else
238                 name = u.sysname;
239
240         return (common_profile_create_string8(buf, eob,
241                         (uint8_t const *)name, strlen(name)));
242 }
243
244 /*
245  * str8 len8 string
246  */
247
248 int32_t
249 common_profile_create_string8(
250                 uint8_t *buf, uint8_t const * const eob,
251                 uint8_t const *data, uint32_t datalen)
252 {
253         if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob)
254                 return (-1);
255
256         SDP_PUT8(SDP_DATA_STR8, buf);
257         SDP_PUT8(datalen, buf);
258         memcpy(buf, data, datalen);
259
260         return (2 + datalen);
261 }
262
263 /*
264  * seq8 len8                    - 2 bytes
265  *      seq8 len8               - 2 bytes
266  *              uuid16 value16  - 3 bytes
267  *      seq8 len8               - 2 bytes
268  *              uuid16 value16  - 3 bytes
269  *              uint8 value8    - 2 bytes
270  */
271
272 int32_t
273 rfcomm_profile_create_protocol_descriptor_list(
274                 uint8_t *buf, uint8_t const * const eob,
275                 uint8_t const *data, uint32_t datalen)
276 {
277         if (datalen != 1 || buf + 14 > eob)
278                 return (-1);
279
280         SDP_PUT8(SDP_DATA_SEQ8, buf);
281         SDP_PUT8(12, buf);
282
283         SDP_PUT8(SDP_DATA_SEQ8, buf);
284         SDP_PUT8(3, buf);
285         SDP_PUT8(SDP_DATA_UUID16, buf);
286         SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
287
288         SDP_PUT8(SDP_DATA_SEQ8, buf);
289         SDP_PUT8(5, buf);
290         SDP_PUT8(SDP_DATA_UUID16, buf);
291         SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
292         SDP_PUT8(SDP_DATA_UINT8, buf);
293         SDP_PUT8(*data, buf);
294
295         return (14);
296 }
297
298 /*
299  * seq8 len8                    - 2 bytes
300  *      seq8 len8               - 2 bytes
301  *              uuid16 value16  - 3 bytes
302  *      seq8 len8               - 2 bytes
303  *              uuid16 value16  - 3 bytes
304  *              uint8 value8    - 2 bytes
305  *      seq8 len8               - 2 bytes
306  *              uuid16 value16  - 3 bytes
307  */
308
309 int32_t
310 obex_profile_create_protocol_descriptor_list(
311                 uint8_t *buf, uint8_t const * const eob,
312                 uint8_t const *data, uint32_t datalen)
313 {
314         if (datalen != 1 || buf + 19 > eob)
315                 return (-1);
316
317         SDP_PUT8(SDP_DATA_SEQ8, buf);
318         SDP_PUT8(17, buf);
319
320         SDP_PUT8(SDP_DATA_SEQ8, buf);
321         SDP_PUT8(3, buf);
322         SDP_PUT8(SDP_DATA_UUID16, buf);
323         SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
324
325         SDP_PUT8(SDP_DATA_SEQ8, buf);
326         SDP_PUT8(5, buf);
327         SDP_PUT8(SDP_DATA_UUID16, buf);
328         SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
329         SDP_PUT8(SDP_DATA_UINT8, buf);
330         SDP_PUT8(*data, buf);
331
332         SDP_PUT8(SDP_DATA_SEQ8, buf);
333         SDP_PUT8(3, buf);
334         SDP_PUT8(SDP_DATA_UUID16, buf);
335         SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf);
336
337         return (19);
338 }
339
340 /*
341  * seq8 len8
342  *      uint8 value8    - bytes
343  *      [ uint8 value 8 ]
344  */
345
346 int32_t
347 obex_profile_create_supported_formats_list(
348                 uint8_t *buf, uint8_t const * const eob,
349                 uint8_t const *data, uint32_t datalen)
350 {
351         int32_t len = 2 * datalen;
352
353         if (len <= 0 || len > 0xff || buf + 2 + len > eob)
354                 return (-1);
355
356         SDP_PUT8(SDP_DATA_SEQ8, buf);
357         SDP_PUT8(len, buf);
358
359         for (; datalen > 0; datalen --) {
360                 SDP_PUT8(SDP_DATA_UINT8, buf);
361                 SDP_PUT8(*data++, buf);
362         }
363
364         return (2 + len);
365 }
366
367 /*
368  * verify server channel number (the first byte in the data)
369  */
370
371 int32_t
372 common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)
373 {
374         if (data[0] < 1 || data[0] > 30)
375                 return (0);
376
377         return (1);
378 }
379
380 /*
381  * verify server channel number and supported_formats_size
382  * sdp_opush_profile and sdp_irmc_profile
383  */
384
385 int32_t
386 obex_profile_data_valid(uint8_t const *data, uint32_t datalen)
387 {
388         sdp_opush_profile_t const *opush = (sdp_opush_profile_t const *) data;
389
390         if (opush->server_channel < 1 ||
391             opush->server_channel > 30 ||
392             opush->supported_formats_size == 0 ||
393             opush->supported_formats_size > sizeof(opush->supported_formats))
394                 return (0);
395
396         return (1);
397 }