1 /* 2 * hci_dump.c 3 * 4 * Dump HCI trace in BlueZ's hcidump format 5 * 6 * Created by Matthias Ringwald on 5/26/09. 7 */ 8 9 #include "hci_dump.h" 10 #include "hci.h" 11 #include "hci_transport_h4.h" 12 13 #include <fcntl.h> // open 14 #include <arpa/inet.h> // hton.. 15 #include <strings.h> // bzero 16 #include <unistd.h> // write 17 #include <stdio.h> 18 #include <time.h> 19 #include <sys/time.h> // for timestamps 20 #include <sys/stat.h> // for mode flags 21 22 // BLUEZ hcidump 23 typedef struct { 24 uint16_t len; 25 uint8_t in; 26 uint8_t pad; 27 uint32_t ts_sec; 28 uint32_t ts_usec; 29 uint8_t packet_type; 30 } __attribute__ ((packed)) hcidump_hdr; 31 32 // APPLE PacketLogger 33 typedef struct { 34 uint32_t len; 35 uint32_t ts_sec; 36 uint32_t ts_usec; 37 uint8_t type; 38 } __attribute__ ((packed)) pktlog_hdr; 39 40 static int dump_file = -1; 41 static int dump_format; 42 static hcidump_hdr header_bluez; 43 static pktlog_hdr header_packetlogger; 44 static char time_string[40]; 45 46 void hci_dump_open(char *filename, hci_dump_format_t format){ 47 dump_format = format; 48 if (dump_format == HCI_DUMP_STDOUT) { 49 dump_file = fileno(stdout); 50 } else { 51 dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 52 } 53 } 54 55 56 void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) { 57 if (dump_file < 0) return; // not activated yet 58 59 // get time 60 struct timeval curr_time; 61 struct tm* ptm; 62 gettimeofday(&curr_time, NULL); 63 64 switch (dump_format){ 65 case HCI_DUMP_STDOUT: 66 /* Obtain the time of day, and convert it to a tm struct. */ 67 ptm = localtime (&curr_time.tv_sec); 68 /* Format the date and time, down to a single second. */ 69 strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm); 70 /* Compute milliseconds from microseconds. */ 71 uint16_t milliseconds = curr_time.tv_usec / 1000; 72 /* Print the formatted time, in seconds, followed by a decimal point 73 and the milliseconds. */ 74 printf ("%s.%03u] ", time_string, milliseconds); 75 switch (packet_type){ 76 case HCI_COMMAND_DATA_PACKET: 77 printf("CMD => "); 78 break; 79 case HCI_EVENT_PACKET: 80 printf("EVT <= "); 81 break; 82 case HCI_ACL_DATA_PACKET: 83 if (in) { 84 printf("ACL <= "); 85 } else { 86 printf("ACL => "); 87 } 88 break; 89 } 90 hexdump(packet, len); 91 break; 92 case HCI_DUMP_BLUEZ: 93 bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len); 94 header_bluez.in = in; 95 header_bluez.pad = 0; 96 bt_store_32( (uint8_t *) &header_bluez.ts_sec, 0, curr_time.tv_sec); 97 bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec); 98 header_bluez.packet_type = packet_type; 99 write (dump_file, &header_bluez, sizeof(hcidump_hdr) ); 100 write (dump_file, packet, len ); 101 break; 102 case HCI_DUMP_PACKETLOGGER: 103 header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len); 104 header_packetlogger.ts_sec = htonl(curr_time.tv_sec); 105 header_packetlogger.ts_usec = htonl(curr_time.tv_usec); 106 switch (packet_type){ 107 case HCI_COMMAND_DATA_PACKET: 108 header_packetlogger.type = 0x00; 109 break; 110 case HCI_ACL_DATA_PACKET: 111 if (in) { 112 header_packetlogger.type = 0x03; 113 } else { 114 header_packetlogger.type = 0x02; 115 } 116 break; 117 case HCI_EVENT_PACKET: 118 header_packetlogger.type = 0x01; 119 break; 120 default: 121 return; 122 } 123 write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) ); 124 write (dump_file, packet, len ); 125 } 126 } 127 128 void hci_dump_close(){ 129 close(dump_file); 130 dump_file = -1; 131 } 132 133