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