1/*	$NetBSD: sdp_data.c,v 1.3 2011/09/15 17:51:57 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_data.c,v 1.3 2011/09/15 17:51:57 plunky Exp $");
34
35#include <sdp.h>
36#include <stdarg.h>
37#include <stdio.h>
38#include <vis.h>
39
40#include "sdp-int.h"
41
42
43/******************************************************************************
44 *	sdp_data_type(data)
45 *
46 * return SDP data element type
47 */
48int
49sdp_data_type(const sdp_data_t *data)
50{
51
52	if (data->next + 1 > data->end)
53		return -1;
54
55	return data->next[0];
56}
57
58
59/******************************************************************************
60 *	sdp_data_size(data)
61 *
62 * return the size of SDP data element. This will fail (return -1) if
63 * the data element does not fit into the data space.
64 */
65ssize_t
66sdp_data_size(const sdp_data_t *data)
67{
68	uint8_t *p = data->next;
69
70	if (p + 1 > data->end)
71		return -1;
72
73	switch (*p++) {
74	case SDP_DATA_NIL:
75		break;
76
77	case SDP_DATA_BOOL:
78	case SDP_DATA_INT8:
79	case SDP_DATA_UINT8:
80		p += 1;
81		break;
82
83	case SDP_DATA_INT16:
84	case SDP_DATA_UINT16:
85	case SDP_DATA_UUID16:
86		p += 2;
87		break;
88
89	case SDP_DATA_INT32:
90	case SDP_DATA_UINT32:
91	case SDP_DATA_UUID32:
92		p += 4;
93		break;
94
95	case SDP_DATA_INT64:
96	case SDP_DATA_UINT64:
97		p += 8;
98		break;
99
100	case SDP_DATA_INT128:
101	case SDP_DATA_UINT128:
102	case SDP_DATA_UUID128:
103		p += 16;
104		break;
105
106	case SDP_DATA_ALT8:
107	case SDP_DATA_SEQ8:
108	case SDP_DATA_STR8:
109	case SDP_DATA_URL8:
110		if (p + 1 > data->end)
111			return -1;
112
113		p += 1 + *p;
114		break;
115
116	case SDP_DATA_ALT16:
117	case SDP_DATA_SEQ16:
118	case SDP_DATA_STR16:
119	case SDP_DATA_URL16:
120		if (p + 2 > data->end)
121			return -1;
122
123		p += 2 + be16dec(p);
124		break;
125
126	case SDP_DATA_ALT32:
127	case SDP_DATA_SEQ32:
128	case SDP_DATA_STR32:
129	case SDP_DATA_URL32:
130		if (p + 4 > data->end)
131			return -1;
132
133		p += 4 + be32dec(p);
134		break;
135
136	default:
137		return -1;
138	}
139
140	if (p > data->end)
141		return -1;
142
143	return (p - data->next);
144}
145
146/******************************************************************************
147 *	sdp_data_valid(data)
148 *
149 * validate an SDP data element list recursively, ensuring elements do not
150 * expand past the claimed length and that there is no invalid data.
151 */
152static bool
153_sdp_data_valid(uint8_t *ptr, uint8_t *end)
154{
155	size_t len;
156
157	while (ptr < end) {
158		if (ptr + 1 > end)
159			return false;
160
161		switch (*ptr++) {
162		case SDP_DATA_NIL:
163			break;
164
165		case SDP_DATA_BOOL:
166		case SDP_DATA_INT8:
167		case SDP_DATA_UINT8:
168			if (ptr + 1 > end)
169				return false;
170
171			ptr += 1;
172			break;
173
174		case SDP_DATA_INT16:
175		case SDP_DATA_UINT16:
176		case SDP_DATA_UUID16:
177			if (ptr + 2 > end)
178				return false;
179
180			ptr += 2;
181			break;
182
183		case SDP_DATA_INT32:
184		case SDP_DATA_UINT32:
185		case SDP_DATA_UUID32:
186			if (ptr + 4 > end)
187				return false;
188
189			ptr += 4;
190			break;
191
192		case SDP_DATA_INT64:
193		case SDP_DATA_UINT64:
194			if (ptr + 8 > end)
195				return false;
196
197			ptr += 8;
198			break;
199
200		case SDP_DATA_INT128:
201		case SDP_DATA_UINT128:
202		case SDP_DATA_UUID128:
203			if (ptr + 16 > end)
204				return false;
205
206			ptr += 16;
207			break;
208
209		case SDP_DATA_STR8:
210		case SDP_DATA_URL8:
211			if (ptr + 1 > end)
212				return false;
213
214			len = *ptr;
215			ptr += 1;
216
217			if (ptr + len > end)
218				return false;
219
220			ptr += len;
221			break;
222
223		case SDP_DATA_STR16:
224		case SDP_DATA_URL16:
225			if (ptr + 2 > end)
226				return false;
227
228			len = be16dec(ptr);
229			ptr += 2;
230
231			if (ptr + len > end)
232				return false;
233
234			ptr += len;
235			break;
236
237		case SDP_DATA_STR32:
238		case SDP_DATA_URL32:
239			if (ptr + 4 > end)
240				return false;
241
242			len = be32dec(ptr);
243			ptr += 4;
244
245			if (ptr + len > end)
246				return false;
247
248			ptr += len;
249			break;
250
251		case SDP_DATA_SEQ8:
252		case SDP_DATA_ALT8:
253			if (ptr + 1 > end)
254				return false;
255
256			len = *ptr;
257			ptr += 1;
258
259			if (ptr + len > end)
260				return false;
261
262			if (!_sdp_data_valid(ptr, ptr + len))
263				return false;
264
265			ptr += len;
266			break;
267
268		case SDP_DATA_SEQ16:
269		case SDP_DATA_ALT16:
270			if (ptr + 2 > end)
271				return false;
272
273			len = be16dec(ptr);
274			ptr += 2;
275
276			if (ptr + len > end)
277				return false;
278
279			if (!_sdp_data_valid(ptr, ptr + len))
280				return false;
281
282			ptr += len;
283			break;
284
285		case SDP_DATA_SEQ32:
286		case SDP_DATA_ALT32:
287			if (ptr + 4 > end)
288				return false;
289
290			len = be32dec(ptr);
291			ptr += 4;
292
293			if (ptr + len > end)
294				return false;
295
296			if (!_sdp_data_valid(ptr, ptr + len))
297				return false;
298
299			ptr += len;
300			break;
301
302		default:
303			return false;
304		}
305	}
306
307	return true;
308}
309
310bool
311sdp_data_valid(const sdp_data_t *data)
312{
313
314	if (data->next == NULL || data->end == NULL)
315		return false;
316
317	if (data->next >= data->end)
318		return false;
319
320	return _sdp_data_valid(data->next, data->end);
321}
322
323/******************************************************************************
324 *	sdp_data_print(data, indent)
325 *
326 * print out a SDP data element list in human readable format
327 */
328static __printflike(3, 4) void
329_sdp_put(int indent, const char *type, const char *fmt, ...)
330{
331	va_list ap;
332
333	indent = printf("%*s%s", indent, "", type);
334	indent = 18 - indent;
335	if (indent < 2)
336		indent = 2;
337
338	printf("%*s", indent, "");
339
340	va_start(ap, fmt);
341	vprintf(fmt, ap);
342	va_end(ap);
343
344	printf("\n");
345}
346
347static void
348_sdp_putstr(int indent, const char *type, const uint8_t *str, size_t len)
349{
350	char buf[50], *dst = buf;
351	int style;
352
353	indent = printf("%*s%s(%zu)", indent, "", type, len);
354	indent = 18 - indent;
355	if (indent < 2)
356		indent = 2;
357
358	printf("%*s", indent, "");
359
360	style = VIS_CSTYLE | VIS_NL;
361	buf[0] = '\0';
362
363	while (len > 0 && (dst + 5) < (buf + sizeof(buf))) {
364		dst = vis(dst, str[0], style, (len > 0 ? str[1] : 0));
365		str++;
366		len--;
367	}
368
369	printf("\"%s%s\n", buf, (len == 0 ? "\"" : " ..."));
370}
371
372bool
373_sdp_data_print(const uint8_t *next, const uint8_t *end, int indent)
374{
375	size_t len;
376
377	while (next < end) {
378		if (next + 1 > end)
379			return false;
380
381		switch (*next++) {
382		case SDP_DATA_NIL:
383			_sdp_put(indent, "nil", "");
384			break;
385
386		case SDP_DATA_BOOL:
387			if (next + 1 > end)
388				return false;
389
390			_sdp_put(indent, "bool", "%s",
391			    (*next == 0x00 ? "false" : "true"));
392
393			next += 1;
394			break;
395
396		case SDP_DATA_INT8:
397			if (next + 1 > end)
398				return false;
399
400			_sdp_put(indent, "int8", "%" PRId8,
401			    *(const int8_t *)next);
402			next += 1;
403			break;
404
405		case SDP_DATA_UINT8:
406			if (next + 1 > end)
407				return false;
408
409			_sdp_put(indent, "uint8", "0x%02" PRIx8,
410			    *next);
411			next += 1;
412			break;
413
414		case SDP_DATA_INT16:
415			if (next + 2 > end)
416				return false;
417
418			_sdp_put(indent, "int16", "%" PRId16,
419			    (int16_t)be16dec(next));
420			next += 2;
421			break;
422
423		case SDP_DATA_UINT16:
424			if (next + 2 > end)
425				return false;
426
427			_sdp_put(indent, "uint16", "0x%04" PRIx16,
428			    be16dec(next));
429			next += 2;
430			break;
431
432		case SDP_DATA_UUID16:
433			if (next + 2 > end)
434				return false;
435
436			_sdp_put(indent, "uuid16", "0x%04" PRIx16,
437			    be16dec(next));
438			next += 2;
439			break;
440
441		case SDP_DATA_INT32:
442			if (next + 4 > end)
443				return false;
444
445			_sdp_put(indent, "int32", "%" PRId32,
446			    (int32_t)be32dec(next));
447			next += 4;
448			break;
449
450		case SDP_DATA_UINT32:
451			if (next + 4 > end)
452				return false;
453
454			_sdp_put(indent, "uint32", "0x%08" PRIx32,
455			    be32dec(next));
456			next += 4;
457			break;
458
459		case SDP_DATA_UUID32:
460			if (next + 4 > end)
461				return false;
462
463			_sdp_put(indent, "uuid32", "0x%08" PRIx32,
464			    be32dec(next));
465			next += 4;
466			break;
467
468		case SDP_DATA_INT64:
469			if (next + 8 > end)
470				return false;
471
472			_sdp_put(indent, "int64", "%" PRId64,
473			    (int64_t)be64dec(next));
474			next += 8;
475			break;
476
477		case SDP_DATA_UINT64:
478			if (next + 8 > end)
479				return false;
480
481			_sdp_put(indent, "uint64", "0x%016" PRIx64,
482			    be64dec(next));
483			next += 8;
484			break;
485
486		case SDP_DATA_INT128:
487			if (next + 16 > end)
488				return false;
489
490			_sdp_put(indent, "int128",
491				"0x%02x%02x%02x%02x%02x%02x%02x%02x"
492				"%02x%02x%02x%02x%02x%02x%02x%02x",
493				next[0], next[1], next[2], next[3],
494				next[4], next[5], next[6], next[7],
495				next[8], next[9], next[10], next[11],
496				next[12], next[13], next[14], next[15]);
497			next += 16;
498			break;
499
500		case SDP_DATA_UINT128:
501			if (next + 16 > end)
502				return false;
503
504			_sdp_put(indent, "uint128",
505				"0x%02x%02x%02x%02x%02x%02x%02x%02x"
506				"%02x%02x%02x%02x%02x%02x%02x%02x",
507				next[0], next[1], next[2], next[3],
508				next[4], next[5], next[6], next[7],
509				next[8], next[9], next[10], next[11],
510				next[12], next[13], next[14], next[15]);
511			next += 16;
512			break;
513
514		case SDP_DATA_UUID128:
515			if (next + 16 > end)
516				return false;
517
518			_sdp_put(indent, "uuid128",
519				"%02x%02x%02x%02x-"
520				"%02x%02x-"
521				"%02x%02x-"
522				"%02x%02x-"
523				"%02x%02x%02x%02x%02x%02x",
524				next[0], next[1], next[2], next[3],
525				next[4], next[5],
526				next[6], next[7],
527				next[8], next[9],
528				next[10], next[11], next[12],
529				next[13], next[14], next[15]);
530			next += 16;
531			break;
532
533		case SDP_DATA_STR8:
534			if (next + 1 > end)
535				return false;
536
537			len = *next;
538			next += 1;
539
540			if (next + len > end)
541				return false;
542
543			_sdp_putstr(indent, "str8", next, len);
544			next += len;
545			break;
546
547		case SDP_DATA_URL8:
548			if (next + 1 > end)
549				return false;
550
551			len = *next;
552			next += 1;
553
554			if (next + len > end)
555				return false;
556
557			_sdp_putstr(indent, "url8", next, len);
558			next += len;
559			break;
560
561		case SDP_DATA_STR16:
562			if (next + 2 > end)
563				return false;
564
565			len = be16dec(next);
566			next += 2;
567
568			if (next + len > end)
569				return false;
570
571			_sdp_putstr(indent, "str16", next, len);
572			next += len;
573			break;
574
575		case SDP_DATA_URL16:
576			if (next + 2 > end)
577				return false;
578
579			len = be16dec(next);
580			next += 2;
581
582			if (next + len > end)
583				return false;
584
585			_sdp_putstr(indent, "url16", next, len);
586			next += len;
587			break;
588
589		case SDP_DATA_STR32:
590			if (next + 4 > end)
591				return false;
592
593			len = be32dec(next);
594			next += 4;
595
596			if (next + len > end)
597				return false;
598
599			_sdp_putstr(indent, "str32", next, len);
600			next += len;
601			break;
602
603		case SDP_DATA_URL32:
604			if (next + 4 > end)
605				return false;
606
607			len = be32dec(next);
608			next += 4;
609
610			if (next + len > end)
611				return false;
612
613			_sdp_putstr(indent, "url32", next, len);
614			next += len;
615			break;
616
617		case SDP_DATA_SEQ8:
618			if (next + 1 > end)
619				return false;
620
621			len = *next;
622			next += 1;
623
624			if (next + len > end)
625				return false;
626
627			printf("%*sseq8(%zu)\n", indent, "", len);
628			if (!_sdp_data_print(next, next + len, indent + 1))
629				return false;
630
631			next += len;
632			break;
633
634		case SDP_DATA_ALT8:
635			if (next + 1 > end)
636				return false;
637
638			len = *next;
639			next += 1;
640
641			if (next + len > end)
642				return false;
643
644			printf("%*salt8(%zu)\n", indent, "", len);
645			if (!_sdp_data_print(next, next + len, indent + 1))
646				return false;
647
648			next += len;
649			break;
650
651		case SDP_DATA_SEQ16:
652			if (next + 2 > end)
653				return false;
654
655			len = be16dec(next);
656			next += 2;
657
658			if (next + len > end)
659				return false;
660
661			printf("%*sseq16(%zu)\n", indent, "", len);
662			if (!_sdp_data_print(next, next + len, indent + 1))
663				return false;
664
665			next += len;
666			break;
667
668		case SDP_DATA_ALT16:
669			if (next + 2 > end)
670				return false;
671
672			len = be16dec(next);
673			next += 2;
674
675			if (next + len > end)
676				return false;
677
678			printf("%*salt16(%zu)\n", indent, "", len);
679			if (!_sdp_data_print(next, next + len, indent + 1))
680				return false;
681
682			next += len;
683			break;
684
685		case SDP_DATA_SEQ32:
686			if (next + 4 > end)
687				return false;
688
689			len = be32dec(next);
690			next += 4;
691
692			if (next + len > end)
693				return false;
694
695			printf("%*sseq32(%zu)\n", indent, "", len);
696			if (!_sdp_data_print(next, next + len, indent + 1))
697				return false;
698
699			next += len;
700			break;
701
702		case SDP_DATA_ALT32:
703			if (next + 4 > end)
704				return false;
705
706			len = be32dec(next);
707			next += 4;
708
709			if (next + len > end)
710				return false;
711
712			printf("%*salt32(%zu)\n", indent, "", len);
713			if (!_sdp_data_print(next, next + len, indent + 1))
714				return false;
715
716			next += len;
717			break;
718
719		default:
720			return false;
721		}
722	}
723
724	return true;
725}
726
727void
728sdp_data_print(const sdp_data_t *data, int indent)
729{
730
731	if (!_sdp_data_print(data->next, data->end, indent))
732		printf("SDP data error\n");
733}
734