1/*	$NetBSD: sdp_put.c,v 1.5 2011/04/05 18:19:04 plunky Exp $	*/
2
3/*-
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Iain Hibbert.
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: sdp_put.c,v 1.5 2011/04/05 18:19:04 plunky Exp $");
34
35#include <bluetooth.h>
36#include <limits.h>
37#include <sdp.h>
38#include <string.h>
39
40/******************************************************************************
41 *	sdp_put_xxxx(data, value)
42 *
43 * write a value to data space and advance data pointers,
44 * fail if data space is not large enough
45 */
46
47bool
48sdp_put_data(sdp_data_t *data, sdp_data_t *value)
49{
50	ssize_t len;
51
52	len = value->end - value->next;
53
54	if (len > data->end - data->next)
55		return false;
56
57	memcpy(data->next, value->next, (size_t)len);
58	data->next += len;
59	return true;
60}
61
62bool
63sdp_put_attr(sdp_data_t *data, uint16_t attr, sdp_data_t *value)
64{
65	sdp_data_t d = *data;
66
67	if (!sdp_put_uint16(&d, attr)
68	    || sdp_data_size(value) != (value->end - value->next)
69	    || !sdp_put_data(&d, value))
70		return false;
71
72	*data = d;
73	return true;
74}
75
76bool
77sdp_put_uuid(sdp_data_t *data, const uuid_t *uuid)
78{
79	uuid_t u = *uuid;
80
81	u.time_low = 0;
82
83	if (uuid_equal(&u, &BLUETOOTH_BASE_UUID, NULL) == 0)
84		return sdp_put_uuid128(data, uuid);
85
86	if (uuid->time_low > UINT16_MAX)
87		return sdp_put_uuid32(data, (uint32_t)uuid->time_low);
88
89	return sdp_put_uuid16(data, (uint16_t)uuid->time_low);
90}
91
92bool
93sdp_put_uuid16(sdp_data_t *data, uint16_t uuid)
94{
95
96	if (data->next + 3 > data->end)
97		return false;
98
99	data->next[0] = SDP_DATA_UUID16;
100	be16enc(data->next + 1, uuid);
101	data->next += 3;
102	return true;
103}
104
105bool
106sdp_put_uuid32(sdp_data_t *data, uint32_t uuid)
107{
108
109	if (data->next + 5 > data->end)
110		return false;
111
112	data->next[0] = SDP_DATA_UUID32;
113	be32enc(data->next + 1, uuid);
114	data->next += 5;
115	return true;
116}
117
118bool
119sdp_put_uuid128(sdp_data_t *data, const uuid_t *uuid)
120{
121
122	if (data->next + 17 > data->end)
123		return false;
124
125	data->next[0] = SDP_DATA_UUID128;
126	uuid_enc_be(data->next + 1, uuid);
127	data->next += 17;
128	return true;
129}
130
131bool
132sdp_put_bool(sdp_data_t *data, bool value)
133{
134
135	if (data->next + 2 > data->end)
136		return false;
137
138	data->next[0] = SDP_DATA_BOOL;
139	data->next[1] = (value ? 0x01 : 0x00);
140	data->next += 2;
141	return true;
142}
143
144bool
145sdp_put_uint(sdp_data_t *data, uintmax_t value)
146{
147
148	if (value > UINT64_MAX)
149		return false;
150
151	if (value > UINT32_MAX)
152		return sdp_put_uint64(data, (uint64_t)value);
153
154	if (value > UINT16_MAX)
155		return sdp_put_uint32(data, (uint32_t)value);
156
157	if (value > UINT8_MAX)
158		return sdp_put_uint16(data, (uint16_t)value);
159
160	return sdp_put_uint8(data, (uint8_t)value);
161}
162
163bool
164sdp_put_uint8(sdp_data_t *data, uint8_t value)
165{
166
167	if (data->next + 2 > data->end)
168		return false;
169
170	data->next[0] = SDP_DATA_UINT8;
171	data->next[1] = value;
172	data->next += 2;
173	return true;
174}
175
176bool
177sdp_put_uint16(sdp_data_t *data, uint16_t value)
178{
179
180	if (data->next + 3 > data->end)
181		return false;
182
183	data->next[0] = SDP_DATA_UINT16;
184	be16enc(data->next + 1, value);
185	data->next += 3;
186	return true;
187}
188
189bool
190sdp_put_uint32(sdp_data_t *data, uint32_t value)
191{
192
193	if (data->next + 5 > data->end)
194		return false;
195
196	data->next[0] = SDP_DATA_UINT32;
197	be32enc(data->next + 1, value);
198	data->next += 5;
199	return true;
200}
201
202bool
203sdp_put_uint64(sdp_data_t *data, uint64_t value)
204{
205
206	if (data->next + 9 > data->end)
207		return false;
208
209	data->next[0] = SDP_DATA_UINT64;
210	be64enc(data->next + 1, value);
211	data->next += 9;
212	return true;
213}
214
215bool
216sdp_put_int(sdp_data_t *data, intmax_t value)
217{
218
219	if (value > INT64_MAX || value < INT64_MIN)
220		return false;
221
222	if (value > INT32_MAX || value < INT32_MIN)
223		return sdp_put_int64(data, (int64_t)value);
224
225	if (value > INT16_MAX || value < INT16_MIN)
226		return sdp_put_int32(data, (int32_t)value);
227
228	if (value > INT8_MAX || value < INT8_MIN)
229		return sdp_put_int16(data, (int16_t)value);
230
231	return sdp_put_int8(data, (int8_t)value);
232}
233
234bool
235sdp_put_int8(sdp_data_t *data, int8_t value)
236{
237
238	if (data->next + 2 > data->end)
239		return false;
240
241	data->next[0] = SDP_DATA_INT8;
242	data->next[1] = (uint8_t)value;
243	data->next += 2;
244	return true;
245}
246
247bool
248sdp_put_int16(sdp_data_t *data, int16_t value)
249{
250
251	if (data->next + 3 > data->end)
252		return false;
253
254	data->next[0] = SDP_DATA_INT16;
255	be16enc(data->next + 1, (uint16_t)value);
256	data->next += 3;
257	return true;
258}
259
260bool
261sdp_put_int32(sdp_data_t *data, int32_t value)
262{
263
264	if (data->next + 5 > data->end)
265		return false;
266
267	data->next[0] = SDP_DATA_INT32;
268	be32enc(data->next + 1, (uint32_t)value);
269	data->next += 5;
270	return true;
271}
272
273bool
274sdp_put_int64(sdp_data_t *data, int64_t value)
275{
276
277	if (data->next + 9 > data->end)
278		return false;
279
280	data->next[0] = SDP_DATA_INT64;
281	be64enc(data->next + 1, (uint64_t)value);
282	data->next += 9;
283	return true;
284}
285
286static bool
287_sdp_put_ext(uint8_t type, sdp_data_t *data, ssize_t len)
288{
289	uint8_t *p = data->next;
290
291	if (len == -1) {
292		if (p + 2 > data->end)
293			return false;
294
295		len = data->end - p - 2;
296
297		if (len > UINT8_MAX)
298			len -= 1;
299
300		if (len > UINT16_MAX)
301			len -= 2;
302	}
303
304	if ((size_t)len > UINT32_MAX)
305		return false;
306
307	if ((size_t)len > UINT16_MAX) {
308		if (len > data->end - 5 - p)
309			return false;
310
311		p[0] = type | SDP_DATA_EXT32;
312		be32enc(p + 1, (uint32_t)len);
313		p += 5;
314	} else if ((size_t)len > UINT8_MAX) {
315		if (len > data->end - 3 - p)
316			return false;
317
318		p[0] = type | SDP_DATA_EXT16;
319		be16enc(p + 1, (uint16_t)len);
320		p += 3;
321	} else {
322		if (len > data->end - 2 - p)
323			return false;
324
325		p[0] = type | SDP_DATA_EXT8;
326		p[1] = (uint8_t)len;
327		p += 2;
328	}
329
330	data->next = p;
331	return true;
332}
333
334bool
335sdp_put_seq(sdp_data_t *data, ssize_t len)
336{
337
338	return _sdp_put_ext(SDP_DATA_SEQ, data, len);
339}
340
341bool
342sdp_put_alt(sdp_data_t *data, ssize_t len)
343{
344
345	return _sdp_put_ext(SDP_DATA_ALT, data, len);
346}
347
348bool
349sdp_put_str(sdp_data_t *data, const char *str, ssize_t len)
350{
351
352	if (len == -1)
353		len = strlen(str);
354
355	if (!_sdp_put_ext(SDP_DATA_STR, data, len))
356		return false;
357
358	memcpy(data->next, str, (size_t)len);
359	data->next += len;
360	return true;
361}
362
363bool
364sdp_put_url(sdp_data_t *data, const char *url, ssize_t len)
365{
366
367	if (len == -1)
368		len = strlen(url);
369
370	if (!_sdp_put_ext(SDP_DATA_URL, data, len))
371		return false;
372
373	memcpy(data->next, url, (size_t)len);
374	data->next += len;
375	return true;
376}
377