hcidump.c revision 174f39016a9aa77cda60ee578f535c8c026ef787
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 "parser.h" 45#include "hcidump.h" 46 47/* Default options */ 48int snap_len = SNAP_LEN; 49int mode = DUMP; 50 51void usage(void) 52{ 53 printf("HCIDump - HCI packet analyzer ver %s\n", VERSION); 54 printf("Usage:\n"); 55 printf("\thcidump <-i hciX> [-ah] [-w file] [-r file]\n"); 56} 57 58void process_frames(int dev, int sock, int file) 59{ 60 char *buf, *data, *ctrl; 61 struct cmsghdr *cmsg; 62 struct msghdr msg; 63 struct iovec iv; 64 struct dump_hdr *dh; 65 int len, in; 66 67 if (snap_len < SNAP_LEN) 68 snap_len = SNAP_LEN; 69 70 if (!(buf = malloc(snap_len + DUMP_HDR_SIZE))) { 71 perror("Can't allocate data buffer"); 72 exit(1); 73 } 74 dh = (void *) buf; 75 data = buf + DUMP_HDR_SIZE; 76 77 if (!(ctrl = malloc(100))) { 78 perror("Can't allocate control buffer"); 79 exit(1); 80 } 81 82 printf("device: hci%d snap_len: %d filter: none\n", dev, snap_len); 83 84 while (1) { 85 iv.iov_base = data; 86 iv.iov_len = snap_len; 87 88 msg.msg_iov = &iv; 89 msg.msg_iovlen = 1; 90 msg.msg_control = ctrl; 91 msg.msg_controllen = 100; 92 93 if ((len = recvmsg(sock, &msg, 0)) < 0) { 94 perror("Receive failed"); 95 exit(1); 96 } 97 98 /* Process control message */ 99 in = 0; 100 cmsg = CMSG_FIRSTHDR(&msg); 101 while (cmsg) { 102 switch (cmsg->cmsg_type) { 103 case HCI_CMSG_DIR: 104 in = *((int *)CMSG_DATA(cmsg)); 105 break; 106 } 107 cmsg = CMSG_NXTHDR(&msg, cmsg); 108 } 109 110 if (file == -1) { 111 /* Parse and print */ 112 struct frame frm; 113 114 frm.data = frm.ptr = data; 115 frm.data_len = frm.len = len; 116 frm.in = in; 117 frm.flags = 0; 118 119 parse(&frm); 120 } else { 121 /* Save dump */ 122 dh->len = __cpu_to_le16(len); 123 dh->in = in; 124 if (write_n(file, data, len + DUMP_HDR_SIZE) < 0) { 125 perror("Write error"); 126 exit(1); 127 } 128 } 129 } 130} 131 132void read_dump(int file) 133{ 134 struct dump_hdr dh; 135 char *data; 136 int err; 137 138 if (!(data = malloc(HCI_MAX_FRAME_SIZE))) { 139 perror("Can't allocate data buffer"); 140 exit(1); 141 } 142 143 while (1) { 144 struct frame frm; 145 int len; 146 147 if ((err = read_n(file, (void *) &dh, DUMP_HDR_SIZE)) < 0) 148 goto failed; 149 if (!err) return; 150 151 len = __le16_to_cpu(dh.len); 152 153 if ((err = read_n(file, data, len)) < 0) 154 goto failed; 155 if (!err) return; 156 157 frm.data = frm.ptr = data; 158 frm.data_len = frm.len = len; 159 frm.in = dh.in; 160 frm.flags = 0; 161 162 parse(&frm); 163 } 164 165failed: 166 perror("Read failed"); 167 exit(1); 168} 169 170int open_file(char *file, int mode) 171{ 172 int f, flags; 173 174 if (mode == WRITE) 175 flags = O_WRONLY | O_CREAT | O_APPEND; 176 else 177 flags = O_RDONLY; 178 179 if ((f = open(file, flags)) < 0) { 180 perror("Can't open output file"); 181 exit(1); 182 } 183 return f; 184} 185 186int open_socket(int dev) 187{ 188 struct sockaddr_hci addr; 189 struct hci_filter flt; 190 int s, opt; 191 192 /* Create HCI socket */ 193 if ((s=socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) { 194 perror("Can't create HCI socket"); 195 exit(1); 196 } 197 198 opt = 1; 199 if (setsockopt(s, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { 200 perror("Can't enable data direction info"); 201 exit(1); 202 } 203 204 /* Setup filter */ 205 flt.type_mask = ~0; // All packet types 206 flt.event_mask[0] = ~0L; // All events 207 flt.event_mask[1] = ~0L; 208 if (setsockopt(s, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { 209 perror("Can't set HCI filter"); 210 exit(1); 211 } 212 213 /* Bind socket to the HCI device */ 214 addr.hci_family = AF_BLUETOOTH; 215 addr.hci_dev = dev; 216 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 217 printf("Can't attach to device hci%d. %s(%d)\n", 218 dev, strerror(errno), errno); 219 exit(1); 220 } 221 return s; 222} 223 224int main(int argc, char *argv[]) 225{ 226 extern int optind, opterr, optopt; 227 extern char *optarg; 228 int dev, opt; 229 long flags; 230 char *file = NULL; 231 232 dev = 0; 233 flags = 0; 234 235 while ((opt=getopt(argc, argv,"i:s:haw:r:")) != EOF) { 236 switch(opt) { 237 case 'i': 238 dev = atoi(optarg+3); 239 break; 240 241 case 'h': 242 flags |= DUMP_HEX; 243 break; 244 245 case 'a': 246 flags |= DUMP_ASCII; 247 break; 248 249 case 's': 250 snap_len = atoi(optarg); 251 break; 252 253 case 'w': 254 mode = WRITE; 255 file = strdup(optarg); 256 break; 257 258 case 'r': 259 mode = READ; 260 file = strdup(optarg); 261 break; 262 263 default: 264 usage(); 265 exit(1); 266 } 267 } 268 269 printf("HCIDump - HCI packet analyzer ver %s.\n", VERSION); 270 271 switch (mode) { 272 case DUMP: 273 init_parser(flags); 274 process_frames(dev, open_socket(dev), -1); 275 break; 276 277 case WRITE: 278 process_frames(dev, open_socket(dev), open_file(file, mode)); 279 break; 280 281 case READ: 282 init_parser(flags); 283 read_dump(open_file(file, mode)); 284 break; 285 } 286 return 0; 287} 288