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 #include <share.h> 62 63 /** 64 * number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC 65 */ 66 #define EPOCH_DIFF 11644473600LL 67 68 static HANDLE dump_file = INVALID_HANDLE_VALUE; 69 static int dump_format; 70 static char log_message_buffer[256]; 71 72 static void hci_dump_windows_fs_reset(void){ 73 btstack_assert(dump_file != INVALID_HANDLE_VALUE); 74 SetEndOfFile(dump_file); 75 } 76 77 // provide summary for ISO Data Packets if not supported by fileformat/viewer yet 78 static uint16_t hci_dump_iso_summary(uint8_t in, uint8_t *packet, uint16_t len){ 79 uint16_t conn_handle = little_endian_read_16(packet, 0) & 0xfff; 80 uint8_t pb = (packet[1] >> 4) & 3; 81 uint8_t ts = (packet[1] >> 6) & 1; 82 uint16_t pos = 4; 83 uint32_t time_stamp = 0; 84 if (ts){ 85 time_stamp = little_endian_read_32(packet, pos); 86 pos += 4; 87 } 88 uint16_t packet_sequence = little_endian_read_16(packet, pos); 89 pos += 2; 90 uint16_t iso_sdu_len = little_endian_read_16(packet, pos); 91 uint8_t packet_status_flag = packet[pos+1] >> 6; 92 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", 93 in ? "IN" : "OUT", conn_handle, pb, time_stamp, packet_sequence, packet_status_flag, iso_sdu_len); 94 } 95 96 static void hci_dump_windows_fs_log_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) { 97 if (dump_file < 0) return; 98 99 static union { 100 uint8_t header_bluez[HCI_DUMP_HEADER_SIZE_BLUEZ]; 101 uint8_t header_packetlogger[HCI_DUMP_HEADER_SIZE_PACKETLOGGER]; 102 uint8_t header_btsnoop[HCI_DUMP_HEADER_SIZE_BTSNOOP+1]; 103 } header; 104 105 uint32_t tv_sec = 0; 106 uint32_t tv_us = 0; 107 uint64_t ts_usec; 108 109 // get time 110 FILETIME file_time; 111 SYSTEMTIME local_time; 112 ULARGE_INTEGER now_time; 113 GetLocalTime(&local_time); 114 SystemTimeToFileTime(&local_time, &file_time); 115 now_time.LowPart = file_time.dwLowDateTime; 116 now_time.HighPart = file_time.dwHighDateTime; 117 118 tv_sec = (uint32_t) ((now_time.QuadPart / 10000000ULL) - EPOCH_DIFF); 119 tv_us = (now_time.QuadPart % 10000000ULL) / 10ULL; 120 121 uint16_t header_len = 0; 122 switch (dump_format){ 123 case HCI_DUMP_BLUEZ: 124 // ISO packets not supported 125 if (packet_type == HCI_ISO_DATA_PACKET){ 126 len = hci_dump_iso_summary(in, packet, len); 127 packet_type = LOG_MESSAGE_PACKET; 128 packet = (uint8_t*) log_message_buffer; 129 } 130 hci_dump_setup_header_bluez(header.header_bluez, tv_sec, tv_us, packet_type, in, len); 131 header_len = HCI_DUMP_HEADER_SIZE_BLUEZ; 132 break; 133 case HCI_DUMP_PACKETLOGGER: 134 hci_dump_setup_header_packetlogger(header.header_packetlogger, tv_sec, tv_us, packet_type, in, len); 135 header_len = HCI_DUMP_HEADER_SIZE_PACKETLOGGER; 136 break; 137 case HCI_DUMP_BTSNOOP: 138 // log messages not supported 139 if (packet_type == LOG_MESSAGE_PACKET) return; 140 ts_usec = 0xdcddb30f2f8000LLU + 1000000LLU * tv_sec + tv_us; 141 // append packet type to pcap header 142 hci_dump_setup_header_btsnoop(header.header_btsnoop, ts_usec >> 32, ts_usec & 0xFFFFFFFF, 0, packet_type, in, len+1); 143 header.header_btsnoop[HCI_DUMP_HEADER_SIZE_BTSNOOP] = packet_type; 144 header_len = HCI_DUMP_HEADER_SIZE_BTSNOOP + 1; 145 break; 146 default: 147 btstack_unreachable(); 148 return; 149 } 150 151 DWORD dwBytesWritten = 0; 152 (void) WriteFile( 153 dump_file, // file handle 154 &header, // start of data to write 155 header_len, // number of bytes to write 156 &dwBytesWritten, // number of bytes that were written 157 NULL); // no overlapped structure 158 UNUSED(dwBytesWritten); 159 160 (void)WriteFile( 161 dump_file, // file handle 162 packet, // start of data to write 163 len, // number of bytes to write 164 &dwBytesWritten, // number of bytes that were written 165 NULL); // no overlapped structure 166 UNUSED(dwBytesWritten); 167 } 168 169 static void hci_dump_windows_fs_log_message(int log_level, const char * format, va_list argptr){ 170 UNUSED(log_level); 171 if (dump_file < 0) return; 172 int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr); 173 hci_dump_windows_fs_log_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len); 174 } 175 176 // returns system errno 177 int hci_dump_windows_fs_open(const char *filename, hci_dump_format_t format){ 178 btstack_assert(format == HCI_DUMP_BLUEZ || format == HCI_DUMP_PACKETLOGGER || format == HCI_DUMP_BTSNOOP); 179 180 dump_format = format; 181 182 dump_file = CreateFile(filename, // name of the write 183 GENERIC_WRITE, // open for writing 184 FILE_SHARE_READ, // readable while still writing 185 NULL, // default security 186 CREATE_ALWAYS, // create new file always 187 FILE_ATTRIBUTE_NORMAL, // normal file 188 NULL); // no attr. template 189 190 if (dump_file == INVALID_HANDLE_VALUE){ 191 printf("failed to open file %s, error code = 0x%lx\n", filename, GetLastError()); 192 return -1; 193 } 194 195 if (format == HCI_DUMP_BTSNOOP){ 196 // write BTSnoop file header 197 const uint8_t file_header[] = { 198 // Identification Pattern: "btsnoop\0" 199 0x62, 0x74, 0x73, 0x6E, 0x6F, 0x6F, 0x70, 0x00, 200 // Version: 1 201 0x00, 0x00, 0x00, 0x01, 202 // Datalink Type: 1002 - H4 203 0x00, 0x00, 0x03, 0xEA, 204 }; 205 206 DWORD dwBytesWritten = 0; 207 (void) WriteFile( 208 dump_file, // file handle 209 file_header, // start of data to write 210 sizeof(file_header), // number of bytes to write 211 &dwBytesWritten, // number of bytes that were written 212 NULL); // no overlapped structure 213 UNUSED(dwBytesWritten); 214 } 215 return 0; 216 } 217 218 void hci_dump_windows_fs_close(void){ 219 CloseHandle(dump_file); 220 dump_file = INVALID_HANDLE_VALUE; 221 } 222 223 const hci_dump_t * hci_dump_windows_fs_get_instance(void){ 224 static const hci_dump_t hci_dump_instance = { 225 // void (*reset)(void); 226 &hci_dump_windows_fs_reset, 227 // void (*log_packet)(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len); 228 &hci_dump_windows_fs_log_packet, 229 // void (*log_message)(int log_level, const char * format, va_list argptr); 230 &hci_dump_windows_fs_log_message, 231 }; 232 return &hci_dump_instance; 233 } 234