1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2001-2002  Ricky Yuen <ryuen@qualcomm.com>
6 *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
7 *
8 *
9 *  This program is free software; you can redistribute it and/or modify
10 *  it under the terms of the GNU General Public License as published by
11 *  the Free Software Foundation; either version 2 of the License, or
12 *  (at your option) any later version.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 */
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28
29#include <stdio.h>
30#include <errno.h>
31#include <ctype.h>
32#include <unistd.h>
33#include <stdlib.h>
34#include <string.h>
35
36#include <sys/types.h>
37#include <netinet/in.h>
38
39#include "parser.h"
40#include "sdp.h"
41
42#define SDP_ERROR_RSP                                  0x01
43#define SDP_SERVICE_SEARCH_REQ                         0x02
44#define SDP_SERVICE_SEARCH_RSP                         0x03
45#define SDP_SERVICE_ATTR_REQ                           0x04
46#define SDP_SERVICE_ATTR_RSP                           0x05
47#define SDP_SERVICE_SEARCH_ATTR_REQ                    0x06
48#define SDP_SERVICE_SEARCH_ATTR_RSP                    0x07
49
50typedef struct {
51	uint8_t  pid;
52	uint16_t tid;
53	uint16_t len;
54} __attribute__ ((packed)) sdp_pdu_hdr;
55#define SDP_PDU_HDR_SIZE 5
56
57/* Data element type descriptor */
58#define SDP_DE_NULL   0
59#define SDP_DE_UINT   1
60#define SDP_DE_INT    2
61#define SDP_DE_UUID   3
62#define SDP_DE_STRING 4
63#define SDP_DE_BOOL   5
64#define SDP_DE_SEQ    6
65#define SDP_DE_ALT    7
66#define SDP_DE_URL    8
67
68/* Data element size index lookup table */
69typedef struct {
70	int addl_bits;
71	int num_bytes;
72} sdp_siz_idx_lookup_table_t;
73
74static sdp_siz_idx_lookup_table_t sdp_siz_idx_lookup_table[] = {
75	{ 0, 1  }, /* Size index = 0 */
76	{ 0, 2  }, /*              1 */
77	{ 0, 4  }, /*              2 */
78	{ 0, 8  }, /*              3 */
79	{ 0, 16 }, /*              4 */
80	{ 1, 1  }, /*              5 */
81	{ 1, 2  }, /*              6 */
82	{ 1, 4  }, /*              7 */
83};
84
85/* UUID name lookup table */
86typedef struct {
87	int   uuid;
88	char* name;
89} sdp_uuid_nam_lookup_table_t;
90
91static sdp_uuid_nam_lookup_table_t sdp_uuid_nam_lookup_table[] = {
92	{ SDP_UUID_SDP,                      "SDP"          },
93	{ SDP_UUID_UDP,                      "UDP"          },
94	{ SDP_UUID_RFCOMM,                   "RFCOMM"       },
95	{ SDP_UUID_TCP,                      "TCP"          },
96	{ SDP_UUID_TCS_BIN,                  "TCS-BIN"      },
97	{ SDP_UUID_TCS_AT,                   "TCS-AT"       },
98	{ SDP_UUID_OBEX,                     "OBEX"         },
99	{ SDP_UUID_IP,                       "IP"           },
100	{ SDP_UUID_FTP,                      "FTP"          },
101	{ SDP_UUID_HTTP,                     "HTTP"         },
102	{ SDP_UUID_WSP,                      "WSP"          },
103	{ SDP_UUID_L2CAP,                    "L2CAP"        },
104	{ SDP_UUID_BNEP,                     "BNEP"         }, /* PAN */
105	{ SDP_UUID_HIDP,                     "HIDP"         }, /* HID */
106	{ SDP_UUID_AVCTP,                    "AVCTP"        }, /* AVCTP */
107	{ SDP_UUID_AVDTP,                    "AVDTP"        }, /* AVDTP */
108	{ SDP_UUID_CMTP,                     "CMTP"         }, /* CIP */
109	{ SDP_UUID_UDI_C_PLANE,              "UDI_C-Plane"  }, /* UDI */
110	{ SDP_UUID_SERVICE_DISCOVERY_SERVER, "SDServer"     },
111	{ SDP_UUID_BROWSE_GROUP_DESCRIPTOR,  "BrwsGrpDesc"  },
112	{ SDP_UUID_PUBLIC_BROWSE_GROUP,      "PubBrwsGrp"   },
113	{ SDP_UUID_SERIAL_PORT,              "SP"           },
114	{ SDP_UUID_LAN_ACCESS_PPP,           "LAN"          },
115	{ SDP_UUID_DIALUP_NETWORKING,        "DUN"          },
116	{ SDP_UUID_IR_MC_SYNC,               "IRMCSync"     },
117	{ SDP_UUID_OBEX_OBJECT_PUSH,         "OBEXObjPush"  },
118	{ SDP_UUID_OBEX_FILE_TRANSFER,       "OBEXObjTrnsf" },
119	{ SDP_UUID_IR_MC_SYNC_COMMAND,       "IRMCSyncCmd"  },
120	{ SDP_UUID_HEADSET,                  "Headset"      },
121	{ SDP_UUID_CORDLESS_TELEPHONY,       "CordlessTel"  },
122	{ SDP_UUID_AUDIO_SOURCE,             "AudioSource"  }, /* A2DP */
123	{ SDP_UUID_AUDIO_SINK,               "AudioSink"    }, /* A2DP */
124	{ SDP_UUID_AV_REMOTE_TARGET,         "AVRemTarget"  }, /* AVRCP */
125	{ SDP_UUID_ADVANCED_AUDIO,           "AdvAudio"     }, /* A2DP */
126	{ SDP_UUID_AV_REMOTE,                "AVRemote"     }, /* AVRCP */
127	{ SDP_UUID_VIDEO_CONFERENCING,       "VideoConf"    }, /* VCP */
128	{ SDP_UUID_INTERCOM,                 "Intercom"     },
129	{ SDP_UUID_FAX,                      "Fax"          },
130	{ SDP_UUID_HEADSET_AUDIO_GATEWAY,    "Headset AG"   },
131	{ SDP_UUID_WAP,                      "WAP"          },
132	{ SDP_UUID_WAP_CLIENT,               "WAP Client"   },
133	{ SDP_UUID_PANU,                     "PANU"         }, /* PAN */
134	{ SDP_UUID_NAP,                      "NAP"          }, /* PAN */
135	{ SDP_UUID_GN,                       "GN"           }, /* PAN */
136	{ SDP_UUID_DIRECT_PRINTING,          "DirectPrint"  }, /* BPP */
137	{ SDP_UUID_REFERENCE_PRINTING,       "RefPrint"     }, /* BPP */
138	{ SDP_UUID_IMAGING,                  "Imaging"      }, /* BIP */
139	{ SDP_UUID_IMAGING_RESPONDER,        "ImagingResp"  }, /* BIP */
140	{ SDP_UUID_HANDSFREE,                "Handsfree"    },
141	{ SDP_UUID_HANDSFREE_AUDIO_GATEWAY,  "Handsfree AG" },
142	{ SDP_UUID_DIRECT_PRINTING_REF_OBJS, "RefObjsPrint" }, /* BPP */
143	{ SDP_UUID_REFLECTED_UI,             "ReflectedUI"  }, /* BPP */
144	{ SDP_UUID_BASIC_PRINTING,           "BasicPrint"   }, /* BPP */
145	{ SDP_UUID_PRINTING_STATUS,          "PrintStatus"  }, /* BPP */
146	{ SDP_UUID_HUMAN_INTERFACE_DEVICE,   "HID"          }, /* HID */
147	{ SDP_UUID_HARDCOPY_CABLE_REPLACE,   "HCRP"         }, /* HCRP */
148	{ SDP_UUID_HCR_PRINT,                "HCRPrint"     }, /* HCRP */
149	{ SDP_UUID_HCR_SCAN,                 "HCRScan"      }, /* HCRP */
150	{ SDP_UUID_COMMON_ISDN_ACCESS,       "CIP"          }, /* CIP */
151	{ SDP_UUID_VIDEO_CONFERENCING_GW,    "VideoConf GW" }, /* VCP */
152	{ SDP_UUID_UDI_MT,                   "UDI MT"       }, /* UDI */
153	{ SDP_UUID_UDI_TA,                   "UDI TA"       }, /* UDI */
154	{ SDP_UUID_AUDIO_VIDEO,              "AudioVideo"   }, /* VCP */
155	{ SDP_UUID_SIM_ACCESS,               "SAP"          }, /* SAP */
156	{ SDP_UUID_PHONEBOOK_ACCESS_PCE,     "PBAP PCE"     }, /* PBAP */
157	{ SDP_UUID_PHONEBOOK_ACCESS_PSE,     "PBAP PSE"     }, /* PBAP */
158	{ SDP_UUID_PHONEBOOK_ACCESS,         "PBAP"         }, /* PBAP */
159	{ SDP_UUID_PNP_INFORMATION,          "PNPInfo"      },
160	{ SDP_UUID_GENERIC_NETWORKING,       "Networking"   },
161	{ SDP_UUID_GENERIC_FILE_TRANSFER,    "FileTrnsf"    },
162	{ SDP_UUID_GENERIC_AUDIO,            "Audio"        },
163	{ SDP_UUID_GENERIC_TELEPHONY,        "Telephony"    },
164	{ SDP_UUID_UPNP_SERVICE,             "UPNP"         }, /* ESDP */
165	{ SDP_UUID_UPNP_IP_SERVICE,          "UPNP IP"      }, /* ESDP */
166	{ SDP_UUID_ESDP_UPNP_IP_PAN,         "UPNP PAN"     }, /* ESDP */
167	{ SDP_UUID_ESDP_UPNP_IP_LAP,         "UPNP LAP"     }, /* ESDP */
168	{ SDP_UUID_ESDP_UPNP_L2CAP,          "UPNP L2CAP"   }, /* ESDP */
169	{ SDP_UUID_VIDEO_SOURCE,             "VideoSource"  }, /* VDP */
170	{ SDP_UUID_VIDEO_SINK,               "VideoSink"    }, /* VDP */
171	{ SDP_UUID_VIDEO_DISTRIBUTION,       "VideoDist"    }, /* VDP */
172	{ SDP_UUID_APPLE_AGENT,              "AppleAgent"   },
173};
174
175#define SDP_UUID_NAM_LOOKUP_TABLE_SIZE \
176	(sizeof(sdp_uuid_nam_lookup_table)/sizeof(sdp_uuid_nam_lookup_table_t))
177
178/* AttrID name lookup table */
179typedef struct {
180	int   attr_id;
181	char* name;
182} sdp_attr_id_nam_lookup_table_t;
183
184static sdp_attr_id_nam_lookup_table_t sdp_attr_id_nam_lookup_table[] = {
185	{ SDP_ATTR_ID_SERVICE_RECORD_HANDLE,             "SrvRecHndl"         },
186	{ SDP_ATTR_ID_SERVICE_CLASS_ID_LIST,             "SrvClassIDList"     },
187	{ SDP_ATTR_ID_SERVICE_RECORD_STATE,              "SrvRecState"        },
188	{ SDP_ATTR_ID_SERVICE_SERVICE_ID,                "SrvID"              },
189	{ SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST,          "ProtocolDescList"   },
190	{ SDP_ATTR_ID_BROWSE_GROUP_LIST,                 "BrwGrpList"         },
191	{ SDP_ATTR_ID_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,   "LangBaseAttrIDList" },
192	{ SDP_ATTR_ID_SERVICE_INFO_TIME_TO_LIVE,         "SrvInfoTimeToLive"  },
193	{ SDP_ATTR_ID_SERVICE_AVAILABILITY,              "SrvAvail"           },
194	{ SDP_ATTR_ID_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, "BTProfileDescList"  },
195	{ SDP_ATTR_ID_DOCUMENTATION_URL,                 "DocURL"             },
196	{ SDP_ATTR_ID_CLIENT_EXECUTABLE_URL,             "ClientExeURL"       },
197	{ SDP_ATTR_ID_ICON_URL,                          "IconURL"            },
198	{ SDP_ATTR_ID_ADDITIONAL_PROTOCOL_DESC_LISTS,    "AdditionalProtocolDescLists" },
199	{ SDP_ATTR_ID_SERVICE_NAME,                      "SrvName"            },
200	{ SDP_ATTR_ID_SERVICE_DESCRIPTION,               "SrvDesc"            },
201	{ SDP_ATTR_ID_PROVIDER_NAME,                     "ProviderName"       },
202	{ SDP_ATTR_ID_VERSION_NUMBER_LIST,               "VersionNumList"     },
203	{ SDP_ATTR_ID_GROUP_ID,                          "GrpID"              },
204	{ SDP_ATTR_ID_SERVICE_DATABASE_STATE,            "SrvDBState"         },
205	{ SDP_ATTR_ID_SERVICE_VERSION,                   "SrvVersion"         },
206	{ SDP_ATTR_ID_SECURITY_DESCRIPTION,              "SecurityDescription"}, /* PAN */
207	{ SDP_ATTR_ID_SUPPORTED_DATA_STORES_LIST,        "SuppDataStoresList" }, /* Synchronization */
208	{ SDP_ATTR_ID_SUPPORTED_FORMATS_LIST,            "SuppFormatsList"    }, /* OBEX Object Push */
209	{ SDP_ATTR_ID_NET_ACCESS_TYPE,                   "NetAccessType"      }, /* PAN */
210	{ SDP_ATTR_ID_MAX_NET_ACCESS_RATE,               "MaxNetAccessRate"   }, /* PAN */
211	{ SDP_ATTR_ID_IPV4_SUBNET,                       "IPv4Subnet"         }, /* PAN */
212	{ SDP_ATTR_ID_IPV6_SUBNET,                       "IPv6Subnet"         }, /* PAN */
213	{ SDP_ATTR_ID_SUPPORTED_CAPABILITIES,            "SuppCapabilities"   }, /* Imaging */
214	{ SDP_ATTR_ID_SUPPORTED_FEATURES,                "SuppFeatures"       }, /* Imaging and Hansfree */
215	{ SDP_ATTR_ID_SUPPORTED_FUNCTIONS,               "SuppFunctions"      }, /* Imaging */
216	{ SDP_ATTR_ID_TOTAL_IMAGING_DATA_CAPACITY,       "SuppTotalCapacity"  }, /* Imaging */
217	{ SDP_ATTR_ID_SUPPORTED_REPOSITORIES,            "SuppRepositories"   }, /* PBAP */
218};
219
220#define SDP_ATTR_ID_NAM_LOOKUP_TABLE_SIZE \
221	(sizeof(sdp_attr_id_nam_lookup_table)/sizeof(sdp_attr_id_nam_lookup_table_t))
222
223char* get_uuid_name(int uuid)
224{
225	unsigned int i;
226
227	for (i = 0; i < SDP_UUID_NAM_LOOKUP_TABLE_SIZE; i++) {
228		if (sdp_uuid_nam_lookup_table[i].uuid == uuid)
229			return sdp_uuid_nam_lookup_table[i].name;
230	}
231
232	return 0;
233}
234
235static inline char* get_attr_id_name(int attr_id)
236{
237	unsigned int i;
238
239	for (i = 0; i < SDP_ATTR_ID_NAM_LOOKUP_TABLE_SIZE; i++)
240		if (sdp_attr_id_nam_lookup_table[i].attr_id == attr_id)
241			return sdp_attr_id_nam_lookup_table[i].name;
242	return 0;
243}
244
245static inline uint8_t parse_de_hdr(struct frame *frm, int *n)
246{
247	uint8_t de_hdr = get_u8(frm);
248	uint8_t de_type = de_hdr >> 3;
249	uint8_t siz_idx = de_hdr & 0x07;
250
251	/* Get the number of bytes */
252	if (sdp_siz_idx_lookup_table[siz_idx].addl_bits) {
253		switch(sdp_siz_idx_lookup_table[siz_idx].num_bytes) {
254		case 1:
255			*n = get_u8(frm); break;
256		case 2:
257			*n = get_u16(frm); break;
258		case 4:
259			*n = get_u32(frm); break;
260		case 8:
261			*n = get_u64(frm); break;
262		}
263	} else
264		*n = sdp_siz_idx_lookup_table[siz_idx].num_bytes;
265
266	return de_type;
267}
268
269static inline void print_int(uint8_t de_type, int level, int n, struct frame *frm, uint16_t *psm, uint8_t *channel)
270{
271	uint64_t val, val2;
272
273	switch(de_type) {
274	case SDP_DE_UINT:
275		printf(" uint");
276		break;
277	case SDP_DE_INT:
278		printf(" int");
279		break;
280	case SDP_DE_BOOL:
281		printf(" bool");
282		break;
283	}
284
285	switch(n) {
286	case 1: /* 8-bit */
287		val = get_u8(frm);
288		if (channel && de_type == SDP_DE_UINT)
289			if (*channel == 0)
290				*channel = val;
291		break;
292	case 2: /* 16-bit */
293		val = get_u16(frm);
294		if (psm && de_type == SDP_DE_UINT)
295			if (*psm == 0)
296				*psm = val;
297		break;
298	case 4: /* 32-bit */
299		val = get_u32(frm);
300		break;
301	case 8: /* 64-bit */
302		val = get_u64(frm);
303		break;
304	case 16:/* 128-bit */
305		get_u128(frm, &val, &val2);
306		printf(" 0x%jx", val2);
307		if (val < 0x1000000000000000LL)
308			printf("0");
309		printf("%jx", val);
310		return;
311	default: /* syntax error */
312		printf(" err");
313		frm->ptr += n;
314		frm->len -= n;
315		return;
316	}
317
318	printf(" 0x%jx", val);
319}
320
321static inline void print_uuid(int n, struct frame *frm, uint16_t *psm, uint8_t *channel)
322{
323	uint32_t uuid = 0;
324	char* s;
325	int i;
326
327	switch(n) {
328	case 2: /* 16-bit UUID */
329		uuid = get_u16(frm);
330		s = "uuid-16";
331		break;
332	case 4: /* 32_bit UUID */
333		uuid = get_u32(frm);
334		s = "uuid-32";
335		break;
336	case 16: /* 128-bit UUID */
337		printf(" uuid-128 ");
338		for (i = 0; i < 16; i++) {
339			printf("%02x", ((unsigned char *) frm->ptr)[i]);
340			if (i == 3 || i == 5 || i == 7 || i == 9)
341				printf("-");
342		}
343		frm->ptr += 16;
344		frm->len -= 16;
345		return;
346	default: /* syntax error */
347		printf(" *err*");
348		frm->ptr += n;
349		frm->len -= n;
350		return;
351	}
352
353	if (psm && *psm > 0 && *psm != 0xffff) {
354		set_proto(frm->handle, *psm, 0, uuid);
355		*psm = 0xffff;
356	}
357
358	if (channel && *channel > 0 && *channel != 0xff) {
359		set_proto(frm->handle, *psm, *channel, uuid);
360		*channel = 0xff;
361	}
362
363	printf(" %s 0x%04x", s, uuid);
364	if ((s = get_uuid_name(uuid)))
365		printf(" (%s)", s);
366}
367
368static inline void print_string(int n, struct frame *frm, const char *name)
369{
370	int i, hex = 0;
371
372	for (i = 0; i < n; i++) {
373		if (i == (n - 1) && ((char *) frm->ptr)[i] == '\0')
374			break;
375
376		if (!isprint(((char *) frm->ptr)[i])) {
377			hex = 1;
378			break;
379		}
380	}
381
382	printf(" %s", name);
383	if (hex) {
384		for (i = 0; i < n; i++)
385			printf(" %02x", ((unsigned char *) frm->ptr)[i]);
386	} else {
387		printf(" \"");
388		for (i = 0; i < n; i++)
389			printf("%c", ((char *) frm->ptr)[i]);
390		printf("\"");
391	}
392
393	frm->ptr += n;
394	frm->len -= n;
395}
396
397static inline void print_de(int, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel);
398
399static inline void print_des(uint8_t de_type, int level, int n, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel)
400{
401	int len = frm->len;
402	while (len - (int) frm->len < n && (int) frm->len > 0)
403		print_de(level, frm, split, psm, channel);
404}
405
406static inline void print_de(int level, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel)
407{
408	int n = 0;
409	uint8_t de_type = parse_de_hdr(frm, &n);
410
411	switch (de_type) {
412	case SDP_DE_NULL:
413		printf(" null");
414		break;
415	case SDP_DE_UINT:
416	case SDP_DE_INT:
417	case SDP_DE_BOOL:
418		print_int(de_type, level, n, frm, psm, channel);
419		break;
420	case SDP_DE_UUID:
421		if (split) {
422			/* Split output by uuids.
423			 * Used for printing Protocol Desc List */
424			if (*split) {
425				printf("\n");
426				p_indent(level, NULL);
427			}
428			++*split;
429		}
430		print_uuid(n, frm, psm, channel);
431		break;
432	case SDP_DE_URL:
433	case SDP_DE_STRING:
434		print_string(n, frm, de_type == SDP_DE_URL? "url": "str");
435		break;
436	case SDP_DE_SEQ:
437		printf(" <");
438		print_des(de_type, level, n, frm, split, psm, channel);
439		printf(" >");
440		break;
441	case SDP_DE_ALT:
442		printf(" [");
443		print_des(de_type, level, n, frm, split, psm, channel);
444		printf(" ]");
445		break;
446	}
447}
448
449static inline void print_srv_srch_pat(int level, struct frame *frm)
450{
451	int len, n1 = 0, n2 = 0;
452
453	p_indent(level, frm);
454	printf("pat");
455
456	if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
457		len = frm->len;
458		while (len - (int) frm->len < n1 && (int) frm->len > 0) {
459			if (parse_de_hdr(frm, &n2) == SDP_DE_UUID) {
460				print_uuid(n2, frm, NULL, NULL);
461			} else {
462				printf("\nERROR: Unexpected syntax (UUID)\n");
463				raw_dump(level, frm);
464			}
465		}
466		printf("\n");
467	} else {
468		printf("\nERROR: Unexpected syntax (SEQ)\n");
469		raw_dump(level, frm);
470	}
471}
472
473static inline void print_attr_id_list(int level, struct frame *frm)
474{
475	uint16_t attr_id;
476	uint32_t attr_id_range;
477	int len, n1 = 0, n2 = 0;
478
479	p_indent(level, frm);
480	printf("aid(s)");
481
482	if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
483		len = frm->len;
484		while (len - (int) frm->len < n1 && (int) frm->len > 0) {
485			/* Print AttributeID */
486			if (parse_de_hdr(frm, &n2) == SDP_DE_UINT) {
487				char *name;
488				switch(n2) {
489				case 2:
490					attr_id = get_u16(frm);
491					name = get_attr_id_name(attr_id);
492					if (!name)
493						name = "unknown";
494					printf(" 0x%04x (%s)", attr_id, name);
495					break;
496				case 4:
497					attr_id_range = get_u32(frm);
498					printf(" 0x%04x - 0x%04x",
499							(attr_id_range >> 16),
500							(attr_id_range & 0xFFFF));
501					break;
502				}
503			} else {
504				printf("\nERROR: Unexpected syntax\n");
505				raw_dump(level, frm);
506			}
507		}
508		printf("\n");
509	} else {
510		printf("\nERROR: Unexpected syntax\n");
511		raw_dump(level, frm);
512	}
513}
514
515static inline void print_attr_list(int level, struct frame *frm)
516{
517	uint16_t attr_id, psm;
518	uint8_t channel;
519	int len, split, n1 = 0, n2 = 0;
520
521	if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
522		len = frm->len;
523		while (len - (int) frm->len < n1 && (int) frm->len > 0) {
524			/* Print AttributeID */
525			if (parse_de_hdr(frm, &n2) == SDP_DE_UINT && n2 == sizeof(attr_id)) {
526				char *name;
527				attr_id = get_u16(frm);
528				p_indent(level, 0);
529				name = get_attr_id_name(attr_id);
530				if (!name)
531					name = "unknown";
532				printf("aid 0x%04x (%s)\n", attr_id, name);
533				split = (attr_id != SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST);
534				psm = 0;
535				channel = 0;
536
537				/* Print AttributeValue */
538				p_indent(level + 1, 0);
539				print_de(level + 1, frm, split ? NULL: &split,
540					attr_id == SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST ? &psm : NULL,
541					attr_id == SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST ? &channel : NULL);
542				printf("\n");
543			} else {
544				printf("\nERROR: Unexpected syntax\n");
545				raw_dump(level, frm);
546				break;
547			}
548		}
549	} else {
550		printf("\nERROR: Unexpected syntax\n");
551		raw_dump(level, frm);
552	}
553}
554
555static inline void print_attr_lists(int level, struct frame *frm)
556{
557	int n = 0, cnt = 0;
558	int count = frm->len;
559
560	if (parse_de_hdr(frm, &n) == SDP_DE_SEQ) {
561		while (count - (int) frm->len < n && (int) frm->len > 0) {
562			p_indent(level, 0);
563			printf("record #%d\n", cnt++);
564			print_attr_list(level + 2, frm);
565		}
566	} else {
567		printf("\nERROR: Unexpected syntax\n");
568		raw_dump(level, frm);
569	}
570}
571
572static inline void print_cont_state(int level, unsigned char *buf)
573{
574	uint8_t cont = buf[0];
575	int i;
576
577	p_indent(level, 0);
578	printf("cont");
579	for (i = 0; i < cont + 1; i++)
580		printf(" %2.2X", buf[i]);
581	printf("\n");
582}
583
584static char *pid2str(uint8_t pid)
585{
586	switch (pid) {
587	case SDP_ERROR_RSP:
588		return "Error Rsp";
589	case SDP_SERVICE_SEARCH_REQ:
590		return "SS Req";
591	case SDP_SERVICE_SEARCH_RSP:
592		return "SS Rsp";
593	case SDP_SERVICE_ATTR_REQ:
594		return "SA Req";
595	case SDP_SERVICE_ATTR_RSP:
596		return "SA Rsp";
597	case SDP_SERVICE_SEARCH_ATTR_REQ:
598		return "SSA Req";
599	case SDP_SERVICE_SEARCH_ATTR_RSP:
600		return "SSA Rsp";
601	default:
602		return "Unknown";
603	}
604}
605
606#define FRAME_TABLE_SIZE 10
607
608static struct frame frame_table[FRAME_TABLE_SIZE];
609
610static int frame_add(struct frame *frm, int count)
611{
612	register struct frame *fr;
613	register unsigned char *data;
614	register int i, len = 0, pos = -1;
615
616	for (i = 0; i < FRAME_TABLE_SIZE; i++) {
617		if (frame_table[i].handle == frm->handle &&
618				frame_table[i].cid == frm->cid) {
619			pos = i;
620			len = frame_table[i].data_len;
621			break;
622		}
623		if (pos < 0 && !frame_table[i].handle)
624			pos = i;
625	}
626
627	if (pos < 0 || count <= 0)
628		return -EIO;
629
630	data = malloc(len + count);
631	if (!data)
632		return -ENOMEM;
633
634	fr = &frame_table[pos];
635
636	if (len > 0) {
637		memcpy(data, fr->data, len);
638		memcpy(data + len, frm->ptr, count);
639	} else
640		memcpy(data, frm->ptr, count);
641
642	if (fr->data)
643		free(fr->data);
644
645	fr->data       = data;
646	fr->data_len   = len + count;
647	fr->len        = fr->data_len;
648	fr->ptr        = fr->data;
649	fr->dev_id     = frm->dev_id;
650	fr->in         = frm->in;
651	fr->ts         = frm->ts;
652	fr->handle     = frm->handle;
653	fr->cid        = frm->cid;
654	fr->num        = frm->num;
655	fr->channel    = frm->channel;
656	fr->pppdump_fd = frm->pppdump_fd;
657	fr->audio_fd   = frm->audio_fd;
658
659	return pos;
660}
661
662static struct frame *frame_get(struct frame *frm, int count)
663{
664	register int pos;
665
666	pos = frame_add(frm, count);
667	if (pos < 0)
668		return frm;
669
670	frame_table[pos].handle = 0;
671
672	return &frame_table[pos];
673}
674
675void sdp_dump(int level, struct frame *frm)
676{
677	sdp_pdu_hdr *hdr = frm->ptr;
678	uint16_t tid = ntohs(hdr->tid);
679	uint16_t len = ntohs(hdr->len);
680	uint16_t total, count;
681	uint8_t cont;
682
683	frm->ptr += SDP_PDU_HDR_SIZE;
684	frm->len -= SDP_PDU_HDR_SIZE;
685
686	p_indent(level, frm);
687	printf("SDP %s: tid 0x%x len 0x%x\n", pid2str(hdr->pid), tid, len);
688
689	switch (hdr->pid) {
690	case SDP_ERROR_RSP:
691		p_indent(level + 1, frm);
692		printf("code 0x%x info ", get_u16(frm));
693		if (frm->len > 0)
694			hex_dump(0, frm, frm->len);
695		else
696			printf("none\n");
697		break;
698
699	case SDP_SERVICE_SEARCH_REQ:
700		/* Parse ServiceSearchPattern */
701		print_srv_srch_pat(level + 1, frm);
702
703		/* Parse MaximumServiceRecordCount */
704		p_indent(level + 1, frm);
705		printf("max %d\n", get_u16(frm));
706
707		/* Parse ContinuationState */
708		print_cont_state(level + 1, frm->ptr);
709		break;
710
711	case SDP_SERVICE_SEARCH_RSP:
712		/* Parse TotalServiceRecordCount */
713		total = get_u16(frm);
714
715		/* Parse CurrentServiceRecordCount */
716		count = get_u16(frm);
717		p_indent(level + 1, frm);
718		if (count < total)
719			printf("count %d of %d\n", count, total);
720		else
721			printf("count %d\n", count);
722
723		/* Parse service record handle(s) */
724		if (count > 0) {
725			int i;
726			p_indent(level + 1, frm);
727			printf("handle%s", count > 1 ? "s" : "");
728			for (i = 0; i < count; i++)
729				printf(" 0x%x", get_u32(frm));
730			printf("\n");
731		}
732
733		/* Parse ContinuationState */
734		print_cont_state(level + 1, frm->ptr);
735		break;
736
737	case SDP_SERVICE_ATTR_REQ:
738		/* Parse ServiceRecordHandle */
739		p_indent(level + 1, frm);
740		printf("handle 0x%x\n", get_u32(frm));
741
742		/* Parse MaximumAttributeByteCount */
743		p_indent(level + 1, frm);
744		printf("max %d\n", get_u16(frm));
745
746		/* Parse ServiceSearchPattern */
747		print_attr_id_list(level + 1, frm);
748
749		/* Parse ContinuationState */
750		print_cont_state(level + 1, frm->ptr);
751		break;
752
753	case SDP_SERVICE_ATTR_RSP:
754		/* Parse AttributeByteCount */
755		count = get_u16(frm);
756		p_indent(level + 1, frm);
757		printf("count %d\n", count);
758
759		/* Parse ContinuationState */
760		cont = *(unsigned char *)(frm->ptr + count);
761
762		if (cont == 0) {
763			/* Parse AttributeList */
764			print_attr_list(level + 1, frame_get(frm, count));
765		} else
766			frame_add(frm, count);
767
768		print_cont_state(level + 1, frm->ptr + count);
769		break;
770
771	case SDP_SERVICE_SEARCH_ATTR_REQ:
772		/* Parse ServiceSearchPattern */
773		print_srv_srch_pat(level + 1, frm);
774
775		/* Parse MaximumAttributeByteCount */
776		p_indent(level + 1, frm);
777		printf("max %d\n", get_u16(frm));
778
779		/* Parse AttributeList */
780		print_attr_id_list(level + 1, frm);
781
782		/* Parse ContinuationState */
783		print_cont_state(level + 1, frm->ptr);
784		break;
785
786	case SDP_SERVICE_SEARCH_ATTR_RSP:
787		/* Parse AttributeByteCount */
788		count = get_u16(frm);
789		p_indent(level + 1, frm);
790		printf("count %d\n", count);
791
792		/* Parse ContinuationState */
793		cont = *(unsigned char *)(frm->ptr + count);
794
795		if (cont == 0) {
796			/* Parse AttributeLists */
797			print_attr_lists(level + 1, frame_get(frm, count));
798		} else
799			frame_add(frm, count);
800
801		print_cont_state(level + 1, frm->ptr + count);
802		break;
803
804	default:
805		raw_dump(level + 1, frm);
806		break;
807	}
808}
809