xref: /netbsd/usr.sbin/sdpd/compat.c (revision 6f9cc4f1)
1*6f9cc4f1Splunky /*	$NetBSD: compat.c,v 1.2 2010/03/07 10:58:40 plunky Exp $	*/
2dfbf818aSplunky 
3dfbf818aSplunky /*-
4dfbf818aSplunky  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5dfbf818aSplunky  * All rights reserved.
6dfbf818aSplunky  *
7dfbf818aSplunky  * This code is derived from software contributed to The NetBSD Foundation
8dfbf818aSplunky  * by Iain Hibbert.
9dfbf818aSplunky  *
10dfbf818aSplunky  * Redistribution and use in source and binary forms, with or without
11dfbf818aSplunky  * modification, are permitted provided that the following conditions
12dfbf818aSplunky  * are met:
13dfbf818aSplunky  * 1. Redistributions of source code must retain the above copyright
14dfbf818aSplunky  *    notice, this list of conditions and the following disclaimer.
15dfbf818aSplunky  * 2. Redistributions in binary form must reproduce the above copyright
16dfbf818aSplunky  *    notice, this list of conditions and the following disclaimer in the
17dfbf818aSplunky  *    documentation and/or other materials provided with the distribution.
18dfbf818aSplunky  *
19dfbf818aSplunky  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20dfbf818aSplunky  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21dfbf818aSplunky  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22dfbf818aSplunky  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23dfbf818aSplunky  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24dfbf818aSplunky  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25dfbf818aSplunky  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26dfbf818aSplunky  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27dfbf818aSplunky  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28dfbf818aSplunky  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29dfbf818aSplunky  * POSSIBILITY OF SUCH DAMAGE.
30dfbf818aSplunky  */
31dfbf818aSplunky 
32dfbf818aSplunky #include <sys/cdefs.h>
33*6f9cc4f1Splunky __RCSID("$NetBSD: compat.c,v 1.2 2010/03/07 10:58:40 plunky Exp $");
34dfbf818aSplunky 
35dfbf818aSplunky #include <arpa/inet.h>
36dfbf818aSplunky 
37dfbf818aSplunky #include <netbt/rfcomm.h>
38dfbf818aSplunky 
39dfbf818aSplunky #include <bluetooth.h>
40dfbf818aSplunky #include <errno.h>
41dfbf818aSplunky #include <sdp.h>
42dfbf818aSplunky #include <stdlib.h>
43dfbf818aSplunky #include <string.h>
44dfbf818aSplunky #include <unistd.h>
45dfbf818aSplunky 
46dfbf818aSplunky #include "sdpd.h"
47dfbf818aSplunky 
48dfbf818aSplunky /*
49dfbf818aSplunky  * This file provides for compatibility with the old ABI. Clients send
50dfbf818aSplunky  * a data structure and we generate a record based from that using the
51dfbf818aSplunky  * server output buffer as temporary storage. The sdp_put functions will
52dfbf818aSplunky  * not write invalid data or overflow the buffer which is big enough to
53dfbf818aSplunky  * contain all these records, no need to worry about that.
54dfbf818aSplunky  */
55dfbf818aSplunky 
56dfbf818aSplunky static bool
dun_profile(sdp_data_t * buf,void * arg,ssize_t len)57dfbf818aSplunky dun_profile(sdp_data_t *buf, void *arg, ssize_t len)
58dfbf818aSplunky {
59dfbf818aSplunky 	sdp_dun_profile_t	*data = arg;
60dfbf818aSplunky 	uint8_t			*first = buf->next;
61dfbf818aSplunky 
62dfbf818aSplunky 	if (len != sizeof(*data)
63dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
64dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX)
65dfbf818aSplunky 		return false;
66dfbf818aSplunky 
67dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
68dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
69dfbf818aSplunky 
70dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
71dfbf818aSplunky 	sdp_put_seq(buf, 3);
72dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_DIALUP_NETWORKING);
73dfbf818aSplunky 
74dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
75dfbf818aSplunky 	sdp_put_seq(buf, 12);
76dfbf818aSplunky 	sdp_put_seq(buf, 3);
77dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
78dfbf818aSplunky 	sdp_put_seq(buf, 5);
79dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
80dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
81dfbf818aSplunky 
82dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
83dfbf818aSplunky 	sdp_put_seq(buf, 3);
84dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
85dfbf818aSplunky 
86dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
87dfbf818aSplunky 	sdp_put_seq(buf, 9);
88dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
89dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
90dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
91dfbf818aSplunky 
92dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
93dfbf818aSplunky 	sdp_put_seq(buf, 8);
94dfbf818aSplunky 	sdp_put_seq(buf, 6);
95dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_DIALUP_NETWORKING);
96dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
97dfbf818aSplunky 
98dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
99dfbf818aSplunky 	sdp_put_str(buf, "Dialup Networking", -1);
100dfbf818aSplunky 
101dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_AUDIO_FEEDBACK_SUPPORT);
102dfbf818aSplunky 	sdp_put_bool(buf, data->audio_feedback_support);
103dfbf818aSplunky 
104dfbf818aSplunky 	buf->end = buf->next;
105dfbf818aSplunky 	buf->next = first;
106dfbf818aSplunky 	return true;
107dfbf818aSplunky }
108dfbf818aSplunky 
109dfbf818aSplunky static bool
ftrn_profile(sdp_data_t * buf,void * arg,ssize_t len)110dfbf818aSplunky ftrn_profile(sdp_data_t *buf, void *arg, ssize_t len)
111dfbf818aSplunky {
112dfbf818aSplunky 	sdp_ftrn_profile_t	*data = arg;
113dfbf818aSplunky 	uint8_t			*first = buf->next;
114dfbf818aSplunky 
115dfbf818aSplunky 	if (len != sizeof(*data)
116dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
117dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX)
118dfbf818aSplunky 		return false;
119dfbf818aSplunky 
120dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
121dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
122dfbf818aSplunky 
123dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
124dfbf818aSplunky 	sdp_put_seq(buf, 3);
125dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER);
126dfbf818aSplunky 
127dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
128dfbf818aSplunky 	sdp_put_seq(buf, 17);
129dfbf818aSplunky 	sdp_put_seq(buf, 3);
130dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
131dfbf818aSplunky 	sdp_put_seq(buf, 5);
132dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
133dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
134dfbf818aSplunky 	sdp_put_seq(buf, 3);
135dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_OBEX);
136dfbf818aSplunky 
137dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
138dfbf818aSplunky 	sdp_put_seq(buf, 3);
139dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
140dfbf818aSplunky 
141dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
142dfbf818aSplunky 	sdp_put_seq(buf, 9);
143dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
144dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
145dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
146dfbf818aSplunky 
147dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
148dfbf818aSplunky 	sdp_put_seq(buf, 8);
149dfbf818aSplunky 	sdp_put_seq(buf, 6);
150dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER);
151dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
152dfbf818aSplunky 
153dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
154dfbf818aSplunky 	sdp_put_str(buf, "OBEX File Transfer", -1);
155dfbf818aSplunky 
156dfbf818aSplunky 	buf->end = buf->next;
157dfbf818aSplunky 	buf->next = first;
158dfbf818aSplunky 	return true;
159dfbf818aSplunky }
160dfbf818aSplunky 
161dfbf818aSplunky static bool
hset_profile(sdp_data_t * buf,void * arg,ssize_t len)162dfbf818aSplunky hset_profile(sdp_data_t *buf, void *arg, ssize_t len)
163dfbf818aSplunky {
164dfbf818aSplunky 	sdp_hset_profile_t	*data = arg;
165dfbf818aSplunky 	uint8_t			*first = buf->next;
166dfbf818aSplunky 
167dfbf818aSplunky 	if (len != sizeof(*data)
168dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
169dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX)
170dfbf818aSplunky 		return false;
171dfbf818aSplunky 
172dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
173dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
174dfbf818aSplunky 
175dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
176dfbf818aSplunky 	sdp_put_seq(buf, 6);
177dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY);
178dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_GENERIC_AUDIO);
179dfbf818aSplunky 
180dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
181dfbf818aSplunky 	sdp_put_seq(buf, 12);
182dfbf818aSplunky 	sdp_put_seq(buf, 3);
183dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
184dfbf818aSplunky 	sdp_put_seq(buf, 5);
185dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
186dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
187dfbf818aSplunky 
188dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
189dfbf818aSplunky 	sdp_put_seq(buf, 3);
190dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
191dfbf818aSplunky 
192dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
193dfbf818aSplunky 	sdp_put_seq(buf, 9);
194dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
195dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
196dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
197dfbf818aSplunky 
198dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
199dfbf818aSplunky 	sdp_put_seq(buf, 8);
200dfbf818aSplunky 	sdp_put_seq(buf, 6);
201dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_HEADSET);
202dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
203dfbf818aSplunky 
204dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
205dfbf818aSplunky 	sdp_put_str(buf, "Voice Gateway", -1);
206dfbf818aSplunky 
207dfbf818aSplunky 	buf->end = buf->next;
208dfbf818aSplunky 	buf->next = first;
209dfbf818aSplunky 	return true;
210dfbf818aSplunky }
211dfbf818aSplunky 
212dfbf818aSplunky static bool
hf_profile(sdp_data_t * buf,void * arg,ssize_t len)213dfbf818aSplunky hf_profile(sdp_data_t *buf, void *arg, ssize_t len)
214dfbf818aSplunky {
215dfbf818aSplunky 	sdp_hf_profile_t	*data = arg;
216dfbf818aSplunky 	uint8_t			*first = buf->next;
217dfbf818aSplunky 
218dfbf818aSplunky 	if (len != sizeof(*data)
219dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
220dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX
221dfbf818aSplunky 	    || (data->supported_features & ~0x001f))
222dfbf818aSplunky 		return false;
223dfbf818aSplunky 
224dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
225dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
226dfbf818aSplunky 
227dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
228dfbf818aSplunky 	sdp_put_seq(buf, 6);
229dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_HANDSFREE);
230dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_GENERIC_AUDIO);
231dfbf818aSplunky 
232dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
233dfbf818aSplunky 	sdp_put_seq(buf, 12);
234dfbf818aSplunky 	sdp_put_seq(buf, 3);
235dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
236dfbf818aSplunky 	sdp_put_seq(buf, 5);
237dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
238dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
239dfbf818aSplunky 
240dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
241dfbf818aSplunky 	sdp_put_seq(buf, 3);
242dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
243dfbf818aSplunky 
244dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
245dfbf818aSplunky 	sdp_put_seq(buf, 9);
246dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
247dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
248dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
249dfbf818aSplunky 
250dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
251dfbf818aSplunky 	sdp_put_seq(buf, 8);
252dfbf818aSplunky 	sdp_put_seq(buf, 6);
253dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_HANDSFREE);
254dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
255dfbf818aSplunky 
256dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
257dfbf818aSplunky 	sdp_put_str(buf, "Hands-Free unit", -1);
258dfbf818aSplunky 
259dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SUPPORTED_FEATURES);
260dfbf818aSplunky 	sdp_put_uint16(buf, data->supported_features);
261dfbf818aSplunky 
262dfbf818aSplunky 	buf->end = buf->next;
263dfbf818aSplunky 	buf->next = first;
264dfbf818aSplunky 	return true;
265dfbf818aSplunky }
266dfbf818aSplunky 
267dfbf818aSplunky static bool
irmc_profile(sdp_data_t * buf,void * arg,ssize_t len)268dfbf818aSplunky irmc_profile(sdp_data_t *buf, void *arg, ssize_t len)
269dfbf818aSplunky {
270dfbf818aSplunky 	sdp_irmc_profile_t	*data = arg;
271dfbf818aSplunky 	uint8_t			*first = buf->next;
272dfbf818aSplunky 	int			i;
273dfbf818aSplunky 
274dfbf818aSplunky 	if (len != sizeof(*data)
275dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
276dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX
277dfbf818aSplunky 	    || data->supported_formats_size == 0
278dfbf818aSplunky 	    || data->supported_formats_size > sizeof(data->supported_formats))
279dfbf818aSplunky 		return false;
280dfbf818aSplunky 
281dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
282dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
283dfbf818aSplunky 
284dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
285dfbf818aSplunky 	sdp_put_seq(buf, 3);
286dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_IR_MC_SYNC);
287dfbf818aSplunky 
288dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
289dfbf818aSplunky 	sdp_put_seq(buf, 17);
290dfbf818aSplunky 	sdp_put_seq(buf, 3);
291dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
292dfbf818aSplunky 	sdp_put_seq(buf, 5);
293dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
294dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
295dfbf818aSplunky 	sdp_put_seq(buf, 3);
296dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_OBEX);
297dfbf818aSplunky 
298dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
299dfbf818aSplunky 	sdp_put_seq(buf, 3);
300dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
301dfbf818aSplunky 
302dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
303dfbf818aSplunky 	sdp_put_seq(buf, 9);
304dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
305dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
306dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
307dfbf818aSplunky 
308dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
309dfbf818aSplunky 	sdp_put_seq(buf, 8);
310dfbf818aSplunky 	sdp_put_seq(buf, 6);
311dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_IR_MC_SYNC);
312dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
313dfbf818aSplunky 
314dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
315dfbf818aSplunky 	sdp_put_str(buf, "IrMC Syncrhonization", -1);
316dfbf818aSplunky 
317dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SUPPORTED_DATA_STORES_LIST);
318dfbf818aSplunky 	sdp_put_seq(buf, data->supported_formats_size * 2);
319dfbf818aSplunky 	for (i = 0; i < data->supported_formats_size; i++)
320dfbf818aSplunky 		sdp_put_uint8(buf, data->supported_formats[i]);
321dfbf818aSplunky 
322dfbf818aSplunky 	buf->end = buf->next;
323dfbf818aSplunky 	buf->next = first;
324dfbf818aSplunky 	return true;
325dfbf818aSplunky }
326dfbf818aSplunky 
327dfbf818aSplunky static bool
irmc_cmd_profile(sdp_data_t * buf,void * arg,ssize_t len)328dfbf818aSplunky irmc_cmd_profile(sdp_data_t *buf, void *arg, ssize_t len)
329dfbf818aSplunky {
330dfbf818aSplunky 	sdp_irmc_command_profile_t	*data = arg;
331dfbf818aSplunky 	uint8_t				*first = buf->next;
332dfbf818aSplunky 
333dfbf818aSplunky 	if (len != sizeof(*data)
334dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
335dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX)
336dfbf818aSplunky 		return false;
337dfbf818aSplunky 
338dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
339dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
340dfbf818aSplunky 
341dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
342dfbf818aSplunky 	sdp_put_seq(buf, 3);
343dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND);
344dfbf818aSplunky 
345dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
346dfbf818aSplunky 	sdp_put_seq(buf, 17);
347dfbf818aSplunky 	sdp_put_seq(buf, 3);
348dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
349dfbf818aSplunky 	sdp_put_seq(buf, 5);
350dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
351dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
352dfbf818aSplunky 	sdp_put_seq(buf, 3);
353dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_OBEX);
354dfbf818aSplunky 
355dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
356dfbf818aSplunky 	sdp_put_seq(buf, 3);
357dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
358dfbf818aSplunky 
359dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
360dfbf818aSplunky 	sdp_put_seq(buf, 9);
361dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
362dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
363dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
364dfbf818aSplunky 
365dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
366dfbf818aSplunky 	sdp_put_seq(buf, 8);
367dfbf818aSplunky 	sdp_put_seq(buf, 6);
368dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND);
369dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
370dfbf818aSplunky 
371dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
372dfbf818aSplunky 	sdp_put_str(buf, "Sync Command Service", -1);
373dfbf818aSplunky 
374dfbf818aSplunky 	buf->end = buf->next;
375dfbf818aSplunky 	buf->next = first;
376dfbf818aSplunky 	return true;
377dfbf818aSplunky }
378dfbf818aSplunky 
379dfbf818aSplunky static bool
lan_profile(sdp_data_t * buf,void * arg,ssize_t len)380dfbf818aSplunky lan_profile(sdp_data_t *buf, void *arg, ssize_t len)
381dfbf818aSplunky {
382dfbf818aSplunky 	sdp_lan_profile_t	*data = arg;
383dfbf818aSplunky 	uint8_t			*first = buf->next;
384dfbf818aSplunky 	struct in_addr		in;
385dfbf818aSplunky 	char			str[32];
386dfbf818aSplunky 
387dfbf818aSplunky 	if (len != sizeof(*data)
388dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
389dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX
390dfbf818aSplunky 	    || data->ip_subnet_radius > 32)
391dfbf818aSplunky 		return false;
392dfbf818aSplunky 
393dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
394dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
395dfbf818aSplunky 
396dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
397dfbf818aSplunky 	sdp_put_seq(buf, 3);
398dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP);
399dfbf818aSplunky 
400dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
401dfbf818aSplunky 	sdp_put_seq(buf, 12);
402dfbf818aSplunky 	sdp_put_seq(buf, 3);
403dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
404dfbf818aSplunky 	sdp_put_seq(buf, 5);
405dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
406dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
407dfbf818aSplunky 
408dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
409dfbf818aSplunky 	sdp_put_seq(buf, 3);
410dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
411dfbf818aSplunky 
412dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
413dfbf818aSplunky 	sdp_put_seq(buf, 9);
414dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
415dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
416dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
417dfbf818aSplunky 
418dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_AVAILABILITY);
419dfbf818aSplunky 	sdp_put_uint8(buf, data->load_factor);
420dfbf818aSplunky 
421dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
422dfbf818aSplunky 	sdp_put_seq(buf, 8);
423dfbf818aSplunky 	sdp_put_seq(buf, 6);
424dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP);
425dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
426dfbf818aSplunky 
427dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
428dfbf818aSplunky 	sdp_put_str(buf, "LAN Access using PPP", -1);
429dfbf818aSplunky 
430dfbf818aSplunky 	in.s_addr= data->ip_subnet;
431dfbf818aSplunky 	sprintf(str, "%s/%d", inet_ntoa(in), data->ip_subnet_radius);
432dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_IP_SUBNET);
433dfbf818aSplunky 	sdp_put_str(buf, str, -1);
434dfbf818aSplunky 
435dfbf818aSplunky 	buf->end = buf->next;
436dfbf818aSplunky 	buf->next = first;
437dfbf818aSplunky 	return true;
438dfbf818aSplunky }
439dfbf818aSplunky 
440dfbf818aSplunky static bool
opush_profile(sdp_data_t * buf,void * arg,ssize_t len)441dfbf818aSplunky opush_profile(sdp_data_t *buf, void *arg, ssize_t len)
442dfbf818aSplunky {
443dfbf818aSplunky 	sdp_opush_profile_t	*data = arg;
444dfbf818aSplunky 	uint8_t			*first = buf->next;
445dfbf818aSplunky 	int			i;
446dfbf818aSplunky 
447dfbf818aSplunky 	if (len != sizeof(*data)
448dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
449dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX
450dfbf818aSplunky 	    || data->supported_formats_size == 0
451dfbf818aSplunky 	    || data->supported_formats_size > sizeof(data->supported_formats))
452dfbf818aSplunky 		return false;
453dfbf818aSplunky 
454dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
455dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
456dfbf818aSplunky 
457dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
458dfbf818aSplunky 	sdp_put_seq(buf, 3);
459dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH);
460dfbf818aSplunky 
461dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
462dfbf818aSplunky 	sdp_put_seq(buf, 17);
463dfbf818aSplunky 	sdp_put_seq(buf, 3);
464dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
465dfbf818aSplunky 	sdp_put_seq(buf, 5);
466dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
467dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
468dfbf818aSplunky 	sdp_put_seq(buf, 3);
469dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_OBEX);
470dfbf818aSplunky 
471dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
472dfbf818aSplunky 	sdp_put_seq(buf, 3);
473dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
474dfbf818aSplunky 
475dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
476dfbf818aSplunky 	sdp_put_seq(buf, 9);
477dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
478dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
479dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
480dfbf818aSplunky 
481dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
482dfbf818aSplunky 	sdp_put_seq(buf, 8);
483dfbf818aSplunky 	sdp_put_seq(buf, 6);
484dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH);
485dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
486dfbf818aSplunky 
487dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
488dfbf818aSplunky 	sdp_put_str(buf, "OBEX Object Push", -1);
489dfbf818aSplunky 
490dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SUPPORTED_FORMATS_LIST);
491dfbf818aSplunky 	sdp_put_seq(buf, data->supported_formats_size * 2);
492dfbf818aSplunky 	for (i = 0; i < data->supported_formats_size; i++)
493dfbf818aSplunky 		sdp_put_uint8(buf, data->supported_formats[i]);
494dfbf818aSplunky 
495dfbf818aSplunky 	buf->end = buf->next;
496dfbf818aSplunky 	buf->next = first;
497dfbf818aSplunky 	return true;
498dfbf818aSplunky }
499dfbf818aSplunky 
500dfbf818aSplunky static bool
sp_profile(sdp_data_t * buf,void * arg,ssize_t len)501dfbf818aSplunky sp_profile(sdp_data_t *buf, void *arg, ssize_t len)
502dfbf818aSplunky {
503dfbf818aSplunky 	sdp_sp_profile_t	*data = arg;
504dfbf818aSplunky 	uint8_t			*first = buf->next;
505dfbf818aSplunky 
506dfbf818aSplunky 	if (len != sizeof(*data)
507dfbf818aSplunky 	    || data->server_channel < RFCOMM_CHANNEL_MIN
508dfbf818aSplunky 	    || data->server_channel > RFCOMM_CHANNEL_MAX)
509dfbf818aSplunky 		return false;
510dfbf818aSplunky 
511dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
512dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
513dfbf818aSplunky 
514dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
515dfbf818aSplunky 	sdp_put_seq(buf, 3);
516dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_SERIAL_PORT);
517dfbf818aSplunky 
518dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
519dfbf818aSplunky 	sdp_put_seq(buf, 12);
520dfbf818aSplunky 	sdp_put_seq(buf, 3);
521dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
522dfbf818aSplunky 	sdp_put_seq(buf, 5);
523dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
524dfbf818aSplunky 	sdp_put_uint8(buf, data->server_channel);
525dfbf818aSplunky 
526dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
527dfbf818aSplunky 	sdp_put_seq(buf, 3);
528dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
529dfbf818aSplunky 
530dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
531dfbf818aSplunky 	sdp_put_seq(buf, 9);
532dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
533dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
534dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
535dfbf818aSplunky 
536dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
537dfbf818aSplunky 	sdp_put_seq(buf, 8);
538dfbf818aSplunky 	sdp_put_seq(buf, 6);
539dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_SERIAL_PORT);
540dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
541dfbf818aSplunky 
542dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
543dfbf818aSplunky 	sdp_put_str(buf, "Serial Port", -1);
544dfbf818aSplunky 
545dfbf818aSplunky 	buf->end = buf->next;
546dfbf818aSplunky 	buf->next = first;
547dfbf818aSplunky 	return true;
548dfbf818aSplunky }
549dfbf818aSplunky 
550dfbf818aSplunky /* list of protocols used by PAN profiles.  */
551dfbf818aSplunky static const uint16_t proto[] = {
552dfbf818aSplunky 	0x0800,	/* IPv4 */
553dfbf818aSplunky 	0x0806,	/* ARP  */
554dfbf818aSplunky #ifdef INET6
555dfbf818aSplunky 	0x86dd,	/* IPv6 */
556dfbf818aSplunky #endif
557dfbf818aSplunky };
558dfbf818aSplunky 
559dfbf818aSplunky static bool
nap_profile(sdp_data_t * buf,void * arg,ssize_t len)560dfbf818aSplunky nap_profile(sdp_data_t *buf, void *arg, ssize_t len)
561dfbf818aSplunky {
562dfbf818aSplunky 	sdp_nap_profile_t	*data = arg;
563dfbf818aSplunky 	uint8_t			*first = buf->next;
564dfbf818aSplunky 	size_t			i;
565dfbf818aSplunky 
566dfbf818aSplunky 	if (len != sizeof(*data)
567dfbf818aSplunky 	    || L2CAP_PSM_INVALID(data->psm)
568dfbf818aSplunky 	    || data->security_description > 0x0002)
569dfbf818aSplunky 		return false;
570dfbf818aSplunky 
571dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
572dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
573dfbf818aSplunky 
574dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
575dfbf818aSplunky 	sdp_put_seq(buf, 3);
576dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_NAP);
577dfbf818aSplunky 
578dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
579dfbf818aSplunky 	sdp_put_seq(buf, 18 + 3 * __arraycount(proto));
580dfbf818aSplunky 	sdp_put_seq(buf, 6);
581dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
582dfbf818aSplunky 	sdp_put_uint16(buf, data->psm);
583dfbf818aSplunky 	sdp_put_seq(buf, 8 + 3 * __arraycount(proto));
584dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_BNEP);
585dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
586dfbf818aSplunky 	sdp_put_seq(buf, 3 * __arraycount(proto));
587dfbf818aSplunky 	for (i = 0; i < __arraycount(proto); i++)
588dfbf818aSplunky 		sdp_put_uint16(buf, proto[i]);
589dfbf818aSplunky 
590dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
591dfbf818aSplunky 	sdp_put_seq(buf, 3);
592dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
593dfbf818aSplunky 
594dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
595dfbf818aSplunky 	sdp_put_seq(buf, 9);
596dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
597dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
598dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
599dfbf818aSplunky 
600dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_AVAILABILITY);
601dfbf818aSplunky 	sdp_put_uint8(buf, data->load_factor);
602dfbf818aSplunky 
603dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
604dfbf818aSplunky 	sdp_put_seq(buf, 8);
605dfbf818aSplunky 	sdp_put_seq(buf, 6);
606dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_NAP);
607dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
608dfbf818aSplunky 
609dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
610dfbf818aSplunky 	sdp_put_str(buf, "Network Access Point", -1);
611dfbf818aSplunky 
612dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET);
613dfbf818aSplunky 	sdp_put_str(buf, "Personal Ad-hoc Network Service", -1);
614dfbf818aSplunky 
615dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SECURITY_DESCRIPTION);
616dfbf818aSplunky 	sdp_put_uint16(buf, data->security_description);
617dfbf818aSplunky 
618dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_NET_ACCESS_TYPE);
619dfbf818aSplunky 	sdp_put_uint16(buf, data->net_access_type);
620dfbf818aSplunky 
621dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_MAX_NET_ACCESS_RATE);
622dfbf818aSplunky 	sdp_put_uint32(buf, data->max_net_access_rate);
623dfbf818aSplunky 
624dfbf818aSplunky 	buf->end = buf->next;
625dfbf818aSplunky 	buf->next = first;
626dfbf818aSplunky 	return true;
627dfbf818aSplunky }
628dfbf818aSplunky 
629dfbf818aSplunky static bool
gn_profile(sdp_data_t * buf,void * arg,ssize_t len)630dfbf818aSplunky gn_profile(sdp_data_t *buf, void *arg, ssize_t len)
631dfbf818aSplunky {
632dfbf818aSplunky 	sdp_gn_profile_t	*data = arg;
633dfbf818aSplunky 	uint8_t			*first = buf->next;
634dfbf818aSplunky 	size_t			i;
635dfbf818aSplunky 
636dfbf818aSplunky 	if (len != sizeof(*data)
637dfbf818aSplunky 	    || L2CAP_PSM_INVALID(data->psm)
638dfbf818aSplunky 	    || data->security_description > 0x0002)
639dfbf818aSplunky 		return false;
640dfbf818aSplunky 
641dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
642dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
643dfbf818aSplunky 
644dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
645dfbf818aSplunky 	sdp_put_seq(buf, 3);
646dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_GN);
647dfbf818aSplunky 
648dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
649dfbf818aSplunky 	sdp_put_seq(buf, 18 + 3 * __arraycount(proto));
650dfbf818aSplunky 	sdp_put_seq(buf, 6);
651dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
652dfbf818aSplunky 	sdp_put_uint16(buf, data->psm);
653dfbf818aSplunky 	sdp_put_seq(buf, 8 + 3 * __arraycount(proto));
654dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_BNEP);
655dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
656dfbf818aSplunky 	sdp_put_seq(buf, 3 * __arraycount(proto));
657dfbf818aSplunky 	for (i = 0; i < __arraycount(proto); i++)
658dfbf818aSplunky 		sdp_put_uint16(buf, proto[i]);
659dfbf818aSplunky 
660dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
661dfbf818aSplunky 	sdp_put_seq(buf, 3);
662dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
663dfbf818aSplunky 
664dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
665dfbf818aSplunky 	sdp_put_seq(buf, 9);
666dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
667dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
668dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
669dfbf818aSplunky 
670dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_AVAILABILITY);
671dfbf818aSplunky 	sdp_put_uint8(buf, data->load_factor);
672dfbf818aSplunky 
673dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
674dfbf818aSplunky 	sdp_put_seq(buf, 8);
675dfbf818aSplunky 	sdp_put_seq(buf, 6);
676dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_GN);
677dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
678dfbf818aSplunky 
679dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
680dfbf818aSplunky 	sdp_put_str(buf, "Group Ad-hoc Network", -1);
681dfbf818aSplunky 
682dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET);
683dfbf818aSplunky 	sdp_put_str(buf, "Personal Group Ad-hoc Network Service", -1);
684dfbf818aSplunky 
685dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SECURITY_DESCRIPTION);
686dfbf818aSplunky 	sdp_put_uint16(buf, data->security_description);
687dfbf818aSplunky 
688dfbf818aSplunky 	buf->end = buf->next;
689dfbf818aSplunky 	buf->next = first;
690dfbf818aSplunky 	return true;
691dfbf818aSplunky }
692dfbf818aSplunky 
693dfbf818aSplunky static bool
panu_profile(sdp_data_t * buf,void * arg,ssize_t len)694dfbf818aSplunky panu_profile(sdp_data_t *buf, void *arg, ssize_t len)
695dfbf818aSplunky {
696dfbf818aSplunky 	sdp_panu_profile_t	*data = arg;
697dfbf818aSplunky 	uint8_t			*first = buf->next;
698dfbf818aSplunky 	size_t			i;
699dfbf818aSplunky 
700dfbf818aSplunky 	if (len != sizeof(*data)
701dfbf818aSplunky 	    || L2CAP_PSM_INVALID(data->psm)
702dfbf818aSplunky 	    || data->security_description > 0x0002)
703dfbf818aSplunky 		return false;
704dfbf818aSplunky 
705dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
706dfbf818aSplunky 	sdp_put_uint32(buf, 0x00000000);
707dfbf818aSplunky 
708dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
709dfbf818aSplunky 	sdp_put_seq(buf, 3);
710dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PANU);
711dfbf818aSplunky 
712dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
713dfbf818aSplunky 	sdp_put_seq(buf, 18 + 3 * __arraycount(proto));
714dfbf818aSplunky 	sdp_put_seq(buf, 6);
715dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
716dfbf818aSplunky 	sdp_put_uint16(buf, data->psm);
717dfbf818aSplunky 	sdp_put_seq(buf, 8 + 3 * __arraycount(proto));
718dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_BNEP);
719dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
720dfbf818aSplunky 	sdp_put_seq(buf, 3 * __arraycount(proto));
721dfbf818aSplunky 	for (i = 0; i < __arraycount(proto); i++)
722dfbf818aSplunky 		sdp_put_uint16(buf, proto[i]);
723dfbf818aSplunky 
724dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
725dfbf818aSplunky 	sdp_put_seq(buf, 3);
726dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
727dfbf818aSplunky 
728dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
729dfbf818aSplunky 	sdp_put_seq(buf, 9);
730dfbf818aSplunky 	sdp_put_uint16(buf, 0x656e);	/* "en" */
731dfbf818aSplunky 	sdp_put_uint16(buf, 106);	/* UTF-8 */
732dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
733dfbf818aSplunky 
734dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SERVICE_AVAILABILITY);
735dfbf818aSplunky 	sdp_put_uint8(buf, data->load_factor);
736dfbf818aSplunky 
737dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
738dfbf818aSplunky 	sdp_put_seq(buf, 8);
739dfbf818aSplunky 	sdp_put_seq(buf, 6);
740dfbf818aSplunky 	sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PANU);
741dfbf818aSplunky 	sdp_put_uint16(buf, 0x0100);	/* v1.0 */
742dfbf818aSplunky 
743dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
744dfbf818aSplunky 	sdp_put_str(buf, "Personal Ad-hoc User Service", -1);
745dfbf818aSplunky 
746dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET);
747dfbf818aSplunky 	sdp_put_str(buf, "Personal Ad-hoc User Service", -1);
748dfbf818aSplunky 
749dfbf818aSplunky 	sdp_put_uint16(buf, SDP_ATTR_SECURITY_DESCRIPTION);
750dfbf818aSplunky 	sdp_put_uint16(buf, data->security_description);
751dfbf818aSplunky 
752dfbf818aSplunky 	buf->end = buf->next;
753dfbf818aSplunky 	buf->next = first;
754dfbf818aSplunky 	return true;
755dfbf818aSplunky }
756dfbf818aSplunky 
757dfbf818aSplunky static const struct {
758dfbf818aSplunky 	uint16_t	class;
759dfbf818aSplunky 	bool		(*create)(sdp_data_t *, void *, ssize_t);
760dfbf818aSplunky } known[] = {
761dfbf818aSplunky 	{ SDP_SERVICE_CLASS_DIALUP_NETWORKING,		dun_profile	    },
762dfbf818aSplunky 	{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,		ftrn_profile	    },
763dfbf818aSplunky 	{ SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY,	hset_profile	    },
764dfbf818aSplunky 	{ SDP_SERVICE_CLASS_HANDSFREE,			hf_profile	    },
765dfbf818aSplunky 	{ SDP_SERVICE_CLASS_IR_MC_SYNC,			irmc_profile	    },
766dfbf818aSplunky 	{ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,		irmc_cmd_profile    },
767dfbf818aSplunky 	{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,	lan_profile	    },
768dfbf818aSplunky 	{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,		opush_profile	    },
769dfbf818aSplunky 	{ SDP_SERVICE_CLASS_SERIAL_PORT,		sp_profile	    },
770dfbf818aSplunky 	{ SDP_SERVICE_CLASS_NAP,			nap_profile	    },
771dfbf818aSplunky 	{ SDP_SERVICE_CLASS_GN,				gn_profile	    },
772dfbf818aSplunky 	{ SDP_SERVICE_CLASS_PANU,			panu_profile	    },
773dfbf818aSplunky };
774dfbf818aSplunky 
775dfbf818aSplunky uint16_t
compat_register_request(server_t * srv,int fd)776dfbf818aSplunky compat_register_request(server_t *srv, int fd)
777dfbf818aSplunky {
778dfbf818aSplunky 	sdp_data_t d, r;
779dfbf818aSplunky 	bdaddr_t bdaddr;
780dfbf818aSplunky 	uint16_t class;
781dfbf818aSplunky 	int i;
782dfbf818aSplunky 
783*6f9cc4f1Splunky 	log_debug("compat RegisterRequest by client on fd#%d", fd);
784*6f9cc4f1Splunky 
785dfbf818aSplunky 	if (!srv->fdidx[fd].control
786dfbf818aSplunky 	    || !srv->fdidx[fd].priv)
787dfbf818aSplunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
788dfbf818aSplunky 
789dfbf818aSplunky 	srv->fdidx[fd].offset = 0;
790dfbf818aSplunky 	db_unselect(srv, fd);
791dfbf818aSplunky 	d.next = srv->ibuf;
792dfbf818aSplunky 	d.end = srv->ibuf + srv->pdu.len;
793dfbf818aSplunky 
794dfbf818aSplunky 	if (d.next + sizeof(uint16_t) + sizeof(bdaddr_t) > d.end)
795dfbf818aSplunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
796dfbf818aSplunky 
797dfbf818aSplunky 	class = be16dec(d.next);
798dfbf818aSplunky 	d.next += sizeof(uint16_t);
799dfbf818aSplunky 
800dfbf818aSplunky 	memcpy(&bdaddr, d.next, sizeof(bdaddr_t));
801dfbf818aSplunky 	d.next += sizeof(bdaddr_t);
802dfbf818aSplunky 
803dfbf818aSplunky 	for (i = 0;; i++) {
804dfbf818aSplunky 		if (i == __arraycount(known))
805dfbf818aSplunky 			return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
806dfbf818aSplunky 
807dfbf818aSplunky 		if (known[i].class == class)
808dfbf818aSplunky 			break;
809dfbf818aSplunky 	}
810dfbf818aSplunky 
811dfbf818aSplunky 	r.next = srv->obuf;
812dfbf818aSplunky 	r.end = srv->obuf + srv->omtu;
813dfbf818aSplunky 	if (!(known[i].create(&r, d.next, d.end - d.next)))
814dfbf818aSplunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
815dfbf818aSplunky 
816dfbf818aSplunky 	if (!db_create(srv, fd, &bdaddr, srv->handle, &r))
817dfbf818aSplunky 		return SDP_ERROR_CODE_INSUFFICIENT_RESOURCES;
818dfbf818aSplunky 
819dfbf818aSplunky 	/* successful return */
820dfbf818aSplunky 	be16enc(srv->obuf, 0x0000);
821dfbf818aSplunky 	be32enc(srv->obuf + sizeof(uint16_t), srv->handle++);
822dfbf818aSplunky 	srv->pdu.pid = SDP_PDU_ERROR_RESPONSE;
823dfbf818aSplunky 	srv->pdu.len = sizeof(uint16_t) + sizeof(uint32_t);
824dfbf818aSplunky 	return 0;
825dfbf818aSplunky }
826dfbf818aSplunky 
827dfbf818aSplunky uint16_t
compat_change_request(server_t * srv,int fd)828dfbf818aSplunky compat_change_request(server_t *srv, int fd)
829dfbf818aSplunky {
830dfbf818aSplunky 	record_t *rec;
831dfbf818aSplunky 	sdp_data_t d, r;
832dfbf818aSplunky 	int i;
833dfbf818aSplunky 
834*6f9cc4f1Splunky 	log_debug("compat ChangeRequest by client on fd#%d", fd);
835*6f9cc4f1Splunky 
836dfbf818aSplunky 	if (!srv->fdidx[fd].control
837dfbf818aSplunky 	    || !srv->fdidx[fd].priv)
838dfbf818aSplunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
839dfbf818aSplunky 
840dfbf818aSplunky 	srv->fdidx[fd].offset = 0;
841dfbf818aSplunky 	db_unselect(srv, fd);
842dfbf818aSplunky 	d.next = srv->ibuf;
843dfbf818aSplunky 	d.end = srv->ibuf + srv->pdu.len;
844dfbf818aSplunky 
845dfbf818aSplunky 	if (d.next + sizeof(uint32_t) > d.end)
846dfbf818aSplunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
847dfbf818aSplunky 
848dfbf818aSplunky 	db_select_handle(srv, fd, be32dec(d.next));
849dfbf818aSplunky 	d.next += sizeof(uint32_t);
850dfbf818aSplunky 
851dfbf818aSplunky 	rec = NULL;
852dfbf818aSplunky 	db_next(srv, fd, &rec);
853dfbf818aSplunky 	if (rec == NULL || rec->fd != fd)
854dfbf818aSplunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
855dfbf818aSplunky 
856dfbf818aSplunky 	/*
857dfbf818aSplunky 	 * This is rather simplistic but it works. We don't keep a
858dfbf818aSplunky 	 * record of the ServiceClass but we do know the format of
859dfbf818aSplunky 	 * of the stored record and where it should be. If we dont
860dfbf818aSplunky 	 * find it there, just give up.
861dfbf818aSplunky 	 */
862dfbf818aSplunky 	r = rec->data;
863dfbf818aSplunky 	r.next += 3;		/* uint16 ServiceRecordHandle	*/
864dfbf818aSplunky 	r.next += 5;		/* uint32 %handle%		*/
865dfbf818aSplunky 	r.next += 3;		/* uint16 ServiceClassIDList	*/
866dfbf818aSplunky 	r.next += 2;		/* seq8				*/
867dfbf818aSplunky 	for (i = 0;; i++) {
868dfbf818aSplunky 		if (i == __arraycount(known))
869dfbf818aSplunky 			return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
870dfbf818aSplunky 
871dfbf818aSplunky 		if (sdp_match_uuid16(&r, known[i].class))
872dfbf818aSplunky 			break;
873dfbf818aSplunky 	}
874dfbf818aSplunky 
875dfbf818aSplunky 	r.next = srv->obuf;
876dfbf818aSplunky 	r.end = srv->obuf + srv->omtu;
877dfbf818aSplunky 	if (!(known[i].create(&r, d.next, d.end - d.next)))
878dfbf818aSplunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
879dfbf818aSplunky 
880dfbf818aSplunky 	if (!db_create(srv, fd, &rec->bdaddr, rec->handle, &r))
881dfbf818aSplunky 		return SDP_ERROR_CODE_INSUFFICIENT_RESOURCES;
882dfbf818aSplunky 
883dfbf818aSplunky 	db_unselect(srv, fd);
884dfbf818aSplunky 
885dfbf818aSplunky 	/* successful return */
886dfbf818aSplunky 	be16enc(srv->obuf, 0x0000);
887dfbf818aSplunky 	srv->pdu.pid = SDP_PDU_ERROR_RESPONSE;
888dfbf818aSplunky 	srv->pdu.len = sizeof(uint16_t);
889dfbf818aSplunky 	return 0;
890dfbf818aSplunky }
891