1 /* 2 * Copyright (C) 2022 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "hci_dump_windows_fs.c" 39 40 /* 41 * hci_dump_windows_fs.c 42 * 43 * Dump HCI trace in various formats into a file: 44 * 45 * - BlueZ's hcidump format 46 * - Apple's PacketLogger 47 * - stdout hexdump 48 * 49 */ 50 51 #include "btstack_config.h" 52 53 #include "hci_dump_windows_fs.h" 54 55 #include "btstack_debug.h" 56 #include "btstack_util.h" 57 #include "hci_cmd.h" 58 59 #include <stdio.h> 60 #include <windows.h> 61 62 /** 63 * number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC 64 */ 65 #define EPOCH_DIFF 11644473600LL 66 67 static HANDLE dump_file = INVALID_HANDLE_VALUE; 68 static int dump_format; 69 static char log_message_buffer[256]; 70 71 static void hci_dump_windows_fs_reset(void){ 72 btstack_assert(dump_file != INVALID_HANDLE_VALUE); 73 SetEndOfFile(dump_file); 74 } 75 76 // provide summary for ISO Data Packets if not supported by fileformat/viewer yet 77 static uint16_t hci_dump_iso_summary(uint8_t in, uint8_t *packet, uint16_t len){ 78 uint16_t conn_handle = little_endian_read_16(packet, 0) & 0xfff; 79 uint8_t pb = (packet[1] >> 4) & 3; 80 uint8_t ts = (packet[1] >> 6) & 1; 81 uint16_t pos = 4; 82 uint32_t time_stamp = 0; 83 if (ts){ 84 time_stamp = little_endian_read_32(packet, pos); 85 pos += 4; 86 } 87 uint16_t packet_sequence = little_endian_read_16(packet, pos); 88 pos += 2; 89 uint16_t iso_sdu_len = little_endian_read_16(packet, pos); 90 uint8_t packet_status_flag = packet[pos+1] >> 6; 91 return snprintf(log_message_buffer,sizeof(log_message_buffer), "ISO %s, handle %04x, pb %u, ts 0x%08x, sequence 0x%04x, packet status %u, iso len %u", 92 in ? "IN" : "OUT", conn_handle, pb, time_stamp, packet_sequence, packet_status_flag, iso_sdu_len); 93 } 94 95 static void hci_dump_windows_fs_log_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) { 96 if (dump_file < 0) return; 97 98 static union { 99 uint8_t header_bluez[HCI_DUMP_HEADER_SIZE_BLUEZ]; 100 uint8_t header_packetlogger[HCI_DUMP_HEADER_SIZE_PACKETLOGGER]; 101 uint8_t header_btsnoop[HCI_DUMP_HEADER_SIZE_BTSNOOP+1]; 102 } header; 103 104 uint32_t tv_sec = 0; 105 uint32_t tv_us = 0; 106 uint64_t ts_usec; 107 108 // get time 109 FILETIME file_time; 110 SYSTEMTIME local_time; 111 ULARGE_INTEGER now_time; 112 GetLocalTime(&local_time); 113 SystemTimeToFileTime(&local_time, &file_time); 114 now_time.LowPart = file_time.dwLowDateTime; 115 now_time.HighPart = file_time.dwHighDateTime; 116 117 tv_sec = (uint32_t) ((now_time.QuadPart / 10000) - EPOCH_DIFF); 118 tv_us = (now_time.QuadPart % 10000) / 10; 119 120 uint16_t header_len = 0; 121 switch (dump_format){ 122 case HCI_DUMP_BLUEZ: 123 // ISO packets not supported 124 if (packet_type == HCI_ISO_DATA_PACKET){ 125 len = hci_dump_iso_summary(in, packet, len); 126 packet_type = LOG_MESSAGE_PACKET; 127 packet = (uint8_t*) log_message_buffer; 128 } 129 hci_dump_setup_header_bluez(header.header_bluez, tv_sec, tv_us, packet_type, in, len); 130 header_len = HCI_DUMP_HEADER_SIZE_BLUEZ; 131 break; 132 case HCI_DUMP_PACKETLOGGER: 133 // ISO packets not supported 134 if (packet_type == HCI_ISO_DATA_PACKET){ 135 len = hci_dump_iso_summary(in, packet, len); 136 packet_type = LOG_MESSAGE_PACKET; 137 packet = (uint8_t*) log_message_buffer; 138 } 139 hci_dump_setup_header_packetlogger(header.header_packetlogger, tv_sec, tv_us, packet_type, in, len); 140 header_len = HCI_DUMP_HEADER_SIZE_PACKETLOGGER; 141 break; 142 case HCI_DUMP_BTSNOOP: 143 // log messages not supported 144 if (packet_type == LOG_MESSAGE_PACKET) return; 145 ts_usec = 0xdcddb30f2f8000LLU + 1000000LLU * tv_sec + tv_us; 146 // append packet type to pcap header 147 hci_dump_setup_header_btsnoop(header.header_btsnoop, ts_usec >> 32, ts_usec & 0xFFFFFFFF, 0, packet_type, in, len+1); 148 header.header_btsnoop[HCI_DUMP_HEADER_SIZE_BTSNOOP] = packet_type; 149 header_len = HCI_DUMP_HEADER_SIZE_BTSNOOP + 1; 150 break; 151 default: 152 btstack_unreachable(); 153 return; 154 } 155 156 DWORD dwBytesWritten = 0; 157 (void) WriteFile( 158 dump_file, // file handle 159 &header, // start of data to write 160 header_len, // number of bytes to write 161 &dwBytesWritten, // number of bytes that were written 162 NULL); // no overlapped structure 163 UNUSED(dwBytesWritten); 164 165 (void)WriteFile( 166 dump_file, // file handle 167 packet, // start of data to write 168 len, // number of bytes to write 169 &dwBytesWritten, // number of bytes that were written 170 NULL); // no overlapped structure 171 UNUSED(dwBytesWritten); 172 } 173 174 static void hci_dump_windows_fs_log_message(int log_level, const char * format, va_list argptr){ 175 UNUSED(log_level); 176 if (dump_file < 0) return; 177 int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr); 178 hci_dump_windows_fs_log_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len); 179 } 180 181 // returns system errno 182 int hci_dump_windows_fs_open(const char *filename, hci_dump_format_t format){ 183 btstack_assert(format == HCI_DUMP_BLUEZ || format == HCI_DUMP_PACKETLOGGER || format == HCI_DUMP_BTSNOOP); 184 185 dump_format = format; 186 187 dump_file = CreateFile(filename, // name of the write 188 GENERIC_WRITE, // open for writing 189 0, // do not share 190 NULL, // default security 191 CREATE_ALWAYS, // create new file always 192 FILE_ATTRIBUTE_NORMAL, // normal file 193 NULL); // no attr. template 194 195 if (dump_file == INVALID_HANDLE_VALUE){ 196 printf("failed to open file %s, error code = 0x%lx\n", filename, GetLastError()); 197 return -1; 198 } 199 200 if (format == HCI_DUMP_BTSNOOP){ 201 // write BTSnoop file header 202 const uint8_t file_header[] = { 203 // Identification Pattern: "btsnoop\0" 204 0x62, 0x74, 0x73, 0x6E, 0x6F, 0x6F, 0x70, 0x00, 205 // Version: 1 206 0x00, 0x00, 0x00, 0x01, 207 // Datalink Type: 1002 - H4 208 0x00, 0x00, 0x03, 0xEA, 209 }; 210 211 DWORD dwBytesWritten = 0; 212 (void) WriteFile( 213 dump_file, // file handle 214 file_header, // start of data to write 215 sizeof(file_header), // number of bytes to write 216 &dwBytesWritten, // number of bytes that were written 217 NULL); // no overlapped structure 218 UNUSED(dwBytesWritten); 219 } 220 return 0; 221 } 222 223 void hci_dump_windows_fs_close(void){ 224 CloseHandle(dump_file); 225 dump_file = INVALID_HANDLE_VALUE; 226 } 227 228 const hci_dump_t * hci_dump_windows_fs_get_instance(void){ 229 static const hci_dump_t hci_dump_instance = { 230 // void (*reset)(void); 231 &hci_dump_windows_fs_reset, 232 // void (*log_packet)(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len); 233 &hci_dump_windows_fs_log_packet, 234 // void (*log_message)(int log_level, const char * format, va_list argptr); 235 &hci_dump_windows_fs_log_message, 236 }; 237 return &hci_dump_instance; 238 } 239