hcidump.c revision dda78ee2b52b86b6008d109db63253fc955304e7
1/* 2 HCIDump - HCI packet analyzer 3 Copyright (C) 2000-2001 Maxim Krasnyansky <maxk@qualcomm.com> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License version 2 as 7 published by the Free Software Foundation; 8 9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, 13 OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER 14 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 15 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 16 USE OR PERFORMANCE OF THIS SOFTWARE. 17 18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, 19 TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. 20*/ 21 22/* 23 * $Id$ 24 */ 25 26#include <stdio.h> 27#include <stdlib.h> 28#include <unistd.h> 29#include <termios.h> 30#include <fcntl.h> 31#include <sys/ioctl.h> 32#include <sys/socket.h> 33#include <sys/types.h> 34#include <sys/uio.h> 35#include <errno.h> 36#include <string.h> 37 38#include <asm/types.h> 39 40#include <bluetooth/bluetooth.h> 41#include <bluetooth/hci.h> 42#include <bluetooth/l2cap.h> 43 44#include <pwd.h> 45#include <argp.h> 46 47#include "parser.h" 48#include "hcidump.h" 49 50/* Default options */ 51static int device; 52static int snap_len = SNAP_LEN; 53static int mode = PARSE; 54static long flags; 55static char *dump_file; 56 57static void process_frames(int dev, int sock, int file) 58{ 59 struct cmsghdr *cmsg; 60 struct msghdr msg; 61 struct iovec iv; 62 struct dump_hdr *dh; 63 struct frame frm; 64 char *buf, *ctrl; 65 66 if (snap_len < SNAP_LEN) 67 snap_len = SNAP_LEN; 68 69 if (!(buf = malloc(snap_len + DUMP_HDR_SIZE))) { 70 perror("Can't allocate data buffer"); 71 exit(1); 72 } 73 dh = (void *) buf; 74 frm.data = buf + DUMP_HDR_SIZE; 75 76 if (!(ctrl = malloc(100))) { 77 perror("Can't allocate control buffer"); 78 exit(1); 79 } 80 81 printf("device: hci%d snap_len: %d filter: none\n", dev, snap_len); 82 83 while (1) { 84 iv.iov_base = frm.data; 85 iv.iov_len = snap_len; 86 87 msg.msg_iov = &iv; 88 msg.msg_iovlen = 1; 89 msg.msg_control = ctrl; 90 msg.msg_controllen = 100; 91 92 if ((frm.data_len = recvmsg(sock, &msg, 0)) < 0) { 93 perror("Receive failed"); 94 exit(1); 95 } 96 97 /* Process control message */ 98 frm.in = 0; 99 cmsg = CMSG_FIRSTHDR(&msg); 100 while (cmsg) { 101 switch (cmsg->cmsg_type) { 102 case HCI_CMSG_DIR: 103 frm.in = *((int *)CMSG_DATA(cmsg)); 104 break; 105 } 106 cmsg = CMSG_NXTHDR(&msg, cmsg); 107 } 108 109 frm.ptr = frm.data; 110 frm.len = frm.data_len; 111 112 switch (mode) { 113 case RAW: 114 /* Print raw dump */ 115 printf("%c ", (frm.in ? '>' : '<')); 116 raw_dump(0, &frm); 117 fflush(stdout); 118 break; 119 120 case WRITE: 121 /* Save dump */ 122 dh->len = __cpu_to_le16(frm.data_len); 123 dh->in = frm.in; 124 if (write_n(file, buf, frm.data_len + DUMP_HDR_SIZE) < 0) { 125 perror("Write error"); 126 exit(1); 127 } 128 break; 129 130 default: 131 /* Parse and print */ 132 parse(&frm); 133 break; 134 } 135 } 136} 137 138static void read_dump(int file) 139{ 140 struct dump_hdr dh; 141 struct frame frm; 142 int err; 143 144 if (!(frm.data = malloc(HCI_MAX_FRAME_SIZE))) { 145 perror("Can't allocate data buffer"); 146 exit(1); 147 } 148 149 while (1) { 150 if ((err = read_n(file, (void *) &dh, DUMP_HDR_SIZE)) < 0) 151 goto failed; 152 if (!err) return; 153 154 frm.data_len = __le16_to_cpu(dh.len); 155 156 if ((err = read_n(file, frm.data, frm.data_len)) < 0) 157 goto failed; 158 if (!err) return; 159 160 frm.ptr = frm.data; 161 frm.len = frm.data_len; 162 frm.in = dh.in; 163 164 parse(&frm); 165 } 166 167failed: 168 perror("Read failed"); 169 exit(1); 170} 171 172static int open_file(char *file, int mode) 173{ 174 int f, flags; 175 176 if (mode == WRITE) 177 flags = O_WRONLY | O_CREAT | O_APPEND; 178 else 179 flags = O_RDONLY; 180 181 if ((f = open(file, flags)) < 0) { 182 perror("Can't open output file"); 183 exit(1); 184 } 185 return f; 186} 187 188static int open_socket(int dev) 189{ 190 struct sockaddr_hci addr; 191 struct hci_filter flt; 192 int s, opt; 193 194 /* Create HCI socket */ 195 if ((s=socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) { 196 perror("Can't create HCI socket"); 197 exit(1); 198 } 199 200 opt = 1; 201 if (setsockopt(s, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { 202 perror("Can't enable data direction info"); 203 exit(1); 204 } 205 206 /* Setup filter */ 207 flt.type_mask = ~0; // All packet types 208 flt.event_mask[0] = ~0L; // All events 209 flt.event_mask[1] = ~0L; 210 if (setsockopt(s, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { 211 perror("Can't set HCI filter"); 212 exit(1); 213 } 214 215 /* Bind socket to the HCI device */ 216 addr.hci_family = AF_BLUETOOTH; 217 addr.hci_dev = dev; 218 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 219 printf("Can't attach to device hci%d. %s(%d)\n", 220 dev, strerror(errno), errno); 221 exit(1); 222 } 223 return s; 224} 225 226const char *argp_program_version = "HCIDump "VERSION; 227const char *argp_program_bug_address = "<bluez-users@lists.sf.net>"; 228 229static struct argp_option options[] = { 230 {"device", 'i', "hci_dev", 0, "HCI device", 0 }, 231 {"snap-len", 's', "len", 0, "Snap len (in bytes)", 1 }, 232 {"save-dump", 'w', "file", 0, "Save dump to a file", 2 }, 233 {"read-dump", 'r', "file", 0, "Read dump from a file", 2 }, 234 {"hex", 'h', 0, 0, "Dump data in hex", 3 }, 235 {"ascii", 'a', 0, 0, "Dump data in ascii", 3 }, 236 {"raw", 'R', 0, 0, "Raw mode", 3 }, 237 { 0 } 238}; 239 240static error_t parse_opt(int key, char *arg, struct argp_state *state) 241{ 242 switch (key) { 243 case 'i': 244 device = atoi(arg+3); 245 break; 246 247 case 'h': 248 flags |= DUMP_HEX; 249 break; 250 251 case 'a': 252 flags |= DUMP_ASCII; 253 break; 254 255 case 's': 256 snap_len = atoi(arg); 257 break; 258 259 case 'R': 260 flags |= DUMP_HEX; 261 mode = RAW; 262 break; 263 264 case 'r': 265 mode = READ; 266 dump_file = strdup(arg); 267 break; 268 269 case 'w': 270 mode = WRITE; 271 dump_file = strdup(arg); 272 break; 273 274 default: 275 return ARGP_ERR_UNKNOWN; 276 } 277 return 0; 278} 279 280static struct argp parser = { 281 options, 282 parse_opt, 283 "", 284 "HCIDump - HCI packet analyzer ver " VERSION 285}; 286 287int main(int argc, char *argv[]) 288{ 289 argp_parse(&parser, argc, argv, 0, NULL, NULL); 290 291 printf("HCIDump - HCI packet analyzer ver %s.\n", VERSION); 292 293 switch (mode) { 294 case RAW: 295 case PARSE: 296 init_parser(flags); 297 process_frames(device, open_socket(device), -1); 298 break; 299 300 case WRITE: 301 process_frames(device, open_socket(device), open_file(dump_file, mode)); 302 break; 303 304 case READ: 305 init_parser(flags); 306 read_dump(open_file(dump_file, mode)); 307 break; 308 } 309 return 0; 310} 311