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