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 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 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 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 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 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