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
41 static char* const adv_data2str(int len, uint8_t* data, char* buffer,
42 int size);
43 static char* const adv_name2str(int len, uint8_t* advdata, char* buffer,
44 int size);
45 static char* const adv_uuid2str(int datalen, uint8_t* data, char* buffer,
46 int size);
47
dump_adv_data(int len,uint8_t * advdata)48 void 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
print_adv_data(int len,uint8_t * advdata)58 void 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
adv_data2str(int datalen,uint8_t * data,char * buffer,int size)186 static 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
adv_name2str(int datalen,uint8_t * data,char * buffer,int size)207 static 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
adv_uuid2str(int datalen,uint8_t * data,char * buffer,int size)219 static 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