First Commit

This commit is contained in:
leeboby
2020-10-30 09:50:39 +08:00
commit e5f9bb65ac
845 changed files with 177861 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,423 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include "btsnoop.h"
struct btsnoop_hdr {
uint8_t id[8]; /* Identification Pattern */
uint32_t version; /* Version Number = 1 */
uint32_t type; /* Datalink Type */
} __attribute__ ((packed));
#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
struct btsnoop_pkt {
uint32_t size; /* Original Length */
uint32_t len; /* Included Length */
uint32_t flags; /* Packet Flags */
uint32_t drops; /* Cumulative Drops */
uint64_t ts; /* Timestamp microseconds */
uint8_t data[0]; /* Packet Data */
} __attribute__ ((packed));
#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
static const uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e,
0x6f, 0x6f, 0x70, 0x00 };
static const uint32_t btsnoop_version = 1;
static uint32_t btsnoop_type = 0;
static int btsnoop_fd = -1;
static uint16_t btsnoop_index = 0xffff;
void btsnoop_create(const char *path, uint32_t type)
{
struct btsnoop_hdr hdr;
ssize_t written;
if (btsnoop_fd >= 0)
return;
btsnoop_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (btsnoop_fd < 0)
return;
btsnoop_type = type;
memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
hdr.version = htonl(btsnoop_version);
hdr.type = htonl(btsnoop_type);
written = write(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
if (written < 0) {
close(btsnoop_fd);
btsnoop_fd = -1;
return;
}
}
void btsnoop_write(struct timeval *tv, uint32_t flags,
const void *data, uint16_t size)
{
struct btsnoop_pkt pkt;
uint64_t ts;
ssize_t written;
ts = (tv->tv_sec - 946684800ll) * 1000000ll + tv->tv_usec;
pkt.size = htonl(size);
pkt.len = htonl(size);
pkt.flags = htonl(flags);
pkt.drops = htonl(0);
pkt.ts = hton64(ts + 0x00E03AB44A676000ll);
written = write(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
if (written < 0)
return;
if (data && size > 0) {
written = write(btsnoop_fd, data, size);
if (written < 0)
return;
}
}
static uint32_t get_flags_from_opcode(uint16_t opcode)
{
switch (opcode) {
case BTSNOOP_OPCODE_NEW_INDEX:
case BTSNOOP_OPCODE_DEL_INDEX:
break;
case BTSNOOP_OPCODE_COMMAND_PKT:
return 0x02;
case BTSNOOP_OPCODE_EVENT_PKT:
return 0x03;
case BTSNOOP_OPCODE_ACL_TX_PKT:
return 0x00;
case BTSNOOP_OPCODE_ACL_RX_PKT:
return 0x01;
case BTSNOOP_OPCODE_SCO_TX_PKT:
case BTSNOOP_OPCODE_SCO_RX_PKT:
break;
}
return 0xff;
}
void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size)
{
uint32_t flags;
if (!tv)
return;
if (btsnoop_fd < 0)
return;
switch (btsnoop_type) {
case BTSNOOP_TYPE_HCI:
if (btsnoop_index == 0xffff)
btsnoop_index = index;
if (index != btsnoop_index)
return;
flags = get_flags_from_opcode(opcode);
if (flags == 0xff)
return;
break;
case BTSNOOP_TYPE_EXTENDED_HCI:
flags = (index << 16) | opcode;
break;
default:
return;
}
btsnoop_write(tv, flags, data, size);
}
void btsnoop_write_phy(struct timeval *tv, uint16_t frequency,
const void *data, uint16_t size)
{
uint32_t flags;
if (!tv)
return;
if (btsnoop_fd < 0)
return;
switch (btsnoop_type) {
case BTSNOOP_TYPE_EXTENDED_PHY:
flags = (1 << 16) | frequency;
break;
default:
return;
}
btsnoop_write(tv, flags, data, size);
}
int btsnoop_open(const char *path, uint32_t *type)
{
struct btsnoop_hdr hdr;
ssize_t len;
if (btsnoop_fd >= 0) {
fprintf(stderr, "Too many open files\n");
return -1;
}
btsnoop_fd = open(path, O_RDONLY | O_CLOEXEC);
if (btsnoop_fd < 0) {
perror("Failed to open file");
return -1;
}
len = read(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
if (len < 0 || len != BTSNOOP_HDR_SIZE) {
perror("Failed to read header");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
if (memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) {
fprintf(stderr, "Invalid btsnoop header\n");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
if (ntohl(hdr.version) != btsnoop_version) {
fprintf(stderr, "Invalid btsnoop version\n");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
btsnoop_type = ntohl(hdr.type);
if (type)
*type = btsnoop_type;
return 0;
}
static uint16_t get_opcode_from_flags(uint8_t type, uint32_t flags)
{
switch (type) {
case HCI_COMMAND_PKT:
return BTSNOOP_OPCODE_COMMAND_PKT;
case HCI_ACLDATA_PKT:
if (flags & 0x01)
return BTSNOOP_OPCODE_ACL_RX_PKT;
else
return BTSNOOP_OPCODE_ACL_TX_PKT;
case HCI_SCODATA_PKT:
if (flags & 0x01)
return BTSNOOP_OPCODE_SCO_RX_PKT;
else
return BTSNOOP_OPCODE_SCO_TX_PKT;
case HCI_EVENT_PKT:
return BTSNOOP_OPCODE_EVENT_PKT;
case 0xff:
if (flags & 0x02) {
if (flags & 0x01)
return BTSNOOP_OPCODE_EVENT_PKT;
else
return BTSNOOP_OPCODE_COMMAND_PKT;
} else {
if (flags & 0x01)
return BTSNOOP_OPCODE_ACL_RX_PKT;
else
return BTSNOOP_OPCODE_ACL_TX_PKT;
}
break;
}
return 0xff;
}
int btsnoop_read_hci(struct timeval *tv, uint16_t *index, uint16_t *opcode,
void *data, uint16_t *size)
{
struct btsnoop_pkt pkt;
uint32_t toread, flags;
uint64_t ts;
uint8_t pkt_type;
ssize_t len;
if (btsnoop_fd < 0)
return -1;
len = read(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
if (len == 0)
return -1;
if (len < 0 || len != BTSNOOP_PKT_SIZE) {
perror("Failed to read packet");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
toread = ntohl(pkt.size);
flags = ntohl(pkt.flags);
ts = ntoh64(pkt.ts) - 0x00E03AB44A676000ll;
tv->tv_sec = (ts / 1000000ll) + 946684800ll;
tv->tv_usec = ts % 1000000ll;
switch (btsnoop_type) {
case BTSNOOP_TYPE_HCI:
*index = 0;
*opcode = get_opcode_from_flags(0xff, flags);
break;
case BTSNOOP_TYPE_UART:
len = read(btsnoop_fd, &pkt_type, 1);
if (len < 0) {
perror("Failed to read packet type");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
toread--;
*index = 0;
*opcode = get_opcode_from_flags(pkt_type, flags);
break;
case BTSNOOP_TYPE_EXTENDED_HCI:
*index = flags >> 16;
*opcode = flags & 0xffff;
break;
default:
fprintf(stderr, "Unknown packet type\n");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
len = read(btsnoop_fd, data, toread);
if (len < 0) {
perror("Failed to read data");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
*size = toread;
return 0;
}
int btsnoop_read_phy(struct timeval *tv, uint16_t *frequency,
void *data, uint16_t *size)
{
struct btsnoop_pkt pkt;
uint32_t toread, flags;
uint64_t ts;
ssize_t len;
if (btsnoop_fd < 0)
return -1;
len = read(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
if (len == 0)
return -1;
if (len < 0 || len != BTSNOOP_PKT_SIZE) {
perror("Failed to read packet");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
toread = ntohl(pkt.size);
flags = ntohl(pkt.flags);
ts = ntoh64(pkt.ts) - 0x00E03AB44A676000ll;
tv->tv_sec = (ts / 1000000ll) + 946684800ll;
tv->tv_usec = ts % 1000000ll;
switch (btsnoop_type) {
case BTSNOOP_TYPE_EXTENDED_PHY:
if ((flags >> 16) != 1)
break;
*frequency = flags & 0xffff;
break;
default:
fprintf(stderr, "Unknown packet type\n");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
len = read(btsnoop_fd, data, toread);
if (len < 0) {
perror("Failed to read data");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
*size = toread;
return 0;
}
void btsnoop_close(void)
{
if (btsnoop_fd < 0)
return;
close(btsnoop_fd);
btsnoop_fd = -1;
btsnoop_index = 0xffff;
}

View File

@@ -0,0 +1,57 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
#include <sys/time.h>
#define BTSNOOP_TYPE_HCI 1001
#define BTSNOOP_TYPE_UART 1002
#define BTSNOOP_TYPE_BCSP 1003
#define BTSNOOP_TYPE_3WIRE 1004
#define BTSNOOP_TYPE_EXTENDED_HCI 2001
#define BTSNOOP_TYPE_EXTENDED_PHY 2002
#define BTSNOOP_OPCODE_NEW_INDEX 0
#define BTSNOOP_OPCODE_DEL_INDEX 1
#define BTSNOOP_OPCODE_COMMAND_PKT 2
#define BTSNOOP_OPCODE_EVENT_PKT 3
#define BTSNOOP_OPCODE_ACL_TX_PKT 4
#define BTSNOOP_OPCODE_ACL_RX_PKT 5
#define BTSNOOP_OPCODE_SCO_TX_PKT 6
#define BTSNOOP_OPCODE_SCO_RX_PKT 7
void btsnoop_create(const char *path, uint32_t type);
void btsnoop_write(struct timeval *tv, uint32_t flags,
const void *data, uint16_t size);
void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size);
void btsnoop_write_phy(struct timeval *tv, uint16_t frequency,
const void *data, uint16_t size);
int btsnoop_open(const char *path, uint32_t *type);
int btsnoop_read_hci(struct timeval *tv, uint16_t *index, uint16_t *opcode,
void *data, uint16_t *size);
int btsnoop_read_phy(struct timeval *tv, uint16_t *frequency,
void *data, uint16_t *size);
void btsnoop_close(void);

View File

@@ -0,0 +1,891 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <lib/bluetooth/bluetooth.h>
#include <lib/bluetooth/hci.h>
#include <lib/mgmt.h>
#include "mainloop.h"
#include "display.h"
#include "packet.h"
#include "btsnoop.h"
#include "hcidump.h"
#include "control.h"
static bool hcidump_fallback = false;
#define MAX_PACKET_SIZE (1486 + 4)
struct control_data {
uint16_t channel;
int fd;
unsigned char buf[MAX_PACKET_SIZE];
uint16_t offset;
};
static void free_data(void *user_data)
{
struct control_data *data = user_data;
close(data->fd);
free(data);
}
static void mgmt_index_added(uint16_t len, const void *buf)
{
printf("@ Index Added\n");
packet_hexdump(buf, len);
}
static void mgmt_index_removed(uint16_t len, const void *buf)
{
printf("@ Index Removed\n");
packet_hexdump(buf, len);
}
static void mgmt_controller_error(uint16_t len, const void *buf)
{
const struct mgmt_ev_controller_error *ev = buf;
if (len < sizeof(*ev)) {
printf("* Malformed Controller Error control\n");
return;
}
printf("@ Controller Error: 0x%2.2x\n", ev->error_code);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
#ifndef NELEM
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
#endif
static const char *settings_str[] = {
"powered", "connectable", "fast-connectable", "discoverable",
"pairable", "link-security", "ssp", "br/edr", "hs", "le",
"advertising",
};
static void mgmt_new_settings(uint16_t len, const void *buf)
{
uint32_t settings;
unsigned int i;
if (len < 4) {
printf("* Malformed New Settings control\n");
return;
}
settings = bt_get_le32(buf);
printf("@ New Settings: 0x%4.4x\n", settings);
printf("%-12c", ' ');
for (i = 0; i < NELEM(settings_str); i++) {
if (settings & (1 << i))
printf("%s ", settings_str[i]);
}
printf("\n");
buf += 4;
len -= 4;
packet_hexdump(buf, len);
}
static void mgmt_class_of_dev_changed(uint16_t len, const void *buf)
{
const struct mgmt_ev_class_of_dev_changed *ev = buf;
if (len < sizeof(*ev)) {
printf("* Malformed Class of Device Changed control\n");
return;
}
printf("@ Class of Device Changed: 0x%2.2x%2.2x%2.2x\n",
ev->class_of_dev[2],
ev->class_of_dev[1],
ev->class_of_dev[0]);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_local_name_changed(uint16_t len, const void *buf)
{
const struct mgmt_ev_local_name_changed *ev = buf;
if (len < sizeof(*ev)) {
printf("* Malformed Local Name Changed control\n");
return;
}
printf("@ Local Name Changed: %s (%s)\n", ev->name, ev->short_name);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_new_link_key(uint16_t len, const void *buf)
{
const struct mgmt_ev_new_link_key *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed New Link Key control\n");
return;
}
ba2str(&ev->key.addr.bdaddr, str);
printf("@ New Link Key: %s (%d)\n", str, ev->key.addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_new_long_term_key(uint16_t len, const void *buf)
{
const struct mgmt_ev_new_long_term_key *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed New Long Term Key control\n");
return;
}
ba2str(&ev->key.addr.bdaddr, str);
printf("@ New Long Term Key: %s (%d)\n", str, ev->key.addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_connected(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_connected *ev = buf;
uint32_t flags;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Connected control\n");
return;
}
flags = btohl(ev->flags);
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Connected: %s (%d) flags 0x%4.4x\n",
str, ev->addr.type, flags);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_disconnected(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_disconnected *ev = buf;
char str[18];
uint8_t reason;
uint16_t consumed_len;
if (len < sizeof(struct mgmt_addr_info)) {
printf("* Malformed Device Disconnected control\n");
return;
}
if (len < sizeof(*ev)) {
reason = MGMT_DEV_DISCONN_UNKNOWN;
consumed_len = len;
} else {
reason = ev->reason;
consumed_len = sizeof(*ev);
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Disconnected: %s (%d) reason %u\n", str, ev->addr.type,
reason);
buf += consumed_len;
len -= consumed_len;
packet_hexdump(buf, len);
}
static void mgmt_connect_failed(uint16_t len, const void *buf)
{
const struct mgmt_ev_connect_failed *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Connect Failed control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Connect Failed: %s (%d) status 0x%2.2x\n",
str, ev->addr.type, ev->status);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_pin_code_request(uint16_t len, const void *buf)
{
const struct mgmt_ev_pin_code_request *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed PIN Code Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ PIN Code Request: %s (%d) secure 0x%2.2x\n",
str, ev->addr.type, ev->secure);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_user_confirm_request(uint16_t len, const void *buf)
{
const struct mgmt_ev_user_confirm_request *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed User Confirmation Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ User Confirmation Request: %s (%d) hint %d value %d\n",
str, ev->addr.type, ev->confirm_hint, ev->value);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_user_passkey_request(uint16_t len, const void *buf)
{
const struct mgmt_ev_user_passkey_request *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed User Passkey Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ PIN User Passkey Request: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_auth_failed(uint16_t len, const void *buf)
{
const struct mgmt_ev_auth_failed *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Authentication Failed control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Authentication Failed: %s (%d) status 0x%2.2x\n",
str, ev->addr.type, ev->status);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_found(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_found *ev = buf;
uint32_t flags;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Found control\n");
return;
}
flags = btohl(ev->flags);
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Found: %s (%d) rssi %d flags 0x%4.4x\n",
str, ev->addr.type, ev->rssi, flags);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_discovering(uint16_t len, const void *buf)
{
const struct mgmt_ev_discovering *ev = buf;
if (len < sizeof(*ev)) {
printf("* Malformed Discovering control\n");
return;
}
printf("@ Discovering: 0x%2.2x (%d)\n", ev->discovering, ev->type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_blocked(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_blocked *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Blocked control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Blocked: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_unblocked(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_unblocked *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Unblocked control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Unblocked: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_unpaired(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_unpaired *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Unpaired control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Unpaired: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_passkey_notify(uint16_t len, const void *buf)
{
const struct mgmt_ev_passkey_notify *ev = buf;
uint32_t passkey;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Passkey Notify control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
passkey = btohl(ev->passkey);
printf("@ Passkey Notify: %s (%d) passkey %06u entered %u\n",
str, ev->addr.type, passkey, ev->entered);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
void control_message(uint16_t opcode, const void *data, uint16_t size)
{
switch (opcode) {
case MGMT_EV_INDEX_ADDED:
mgmt_index_added(size, data);
break;
case MGMT_EV_INDEX_REMOVED:
mgmt_index_removed(size, data);
break;
case MGMT_EV_CONTROLLER_ERROR:
mgmt_controller_error(size, data);
break;
case MGMT_EV_NEW_SETTINGS:
mgmt_new_settings(size, data);
break;
case MGMT_EV_CLASS_OF_DEV_CHANGED:
mgmt_class_of_dev_changed(size, data);
break;
case MGMT_EV_LOCAL_NAME_CHANGED:
mgmt_local_name_changed(size, data);
break;
case MGMT_EV_NEW_LINK_KEY:
mgmt_new_link_key(size, data);
break;
case MGMT_EV_NEW_LONG_TERM_KEY:
mgmt_new_long_term_key(size, data);
break;
case MGMT_EV_DEVICE_CONNECTED:
mgmt_device_connected(size, data);
break;
case MGMT_EV_DEVICE_DISCONNECTED:
mgmt_device_disconnected(size, data);
break;
case MGMT_EV_CONNECT_FAILED:
mgmt_connect_failed(size, data);
break;
case MGMT_EV_PIN_CODE_REQUEST:
mgmt_pin_code_request(size, data);
break;
case MGMT_EV_USER_CONFIRM_REQUEST:
mgmt_user_confirm_request(size, data);
break;
case MGMT_EV_USER_PASSKEY_REQUEST:
mgmt_user_passkey_request(size, data);
break;
case MGMT_EV_AUTH_FAILED:
mgmt_auth_failed(size, data);
break;
case MGMT_EV_DEVICE_FOUND:
mgmt_device_found(size, data);
break;
case MGMT_EV_DISCOVERING:
mgmt_discovering(size, data);
break;
case MGMT_EV_DEVICE_BLOCKED:
mgmt_device_blocked(size, data);
break;
case MGMT_EV_DEVICE_UNBLOCKED:
mgmt_device_unblocked(size, data);
break;
case MGMT_EV_DEVICE_UNPAIRED:
mgmt_device_unpaired(size, data);
break;
case MGMT_EV_PASSKEY_NOTIFY:
mgmt_passkey_notify(size, data);
break;
default:
printf("* Unknown control (code %d len %d)\n", opcode, size);
packet_hexdump(data, size);
break;
}
}
static void data_callback(int fd, uint32_t events, void *user_data)
{
struct control_data *data = user_data;
unsigned char control[32];
struct mgmt_hdr hdr;
struct msghdr msg;
struct iovec iov[2];
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(data->fd);
return;
}
iov[0].iov_base = &hdr;
iov[0].iov_len = MGMT_HDR_SIZE;
iov[1].iov_base = data->buf;
iov[1].iov_len = sizeof(data->buf);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 2;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
while (1) {
struct cmsghdr *cmsg;
struct timeval *tv = NULL;
struct timeval ctv;
uint16_t opcode, index, pktlen;
ssize_t len;
len = recvmsg(data->fd, &msg, MSG_DONTWAIT);
if (len < 0)
break;
if (len < MGMT_HDR_SIZE)
break;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_SOCKET)
continue;
if (cmsg->cmsg_type == SCM_TIMESTAMP) {
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
tv = &ctv;
}
}
opcode = btohs(hdr.opcode);
index = btohs(hdr.index);
pktlen = btohs(hdr.len);
switch (data->channel) {
case HCI_CHANNEL_CONTROL:
packet_control(tv, index, opcode, data->buf, pktlen);
break;
case HCI_CHANNEL_MONITOR:
packet_monitor(tv, index, opcode, data->buf, pktlen);
btsnoop_write_hci(tv, index, opcode, data->buf, pktlen);
break;
}
}
}
static int open_socket(uint16_t channel)
{
struct sockaddr_hci addr;
int fd, opt = 1;
fd = socket(AF_BLUETOOTH, SOCK_RAW | O_CLOEXEC, BTPROTO_HCI);
if (fd < 0) {
perror("Failed to open channel");
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = HCI_DEV_NONE;
addr.hci_channel = channel;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
if (errno == EINVAL) {
/* Fallback to hcidump support */
hcidump_fallback = true;
close(fd);
return -1;
}
perror("Failed to bind channel");
close(fd);
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) {
perror("Failed to enable timestamps");
close(fd);
return -1;
}
return fd;
}
static int open_channel(uint16_t channel)
{
struct control_data *data;
data = malloc(sizeof(*data));
if (!data)
return -1;
memset(data, 0, sizeof(*data));
data->channel = channel;
data->fd = open_socket(channel);
if (data->fd < 0) {
free(data);
return -1;
}
mainloop_add_fd(data->fd, EPOLLIN, data_callback, data, free_data);
return 0;
}
static void client_callback(int fd, uint32_t events, void *user_data)
{
struct control_data *data = user_data;
ssize_t len;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(data->fd);
return;
}
len = recv(data->fd, data->buf + data->offset,
sizeof(data->buf) - data->offset, MSG_DONTWAIT);
if (len < 0)
return;
data->offset += len;
if (data->offset > MGMT_HDR_SIZE) {
struct mgmt_hdr *hdr = (struct mgmt_hdr *) data->buf;
uint16_t pktlen = btohs(hdr->len);
if (data->offset > pktlen + MGMT_HDR_SIZE) {
uint16_t opcode = btohs(hdr->opcode);
uint16_t index = btohs(hdr->index);
packet_monitor(NULL, index, opcode,
data->buf + MGMT_HDR_SIZE, pktlen);
data->offset -= pktlen + MGMT_HDR_SIZE;
if (data->offset > 0)
memmove(data->buf, data->buf +
MGMT_HDR_SIZE + pktlen, data->offset);
}
}
}
static void server_accept_callback(int fd, uint32_t events, void *user_data)
{
struct control_data *data;
struct sockaddr_un addr;
socklen_t len;
int nfd;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(fd);
return;
}
memset(&addr, 0, sizeof(addr));
len = sizeof(addr);
nfd = accept(fd, (struct sockaddr *) &addr, &len);
if (nfd < 0) {
perror("Failed to accept client socket");
return;
}
printf("--- New monitor connection ---\n");
data = malloc(sizeof(*data));
if (!data) {
close(nfd);
return;
}
memset(data, 0, sizeof(*data));
data->channel = HCI_CHANNEL_MONITOR;
data->fd = nfd;
mainloop_add_fd(data->fd, EPOLLIN, client_callback, data, free_data);
}
static int server_fd = -1;
void control_server(const char *path)
{
struct sockaddr_un addr;
int fd;
if (server_fd >= 0)
return;
unlink(path);
fd = socket(PF_UNIX, SOCK_STREAM | O_CLOEXEC, 0);
if (fd < 0) {
perror("Failed to open server socket");
return;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Failed to bind server socket");
close(fd);
return;
}
if (listen(fd, 5) < 0) {
perror("Failed to listen server socket");
close(fd);
return;
}
if (mainloop_add_fd(fd, EPOLLIN, server_accept_callback,
NULL, NULL) < 0) {
close(fd);
return;
}
server_fd = fd;
}
void control_writer(const char *path)
{
btsnoop_create(path, BTSNOOP_TYPE_EXTENDED_HCI);
}
void control_reader(const char *path)
{
unsigned char buf[MAX_PACKET_SIZE];
uint16_t pktlen;
uint32_t type;
struct timeval tv;
if (btsnoop_open(path, &type) < 0)
return;
switch (type) {
case BTSNOOP_TYPE_HCI:
case BTSNOOP_TYPE_UART:
case BTSNOOP_TYPE_EXTENDED_PHY:
packet_del_filter(PACKET_FILTER_SHOW_INDEX);
break;
case BTSNOOP_TYPE_EXTENDED_HCI:
packet_add_filter(PACKET_FILTER_SHOW_INDEX);
break;
}
open_pager();
switch (type) {
case BTSNOOP_TYPE_HCI:
case BTSNOOP_TYPE_UART:
case BTSNOOP_TYPE_EXTENDED_HCI:
while (1) {
uint16_t index, opcode;
if (btsnoop_read_hci(&tv, &index, &opcode,
buf, &pktlen) < 0)
break;
packet_monitor(&tv, index, opcode, buf, pktlen);
}
break;
case BTSNOOP_TYPE_EXTENDED_PHY:
while (1) {
uint16_t frequency;
if (btsnoop_read_phy(&tv, &frequency,
buf, &pktlen) < 0)
break;
packet_simulator(&tv, frequency, buf, pktlen);
}
break;
}
close_pager();
btsnoop_close();
}
int control_tracing(void)
{
packet_add_filter(PACKET_FILTER_SHOW_INDEX);
if (server_fd >= 0)
return 0;
if (open_channel(HCI_CHANNEL_MONITOR) < 0) {
if (!hcidump_fallback)
return -1;
if (hcidump_tracing() < 0)
return -1;
return 0;
}
open_channel(HCI_CHANNEL_CONTROL);
return 0;
}

View File

@@ -0,0 +1,32 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
void control_writer(const char *path);
void control_reader(const char *path);
void control_server(const char *path);
int control_tracing(void);
void control_message(uint16_t opcode, const void *data, uint16_t size);

View File

@@ -0,0 +1,84 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "crc.h"
uint32_t crc24_bit_reverse(uint32_t value)
{
uint32_t result = 0;
uint8_t i;
for (i = 0; i < 24; i++)
result |= ((value >> i) & 1) << (23 - i);
return result;
}
uint32_t crc24_calculate(uint32_t preset, const uint8_t *data, uint8_t len)
{
uint32_t state = preset;
uint8_t i;
for (i = 0; i < len; i++) {
uint8_t n, cur = data[i];
for (n = 0; n < 8; n++) {
int next_bit = (state ^ cur) & 1;
cur >>= 1;
state >>= 1;
if (next_bit) {
state |= 1 << 23;
state ^= 0x5a6000;
}
}
}
return state;
}
uint32_t crc24_reverse(uint32_t crc, const uint8_t *data, uint8_t len)
{
uint32_t state = crc;
uint8_t i;
for (i = 0; i < len; i++) {
uint8_t n, cur = data[len - i - 1];
for (n = 0; n < 8; n++) {
int top_bit = state >> 23;
state = (state << 1) & 0xffffff;
state |= top_bit ^ ((cur >> (7 - n)) & 1);
if (top_bit)
state ^= 0xb4c000;
}
}
return state;
}

View File

@@ -0,0 +1,30 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
uint32_t crc24_bit_reverse(uint32_t value);
uint32_t crc24_calculate(uint32_t preset, const uint8_t *data, uint8_t len);
uint32_t crc24_reverse(uint32_t crc, const uint8_t *data, uint8_t len);

View File

@@ -0,0 +1,171 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include "display.h"
static pid_t pager_pid = 0;
bool use_color(void)
{
static int cached_use_color = -1;
if (__builtin_expect(!!(cached_use_color < 0), 0))
cached_use_color = isatty(STDOUT_FILENO) > 0 || pager_pid > 0;
return cached_use_color;
}
int num_columns(void)
{
static int cached_num_columns = -1;
if (__builtin_expect(!!(cached_num_columns < 0), 0)) {
struct winsize ws;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0)
return -1;
if (ws.ws_col > 0)
cached_num_columns = ws.ws_col;
}
return cached_num_columns;
}
static void close_pipe(int p[])
{
if (p[0] >= 0)
close(p[0]);
if (p[1] >= 0)
close(p[1]);
}
static void wait_for_terminate(pid_t pid)
{
siginfo_t dummy;
for (;;) {
memset(&dummy, 0, sizeof(dummy));
if (waitid(P_PID, pid, &dummy, WEXITED) < 0) {
if (errno == EINTR)
continue;
return;
}
return;
}
}
void open_pager(void)
{
const char *pager;
pid_t parent_pid;
int fd[2];
if (pager_pid > 0)
return;
pager = getenv("PAGER");
if (pager) {
if (!*pager || strcmp(pager, "cat") == 0)
return;
}
if (!(isatty(STDOUT_FILENO) > 0))
return;
num_columns();
if (pipe(fd) < 0) {
perror("Failed to create pager pipe");
return;
}
parent_pid = getpid();
pager_pid = fork();
if (pager_pid < 0) {
perror("Failed to fork pager");
close_pipe(fd);
return;
}
if (pager_pid == 0) {
dup2(fd[0], STDIN_FILENO);
close_pipe(fd);
setenv("LESS", "FRSX", 0);
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
_exit(EXIT_FAILURE);
if (getppid() != parent_pid)
_exit(EXIT_SUCCESS);
if (pager) {
execlp(pager, pager, NULL);
execl("/bin/sh", "sh", "-c", pager, NULL);
}
execlp("pager", "pager", NULL);
execlp("less", "less", NULL);
execlp("more", "more", NULL);
_exit(EXIT_FAILURE);
}
if (dup2(fd[1], STDOUT_FILENO) < 0) {
perror("Failed to duplicate pager pipe");
return;
}
close_pipe(fd);
}
void close_pager(void)
{
if (pager_pid <= 0)
return;
fclose(stdout);
kill(pager_pid, SIGCONT);
wait_for_terminate(pager_pid);
pager_pid = 0;
}

View File

@@ -0,0 +1,60 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdbool.h>
bool use_color(void);
#define COLOR_OFF "\x1B[0m"
#define COLOR_BLACK "\x1B[0;30m"
#define COLOR_RED "\x1B[0;31m"
#define COLOR_GREEN "\x1B[0;32m"
#define COLOR_YELLOW "\x1B[0;33m"
#define COLOR_BLUE "\x1B[0;34m"
#define COLOR_MAGENTA "\x1B[0;35m"
#define COLOR_CYAN "\x1B[0;36m"
#define COLOR_WHITE "\x1B[0;37m"
#define COLOR_WHITE_BG "\x1B[0;47m"
#define COLOR_HIGHLIGHT "\x1B[1;39m"
#define COLOR_ERROR "\x1B[1;31m"
#define print_indent(indent, color1, prefix, title, color2, fmt, args...) \
do { \
printf("%*c%s%s%s%s" fmt "%s\n", (indent), ' ', \
use_color() ? (color1) : "", prefix, title, \
use_color() ? (color2) : "", ## args, \
use_color() ? COLOR_OFF : ""); \
} while (0)
#define print_text(color, fmt, args...) \
print_indent(8, COLOR_OFF, "", "", color, fmt, ## args)
#define print_field(fmt, args...) \
print_indent(8, COLOR_OFF, "", "", COLOR_OFF, fmt, ## args)
int num_columns(void);
void open_pager(void);
void close_pager(void);

View File

@@ -0,0 +1,411 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include "mainloop.h"
#include "packet.h"
#include "hcidump.h"
struct hcidump_data {
uint16_t index;
int fd;
};
static void free_data(void *user_data)
{
struct hcidump_data *data = user_data;
close(data->fd);
free(data);
}
static int open_hci_dev(uint16_t index)
{
struct sockaddr_hci addr;
struct hci_filter flt;
int fd, opt = 1;
fd = socket(AF_BLUETOOTH, SOCK_RAW | O_CLOEXEC, BTPROTO_HCI);
if (fd < 0) {
perror("Failed to open channel");
return -1;
}
/* Setup filter */
hci_filter_clear(&flt);
hci_filter_all_ptypes(&flt);
hci_filter_all_events(&flt);
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
perror("Failed to set HCI filter");
close(fd);
return -1;
}
if (setsockopt(fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
perror("Failed to enable HCI data direction info");
close(fd);
return -1;
}
if (setsockopt(fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
perror("Failed to enable HCI time stamps");
close(fd);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = index;
addr.hci_channel = HCI_CHANNEL_RAW;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Failed to bind channel");
close(fd);
return -1;
}
return fd;
}
static void device_callback(int fd, uint32_t events, void *user_data)
{
struct hcidump_data *data = user_data;
unsigned char buf[HCI_MAX_FRAME_SIZE * 2];
unsigned char control[64];
struct msghdr msg;
struct iovec iov;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(fd);
return;
}
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
while (1) {
struct cmsghdr *cmsg;
struct timeval *tv = NULL;
struct timeval ctv;
int dir = -1;
ssize_t len;
len = recvmsg(fd, &msg, MSG_DONTWAIT);
if (len < 0)
break;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_HCI)
continue;
switch (cmsg->cmsg_type) {
case HCI_DATA_DIR:
memcpy(&dir, CMSG_DATA(cmsg), sizeof(dir));
break;
case HCI_CMSG_TSTAMP:
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
tv = &ctv;
break;
}
}
if (dir < 0 || len < 1)
continue;
switch (buf[0]) {
case HCI_COMMAND_PKT:
packet_hci_command(tv, data->index, buf + 1, len - 1);
break;
case HCI_EVENT_PKT:
packet_hci_event(tv, data->index, buf + 1, len - 1);
break;
case HCI_ACLDATA_PKT:
packet_hci_acldata(tv, data->index, !!dir,
buf + 1, len - 1);
break;
case HCI_SCODATA_PKT:
packet_hci_scodata(tv, data->index, !!dir,
buf + 1, len - 1);
break;
}
}
}
static void open_device(uint16_t index)
{
struct hcidump_data *data;
data = malloc(sizeof(*data));
if (!data)
return;
memset(data, 0, sizeof(*data));
data->index = index;
data->fd = open_hci_dev(index);
if (data->fd < 0) {
free(data);
return;
}
mainloop_add_fd(data->fd, EPOLLIN, device_callback, data, free_data);
}
static void device_info(int fd, uint16_t index, uint8_t *type, uint8_t *bus,
bdaddr_t *bdaddr, char *name)
{
struct hci_dev_info di;
memset(&di, 0, sizeof(di));
di.dev_id = index;
if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0) {
perror("Failed to get device information");
return;
}
*type = di.type >> 4;
*bus = di.type & 0x0f;
bacpy(bdaddr, &di.bdaddr);
memcpy(name, di.name, 8);
}
static void device_list(int fd, int max_dev)
{
struct hci_dev_list_req *dl;
struct hci_dev_req *dr;
int i;
dl = malloc(max_dev * sizeof(*dr) + sizeof(*dl));
if (!dl) {
perror("Failed to allocate device list memory");
return;
}
memset(dl, 0, max_dev * sizeof(*dr) + sizeof(*dl));
dl->dev_num = max_dev;
dr = dl->dev_req;
if (ioctl(fd, HCIGETDEVLIST, (void *) dl) < 0) {
perror("Failed to get device list");
goto done;
}
for (i = 0; i < dl->dev_num; i++, dr++) {
struct timeval tmp_tv, *tv = NULL;
uint8_t type = 0xff, bus = 0xff;
char str[18], name[8] = "";
bdaddr_t bdaddr;
bacpy(&bdaddr, BDADDR_ANY);
if (!gettimeofday(&tmp_tv, NULL))
tv = &tmp_tv;
device_info(fd, dr->dev_id, &type, &bus, &bdaddr, name);
ba2str(&bdaddr, str);
packet_new_index(tv, dr->dev_id, str, type, bus, name);
open_device(dr->dev_id);
}
done:
free(dl);
}
static int open_stack_internal(void)
{
struct sockaddr_hci addr;
struct hci_filter flt;
int fd, opt = 1;
fd = socket(AF_BLUETOOTH, SOCK_RAW | O_CLOEXEC, BTPROTO_HCI);
if (fd < 0) {
perror("Failed to open channel");
return -1;
}
/* Setup filter */
hci_filter_clear(&flt);
hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
perror("Failed to set HCI filter");
close(fd);
return -1;
}
if (setsockopt(fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
perror("Failed to enable HCI time stamps");
close(fd);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = HCI_DEV_NONE;
addr.hci_channel = HCI_CHANNEL_RAW;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Failed to bind channel");
close(fd);
return -1;
}
device_list(fd, HCI_MAX_DEV);
return fd;
}
static void stack_internal_callback(int fd, uint32_t events, void *user_data)
{
unsigned char buf[HCI_MAX_FRAME_SIZE];
unsigned char control[32];
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
ssize_t len;
hci_event_hdr *eh;
evt_stack_internal *si;
evt_si_device *sd;
struct timeval *tv = NULL;
struct timeval ctv;
uint8_t type = 0xff, bus = 0xff;
char str[18], name[8] = "";
bdaddr_t bdaddr;
bacpy(&bdaddr, BDADDR_ANY);
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(fd);
return;
}
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
len = recvmsg(fd, &msg, MSG_DONTWAIT);
if (len < 0)
return;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_HCI)
continue;
switch (cmsg->cmsg_type) {
case HCI_CMSG_TSTAMP:
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
tv = &ctv;
break;
}
}
if (len < 1 + HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE +
EVT_SI_DEVICE_SIZE)
return;
if (buf[0] != HCI_EVENT_PKT)
return;
eh = (hci_event_hdr *) (buf + 1);
if (eh->evt != EVT_STACK_INTERNAL)
return;
si = (evt_stack_internal *) (buf + 1 + HCI_EVENT_HDR_SIZE);
if (si->type != EVT_SI_DEVICE)
return;
sd = (evt_si_device *) &si->data;
switch (sd->event) {
case HCI_DEV_REG:
device_info(fd, sd->dev_id, &type, &bus, &bdaddr, name);
ba2str(&bdaddr, str);
packet_new_index(tv, sd->dev_id, str, type, bus, name);
open_device(sd->dev_id);
break;
case HCI_DEV_UNREG:
ba2str(&bdaddr, str);
packet_del_index(tv, sd->dev_id, str);
break;
}
}
int hcidump_tracing(void)
{
struct hcidump_data *data;
data = malloc(sizeof(*data));
if (!data)
return -1;
memset(data, 0, sizeof(*data));
data->index = HCI_DEV_NONE;
data->fd = open_stack_internal();
if (data->fd < 0) {
free(data);
return -1;
}
mainloop_add_fd(data->fd, EPOLLIN, stack_internal_callback,
data, free_data);
return 0;
}

View File

@@ -0,0 +1,25 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
int hcidump_tracing(void);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
#include <stdbool.h>
struct l2cap_frame {
uint16_t index;
bool in;
uint16_t handle;
uint16_t cid;
const void *data;
uint16_t size;
};
static inline void l2cap_frame_init(struct l2cap_frame *frame,
uint16_t index, bool in, uint16_t handle,
uint16_t cid, const void *data, uint16_t size)
{
frame->index = index;
frame->in = in;
frame->handle = handle;
frame->cid = cid;
frame->data = data;
frame->size = size;
}
static inline void l2cap_frame_pull(struct l2cap_frame *frame,
const struct l2cap_frame *source, uint16_t len)
{
frame->index = source->index;
frame->in = source->in;
frame->handle = source->handle;
frame->cid = source->cid;
frame->data = source->data + len;
frame->size = source->size - len;
}
void l2cap_packet(uint16_t index, bool in, uint16_t handle, uint8_t flags,
const void *data, uint16_t size);

View File

@@ -0,0 +1,549 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <inttypes.h>
#include <bluetooth/bluetooth.h>
#include "display.h"
#include "packet.h"
#include "crc.h"
#include "bt.h"
#include "ll.h"
#define COLOR_OPCODE COLOR_MAGENTA
#define COLOR_OPCODE_UNKNOWN COLOR_WHITE_BG
#define MAX_CHANNEL 16
struct channel_data {
uint32_t access_addr;
uint32_t crc_init;
};
static struct channel_data channel_list[MAX_CHANNEL];
static void set_crc_init(uint32_t access_addr, uint32_t crc_init)
{
int i;
for (i = 0; i < MAX_CHANNEL; i++) {
if (channel_list[i].access_addr == 0x00000000 ||
channel_list[i].access_addr == access_addr) {
channel_list[i].access_addr = access_addr;
channel_list[i].crc_init = crc_init;
break;
}
}
}
static uint32_t get_crc_init(uint32_t access_addr)
{
int i;
for (i = 0; i < MAX_CHANNEL; i++) {
if (channel_list[i].access_addr == access_addr)
return channel_list[i].crc_init;
}
return 0x00000000;
}
static void advertising_packet(const void *data, uint8_t size)
{
const uint8_t *ptr = data;
uint8_t pdu_type, length, win_size, hop, sca;
bool tx_add, rx_add;
uint32_t access_addr, crc_init;
uint16_t win_offset, interval, latency, timeout;
const char *str;
if (size < 2) {
print_text(COLOR_ERROR, "packet too short");
packet_hexdump(data, size);
return;
}
pdu_type = ptr[0] & 0x0f;
tx_add = !!(ptr[0] & 0x40);
rx_add = !!(ptr[0] & 0x80);
length = ptr[1] & 0x3f;
switch (pdu_type) {
case 0x00:
str = "ADV_IND";
break;
case 0x01:
str = "ADV_DIRECT_IND";
break;
case 0x02:
str = "ADV_NONCONN_IND";
break;
case 0x03:
str = "SCAN_REQ";
break;
case 0x04:
str = "SCAN_RSP";
break;
case 0x05:
str = "CONNECT_REQ";
break;
case 0x06:
str = "ADV_SCAN_IND";
break;
default:
str = "Reserved";
break;
}
print_field("Type: %s (0x%2.2x)", str, pdu_type);
print_field("TxAdd: %u", tx_add);
print_field("RxAdd: %u", rx_add);
print_field("Length: %u", length);
if (length != size - 2) {
print_text(COLOR_ERROR, "packet size mismatch");
packet_hexdump(data + 2, size - 2);
return;
}
switch (pdu_type) {
case 0x00: /* ADV_IND */
case 0x02: /* AVD_NONCONN_IND */
case 0x06: /* ADV_SCAN_IND */
case 0x04: /* SCAN_RSP */
if (length < 6) {
print_text(COLOR_ERROR, "payload too short");
packet_hexdump(data + 2, length);
return;
}
packet_print_addr("Advertiser address", data + 2, tx_add);
packet_print_ad(data + 8, length - 6);
break;
case 0x01: /* ADV_DIRECT_IND */
if (length < 12) {
print_text(COLOR_ERROR, "payload too short");
packet_hexdump(data + 2, length);
return;
}
packet_print_addr("Advertiser address", data + 2, tx_add);
packet_print_addr("Inititator address", data + 8, rx_add);
break;
case 0x03: /* SCAN_REQ */
if (length < 12) {
print_text(COLOR_ERROR, "payload too short");
packet_hexdump(data + 2, length);
return;
}
packet_print_addr("Scanner address", data + 2, tx_add);
packet_print_addr("Advertiser address", data + 8, rx_add);
break;
case 0x05: /* CONNECT_REQ */
if (length < 34) {
print_text(COLOR_ERROR, "payload too short");
packet_hexdump(data + 2, length);
return;
}
packet_print_addr("Inititator address", data + 2, tx_add);
packet_print_addr("Advertiser address", data + 8, rx_add);
access_addr = ptr[14] | ptr[15] << 8 |
ptr[16] << 16 | ptr[17] << 24;
crc_init = ptr[18] | ptr[19] << 8 | ptr[20] << 16;
print_field("Access address: 0x%8.8x", access_addr);
print_field("CRC init: 0x%6.6x", crc_init);
set_crc_init(access_addr, crc24_bit_reverse(crc_init));
win_size = ptr[21];
win_offset = ptr[22] | ptr[23] << 8;
interval = ptr[24] | ptr[25] << 8;
latency = ptr[26] | ptr[27] << 8;
timeout = ptr[28] | ptr[29] << 8;
print_field("Transmit window size: %u", win_size);
print_field("Transmit window offset: %u", win_offset);
print_field("Connection interval: %u", interval);
print_field("Connection slave latency: %u", latency);
print_field("Connection supervision timeout: %u", timeout);
packet_print_channel_map_ll(ptr + 30);
hop = ptr[35] & 0x1f;
sca = (ptr[35] & 0xe0) >> 5;
switch (sca) {
case 0:
str = "251 ppm to 500 ppm";
break;
case 1:
str = "151 ppm to 250 ppm";
break;
case 2:
str = "101 ppm to 150ppm";
break;
case 3:
str = "76 ppm to 100 ppm";
break;
case 4:
str = "51 ppm to 75 ppm";
break;
case 5:
str = "31 ppm to 50 ppm";
break;
case 6:
str = "21 ppm to 30 ppm";
break;
case 7:
str = "0 ppm to 20 ppm";
break;
default:
str = "Invalid";
break;
}
print_field("Hop increment: %u", hop);
print_field("Sleep clock accuracy: %s (%u)", str, sca);
break;
default:
packet_hexdump(data + 2, length);
break;
}
}
static void data_packet(const void *data, uint8_t size)
{
const uint8_t *ptr = data;
uint8_t llid, length;
bool nesn, sn, md;
const char *str;
if (size < 2) {
print_text(COLOR_ERROR, "packet too short");
packet_hexdump(data, size);
return;
}
llid = ptr[0] & 0x03;
nesn = !!(ptr[0] & 0x04);
sn = !!(ptr[0] & 0x08);
md = !!(ptr[0] & 0x10);
length = ptr[1] & 0x1f;
switch (llid) {
case 0x01:
if (length > 0)
str = "Continuation fragement of L2CAP message";
else
str = "Empty message";
break;
case 0x02:
str = "Start of L2CAP message";
break;
case 0x03:
str = "Control";
break;
default:
str = "Reserved";
break;
}
print_field("LLID: %s (0x%2.2x)", str, llid);
print_field("Next expected sequence number: %u", nesn);
print_field("Sequence number: %u", sn);
print_field("More data: %u", md);
print_field("Length: %u", length);
switch (llid) {
case 0x03:
llcp_packet(data + 2, size - 2);
break;
default:
packet_hexdump(data + 2, size - 2);
break;
}
}
void ll_packet(uint16_t frequency, const void *data, uint8_t size)
{
const struct bt_ll_hdr *hdr = data;
uint8_t channel = (frequency - 2402) / 2;
uint32_t access_addr;
char access_str[12];
const char *channel_label, *channel_color;
const uint8_t *pdu_data;
uint8_t pdu_len;
uint32_t pdu_crc, crc, crc_init;
if (size < sizeof(*hdr)) {
print_text(COLOR_ERROR, "packet missing header");
packet_hexdump(data, size);
return;
}
if (size < sizeof(*hdr) + 3) {
print_text(COLOR_ERROR, "packet missing checksum");
packet_hexdump(data, size);
return;
}
if (hdr->preamble != 0xaa && hdr->preamble != 0x55) {
print_text(COLOR_ERROR, "invalid preamble");
packet_hexdump(data, size);
return;
}
access_addr = btohl(hdr->access_addr);
pdu_data = data + sizeof(*hdr);
pdu_len = size - sizeof(*hdr) - 3;
pdu_crc = pdu_data[pdu_len + 0] | (pdu_data[pdu_len + 1] << 8) |
(pdu_data[pdu_len + 2] << 16);
if (access_addr == 0x8e89bed6) {
channel_label = "Advertising channel: ";
channel_color = COLOR_MAGENTA;
} else {
channel_label = "Data channel: ";
channel_color = COLOR_CYAN;
}
sprintf(access_str, "0x%8.8x", access_addr);
print_indent(6, channel_color, channel_label, access_str, COLOR_OFF,
" (channel %d) len %d crc 0x%6.6x", channel, pdu_len, pdu_crc);
if (access_addr == 0x8e89bed6)
crc_init = 0xaaaaaa;
else
crc_init = get_crc_init(access_addr);
if (crc_init) {
crc = crc24_calculate(crc_init, pdu_data, pdu_len);
if (crc != pdu_crc) {
print_text(COLOR_ERROR, "invalid checksum");
packet_hexdump(pdu_data, pdu_len);
return;
}
} else
print_text(COLOR_ERROR, "unknown access address");
if (access_addr == 0x8e89bed6)
advertising_packet(pdu_data, pdu_len);
else
data_packet(pdu_data, pdu_len);
}
static void null_pdu(const void *data, uint8_t size)
{
}
static void conn_update_req(const void *data, uint8_t size)
{
const struct bt_ll_conn_update_req *pdu = data;
print_field("Transmit window size: %u", pdu->win_size);
print_field("Transmit window offset: %u", btohs(pdu->win_offset));
print_field("Connection interval: %u", btohs(pdu->interval));
print_field("Connection slave latency: %u", btohs(pdu->latency));
print_field("Connection supervision timeout: %u", btohs(pdu->timeout));;
print_field("Connection instant: %u", btohs(pdu->instant));
}
static void channel_map_req(const void *data, uint8_t size)
{
const struct bt_ll_channel_map_req *pdu = data;
packet_print_channel_map_ll(pdu->map);
print_field("Connection instant: %u", btohs(pdu->instant));
}
static void terminate_ind(const void *data, uint8_t size)
{
const struct bt_ll_terminate_ind *pdu = data;
print_field("Error code: 0x%2.2x", pdu->error);
}
static void enc_req(const void *data, uint8_t size)
{
const struct bt_ll_enc_req *pdu = data;
print_field("Rand: 0x%16.16" PRIx64, btohll(pdu->rand));
print_field("EDIV: 0x%4.4x", btohs(pdu->ediv));
print_field("SKD (master): 0x%16.16" PRIx64, btohll(pdu->skd));
print_field("IV (master): 0x%8.8x", btohl(pdu->iv));
}
static void enc_rsp(const void *data, uint8_t size)
{
const struct bt_ll_enc_rsp *pdu = data;
print_field("SKD (slave): 0x%16.16" PRIx64, btohll(pdu->skd));
print_field("IV (slave): 0x%8.8x", btohl(pdu->iv));
}
static const char *opcode_to_string(uint8_t opcode);
static void unknown_rsp(const void *data, uint8_t size)
{
const struct bt_ll_unknown_rsp *pdu = data;
print_field("Unknown type: %s (0x%2.2x)",
opcode_to_string(pdu->type), pdu->type);
}
static void feature_req(const void *data, uint8_t size)
{
const struct bt_ll_feature_req *pdu = data;
packet_print_features_ll(pdu->features);
}
static void feature_rsp(const void *data, uint8_t size)
{
const struct bt_ll_feature_rsp *pdu = data;
packet_print_features_ll(pdu->features);
}
static void version_ind(const void *data, uint8_t size)
{
const struct bt_ll_version_ind *pdu = data;
packet_print_version("Version", pdu->version,
"Subversion", btohs(pdu->subversion));
packet_print_company("Company", btohs(pdu->company));
}
static void reject_ind(const void *data, uint8_t size)
{
const struct bt_ll_reject_ind *pdu = data;
print_field("Error code: 0x%2.2x", pdu->error);
}
struct llcp_data {
uint8_t opcode;
const char *str;
void (*func) (const void *data, uint8_t size);
uint8_t size;
bool fixed;
};
static const struct llcp_data llcp_table[] = {
{ 0x00, "LL_CONNECTION_UPDATE_REQ", conn_update_req, 11, true },
{ 0x01, "LL_CHANNEL_MAP_REQ", channel_map_req, 7, true },
{ 0x02, "LL_TERMINATE_IND", terminate_ind, 1, true },
{ 0x03, "LL_ENC_REQ", enc_req, 22, true },
{ 0x04, "LL_ENC_RSP", enc_rsp, 12, true },
{ 0x05, "LL_START_ENC_REQ", null_pdu, 0, true },
{ 0x06, "LL_START_ENC_RSP", null_pdu, 0, true },
{ 0x07, "LL_UNKNOWN_RSP", unknown_rsp, 1, true },
{ 0x08, "LL_FEATURE_REQ", feature_req, 8, true },
{ 0x09, "LL_FEATURE_RSP", feature_rsp, 8, true },
{ 0x0a, "LL_PAUSE_ENC_REQ", null_pdu, 0, true },
{ 0x0b, "LL_PAUSE_ENC_RSP", null_pdu, 0, true },
{ 0x0c, "LL_VERSION_IND", version_ind, 5, true },
{ 0x0d, "LL_REJECT_IND", reject_ind, 1, true },
{ }
};
static const char *opcode_to_string(uint8_t opcode)
{
int i;
for (i = 0; llcp_table[i].str; i++) {
if (llcp_table[i].opcode == opcode)
return llcp_table[i].str;
}
return "Unknown";
}
void llcp_packet(const void *data, uint8_t size)
{
uint8_t opcode = ((const uint8_t *) data)[0];
const struct llcp_data *llcp_data = NULL;
const char *opcode_color, *opcode_str;
int i;
for (i = 0; llcp_table[i].str; i++) {
if (llcp_table[i].opcode == opcode) {
llcp_data = &llcp_table[i];
break;
}
}
if (llcp_data) {
if (llcp_data->func)
opcode_color = COLOR_OPCODE;
else
opcode_color = COLOR_OPCODE_UNKNOWN;
opcode_str = llcp_data->str;
} else {
opcode_color = COLOR_OPCODE_UNKNOWN;
opcode_str = "Unknown";
}
print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
" (0x%2.2x)", opcode);
if (!llcp_data || !llcp_data->func) {
packet_hexdump(data + 1, size - 1);
return;
}
if (llcp_data->fixed) {
if (size - 1 != llcp_data->size) {
print_text(COLOR_ERROR, "invalid packet size");
packet_hexdump(data + 1, size - 1);
return;
}
} else {
if (size - 1 < llcp_data->size) {
print_text(COLOR_ERROR, "too short packet");
packet_hexdump(data + 1, size - 1);
return;
}
}
llcp_data->func(data + 1, size - 1);
}

View File

@@ -0,0 +1,28 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
void ll_packet(uint16_t frequency, const void *data, uint8_t size);
void llcp_packet(const void *data, uint8_t size);

View File

@@ -0,0 +1,215 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include "display.h"
#include "packet.h"
#include "lmp.h"
#define COLOR_OPCODE COLOR_MAGENTA
#define COLOR_OPCODE_UNKNOWN COLOR_WHITE_BG
#define ESC4(x) ((127 << 8) | (x))
struct lmp_data {
uint16_t opcode;
const char *str;
void (*func) (const void *data, uint8_t size);
uint8_t size;
bool fixed;
};
static const struct lmp_data lmp_table[] = {
{ 1, "LMP_name_req" },
{ 2, "LMP_name_res" },
{ 3, "LMP_accepted" },
{ 4, "LMP_not_accepted" },
{ 5, "LMP_clkoffset_req" },
{ 6, "LMP_clkoffset_res" },
{ 7, "LMP_detach" },
{ 8, "LMP_in_rand" },
{ 9, "LMP_comb_key" },
{ 10, "LMP_unit_key" },
{ 11, "LMP_au_rand" },
{ 12, "LMP_sres" },
{ 13, "LMP_temp_rand" },
{ 14, "LMP_temp_key" },
{ 15, "LMP_encryption_mode_req" },
{ 16, "LMP_encryption_key_size_req" },
{ 17, "LMP_start_encryption_req" },
{ 18, "LMP_stop_encryption_req" },
{ 19, "LMP_switch_req" },
{ 20, "LMP_hold" },
{ 21, "LMP_hold_req" },
{ 22, "LMP_sniff" },
{ 23, "LMP_sniff_req" },
{ 24, "LMP_unsniff_req" },
{ 25, "LMP_park_req" },
{ 26, "LMP_park" },
{ 27, "LMP_set_broadcast_scan_window" },
{ 28, "LMP_modify_beacon" },
{ 29, "LMP_unpark_BD_ADDR_req" },
{ 30, "LMP_unpark_PM_ADDR_req" },
{ 31, "LMP_incr_power_req" },
{ 32, "LMP_decr_power_req" },
{ 33, "LMP_max_power" },
{ 34, "LMP_min_power" },
{ 35, "LMP_auto_rate" },
{ 36, "LMP_preferred_rate" },
{ 37, "LMP_version_req" },
{ 38, "LMP_version_res" },
{ 39, "LMP_features_req" },
{ 40, "LMP_features_res" },
{ 41, "LMP_quality_of_service" },
{ 42, "LMP_quality_of_service_req" },
{ 43, "LMP_SCO_link_req" },
{ 44, "LMP_remove_SCO_link_req" },
{ 45, "LMP_max_slot" },
{ 46, "LMP_max_slot_req" },
{ 47, "LMP_timing_accuracy_req" },
{ 48, "LMP_timing_accuracy_res" },
{ 49, "LMP_setup_complete" },
{ 50, "LMP_use_semi_permanent_key" },
{ 51, "LMP_host_connection_req" },
{ 52, "LMP_slot_offset" },
{ 53, "LMP_page_mode_req" },
{ 54, "LMP_Page_scan_mode_req" },
{ 55, "LMP_supervision_timeout" },
{ 56, "LMP_test_activate" },
{ 57, "LMP_test_control" },
{ 58, "LMP_encryption_key_size_mask_req" },
{ 59, "LMP_encryption_key_size_mask_res" },
{ 60, "LMP_set_AFH" },
{ 61, "LMP_encapsulated_header" },
{ 62, "LMP_encapsulated_payload" },
{ 63, "LMP_simple_pairing_confirm" },
{ 64, "LMP_simple_pairing_number" },
{ 65, "LMP_DHkey_check" },
{ 66, "LMP_pause_encryption_aes_req" },
{ ESC4(1), "LMP_accepted_ext" },
{ ESC4(2), "LMP_not_accepted_ext" },
{ ESC4(3), "LMP_features_req_ext" },
{ ESC4(4), "LMP_features_res_ext" },
{ ESC4(5), "LMP_clk_adj" },
{ ESC4(6), "LMP_clk_adj_ack" },
{ ESC4(7), "LMP_clk_adj_req" },
{ ESC4(11), "LMP_packet_type_table" },
{ ESC4(12), "LMP_eSCO_link_req" },
{ ESC4(13), "LMP_remove_eSCO_link_req" },
{ ESC4(16), "LMP_channel_classification_req" },
{ ESC4(17), "LMP_channel_classification" },
{ ESC4(21), "LMP_sniff_subrating_req" },
{ ESC4(22), "LMP_sniff_subrating_res" },
{ ESC4(23), "LMP_pause_encryption_req" },
{ ESC4(24), "LMP_resume_encryption_req" },
{ ESC4(25), "LMP_IO_capability_req" },
{ ESC4(26), "LMP_IO_capability_res" },
{ ESC4(27), "LMP_numeric_comparision_failed" },
{ ESC4(28), "LMP_passkey_failed" },
{ ESC4(29), "LMP_oob_failed" },
{ ESC4(30), "LMP_keypress_notification" },
{ ESC4(31), "LMP_power_control_req" },
{ ESC4(32), "LMP_power_control_res" },
{ ESC4(33), "LMP_ping_req" },
{ ESC4(34), "LMP_ping_res" },
{ }
};
void lmp_packet(const void *data, uint8_t size)
{
const struct lmp_data *lmp_data = NULL;
const char *opcode_color, *opcode_str;
uint16_t opcode;
uint8_t tid, off;
int i;
tid = ((const uint8_t *) data)[0] & 0x01;
opcode = (((const uint8_t *) data)[0] & 0xfe) >> 1;
switch (opcode) {
case 127:
opcode = ESC4(((const uint8_t *) data)[1]);
off = 2;
break;
case 126:
case 125:
case 124:
return;
default:
off = 1;
break;
}
for (i = 0; lmp_table[i].str; i++) {
if (lmp_table[i].opcode == opcode) {
lmp_data = &lmp_table[i];
break;
}
}
if (lmp_data) {
if (lmp_data->func)
opcode_color = COLOR_OPCODE;
else
opcode_color = COLOR_OPCODE_UNKNOWN;
opcode_str = lmp_data->str;
} else {
opcode_color = COLOR_OPCODE_UNKNOWN;
opcode_str = "Unknown";
}
if (opcode & 0xff00)
print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
" (%d/%d) TID %d", opcode >> 8, opcode & 0xff, tid);
else
print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
" (%d) TID %d", opcode, tid);
if (!lmp_data || !lmp_data->func) {
packet_hexdump(data + off, size - off);
return;
}
if (lmp_data->fixed) {
if (size - 1 != lmp_data->size) {
print_text(COLOR_ERROR, "invalid packet size");
packet_hexdump(data + off, size - off);
return;
}
} else {
if (size - 1 < lmp_data->size) {
print_text(COLOR_ERROR, "too short packet");
packet_hexdump(data + off, size - off);
return;
}
}
lmp_data->func(data + off, size - off);
}

View File

@@ -0,0 +1,27 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
void lmp_packet(const void *data, uint8_t size);

View File

@@ -0,0 +1,167 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "mainloop.h"
#include "packet.h"
#include "control.h"
static void signal_callback(int signum, void *user_data)
{
switch (signum) {
case SIGINT:
case SIGTERM:
mainloop_quit();
break;
}
}
static void usage(void)
{
printf("btmon - Bluetooth monitor\n"
"Usage:\n");
printf("\tbtmon [options]\n");
printf("options:\n"
"\t-r, --read <file> Read traces in btsnoop format\n"
"\t-w, --write <file> Save traces in btsnoop format\n"
"\t-s, --server <socket> Start monitor server socket\n"
"\t-i, --index <num> Show only specified controller\n"
"\t-t, --time Show time instead of time offset\n"
"\t-T, --date Show time and date information\n"
"\t-S, --sco Dump SCO traffic\n"
"\t-h, --help Show help options\n");
}
static const struct option main_options[] = {
{ "read", required_argument, NULL, 'r' },
{ "write", required_argument, NULL, 'w' },
{ "server", required_argument, NULL, 's' },
{ "index", required_argument, NULL, 'i' },
{ "time", no_argument, NULL, 't' },
{ "date", no_argument, NULL, 'T' },
{ "sco", no_argument, NULL, 'S' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
};
int main(int argc, char *argv[])
{
unsigned long filter_mask = 0;
const char *str, *reader_path = NULL, *writer_path = NULL;
sigset_t mask;
mainloop_init();
filter_mask |= PACKET_FILTER_SHOW_TIME_OFFSET;
for (;;) {
int opt;
opt = getopt_long(argc, argv, "r:w:s:i:tTSvh",
main_options, NULL);
if (opt < 0)
break;
switch (opt) {
case 'r':
reader_path = optarg;
break;
case 'w':
writer_path = optarg;
break;
case 's':
control_server(optarg);
break;
case 'i':
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
str = optarg + 3;
else
str = optarg;
if (!isdigit(*str)) {
usage();
return EXIT_FAILURE;
}
packet_select_index(atoi(str));
break;
case 't':
filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
filter_mask |= PACKET_FILTER_SHOW_TIME;
break;
case 'T':
filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
filter_mask |= PACKET_FILTER_SHOW_TIME;
filter_mask |= PACKET_FILTER_SHOW_DATE;
break;
case 'S':
filter_mask |= PACKET_FILTER_SHOW_SCO_DATA;
break;
case 'v':
printf("%s\n", VERSION);
return EXIT_SUCCESS;
case 'h':
usage();
return EXIT_SUCCESS;
default:
return EXIT_FAILURE;
}
}
if (argc - optind > 0) {
fprintf(stderr, "Invalid command line parameters\n");
return EXIT_FAILURE;
}
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
mainloop_set_signal(&mask, signal_callback, NULL, NULL);
printf("Bluetooth monitor ver %s\n", VERSION);
packet_set_filter(filter_mask);
if (reader_path) {
control_reader(reader_path);
return EXIT_SUCCESS;
}
if (writer_path)
control_writer(writer_path);
if (control_tracing() < 0)
return EXIT_FAILURE;
return mainloop_run();
}

View File

@@ -0,0 +1,389 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include "mainloop.h"
#define MAX_EPOLL_EVENTS 10
static int epoll_fd;
static int epoll_terminate;
struct mainloop_data {
int fd;
uint32_t events;
mainloop_event_func callback;
mainloop_destroy_func destroy;
void *user_data;
};
#define MAX_MAINLOOP_ENTRIES 128
static struct mainloop_data *mainloop_list[MAX_MAINLOOP_ENTRIES];
struct timeout_data {
int fd;
mainloop_timeout_func callback;
mainloop_destroy_func destroy;
void *user_data;
};
struct signal_data {
int fd;
sigset_t mask;
mainloop_signal_func callback;
mainloop_destroy_func destroy;
void *user_data;
};
static struct signal_data *signal_data;
void mainloop_init(void)
{
unsigned int i;
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++)
mainloop_list[i] = NULL;
epoll_terminate = 0;
}
void mainloop_quit(void)
{
epoll_terminate = 1;
}
static void signal_callback(int fd, uint32_t events, void *user_data)
{
struct signal_data *data = user_data;
struct signalfd_siginfo si;
ssize_t result;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_quit();
return;
}
result = read(fd, &si, sizeof(si));
if (result != sizeof(si))
return;
if (data->callback)
data->callback(si.ssi_signo, data->user_data);
}
int mainloop_run(void)
{
unsigned int i;
if (signal_data) {
if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0)
return 1;
signal_data->fd = signalfd(-1, &signal_data->mask,
SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_data->fd < 0)
return 1;
if (mainloop_add_fd(signal_data->fd, EPOLLIN,
signal_callback, signal_data, NULL) < 0) {
close(signal_data->fd);
return 1;
}
}
while (!epoll_terminate) {
struct epoll_event events[MAX_EPOLL_EVENTS];
int n, nfds;
nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);
if (nfds < 0)
continue;
for (n = 0; n < nfds; n++) {
struct mainloop_data *data = events[n].data.ptr;
data->callback(data->fd, events[n].events,
data->user_data);
}
}
if (signal_data) {
mainloop_remove_fd(signal_data->fd);
close(signal_data->fd);
if (signal_data->destroy)
signal_data->destroy(signal_data->user_data);
}
for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++) {
struct mainloop_data *data = mainloop_list[i];
mainloop_list[i] = NULL;
if (data) {
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
if (data->destroy)
data->destroy(data->user_data);
free(data);
}
}
close(epoll_fd);
epoll_fd = 0;
return 0;
}
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
void *user_data, mainloop_destroy_func destroy)
{
struct mainloop_data *data;
struct epoll_event ev;
int err;
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1 || !callback)
return -EINVAL;
data = malloc(sizeof(*data));
if (!data)
return -ENOMEM;
memset(data, 0, sizeof(*data));
data->fd = fd;
data->events = events;
data->callback = callback;
data->destroy = destroy;
data->user_data = user_data;
memset(&ev, 0, sizeof(ev));
ev.events = events;
ev.data.ptr = data;
err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev);
if (err < 0) {
free(data);
return err;
}
mainloop_list[fd] = data;
return 0;
}
int mainloop_modify_fd(int fd, uint32_t events)
{
struct mainloop_data *data;
struct epoll_event ev;
int err;
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
return -EINVAL;
data = mainloop_list[fd];
if (!data)
return -ENXIO;
if (data->events == events)
return 0;
memset(&ev, 0, sizeof(ev));
ev.events = events;
ev.data.ptr = data;
err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev);
if (err < 0)
return err;
data->events = events;
return 0;
}
int mainloop_remove_fd(int fd)
{
struct mainloop_data *data;
int err;
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
return -EINVAL;
data = mainloop_list[fd];
if (!data)
return -ENXIO;
mainloop_list[fd] = NULL;
err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
if (data->destroy)
data->destroy(data->user_data);
free(data);
return err;
}
static void timeout_destroy(void *user_data)
{
struct timeout_data *data = user_data;
close(data->fd);
data->fd = -1;
if (data->destroy)
data->destroy(data->user_data);
}
static void timeout_callback(int fd, uint32_t events, void *user_data)
{
struct timeout_data *data = user_data;
uint64_t expired;
ssize_t result;
if (events & (EPOLLERR | EPOLLHUP))
return;
result = read(data->fd, &expired, sizeof(expired));
if (result != sizeof(expired))
return;
if (data->callback)
data->callback(data->fd, data->user_data);
}
static inline int timeout_set(int fd, unsigned int seconds)
{
struct itimerspec itimer;
memset(&itimer, 0, sizeof(itimer));
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_nsec = 0;
itimer.it_value.tv_sec = seconds;
itimer.it_value.tv_nsec = 0;
return timerfd_settime(fd, 0, &itimer, NULL);
}
int mainloop_add_timeout(unsigned int seconds, mainloop_timeout_func callback,
void *user_data, mainloop_destroy_func destroy)
{
struct timeout_data *data;
if (!callback)
return -EINVAL;
data = malloc(sizeof(*data));
if (!data)
return -ENOMEM;
memset(data, 0, sizeof(*data));
data->callback = callback;
data->destroy = destroy;
data->user_data = user_data;
data->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (data->fd < 0) {
free(data);
return -EIO;
}
if (seconds > 0) {
if (timeout_set(data->fd, seconds) < 0) {
close(data->fd);
free(data);
return -EIO;
}
}
if (mainloop_add_fd(data->fd, EPOLLIN | EPOLLONESHOT,
timeout_callback, data, timeout_destroy) < 0) {
close(data->fd);
free(data);
return -EIO;
}
return data->fd;
}
int mainloop_modify_timeout(int id, unsigned int seconds)
{
if (seconds > 0) {
if (timeout_set(id, seconds) < 0)
return -EIO;
}
if (mainloop_modify_fd(id, EPOLLIN | EPOLLONESHOT) < 0)
return -EIO;
return 0;
}
int mainloop_remove_timeout(int id)
{
return mainloop_remove_fd(id);
}
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
void *user_data, mainloop_destroy_func destroy)
{
struct signal_data *data;
if (!mask || !callback)
return -EINVAL;
data = malloc(sizeof(*data));
if (!data)
return -ENOMEM;
memset(data, 0, sizeof(*data));
data->callback = callback;
data->destroy = destroy;
data->user_data = user_data;
data->fd = -1;
memcpy(&data->mask, mask, sizeof(sigset_t));
free(signal_data);
signal_data = data;
return 0;
}

View File

@@ -0,0 +1,49 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <signal.h>
#include <sys/epoll.h>
typedef void (*mainloop_destroy_func) (void *user_data);
typedef void (*mainloop_event_func) (int fd, uint32_t events, void *user_data);
typedef void (*mainloop_timeout_func) (int id, void *user_data);
typedef void (*mainloop_signal_func) (int signum, void *user_data);
void mainloop_init(void);
void mainloop_quit(void);
int mainloop_run(void);
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
void *user_data, mainloop_destroy_func destroy);
int mainloop_modify_fd(int fd, uint32_t events);
int mainloop_remove_fd(int fd);
int mainloop_add_timeout(unsigned int seconds, mainloop_timeout_func callback,
void *user_data, mainloop_destroy_func destroy);
int mainloop_modify_timeout(int fd, unsigned int seconds);
int mainloop_remove_timeout(int id);
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
void *user_data, mainloop_destroy_func destroy);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
#include <stdbool.h>
#include <sys/time.h>
#define PACKET_FILTER_SHOW_INDEX (1 << 0)
#define PACKET_FILTER_SHOW_DATE (1 << 1)
#define PACKET_FILTER_SHOW_TIME (1 << 2)
#define PACKET_FILTER_SHOW_TIME_OFFSET (1 << 3)
#define PACKET_FILTER_SHOW_ACL_DATA (1 << 4)
#define PACKET_FILTER_SHOW_SCO_DATA (1 << 5)
void packet_set_filter(unsigned long filter);
void packet_add_filter(unsigned long filter);
void packet_del_filter(unsigned long filter);
void packet_select_index(uint16_t index);
void packet_hexdump(const unsigned char *buf, uint16_t len);
void packet_print_version(const char *label, uint8_t version,
const char *sublabel, uint16_t subversion);
void packet_print_company(const char *label, uint16_t company);
void packet_print_addr(const char *label, const void *data, bool random);
void packet_print_ad(const void *data, uint8_t size);
void packet_print_features_ll(const uint8_t *features);
void packet_print_channel_map_ll(const uint8_t *map);
void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size);
void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size);
void packet_simulator(struct timeval *tv, uint16_t frequency,
const void *data, uint16_t size);
void packet_new_index(struct timeval *tv, uint16_t index, const char *label,
uint8_t type, uint8_t bus, const char *name);
void packet_del_index(struct timeval *tv, uint16_t index, const char *label);
void packet_hci_command(struct timeval *tv, uint16_t index,
const void *data, uint16_t size);
void packet_hci_event(struct timeval *tv, uint16_t index,
const void *data, uint16_t size);
void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
const void *data, uint16_t size);
void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
const void *data, uint16_t size);

View File

@@ -0,0 +1,748 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <bluetooth/bluetooth.h>
#include "bt.h"
#include "packet.h"
#include "display.h"
#include "l2cap.h"
#include "uuid.h"
#include "sdp.h"
#define MAX_TID 16
struct tid_data {
bool inuse;
uint16_t tid;
uint16_t channel;
uint8_t cont[17];
};
static struct tid_data tid_list[MAX_TID];
static struct tid_data *get_tid(uint16_t tid, uint16_t channel)
{
int i, n = -1;
for (i = 0; i < MAX_TID; i++) {
if (!tid_list[i].inuse) {
if (n < 0)
n = i;
continue;
}
if (tid_list[i].tid == tid && tid_list[i].channel == channel)
return &tid_list[i];
}
if (n < 0)
return NULL;
tid_list[n].inuse = true;
tid_list[n].tid = tid;
tid_list[n].channel = channel;
return &tid_list[n];
}
static void clear_tid(struct tid_data *tid)
{
if (tid)
tid->inuse = false;
}
static void print_uint(uint8_t indent, const uint8_t *data, uint32_t size)
{
switch (size) {
case 1:
print_field("%*c0x%2.2x", indent, ' ', data[0]);
break;
case 2:
print_field("%*c0x%4.4x", indent, ' ', bt_get_be16(data));
break;
case 4:
print_field("%*c0x%8.8x", indent, ' ', bt_get_be32(data));
break;
case 8:
print_field("%*c0x%16.16" PRIx64, indent, ' ',
bt_get_be64(data));
break;
default:
packet_hexdump(data, size);
break;
}
}
static void print_sint(uint8_t indent, const uint8_t *data, uint32_t size)
{
packet_hexdump(data, size);
}
static void print_uuid(uint8_t indent, const uint8_t *data, uint32_t size)
{
switch (size) {
case 2:
print_field("%*c%s (0x%4.4x)", indent, ' ',
uuid16_to_str(bt_get_be16(data)), bt_get_be16(data));
break;
case 4:
print_field("%*c%s (0x%8.8x)", indent, ' ',
uuid32_to_str(bt_get_be32(data)), bt_get_be32(data));
break;
case 16:
/* BASE_UUID = 00000000-0000-1000-8000-00805F9B34FB */
print_field("%*c%8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.4x",
indent, ' ',
bt_get_be32(data), bt_get_be16(data + 4),
bt_get_be16(data + 6), bt_get_be16(data + 8),
bt_get_be16(data + 10), bt_get_be32(data + 12));
if (bt_get_be16(data + 4) == 0x0000 &&
bt_get_be16(data + 6) == 0x1000 &&
bt_get_be16(data + 8) == 0x8000 &&
bt_get_be16(data + 10) == 0x0080 &&
bt_get_be32(data + 12) == 0x5F9B34FB)
print_field("%*c%s", indent, ' ',
uuid32_to_str(bt_get_be32(data)));
break;
default:
packet_hexdump(data, size);
break;
}
}
static void print_string(uint8_t indent, const uint8_t *data, uint32_t size)
{
char *str = alloca(size + 1);
str[size] = '\0';
strncpy(str, (const char *) data, size);
print_field("%*c%s [len %d]", indent, ' ', str, size);
}
static void print_boolean(uint8_t indent, const uint8_t *data, uint32_t size)
{
print_field("%*c%s", indent, ' ', data[0] ? "true" : "false");
}
#define SIZES(args...) ((uint8_t[]) { args, 0xff } )
static struct {
uint8_t value;
uint8_t *sizes;
bool recurse;
const char *str;
void (*print) (uint8_t indent, const uint8_t *data, uint32_t size);
} type_table[] = {
{ 0, SIZES(0), false, "Nil" },
{ 1, SIZES(0, 1, 2, 3, 4), false, "Unsigned Integer", print_uint },
{ 2, SIZES(0, 1, 2, 3, 4), false, "Signed Integer", print_sint },
{ 3, SIZES(1, 2, 4), false, "UUID", print_uuid },
{ 4, SIZES(5, 6, 7), false, "String", print_string },
{ 5, SIZES(0), false, "Boolean", print_boolean },
{ 6, SIZES(5, 6, 7), true, "Sequence" },
{ 7, SIZES(5, 6, 7), true, "Alternative" },
{ 8, SIZES(5, 6, 7), false, "URL", print_string },
{ }
};
static struct {
uint8_t index;
uint8_t bits;
uint8_t size;
const char *str;
} size_table[] = {
{ 0, 0, 1, "1 byte" },
{ 1, 0, 2, "2 bytes" },
{ 2, 0, 4, "4 bytes" },
{ 3, 0, 8, "8 bytes" },
{ 4, 0, 16, "16 bytes" },
{ 5, 8, 0, "8 bits" },
{ 6, 16, 0, "16 bits" },
{ 7, 32, 0, "32 bits" },
{ }
};
static bool valid_size(uint8_t size, uint8_t *sizes)
{
int i;
for (i = 0; sizes[i] != 0xff; i++) {
if (sizes[i] == size)
return true;
}
return false;
}
static uint8_t get_bits(const uint8_t *data, uint32_t size)
{
int i;
for (i = 0; size_table[i].str; i++) {
if (size_table[i].index == (data[0] & 0x07))
return size_table[i].bits;
}
return 0;
}
static uint32_t get_size(const uint8_t *data, uint32_t size)
{
int i;
for (i = 0; size_table[i].str; i++) {
if (size_table[i].index == (data[0] & 0x07)) {
switch (size_table[i].bits) {
case 0:
if ((data[0] & 0xf8) == 0)
return 0;
else
return size_table[i].size;
case 8:
return data[1];
case 16:
return bt_get_be16(data + 1);
case 32:
return bt_get_be32(data + 1);
default:
return 0;
}
}
}
return 0;
}
static void decode_data_elements(uint32_t position, uint8_t indent,
const uint8_t *data, uint32_t size,
void (*print_func) (uint32_t, uint8_t, uint8_t,
const uint8_t *, uint32_t))
{
uint32_t datalen, elemlen, extrabits;
int i;
if (!size)
return;
extrabits = get_bits(data, size);
if (size < 1 + (extrabits / 8)) {
print_text(COLOR_ERROR, "data element descriptor too short");
packet_hexdump(data, size);
return;
}
datalen = get_size(data, size);
if (size < 1 + (extrabits / 8) + datalen) {
print_text(COLOR_ERROR, "data element size too short");
packet_hexdump(data, size);
return;
}
elemlen = 1 + (extrabits / 8) + datalen;
for (i = 0; type_table[i].str; i++) {
uint8_t type = (data[0] & 0xf8) >> 3;
if (type_table[i].value != type)
continue;
if (print_func) {
print_func(position, indent, type,
data + 1 + (extrabits / 8), datalen);
break;
}
print_field("%*c%s (%d) with %u byte%s [%u extra bits] len %u",
indent, ' ', type_table[i].str, type,
datalen, datalen == 1 ? "" : "s",
extrabits, elemlen);
if (!valid_size(data[0] & 0x07, type_table[i].sizes)) {
print_text(COLOR_ERROR, "invalid data element size");
packet_hexdump(data + 1 + (extrabits / 8), datalen);
break;
}
if (type_table[i].recurse)
decode_data_elements(0, indent + 2,
data + 1 + (extrabits / 8), datalen,
print_func);
else if (type_table[i].print)
type_table[i].print(indent + 2,
data + 1 + (extrabits / 8), datalen);
break;
}
data += elemlen;
size -= elemlen;
decode_data_elements(position + 1, indent, data, size, print_func);
}
static uint32_t get_bytes(const uint8_t *data, uint32_t size)
{
switch (data[0] & 0x07) {
case 5:
return 2 + data[1];
case 6:
return 3 + bt_get_be16(data + 1);
case 7:
return 5 + bt_get_be32(data + 1);
}
return 0;
}
static struct {
uint16_t id;
const char *str;
} attribute_table[] = {
{ 0x0000, "Service Record Handle" },
{ 0x0001, "Service Class ID List" },
{ 0x0002, "Service Record State" },
{ 0x0003, "Service ID" },
{ 0x0004, "Protocol Descriptor List" },
{ 0x0005, "Browse Group List" },
{ 0x0006, "Language Base Attribute ID List" },
{ 0x0007, "Service Info Time To Live" },
{ 0x0008, "Service Availability" },
{ 0x0009, "Bluetooth Profile Descriptor List" },
{ 0x000a, "Documentation URL" },
{ 0x000b, "Client Executable URL" },
{ 0x000c, "Icon URL" },
{ 0x000d, "Additional Protocol Descriptor List" },
{ }
};
static void print_attr(uint32_t position, uint8_t indent, uint8_t type,
const uint8_t *data, uint32_t size)
{
int i;
if ((position % 2) == 0) {
uint16_t id = bt_get_be16(data);
const char *str = "Unknown";
for (i = 0; attribute_table[i].str; i++) {
if (attribute_table[i].id == id)
str = attribute_table[i].str;
}
print_field("%*cAttribute: %s (0x%4.4x) [len %d]",
indent, ' ', str, id, size);
return;
}
for (i = 0; type_table[i].str; i++) {
if (type_table[i].value != type)
continue;
if (type_table[i].recurse)
decode_data_elements(0, indent + 2, data, size, NULL);
else if (type_table[i].print)
type_table[i].print(indent + 2, data, size);
break;
}
}
static void print_attr_list(uint32_t position, uint8_t indent, uint8_t type,
const uint8_t *data, uint32_t size)
{
print_field("%*cAttribute list: [len %d] {position %d}",
indent, ' ', size, position);
decode_data_elements(0, indent + 2, data, size, print_attr);
}
static void print_attr_lists(uint32_t position, uint8_t indent, uint8_t type,
const uint8_t *data, uint32_t size)
{
decode_data_elements(0, indent, data, size, print_attr_list);
}
static void print_continuation(const uint8_t *data, uint16_t size)
{
if (data[0] != size - 1) {
print_text(COLOR_ERROR, "invalid continuation state");
packet_hexdump(data, size);
return;
}
print_field("Continuation state: %d", data[0]);
packet_hexdump(data + 1, size - 1);
}
static void store_continuation(struct tid_data *tid,
const uint8_t *data, uint16_t size)
{
memcpy(tid->cont, data, size);
print_continuation(data, size);
}
#define MAX_CONT 8
struct cont_data {
uint16_t channel;
uint8_t cont[17];
void *data;
uint32_t size;
};
static struct cont_data cont_list[MAX_CONT];
static void handle_continuation(struct tid_data *tid, bool nested,
uint16_t bytes, const uint8_t *data, uint16_t size)
{
uint8_t *newdata;
int i, n = -1;
if (bytes + 1 > size) {
print_text(COLOR_ERROR, "missing continuation state");
return;
}
if (tid->cont[0] == 0x00 && data[bytes] == 0x00) {
decode_data_elements(0, 2, data, bytes,
nested ? print_attr_lists : print_attr_list);
print_continuation(data + bytes, size - bytes);
return;
}
for (i = 0; i < MAX_CONT; i++) {
if (cont_list[i].cont[0] == 0x00) {
if (n < 0)
n = i;
continue;
}
if (cont_list[i].channel != tid->channel)
continue;
if (cont_list[i].cont[0] != tid->cont[0])
continue;
if (!memcmp(cont_list[i].cont + 1,
tid->cont + 1, tid->cont[0])) {
n = i;
break;
}
}
print_continuation(data + bytes, size - bytes);
if (n < 0)
return;
newdata = realloc(cont_list[n].data, cont_list[n].size + bytes);
if (!newdata) {
print_text(COLOR_ERROR, "failed buffer allocation");
free(cont_list[n].data);
cont_list[n].data = NULL;
cont_list[n].size = 0;
return;
}
cont_list[n].channel = tid->channel;
cont_list[n].data = newdata;
if (bytes > 0) {
memcpy(cont_list[n].data + cont_list[n].size, data, bytes);
cont_list[n].size += bytes;
}
if (data[bytes] == 0x00) {
print_field("Combined attribute bytes: %d", cont_list[n].size);
decode_data_elements(0, 2, cont_list[n].data, cont_list[n].size,
nested ? print_attr_lists : print_attr_list);
free(cont_list[n].data);
cont_list[n].data = NULL;
cont_list[n].size = 0;
} else
memcpy(cont_list[i].cont, data + bytes, data[bytes] + 1);
}
static uint16_t common_rsp(const struct l2cap_frame *frame,
struct tid_data *tid)
{
uint16_t bytes;
if (frame->size < 2) {
print_text(COLOR_ERROR, "invalid size");
packet_hexdump(frame->data, frame->size);
return 0;
}
bytes = bt_get_be16(frame->data);
print_field("Attribute bytes: %d", bytes);
if (bytes > frame->size - 2) {
print_text(COLOR_ERROR, "invalid attribute size");
packet_hexdump(frame->data + 2, frame->size - 2);
return 0;
}
return bytes;
}
static void error_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint16_t error;
clear_tid(tid);
if (frame->size < 2) {
print_text(COLOR_ERROR, "invalid size");
packet_hexdump(frame->data, frame->size);
return;
}
error = bt_get_be16(frame->data);
print_field("Error code: 0x%2.2x", error);
}
static void service_req(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint32_t search_bytes;
search_bytes = get_bytes(frame->data, frame->size);
print_field("Search pattern: [len %d]", search_bytes);
if (search_bytes + 2 > frame->size) {
print_text(COLOR_ERROR, "invalid search list length");
packet_hexdump(frame->data, frame->size);
return;
}
decode_data_elements(0, 2, frame->data, search_bytes, NULL);
print_field("Max record count: %d",
bt_get_be16(frame->data + search_bytes));
print_continuation(frame->data + search_bytes + 2,
frame->size - search_bytes - 2);
}
static void service_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint16_t count;
int i;
clear_tid(tid);
if (frame->size < 4) {
print_text(COLOR_ERROR, "invalid size");
packet_hexdump(frame->data, frame->size);
return;
}
count = bt_get_be16(frame->data + 2);
print_field("Total record count: %d", bt_get_be16(frame->data));
print_field("Current record count: %d", count);
for (i = 0; i < count; i++)
print_field("Record handle: 0x%4.4x",
bt_get_be32(frame->data + 4 + (i * 4)));
print_continuation(frame->data + 4 + (count * 4),
frame->size - 4 - (count * 4));
}
static void attr_req(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint32_t attr_bytes;
if (frame->size < 6) {
print_text(COLOR_ERROR, "invalid size");
packet_hexdump(frame->data, frame->size);
return;
}
print_field("Record handle: 0x%4.4x", bt_get_be32(frame->data));
print_field("Max attribute bytes: %d", bt_get_be16(frame->data + 4));
attr_bytes = get_bytes(frame->data + 6, frame->size - 6);
print_field("Attribute list: [len %d]", attr_bytes);
if (attr_bytes + 6 > frame->size) {
print_text(COLOR_ERROR, "invalid attribute list length");
packet_hexdump(frame->data, frame->size);
return;
}
decode_data_elements(0, 2, frame->data + 6, attr_bytes, NULL);
store_continuation(tid, frame->data + 6 + attr_bytes,
frame->size - 6 - attr_bytes);
}
static void attr_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint16_t bytes;
bytes = common_rsp(frame, tid);
handle_continuation(tid, false, bytes,
frame->data + 2, frame->size - 2);
clear_tid(tid);
}
static void search_attr_req(const struct l2cap_frame *frame,
struct tid_data *tid)
{
uint32_t search_bytes, attr_bytes;
search_bytes = get_bytes(frame->data, frame->size);
print_field("Search pattern: [len %d]", search_bytes);
if (search_bytes + 2 > frame->size) {
print_text(COLOR_ERROR, "invalid search list length");
packet_hexdump(frame->data, frame->size);
return;
}
decode_data_elements(0, 2, frame->data, search_bytes, NULL);
print_field("Max record count: %d",
bt_get_be16(frame->data + search_bytes));
attr_bytes = get_bytes(frame->data + search_bytes + 2,
frame->size - search_bytes - 2);
print_field("Attribute list: [len %d]", attr_bytes);
decode_data_elements(0, 2, frame->data + search_bytes + 2,
attr_bytes, NULL);
store_continuation(tid, frame->data + search_bytes + 2 + attr_bytes,
frame->size - search_bytes - 2 - attr_bytes);
}
static void search_attr_rsp(const struct l2cap_frame *frame,
struct tid_data *tid)
{
uint16_t bytes;
bytes = common_rsp(frame, tid);
handle_continuation(tid, true, bytes, frame->data + 2, frame->size - 2);
clear_tid(tid);
}
struct sdp_data {
uint8_t pdu;
const char *str;
void (*func) (const struct l2cap_frame *frame, struct tid_data *tid);
};
static const struct sdp_data sdp_table[] = {
{ 0x01, "Error Response", error_rsp },
{ 0x02, "Service Search Request", service_req },
{ 0x03, "Service Search Response", service_rsp },
{ 0x04, "Service Attribute Request", attr_req },
{ 0x05, "Service Attribute Response", attr_rsp },
{ 0x06, "Service Search Attribute Request", search_attr_req },
{ 0x07, "Service Search Attribute Response", search_attr_rsp },
{ }
};
void sdp_packet(const struct l2cap_frame *frame, uint16_t channel)
{
uint8_t pdu;
uint16_t tid, plen;
struct l2cap_frame sdp_frame;
struct tid_data *tid_info;
const struct sdp_data *sdp_data = NULL;
const char *pdu_color, *pdu_str;
int i;
if (frame->size < 5) {
print_text(COLOR_ERROR, "frame too short");
packet_hexdump(frame->data, frame->size);
return;
}
pdu = *((uint8_t *) frame->data);
tid = bt_get_be16(frame->data + 1);
plen = bt_get_be16(frame->data + 3);
if (frame->size != plen + 5) {
print_text(COLOR_ERROR, "invalid frame size");
packet_hexdump(frame->data, frame->size);
return;
}
for (i = 0; sdp_table[i].str; i++) {
if (sdp_table[i].pdu == pdu) {
sdp_data = &sdp_table[i];
break;
}
}
if (sdp_data) {
if (sdp_data->func) {
if (frame->in)
pdu_color = COLOR_MAGENTA;
else
pdu_color = COLOR_BLUE;
} else
pdu_color = COLOR_WHITE_BG;
pdu_str = sdp_data->str;
} else {
pdu_color = COLOR_WHITE_BG;
pdu_str = "Unknown";
}
print_indent(6, pdu_color, "SDP: ", pdu_str, COLOR_OFF,
" (0x%2.2x) tid %d len %d", pdu, tid, plen);
if (!sdp_data || !sdp_data->func) {
packet_hexdump(frame->data + 5, frame->size - 5);
return;
}
tid_info = get_tid(tid, channel);
l2cap_frame_pull(&sdp_frame, frame, 5);
sdp_data->func(&sdp_frame, tid_info);
}

View File

@@ -0,0 +1,25 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
void sdp_packet(const struct l2cap_frame *frame, uint16_t channel);

View File

@@ -0,0 +1,284 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include "uuid.h"
static struct {
uint16_t uuid;
const char *str;
} uuid16_table[] = {
{ 0x0001, "SDP" },
{ 0x0003, "RFCOMM" },
{ 0x0005, "TCS-BIN" },
{ 0x0007, "ATT" },
{ 0x0008, "OBEX" },
{ 0x000f, "BNEP" },
{ 0x0010, "UPNP" },
{ 0x0011, "HIDP" },
{ 0x0012, "Hardcopy Control Channel" },
{ 0x0014, "Hardcopy Data Channel" },
{ 0x0016, "Hardcopy Notification" },
{ 0x0017, "AVCTP" },
{ 0x0019, "AVDTP" },
{ 0x001b, "CMTP" },
{ 0x001e, "MCAP Control Channel" },
{ 0x001f, "MCAP Data Channel" },
{ 0x0100, "L2CAP" },
{ 0x1000, "Service Discovery Server Service Class" },
{ 0x1001, "Browse Group Descriptor Service Class" },
{ 0x1002, "Public Browse Root" },
{ 0x1101, "Serial Port" },
{ 0x1102, "LAN Access Using PPP" },
{ 0x1103, "Dialup Networking" },
{ 0x1104, "IrMC Sync" },
{ 0x1105, "OBEX Object Push" },
{ 0x1106, "OBEX File Transfer" },
{ 0x1107, "IrMC Sync Command" },
{ 0x1108, "Headset" },
{ 0x1109, "Cordless Telephony" },
{ 0x110a, "Audio Source" },
{ 0x110b, "Audio Sink" },
{ 0x110c, "A/V Remote Control Target" },
{ 0x110d, "Advanced Audio Distribution" },
{ 0x110e, "A/V Remote Control" },
{ 0x110f, "A/V Remote Control Controller" },
{ 0x1110, "Intercom" },
{ 0x1111, "Fax" },
{ 0x1112, "Headset AG" },
{ 0x1113, "WAP" },
{ 0x1114, "WAP Client" },
{ 0x1115, "PANU" },
{ 0x1116, "NAP" },
{ 0x1117, "GN" },
{ 0x1118, "Direct Printing" },
{ 0x1119, "Reference Printing" },
{ 0x111a, "Basic Imaging Profile" },
{ 0x111b, "Imaging Responder" },
{ 0x111c, "Imaging Automatic Archive" },
{ 0x111d, "Imaging Referenced Objects" },
{ 0x111e, "Handsfree" },
{ 0x111f, "Handsfree Audio Gateway" },
{ 0x1120, "Direct Printing Refrence Objects Service" },
{ 0x1121, "Reflected UI" },
{ 0x1122, "Basic Printing" },
{ 0x1123, "Printing Status" },
{ 0x1124, "Human Interface Device Service" },
{ 0x1125, "Hardcopy Cable Replacement" },
{ 0x1126, "HCR Print" },
{ 0x1127, "HCR Scan" },
{ 0x1128, "Common ISDN Access" },
{ 0x112d, "SIM Access" },
{ 0x112e, "Phonebook Access Client" },
{ 0x112f, "Phonebook Access Server" },
{ 0x1130, "Phonebook Access" },
{ 0x1131, "Headset HS" },
{ 0x1132, "Message Access Server" },
{ 0x1133, "Message Notification Server" },
{ 0x1134, "Message Access Profile" },
{ 0x1135, "GNSS" },
{ 0x1136, "GNSS Server" },
{ 0x1200, "PnP Information" },
{ 0x1201, "Generic Networking" },
{ 0x1202, "Generic File Transfer" },
{ 0x1203, "Generic Audio" },
{ 0x1204, "Generic Telephony" },
{ 0x1205, "UPNP Service" },
{ 0x1206, "UPNP IP Service" },
{ 0x1300, "UPNP IP PAN" },
{ 0x1301, "UPNP IP LAP" },
{ 0x1302, "UPNP IP L2CAP" },
{ 0x1303, "Video Source" },
{ 0x1304, "Video Sink" },
{ 0x1305, "Video Distribution" },
{ 0x1400, "HDP" },
{ 0x1401, "HDP Source" },
{ 0x1402, "HDP Sink" },
{ 0x1800, "Generic Access Profile" },
{ 0x1801, "Generic Attribute Profile" },
{ 0x1802, "Immediate Alert" },
{ 0x1803, "Link Loss" },
{ 0x1804, "Tx Power" },
{ 0x1805, "Current Time Service" },
{ 0x1806, "Reference Time Update Service" },
{ 0x1807, "Next DST Change Service" },
{ 0x1808, "Glucose" },
{ 0x1809, "Health Thermometer" },
{ 0x180a, "Device Information" },
/* 0x180b and 0x180c undefined */
{ 0x180d, "Heart Rate" },
{ 0x180e, "Phone Alert Status Service" },
{ 0x180f, "Battery Service" },
{ 0x1810, "Blood Pressure" },
{ 0x1811, "Alert Notification Service" },
{ 0x1812, "Human Interface Device" },
{ 0x1813, "Scan Parameters" },
{ 0x1814, "Running Speed and Cadence" },
/* 0x1815 undefined */
{ 0x1816, "Cycling Speed and Cadence" },
{ 0x2800, "Primary Service" },
{ 0x2801, "Secondary Service" },
{ 0x2802, "Include" },
{ 0x2803, "Characteristic" },
{ 0x2900, "Characteristic Extended Properties" },
{ 0x2901, "Characteristic User Description" },
{ 0x2902, "Client Characteristic Configuration" },
{ 0x2903, "Server Characteristic Configuration" },
{ 0x2904, "Characteristic Format" },
{ 0x2905, "Characteristic Aggregate Formate" },
{ 0x2906, "Valid Range" },
{ 0x2907, "External Report Reference" },
{ 0x2908, "Report Reference" },
{ 0x2a00, "Device Name" },
{ 0x2a01, "Appearance" },
{ 0x2a02, "Peripheral Privacy Flag" },
{ 0x2a03, "Reconnection Address" },
{ 0x2a04, "Peripheral Preferred Connection Parameters" },
{ 0x2a05, "Service Changed" },
{ 0x2a06, "Alert Level" },
{ 0x2a07, "Tx Power Level" },
{ 0x2a08, "Date Time" },
{ 0x2a09, "Day of Week" },
{ 0x2a0a, "Day Date Time" },
/* 0x2a0b undefined */
{ 0x2a0c, "Exact Time 256" },
{ 0x2a0d, "DST Offset" },
{ 0x2a0e, "Time Zone" },
{ 0x2a0f, "Local Time Information" },
/* 0x2a10 undefined */
{ 0x2a11, "Time with DST" },
{ 0x2a12, "Time Accuracy" },
{ 0x2a13, "Time Source" },
{ 0x2a14, "Reference Time Information" },
/* 0x2a15 undefined */
{ 0x2a16, "Time Update Control Point" },
{ 0x2a17, "Time Update State" },
{ 0x2a18, "Glucose Measurement" },
{ 0x2a19, "Battery Level" },
/* 0x2a1a and 0x2a1b undefined */
{ 0x2a1c, "Temperature Measurement" },
{ 0x2a1d, "Temperature Type" },
{ 0x2a1e, "Intermediate Temperature" },
/* 0x2a1f and 0x2a20 undefined */
{ 0x2a21, "Measurement Interval" },
{ 0x2a22, "Boot Keyboard Input Report" },
{ 0x2a23, "System ID" },
{ 0x2a24, "Model Number String" },
{ 0x2a25, "Serial Number String" },
{ 0x2a26, "Firmware Revision String" },
{ 0x2a27, "Hardware Revision String" },
{ 0x2a28, "Software Revision String" },
{ 0x2a29, "Manufacturer Name String" },
{ 0x2a2a, "IEEE 11073-20601 Regulatory Cert. Data List" },
{ 0x2a2b, "Current Time" },
/* 0x2a2c to 0x2a30 undefined */
{ 0x2a31, "Scan Refresh" },
{ 0x2a32, "Boot Keyboard Output Report" },
{ 0x2a33, "Boot Mouse Input Report" },
{ 0x2a34, "Glucose Measurement Context" },
{ 0x2a35, "Blood Pressure Measurement" },
{ 0x2a36, "Intermediate Cuff Pressure" },
{ 0x2a37, "Heart Rate Measurement" },
{ 0x2a38, "Body Sensor Location" },
{ 0x2a39, "Heart Rate Control Point" },
/* 0x2a3a to 0x2a3e undefined */
{ 0x2a3f, "Alert Status" },
{ 0x2a40, "Ringer Control Point" },
{ 0x2a41, "Ringer Setting" },
{ 0x2a42, "Alert Category ID Bit Mask" },
{ 0x2a43, "Alert Category ID" },
{ 0x2a44, "Alert Notification Control Point" },
{ 0x2a45, "Unread Alert Status" },
{ 0x2a46, "New Alert" },
{ 0x2a47, "Supported New Alert Category" },
{ 0x2a48, "Supported Unread Alert Category" },
{ 0x2a49, "Blood Pressure Feature" },
{ 0x2a4a, "HID Information" },
{ 0x2a4b, "Report Map" },
{ 0x2a4c, "HID Control Point" },
{ 0x2a4d, "Report" },
{ 0x2a4e, "Protocol Mode" },
{ 0x2a4f, "Scan Interval Window" },
{ 0x2a50, "PnP ID" },
{ 0x2a51, "Glucose Feature" },
{ 0x2a52, "Record Access Control Point" },
{ 0x2a53, "RSC Measurement" },
{ 0x2a54, "RSC Feature" },
{ 0x2a55, "SC Control Point" },
/* 0x2a56 to 0x2a5a undefined */
{ 0x2a5b, "CSC Measurement" },
{ 0x2a5c, "CSC Feature" },
{ 0x2a5d, "Sensor Location" },
{ }
};
const char *uuid16_to_str(uint16_t uuid)
{
int i;
for (i = 0; uuid16_table[i].str; i++) {
if (uuid16_table[i].uuid == uuid)
return uuid16_table[i].str;
}
return "Unknown";
}
const char *uuid32_to_str(uint32_t uuid)
{
if ((uuid & 0xffff0000) == 0x0000)
return uuid16_to_str(uuid & 0x0000ffff);
return "Unknown";
}
const char *uuid128_to_str(const unsigned char *uuid)
{
return "Unknown";
}
const char *uuidstr_to_str(const char *uuid)
{
uint32_t val;
if (!uuid)
return NULL;
if (strlen(uuid) != 36)
return NULL;
if (strncasecmp(uuid + 8, "-0000-1000-8000-00805f9b34fb", 28))
return "Vendor specific";
if (sscanf(uuid, "%08x-0000-1000-8000-00805f9b34fb", &val) != 1)
return NULL;
return uuid32_to_str(val);
}

View File

@@ -0,0 +1,31 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
const char *uuid16_to_str(uint16_t uuid);
const char *uuid32_to_str(uint32_t uuid);
const char *uuid128_to_str(const unsigned char *uuid);
const char *uuidstr_to_str(const char *uuid);

View File

@@ -0,0 +1,35 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "packet.h"
#include "vendor.h"
void vendor_event(uint16_t manufacturer, const void *data, uint8_t size)
{
packet_hexdump(data, size);
}

View File

@@ -0,0 +1,27 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
void vendor_event(uint16_t manufacturer, const void *data, uint8_t size);