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 / 10000000ULL) - EPOCH_DIFF); 118 tv_us = (now_time.QuadPart % 10000000ULL) / 10ULL; 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 hci_dump_setup_header_packetlogger(header.header_packetlogger, tv_sec, tv_us, packet_type, in, len); 134 header_len = HCI_DUMP_HEADER_SIZE_PACKETLOGGER; 135 break; 136 case HCI_DUMP_BTSNOOP: 137 // log messages not supported 138 if (packet_type == LOG_MESSAGE_PACKET) return; 139 ts_usec = 0xdcddb30f2f8000LLU + 1000000LLU * tv_sec + tv_us; 140 // append packet type to pcap header 141 hci_dump_setup_header_btsnoop(header.header_btsnoop, ts_usec >> 32, ts_usec & 0xFFFFFFFF, 0, packet_type, in, len+1); 142 header.header_btsnoop[HCI_DUMP_HEADER_SIZE_BTSNOOP] = packet_type; 143 header_len = HCI_DUMP_HEADER_SIZE_BTSNOOP + 1; 144 break; 145 default: 146 btstack_unreachable(); 147 return; 148 } 149 150 DWORD dwBytesWritten = 0; 151 (void) WriteFile( 152 dump_file, // file handle 153 &header, // start of data to write 154 header_len, // number of bytes to write 155 &dwBytesWritten, // number of bytes that were written 156 NULL); // no overlapped structure 157 UNUSED(dwBytesWritten); 158 159 (void)WriteFile( 160 dump_file, // file handle 161 packet, // start of data to write 162 len, // number of bytes to write 163 &dwBytesWritten, // number of bytes that were written 164 NULL); // no overlapped structure 165 UNUSED(dwBytesWritten); 166 } 167 168 static void hci_dump_windows_fs_log_message(int log_level, const char * format, va_list argptr){ 169 UNUSED(log_level); 170 if (dump_file < 0) return; 171 int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr); 172 hci_dump_windows_fs_log_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len); 173 } 174 175 // returns system errno 176 int hci_dump_windows_fs_open(const char *filename, hci_dump_format_t format){ 177 btstack_assert(format == HCI_DUMP_BLUEZ || format == HCI_DUMP_PACKETLOGGER || format == HCI_DUMP_BTSNOOP); 178 179 dump_format = format; 180 181 dump_file = CreateFile(filename, // name of the write 182 GENERIC_WRITE, // open for writing 183 0, // do not share 184 NULL, // default security 185 CREATE_ALWAYS, // create new file always 186 FILE_ATTRIBUTE_NORMAL, // normal file 187 NULL); // no attr. template 188 189 if (dump_file == INVALID_HANDLE_VALUE){ 190 printf("failed to open file %s, error code = 0x%lx\n", filename, GetLastError()); 191 return -1; 192 } 193 194 if (format == HCI_DUMP_BTSNOOP){ 195 // write BTSnoop file header 196 const uint8_t file_header[] = { 197 // Identification Pattern: "btsnoop\0" 198 0x62, 0x74, 0x73, 0x6E, 0x6F, 0x6F, 0x70, 0x00, 199 // Version: 1 200 0x00, 0x00, 0x00, 0x01, 201 // Datalink Type: 1002 - H4 202 0x00, 0x00, 0x03, 0xEA, 203 }; 204 205 DWORD dwBytesWritten = 0; 206 (void) WriteFile( 207 dump_file, // file handle 208 file_header, // start of data to write 209 sizeof(file_header), // number of bytes to write 210 &dwBytesWritten, // number of bytes that were written 211 NULL); // no overlapped structure 212 UNUSED(dwBytesWritten); 213 } 214 return 0; 215 } 216 217 void hci_dump_windows_fs_close(void){ 218 CloseHandle(dump_file); 219 dump_file = INVALID_HANDLE_VALUE; 220 } 221 222 const hci_dump_t * hci_dump_windows_fs_get_instance(void){ 223 static const hci_dump_t hci_dump_instance = { 224 // void (*reset)(void); 225 &hci_dump_windows_fs_reset, 226 // void (*log_packet)(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len); 227 &hci_dump_windows_fs_log_packet, 228 // void (*log_message)(int log_level, const char * format, va_list argptr); 229 &hci_dump_windows_fs_log_message, 230 }; 231 return &hci_dump_instance; 232 } 233