diff --git a/tools/hcidump.1 b/tools/hcidump.1
index 457b51c..e7ce4c2 100644
--- a/tools/hcidump.1
+++ b/tools/hcidump.1
.BR -R ", " "\-\^\-raw"
For every packet, only the raw data is displayed.
.TP
-.BR -C ", " "\-\^\-cmtp"
+.BR -C ", " "\-\^\-cmtp=" "<psm>"
Sets the PSM value for the CAPI Message Transport Protocol.
.TP
-.BR -H ", " "\-\^\-hcrp"
+.BR -H ", " "\-\^\-hcrp=" "<psm>"
Sets the PSM value for the Hardcopy Control Channel.
.TP
-.BR -O ", " "\-\^\-obex"
+.BR -O ", " "\-\^\-obex=" "<channel>"
Sets the RFCOMM channel value for the Object Exchange protocol.
.TP
+.BR -A ", " "\-\^\-audio=" "<file>"
+Extract SCO audio data.
+.TP
.BR -B ", " "\-\^\-btsnoop"
Use the BTSnoop file format.
.TP
diff --git a/tools/hcidump.c b/tools/hcidump.c
index 9f7f866..bd2e073 100644
--- a/tools/hcidump.c
+++ b/tools/hcidump.c
READ,
WRITE,
RECEIVE,
- SEND
+ SEND,
+ AUDIO
};
/* Default options */
static int permcheck = 1;
static long flags;
static long filter;
-static char *dump_file;
+static char *dump_file = NULL;
+static char *audio_file = NULL;
static in_addr_t dump_addr = INADDR_LOOPBACK;
static in_port_t dump_port = DEFAULT_PORT;
frm.data_len = len;
frm.dev_id = dev;
frm.in = 0;
+ frm.audio_fd = parser.audio_fd;
cmsg = CMSG_FIRSTHDR(&msg);
while (cmsg) {
struct btsnoop_hdr hdr;
int fd, len, open_flags;
- if (mode == WRITE) {
+ if (mode == WRITE || mode == AUDIO) {
if (flags & DUMP_BTSNOOP)
open_flags = O_WRONLY | O_CREAT;
else
" -C, --cmtp=psm PSM for CMTP\n"
" -H, --hcrp=psm PSM for HCRP\n"
" -O, --obex=channel Channel for OBEX\n"
+ " -A, --audio=file Extract SCO audio data\n"
" -B, --btsnoop Use BTSnoop file format\n"
" -V, --verbose Verbose decoding\n"
" -h, --help Give this help list\n"
{ "cmtp", 1, 0, 'C' },
{ "hcrp", 1, 0, 'H' },
{ "obex", 1, 0, 'O' },
+ { "audio", 1, 0, 'A' },
{ "btsnoop", 0, 0, 'B' },
{ "verbose", 0, 0, 'V' },
{ "help", 0, 0, 'h' },
{
struct hostent *host;
struct in_addr addr;
- int opt;
+ int opt, fd = -1;
printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION);
- while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRC:H:O:BVZh", main_options, NULL)) != -1) {
+ while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRC:H:O:A:BVZh", main_options, NULL)) != -1) {
switch(opt) {
case 'i':
if (strcasecmp(optarg, "none") && strcasecmp(optarg, "system"))
set_proto(0, 0, atoi(optarg), SDP_UUID_OBEX);
break;
+ case 'A':
+ audio_file = strdup(optarg);
+ break;
+
case 'B':
flags |= DUMP_BTSNOOP;
break;
if (!filter)
filter = ~0L;
+ if (audio_file)
+ fd = open_file(audio_file, AUDIO, flags);
+
switch (mode) {
case PARSE:
- init_parser(flags, filter, defpsm, defcompid);
+ init_parser(flags, filter, defpsm, defcompid, fd);
process_frames(device, open_socket(device, flags), -1, flags);
break;
case READ:
- init_parser(flags, filter, defpsm, defcompid);
+ init_parser(flags, filter, defpsm, defcompid, fd);
read_dump(open_file(dump_file, mode, flags));
break;
break;
case RECEIVE:
- init_parser(flags, filter, defpsm, defcompid);
+ init_parser(flags, filter, defpsm, defcompid, fd);
read_dump(wait_connection(dump_addr, dump_port));
break;
diff --git a/tools/parser/hci.c b/tools/parser/hci.c
index ca44dff..a651930 100644
--- a/tools/parser/hci.c
+++ b/tools/parser/hci.c
hci_sco_hdr *hdr = (void *) frm->ptr;
uint16_t handle = btohs(hdr->handle);
+ if (frm->audio_fd > 2)
+ write(frm->audio_fd, frm->ptr + HCI_SCO_HDR_SIZE, hdr->dlen);
+
if (!p_filter(FILT_SCO)) {
p_indent(level, frm);
printf("SCO data: handle %d dlen %d\n",
diff --git a/tools/parser/l2cap.c b/tools/parser/l2cap.c
index 168ad6f..38adc59 100644
--- a/tools/parser/l2cap.c
+++ b/tools/parser/l2cap.c
fr->num = frm->num;
fr->dlci = frm->dlci;
fr->channel = frm->channel;
+ fr->audio_fd = frm->audio_fd;
} else {
if (!(fr = get_frame(frm->handle))) {
fprintf(stderr, "Not enough connection handles\n");
diff --git a/tools/parser/obex.c b/tools/parser/obex.c
index 9e5a509..2e5ee43 100644
--- a/tools/parser/obex.c
+++ b/tools/parser/obex.c
fr->num = frm->num;
fr->dlci = frm->dlci;
fr->channel = frm->channel;
+ fr->audio_fd = frm->audio_fd;
return fr;
}
diff --git a/tools/parser/parser.c b/tools/parser/parser.c
index fbbd045..34ae4e5 100644
--- a/tools/parser/parser.c
+++ b/tools/parser/parser.c
struct parser_t parser;
void init_parser(unsigned long flags, unsigned long filter,
- unsigned short defpsm, unsigned short defcompid)
+ unsigned short defpsm, unsigned short defcompid,
+ int audio_fd)
{
if ((flags & DUMP_RAW) && !(flags & DUMP_TYPE_MASK))
flags |= DUMP_HEX;
parser.defpsm = defpsm;
parser.defcompid = defcompid;
parser.state = 0;
+ parser.audio_fd = audio_fd;
}
#define PROTO_TABLE_SIZE 20
diff --git a/tools/parser/parser.h b/tools/parser/parser.h
index d515ddd..ffcc454 100644
--- a/tools/parser/parser.h
+++ b/tools/parser/parser.h
uint8_t channel;
unsigned long flags;
struct timeval ts;
+ int audio_fd;
};
/* Parser flags */
unsigned short defpsm;
unsigned short defcompid;
int state;
+ int audio_fd;
};
extern struct parser_t parser;
void init_parser(unsigned long flags, unsigned long filter,
- unsigned short defpsm, unsigned short defcompid);
+ unsigned short defpsm, unsigned short defcompid,
+ int audio_fd);
static inline int p_filter(unsigned long f)
{
diff --git a/tools/parser/sdp.c b/tools/parser/sdp.c
index 7a360a8..e5a750a 100644
--- a/tools/parser/sdp.c
+++ b/tools/parser/sdp.c
fr->cid = frm->cid;
fr->num = frm->num;
fr->channel = frm->channel;
+ fr->audio_fd = frm->audio_fd;
return pos;
}