1/*-
2 * adv_data.c
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5
6 * Copyright (c) 2020 Marc Veldman <marc@bumblingdork.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id$
31 */
32
33#include <sys/types.h>
34#include <stdio.h>
35#include <string.h>
36#include <uuid.h>
37#define L2CAP_SOCKET_CHECKED
38#include <bluetooth.h>
39#include "hccontrol.h"
40
41static char* const adv_data2str(int len, uint8_t* data, char* buffer,
42	int size);
43static char* const adv_name2str(int len, uint8_t* advdata, char* buffer,
44	int size);
45static char* const adv_uuid2str(int datalen, uint8_t* data, char* buffer,
46	int size);
47
48void dump_adv_data(int len, uint8_t* advdata)
49{
50	int n=0;
51	fprintf(stdout, "\tADV Data: ");
52	for (n = 0; n < len+1; n++) {
53		fprintf(stdout, "%02x ", advdata[n]);
54	}
55	fprintf(stdout, "\n");
56}
57
58void print_adv_data(int len, uint8_t* advdata)
59{
60	int n=0;
61	while(n < len)
62	{
63		char buffer[2048];
64		uint8_t datalen = advdata[n];
65		uint8_t datatype = advdata[++n];
66		/* Skip type */
67		++n;
68		datalen--;
69		switch (datatype) {
70			case 0x01:
71				fprintf(stdout,
72					"\tFlags: %s\n",
73					adv_data2str(
74						datalen,
75						&advdata[n],
76						buffer,
77						sizeof(buffer)));
78				break;
79			case 0x02:
80				fprintf(stdout,
81					"\tIncomplete list of service"
82					" class UUIDs (16-bit): %s\n",
83					adv_data2str(
84						datalen,
85						&advdata[n],
86						buffer,
87						sizeof(buffer)));
88				break;
89			case 0x03:
90				fprintf(stdout,
91					"\tComplete list of service "
92					"class UUIDs (16-bit): %s\n",
93					adv_data2str(
94						datalen,
95						&advdata[n],
96						buffer,
97						sizeof(buffer)));
98				break;
99			case 0x07:
100				fprintf(stdout,
101					"\tComplete list of service "
102					"class UUIDs (128 bit): %s\n",
103					adv_uuid2str(
104						datalen,
105						&advdata[n],
106						buffer,
107						sizeof(buffer)));
108				break;
109			case 0x08:
110				fprintf(stdout,
111					"\tShortened local name: %s\n",
112					adv_name2str(
113						datalen,
114						&advdata[n],
115						buffer,
116						sizeof(buffer)));
117				break;
118			case 0x09:
119				fprintf(stdout,
120					"\tComplete local name: %s\n",
121					adv_name2str(
122						datalen,
123						&advdata[n],
124						buffer,
125						sizeof(buffer)));
126				break;
127			case 0x0a:
128				fprintf(stdout,
129					"\tTx Power level: %d dBm\n",
130						(int8_t)advdata[n]);
131				break;
132			case 0x0d:
133				fprintf(stdout,
134					"\tClass of device: %s\n",
135					adv_data2str(
136						datalen,
137						&advdata[n],
138						buffer,
139						sizeof(buffer)));
140				break;
141			case 0x16:
142				fprintf(stdout,
143					"\tService data: %s\n",
144					adv_data2str(
145						datalen,
146						&advdata[n],
147						buffer,
148						sizeof(buffer)));
149				break;
150			case 0x19:
151				fprintf(stdout,
152					"\tAppearance: %s\n",
153					adv_data2str(
154						datalen,
155						&advdata[n],
156						buffer,
157						sizeof(buffer)));
158				break;
159			case 0xff:
160				fprintf(stdout,
161					"\tManufacturer: %s\n",
162			       		hci_manufacturer2str(
163						advdata[n]|advdata[n+1]<<8));
164				fprintf(stdout,
165					"\tManufacturer specific data: %s\n",
166					adv_data2str(
167						datalen-2,
168						&advdata[n+2],
169						buffer,
170						sizeof(buffer)));
171				break;
172			default:
173				fprintf(stdout,
174					"\tUNKNOWN datatype: %02x data %s\n",
175					datatype,
176					adv_data2str(
177						datalen,
178						&advdata[n],
179						buffer,
180						sizeof(buffer)));
181		}
182		n += datalen;
183	}
184}
185
186static char* const adv_data2str(int datalen, uint8_t* data, char* buffer,
187	int size)
188{
189        int i = 0;
190	char tmpbuf[5];
191
192	if (buffer == NULL)
193		return NULL;
194
195	memset(buffer, 0, size);
196
197	while(i < datalen) {
198		(void)snprintf(tmpbuf, sizeof(tmpbuf), "%02x ", data[i]);
199		/* Check if buffer is full */
200		if (strlcat(buffer, tmpbuf, size) > size)
201			break;
202		i++;
203	}
204	return buffer;
205}
206
207static char* const adv_name2str(int datalen, uint8_t* data, char* buffer,
208	int size)
209{
210	if (buffer == NULL)
211		return NULL;
212
213	memset(buffer, 0, size);
214
215	(void)strlcpy(buffer, (char*)data, datalen+1);
216	return buffer;
217}
218
219static char* const adv_uuid2str(int datalen, uint8_t* data, char* buffer,
220	int size)
221{
222	int i;
223	uuid_t uuid;
224	uint32_t ustatus;
225	char* tmpstr;
226
227	if (buffer == NULL)
228		return NULL;
229
230	memset(buffer, 0, size);
231	if (datalen < 16)
232		return buffer;
233	uuid.time_low = le32dec(data+12);
234	uuid.time_mid = le16dec(data+10);
235	uuid.time_hi_and_version = le16dec(data+8);
236	uuid.clock_seq_hi_and_reserved = data[7];
237	uuid.clock_seq_low = data[6];
238	for(i = 0; i < _UUID_NODE_LEN; i++){
239		uuid.node[i] = data[5 - i];
240	}
241	uuid_to_string(&uuid, &tmpstr, &ustatus);
242	if(ustatus == uuid_s_ok) {
243		strlcpy(buffer, tmpstr, size);
244	}
245	free(tmpstr);
246
247	return buffer;
248}
249