diff options
author | Ruben Undheim <ruben.undheim@gmail.com> | 2018-08-10 09:45:25 +0200 |
---|---|---|
committer | Ruben Undheim <ruben.undheim@gmail.com> | 2018-08-10 09:45:25 +0200 |
commit | 8d1250c286f3b33bffbb89ae6756c7703f9b8d16 (patch) | |
tree | 3e75768105738e3efe7ff751b0b161808abe66c0 | |
parent | 7b9ad0d7d67e208cd65b7f0e647b41b2b09cc43e (diff) |
New upstream version 2018.08.R1
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | changelog | 7 | ||||
-rw-r--r-- | firmware/bluetooth_rxtx/bluetooth_le.h | 3 | ||||
-rw-r--r-- | firmware/bluetooth_rxtx/bluetooth_rxtx.c | 44 | ||||
-rw-r--r-- | firmware/bluetooth_rxtx/le_phy.c | 108 | ||||
-rw-r--r-- | firmware/bluetooth_rxtx/ubertooth_usb.c | 2 | ||||
-rw-r--r-- | host/CMakeLists.txt | 2 | ||||
-rw-r--r-- | host/cmake/set_release.cmake | 2 | ||||
-rw-r--r-- | host/doc/man/ubertooth-btle.1 | 47 | ||||
-rw-r--r-- | host/doc/ubertooth-btle.md | 34 | ||||
-rw-r--r-- | host/libubertooth/src/ubertooth_control.c | 27 | ||||
-rw-r--r-- | host/libubertooth/src/ubertooth_control.h | 4 | ||||
-rw-r--r-- | host/libubertooth/src/ubertooth_interface.h | 2 | ||||
-rw-r--r-- | host/ubertooth-tools/src/ubertooth-btle.c | 91 | ||||
-rw-r--r-- | tools/RELEASENOTES | 29 |
15 files changed, 333 insertions, 73 deletions
@@ -6,10 +6,10 @@ suitable for Bluetooth experimentation. Ubertooth ships with a capable BLE (Bluetooth Smart) sniffer and can sniff some data from Basic Rate (BR) Bluetooth Classic connections. -The latest release is [2018-06-R1](https://github.com/greatscottgadgets/ubertooth/releases/tag/2018-06-R1). +The latest release is [2018-08-R1](https://github.com/greatscottgadgets/ubertooth/releases/tag/2018-08-R1). The latest firmware build can be found on the release page. -This release is paired with [libbtbb 2018-06-R1](https://github.com/greatscottgadgets/libbtbb/releases/tag/2018-06-R1). +This release is paired with [libbtbb 2018-08-R1](https://github.com/greatscottgadgets/libbtbb/releases/tag/2018-08-R1). Instructions for flashing the firmware can be found [on the corresponding Wiki page](https://github.com/greatscottgadgets/ubertooth/wiki/Firmware). Instructions for building libbrbb can be found [on the corresponding Wiki page](https://github.com/greatscottgadgets/ubertooth/wiki/Build-Guide). @@ -1,3 +1,10 @@ +ubertooth (2018-08-R1) unstable; urgency=low + * Support for partial channel map updates + * LE no-follow mode (advertising packets only) + * USB API version bumped to 1.04 + + -- Mike Ryan <mikeryan@lacklustre.net> 07 Aug 2018 15:20:00 -0700 + ubertooth (2018-06-R1) unstable; urgency=low * Brand new LE sniffing engine * Support for partial channel maps and channel map updates during connection diff --git a/firmware/bluetooth_rxtx/bluetooth_le.h b/firmware/bluetooth_rxtx/bluetooth_le.h index 1830416..ac1ec4d 100644 --- a/firmware/bluetooth_rxtx/bluetooth_le.h +++ b/firmware/bluetooth_rxtx/bluetooth_le.h @@ -59,7 +59,10 @@ typedef struct _le_state_t { u8 win_size_update; // the new window size u16 win_offset_update; // the new window offset + int do_follow; // 1 if follow connections, 0 to only log advertising packets + u8 target[6]; // target MAC for connection following (byte order reversed) + u8 target_mask[6]; // mask for MAC connection following (byte order reversed) int target_set; // whether a target has been set (default: false) u32 last_packet; // when was the last packet received } le_state_t; diff --git a/firmware/bluetooth_rxtx/bluetooth_rxtx.c b/firmware/bluetooth_rxtx/bluetooth_rxtx.c index 6982c01..3bfbec3 100644 --- a/firmware/bluetooth_rxtx/bluetooth_rxtx.c +++ b/firmware/bluetooth_rxtx/bluetooth_rxtx.c @@ -88,6 +88,7 @@ le_state_t le = { .link_state = LINK_INACTIVE, .conn_epoch = 0, + .do_follow = 1, .target_set = 0, .last_packet = 0, }; @@ -538,6 +539,7 @@ static int vendor_request_handler(uint8_t request, uint16_t* request_params, uin break; case UBERTOOTH_BTLE_SNIFFING: + le.do_follow = request_params[0]; *data_len = 0; do_hop = 0; @@ -647,13 +649,41 @@ static int vendor_request_handler(uint8_t request, uint16_t* request_params, uin case UBERTOOTH_BTLE_SET_TARGET: // Addresses appear in packets in reverse-octet order. // Store the target address in reverse order so that we can do a simple memcmp later - le.target[0] = data[5]; - le.target[1] = data[4]; - le.target[2] = data[3]; - le.target[3] = data[2]; - le.target[4] = data[1]; - le.target[5] = data[0]; - le.target_set = 1; + if (data[6] > 48) { + return 1; // invalid mask + } + else if (data[6] == 0) { + le.target_set = 0; + memset(le.target, 0, 6); + memset(le.target_mask, 0, 6); + } else { + unsigned last; + + for (i = 0; i < 6; ++i) + le.target[i] = data[5-i]; + + // compute mask + memset(le.target_mask, 0, 6); + for (i = 5; data[6] > 8; --i, data[6] -= 8) { + le.target_mask[i] = 0xff; + } + last = i; + + if (data[6] > 0) { + uint8_t final_byte = 0; + for (i = 0; i < data[6]; ++i) { + final_byte >>= 1; + final_byte |= 0b10000000; + } + le.target_mask[last] = final_byte; + } + + // in case the user specifies a bad mask + for (i = 0; i < 5; ++i) + le.target[i] &= le.target_mask[i]; + + le.target_set = 1; + } break; case UBERTOOTH_CANCEL_FOLLOW: diff --git a/firmware/bluetooth_rxtx/le_phy.c b/firmware/bluetooth_rxtx/le_phy.c index 2f4782d..caafbde 100644 --- a/firmware/bluetooth_rxtx/le_phy.c +++ b/firmware/bluetooth_rxtx/le_phy.c @@ -112,6 +112,11 @@ typedef struct _le_conn_t { uint16_t conn_event_counter; + int conn_update_pending; + uint32_t conn_update_pending_interval; + uint32_t conn_update_pending_supervision_timeout; + uint16_t conn_update_instant; + int channel_map_update_pending; uint16_t channel_map_update_instant; le_channel_remapping_t pending_remapping; @@ -202,8 +207,9 @@ static void reset_conn_event(void) { // finish a connection event // // 1) update the anchor point (see details below) -// 2) check if supervision timeout is exceeded -// 2) setup radio for next packet (data or adv if timeout exceeded) +// 2) increment connection event counter +// 3) check if supervision timeout is exceeded +// 4) setup radio for next packet (data or adv if timeout exceeded) // // anchor update logic can be summarized thusly: // 1) if we received two packets, set the connection anchor to the @@ -558,11 +564,45 @@ static void timer1_cancel_fs_lock(void) { } void TIMER1_IRQHandler(void) { + // MR0: connection events if (T1IR & TIR_MR0_Interrupt) { // ack the interrupt T1IR = TIR_MR0_Interrupt; - // channel map update, can be interleaved with connection update + // connection update procedure + if (conn.conn_update_pending && + conn.conn_event_counter == conn.conn_update_instant) { + + // on the first past through, handle the transmit window + // offset. if there's no offset, skip down to else block + if (!conn_event.opened && conn.win_offset > 0) { + timer1_set_match(conn.last_anchor + conn.conn_interval + + conn.win_offset - RX_WARMUP_TIME); + conn_event.opened = 1; + } + + // after the transmit window offset, or if there is no + // transmit window, set a packet timeout and change the + // channel + else { // conn_event.opened || conn.win_offset == 0 + conn_event.opened = 1; + + // this is like a new connection, so set all values + // accordingly + conn.anchor_set = 0; + conn.conn_interval = conn.conn_update_pending_interval; + conn.supervision_timeout = conn.conn_update_pending_supervision_timeout; + conn.conn_update_pending = 0; + + // timeout after conn window + max packet length + timer1_set_match(conn.last_anchor + conn.conn_interval + + conn.win_offset + conn.win_size + USEC(2120)); + change_channel(); + } + return; + } + + // channel map update if (conn.channel_map_update_pending && conn.conn_event_counter == conn.channel_map_update_instant) { conn.remapping = conn.pending_remapping; @@ -577,9 +617,25 @@ void TIMER1_IRQHandler(void) { change_channel(); } - // timeout: close connection event and set timer for next hop + // regular connection event, plus timeout from connection updates + // FIXME connection update timeouts and initial connection + // timeouts need to be handled differently: they should have a + // full window until the packets from the new connection are + // captured and a new anchor is set. else { - finish_conn_event(); + // new connection event: set timeout and change channel + if (!conn_event.opened) { + conn_event.opened = 1; + + // timeout is max packet length + warmup time (slack) + timer1_set_match(NOW + USEC(2120) + RX_WARMUP_TIME); + change_channel(); + } + + // timeout: close connection event and set timer for next hop + else { + finish_conn_event(); + } } } @@ -687,6 +743,9 @@ static void le_connect_handler(le_rx_t *buf) { uint32_t aa, crc_init; uint32_t win_size, max_win_size; + if (!le.do_follow) + return; + if (buf->size != 2 + 6 + 6 + 22 + 3) return; @@ -747,6 +806,24 @@ err_out: reset_conn(); } +static void connection_update_handler(le_rx_t *buf) { + conn.win_size = extract_field(buf, 3, 1); + conn.win_offset = extract_field(buf, 4, 2); + conn.conn_update_pending_interval = extract_field(buf, 6, 2); + conn.conn_update_pending_supervision_timeout = extract_field(buf, 10, 2); + conn.conn_update_instant = extract_field(buf, 12, 2); + + // TODO check for invalid values. XXX what do we even do in that + // case? we will probably drop the connection, but at least it's on + // our own terms and not some impossibly long supervision timeout. + conn.win_size *= USEC(1250); + conn.win_offset *= USEC(1250); + conn.conn_update_pending_interval *= USEC(1250); + conn.conn_update_pending_supervision_timeout *= MSEC(10); + + conn.conn_update_pending = 1; +} + static void channel_map_update_handler(le_rx_t *buf) { conn.channel_map_update_pending = 1; conn.channel_map_update_instant = extract_field(buf, 8, 2); @@ -759,6 +836,7 @@ static void packet_handler(le_rx_t *buf) { switch (buf->data[0] & 0xf) { // CONNECT_REQ case 0x05: + // TODO validate length le_connect_handler(buf); break; } @@ -769,6 +847,12 @@ static void packet_handler(le_rx_t *buf) { // LL control PDU if ((buf->data[0] & 0b11) == 0b11 && buf->data[1] > 0) { switch (buf->data[2]) { + // LE_CONNECTION_UPDATE_REQ -- update connection parameters + case 0x0: + if (buf->data[1] == 12) + connection_update_handler(buf); + break; + // LE_CHANNEL_MAP_REQ -- update channel map case 0x1: if (buf->data[1] == 8) @@ -777,7 +861,15 @@ static void packet_handler(le_rx_t *buf) { } } } +} +// compare a BD addr against target with mask +static int bd_addr_cmp(uint8_t *bd_addr) { + unsigned i; + for (i = 0; i < 6; ++i) + if ((bd_addr[i] & le.target_mask[i]) != le.target[i]) + return 0; + return 1; } static int filter_match(le_rx_t *buf) { @@ -797,7 +889,7 @@ static int filter_match(le_rx_t *buf) { // header + one address if (buf->size < 2 + 6) return 0; - return memcmp(&buf->data[2], le.target, 6) == 0; + return bd_addr_cmp(&buf->data[2]); break; // ADV_DIRECT_IND, SCAN_REQ, CONNECT_REQ @@ -807,8 +899,8 @@ static int filter_match(le_rx_t *buf) { // header + two addresses if (buf->size < 2 + 6 + 6) return 0; - return memcmp(&buf->data[2], le.target, 6) == 0 || - memcmp(&buf->data[8], le.target, 6) == 0; + return bd_addr_cmp(&buf->data[2]) || + bd_addr_cmp(&buf->data[8]); break; default: diff --git a/firmware/bluetooth_rxtx/ubertooth_usb.c b/firmware/bluetooth_rxtx/ubertooth_usb.c index 939aaa0..cc27a18 100644 --- a/firmware/bluetooth_rxtx/ubertooth_usb.c +++ b/firmware/bluetooth_rxtx/ubertooth_usb.c @@ -91,7 +91,7 @@ static u8 abDescriptors[] = { MAX_PACKET_SIZE0, // bMaxPacketSize LE_WORD(ID_VENDOR), // idVendor LE_WORD(ID_PRODUCT), // idProduct - LE_WORD(0x0103), // bcdDevice + LE_WORD(0x0105), // bcdDevice 0x01, // iManufacturer 0x02, // iProduct 0x03, // iSerialNumber diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 7ecca53..ea0dfa6 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -26,7 +26,7 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules CACHE STRING "CMake module path") set(MAJOR_VERSION 1 CACHE INT "libUbertooth major version number") -set(MINOR_VERSION 0 CACHE INT "libUbertooth minor version number") +set(MINOR_VERSION 1 CACHE INT "libUbertooth minor version number") set( VERSION ${MAJOR_VERSION}.${MINOR_VERSION} ) add_definitions( -DVERSION="${VERSION}" ) diff --git a/host/cmake/set_release.cmake b/host/cmake/set_release.cmake index 39851e8..74628b2 100644 --- a/host/cmake/set_release.cmake +++ b/host/cmake/set_release.cmake @@ -6,7 +6,7 @@ # tagged if(NOT DEFINED RELEASE_STRING) - set(LATEST_RELEASE "2018-06-R1") + set(LATEST_RELEASE "2018-08-R1") execute_process( COMMAND git log -n 1 --format=%h diff --git a/host/doc/man/ubertooth-btle.1 b/host/doc/man/ubertooth-btle.1 index b97deb5..110bd00 100644 --- a/host/doc/man/ubertooth-btle.1 +++ b/host/doc/man/ubertooth-btle.1 @@ -1,4 +1,4 @@ -.TH UBERTOOTH\-BTLE 1 "March 2017" "Project Ubertooth" "User Commands" +.TH UBERTOOTH\-BTLE 1 "July 2018" "Project Ubertooth" "User Commands" .SH NAME .PP ubertooth\-btle \-\- Bluetooth Low Energy (BLE) sniffing and more @@ -36,6 +36,9 @@ sent between the central and peripheral. After the connection terminates, Ubertooth will return to the advertising channel and wait for another connection. .PP +No\-follow mode is similar to follow mode, but it only logs advertising +packets and will not follow connections as they are established. +.PP Promiscuous mode is an experimental mode for sniffing connections after they have already been established. This mode can be used to sniff long\-lived connections. @@ -56,7 +59,34 @@ ubertooth\-btle \-f \-t22:44:66:88:AA:CC .fi .RE .PP -In both sniffing modes, Ubertooth can log data to PCAP or PcapNG with a +\fB\fC\-t\fR can also take a mask length in CIDR\-like notation. Masks can be +between 1 and 48 bits long, with a 48 bit mask matching the entire +address. Using a /24 mask will filter on just the OUI. For example, to +limit sniffing to just TI devices with the OUI 00:1A:7D, use the +following: +.PP +.RS +.nf +ubertooth\-btle \-t 00:1A:7D:00:00:00/24 +.fi +.RE +.PP +Filters persist until they are explicitly cleared or the system restarts +(either via \fB\fCubertooth\-util \-r\fR or unplug/replug). To clear a filter, +use the special filter \fB\fCnone\fR\&. Example: +.PP +.RS +.nf +ubertooth\-btle \-t none +.fi +.RE +.PP +When filtering, previous versions of the firmware would still log all +advertising packets but only follow connections based on the filter +parameters. As of 2018\-06\-R1, advertising packets that do not match the +filter are dropped. +.PP +In all sniffing modes, Ubertooth can log data to PCAP or PcapNG with a variety of pseudoheaders. The recommended logging format is PcapNG (\fB\fC\-r\fR) or PCAP with LE Pseudoheader (\fB\fC\-q\fR). For compatibility with crackle (see [USING WITH CRACKLE][]), use PCAP with PPI (\fB\fC\-c\fR). @@ -83,6 +113,14 @@ ubertooth\-btle \-f \-A 38 \-r log.pcapng .fi .RE .PP +Log advertising packets without following connections: +.PP +.RS +.nf +ubertooth\-btle \-n +.fi +.RE +.PP Interfere with connections recovered with promiscuous mode: .PP .RS @@ -111,6 +149,9 @@ Major modes: \fB\fC\-f\fR : Follow mode: sniff connections as they are established .IP \(bu 2 +\fB\fC\-n\fR : +No\-follow mode: log advertising packets but don't follow connections +.IP \(bu 2 \fB\fC\-p\fR : Promiscuous mode: sniff already\-established connections .IP \(bu 2 @@ -193,5 +234,5 @@ Refer to \fB\fCcrackle\fR documentation for further details. \[la]https://github.com/mikeryan/crackle\[ra] .SH COPYRIGHT .PP -\fB\fCubertooth\-btle\fR is Copyright (C) 2012\-2017 Mike Ryan. This tool is +\fB\fCubertooth\-btle\fR is Copyright (C) 2012\-2018 Mike Ryan. This tool is released under the GPLv2. Refer to COPYING for futher details. diff --git a/host/doc/ubertooth-btle.md b/host/doc/ubertooth-btle.md index 087f36e..fee2f53 100644 --- a/host/doc/ubertooth-btle.md +++ b/host/doc/ubertooth-btle.md @@ -1,4 +1,4 @@ -# UBERTOOTH-BTLE 1 "March 2017" "Project Ubertooth" "User Commands" +# UBERTOOTH-BTLE 1 "July 2018" "Project Ubertooth" "User Commands" ## NAME @@ -29,6 +29,9 @@ sent between the central and peripheral. After the connection terminates, Ubertooth will return to the advertising channel and wait for another connection. +No-follow mode is similar to follow mode, but it only logs advertising +packets and will not follow connections as they are established. + Promiscuous mode is an experimental mode for sniffing connections after they have already been established. This mode can be used to sniff long-lived connections. @@ -45,7 +48,26 @@ sniff connections where the central or peripheral's BD ADDR is ubertooth-btle -f -t22:44:66:88:AA:CC -In both sniffing modes, Ubertooth can log data to PCAP or PcapNG with a +`-t` can also take a mask length in CIDR-like notation. Masks can be +between 1 and 48 bits long, with a 48 bit mask matching the entire +address. Using a /24 mask will filter on just the OUI. For example, to +limit sniffing to just TI devices with the OUI 00:1A:7D, use the +following: + + ubertooth-btle -t 00:1A:7D:00:00:00/24 + +Filters persist until they are explicitly cleared or the system restarts +(either via `ubertooth-util -r` or unplug/replug). To clear a filter, +use the special filter `none`. Example: + + ubertooth-btle -t none + +When filtering, previous versions of the firmware would still log all +advertising packets but only follow connections based on the filter +parameters. As of 2018-06-R1, advertising packets that do not match the +filter are dropped. + +In all sniffing modes, Ubertooth can log data to PCAP or PcapNG with a variety of pseudoheaders. The recommended logging format is PcapNG (`-r`) or PCAP with LE Pseudoheader (`-q`). For compatibility with crackle (see [USING WITH CRACKLE][]), use PCAP with PPI (`-c`). @@ -69,6 +91,10 @@ PcapNG: ubertooth-btle -f -A 38 -r log.pcapng +Log advertising packets without following connections: + + ubertooth-btle -n + Interfere with connections recovered with promiscuous mode: ubertooth-btle -p -I @@ -86,6 +112,8 @@ Major modes: - `-f` : Follow mode: sniff connections as they are established + - `-n` : + No-follow mode: log advertising packets but don't follow connections - `-p` : Promiscuous mode: sniff already-established connections - `-s<BD ADDR>` : @@ -147,5 +175,5 @@ crackle(1): https://github.com/mikeryan/crackle ## COPYRIGHT -`ubertooth-btle` is Copyright (C) 2012-2017 Mike Ryan. This tool is +`ubertooth-btle` is Copyright (C) 2012-2018 Mike Ryan. This tool is released under the GPLv2. Refer to COPYING for futher details. diff --git a/host/libubertooth/src/ubertooth_control.c b/host/libubertooth/src/ubertooth_control.c index 6b90fc2..a542caf 100644 --- a/host/libubertooth/src/ubertooth_control.c +++ b/host/libubertooth/src/ubertooth_control.c @@ -724,11 +724,11 @@ uint32_t cmd_get_clock(struct libusb_device_handle* devh) return clock; } -int cmd_btle_sniffing(struct libusb_device_handle* devh, u16 num) +int cmd_btle_sniffing(struct libusb_device_handle* devh, uint8_t do_follow) { int r; - r = libusb_control_transfer(devh, CTRL_OUT, UBERTOOTH_BTLE_SNIFFING, num, 0, + r = libusb_control_transfer(devh, CTRL_OUT, UBERTOOTH_BTLE_SNIFFING, do_follow, 0, NULL, 0, 1000); if (r < 0) { if (r == LIBUSB_ERROR_PIPE) { @@ -866,11 +866,16 @@ int cmd_set_crc_verify(struct libusb_device_handle* devh, int verify) int cmd_poll(struct libusb_device_handle* devh, usb_pkt_rx *p) { int r; - - r = libusb_control_transfer(devh, CTRL_IN, UBERTOOTH_POLL, 0, 0, - (u8 *)p, sizeof(usb_pkt_rx), 1000); - if (r < 0) { - show_libusb_error(r); + unsigned i; + + // retry up to three times due to stalls + for (i = 0; i < 3; ++i) { + r = libusb_control_transfer(devh, CTRL_IN, UBERTOOTH_POLL, 0, 0, + (u8 *)p, sizeof(usb_pkt_rx), 1000); + if (r == LIBUSB_ERROR_PIPE) // retry + continue; + if (r < 0) + show_libusb_error(r); return r; } return r; @@ -930,12 +935,16 @@ int cmd_btle_slave(struct libusb_device_handle* devh, u8 *mac_address) return 0; } -int cmd_btle_set_target(struct libusb_device_handle* devh, u8 *mac_address) +int cmd_btle_set_target(struct libusb_device_handle* devh, uint8_t *mac_address, uint8_t mac_mask) { int r; + uint8_t cmd_buf[7]; + + memcpy(cmd_buf, mac_address, 6); + cmd_buf[6] = mac_mask; r = libusb_control_transfer(devh, CTRL_OUT, UBERTOOTH_BTLE_SET_TARGET, 0, 0, - mac_address, 6, 1000); + cmd_buf, 7, 1000); if (r < 0) { if (r == LIBUSB_ERROR_PIPE) { fprintf(stderr, "control message unsupported\n"); diff --git a/host/libubertooth/src/ubertooth_control.h b/host/libubertooth/src/ubertooth_control.h index e53f70f..675b899 100644 --- a/host/libubertooth/src/ubertooth_control.h +++ b/host/libubertooth/src/ubertooth_control.h @@ -124,7 +124,7 @@ int cmd_set_clock(struct libusb_device_handle* devh, u32 clkn); uint32_t cmd_get_clock(struct libusb_device_handle* devh); int cmd_set_afh_map(struct libusb_device_handle* devh, u8* afh_map); int cmd_clear_afh_map(struct libusb_device_handle* devh); -int cmd_btle_sniffing(struct libusb_device_handle* devh, u16 num); +int cmd_btle_sniffing(struct libusb_device_handle* devh, uint8_t do_follow); u32 cmd_get_access_address(struct libusb_device_handle* devh); int cmd_set_access_address(struct libusb_device_handle* devh, u32 access_address); int cmd_do_something(struct libusb_device_handle *devh, unsigned char *data, int len); @@ -135,7 +135,7 @@ int cmd_poll(struct libusb_device_handle* devh, usb_pkt_rx *p); int cmd_btle_promisc(struct libusb_device_handle* devh); int cmd_read_register(struct libusb_device_handle* devh, u8 reg); int cmd_btle_slave(struct libusb_device_handle* devh, u8 *mac_address); -int cmd_btle_set_target(struct libusb_device_handle* devh, u8 *mac_address); +int cmd_btle_set_target(struct libusb_device_handle* devh, uint8_t *mac_address, uint8_t mac_mask); int cmd_set_jam_mode(struct libusb_device_handle* devh, int mode); int cmd_ego(struct libusb_device_handle* devh, int mode); int cmd_afh(struct libusb_device_handle* devh); diff --git a/host/libubertooth/src/ubertooth_interface.h b/host/libubertooth/src/ubertooth_interface.h index 01e8796..b170332 100644 --- a/host/libubertooth/src/ubertooth_interface.h +++ b/host/libubertooth/src/ubertooth_interface.h @@ -25,7 +25,7 @@ #include <stdint.h> // increment on every API change -#define UBERTOOTH_API_VERSION 0x0103 +#define UBERTOOTH_API_VERSION 0x0105 #define DMA_SIZE 50 diff --git a/host/ubertooth-tools/src/ubertooth-btle.c b/host/ubertooth-tools/src/ubertooth-btle.c index 0583fad..2959a2c 100644 --- a/host/ubertooth-tools/src/ubertooth-btle.c +++ b/host/ubertooth-tools/src/ubertooth-btle.c @@ -42,8 +42,38 @@ static void quit(int sig __attribute__((unused))) { running = 0; } -int convert_mac_address(char *s, uint8_t *o) { +void print_mac(uint8_t *mac_address, int mask) { + unsigned i; + for (i = 0; i < 5; ++i) + printf("%02x:", mac_address[i]); + printf("%02x", mac_address[5]); + if (mask >= 0) + printf("/%u", mask); +} + +int convert_mac_address(char *s, uint8_t *o, uint8_t *mask_out) { int i; + char *mask_p; + unsigned mask = 48; // default mask is entire BD ADDR + + if (strcmp(s, "none") == 0) { + memset(o, 0, 6); + mask_out = 0; + return 1; + } + + // if there is a mask included, parse it + mask_p = strchr(s, '/'); + if (mask_p != NULL) { + *mask_p = '\0'; + ++mask_p; + mask = strtoul(mask_p, NULL, 10); + if (mask > 48) { + printf("Error: MAC mask must be between 0 and 48\n"); + return 0; + } + } + *mask_out = mask; // see above, default 48, otherwise user-supplied // validate length if (strlen(s) != 6 * 2 + 5) { @@ -82,10 +112,13 @@ static void usage(void) printf("\n"); printf(" Major modes:\n"); printf("\t-f follow connections\n"); + printf("\t-n don't follow, only print advertisements\n"); printf("\t-p promiscuous: sniff active connections\n"); + printf("\n"); printf("\t-a[address] get/set access address (example: -a8e89bed6)\n"); printf("\t-s<address> faux slave mode, using MAC addr (example: -s22:44:66:88:aa:cc)\n"); - printf("\t-t<address> set connection following target (example: -t22:44:66:88:aa:cc)\n"); + printf("\t-t<address> set connection following target (example: -t22:44:66:88:aa:cc/48)\n"); + printf("\t-tnone unset connection following target\n"); printf("\n"); printf(" Interference (use with -f or -p):\n"); printf("\t-i interfere with one connection and return to idle\n"); @@ -109,7 +142,7 @@ static void usage(void) int main(int argc, char *argv[]) { int opt; - int do_follow, do_promisc; + int do_follow, do_no_follow, do_promisc; int do_get_aa, do_set_aa; int do_crc; int do_adv_index; @@ -124,14 +157,15 @@ int main(int argc, char *argv[]) int r; u32 access_address; uint8_t mac_address[6] = { 0, }; + uint8_t mac_mask = 0; - do_follow = do_promisc = 0; + do_follow = do_no_follow = do_promisc = 0; do_get_aa = do_set_aa = 0; do_crc = -1; // 0 and 1 mean set, 2 means get do_adv_index = 37; do_slave_mode = do_target = 0; - while ((opt=getopt(argc,argv,"a::r:hfpU:v::A:s:t:x:c:q:jJiI")) != EOF) { + while ((opt=getopt(argc,argv,"a::r:hfnpU:v::A:s:t:x:c:q:jJiI")) != EOF) { switch(opt) { case 'a': if (optarg == NULL) { @@ -144,6 +178,9 @@ int main(int argc, char *argv[]) case 'f': do_follow = 1; break; + case 'n': + do_no_follow = 1; + break; case 'p': do_promisc = 1; break; @@ -196,7 +233,7 @@ int main(int argc, char *argv[]) break; case 's': do_slave_mode = 1; - r = convert_mac_address(optarg, mac_address); + r = convert_mac_address(optarg, mac_address, &mac_mask); if (!r) { usage(); return 1; @@ -204,7 +241,7 @@ int main(int argc, char *argv[]) break; case 't': do_target = 1; - r = convert_mac_address(optarg, mac_address); + r = convert_mac_address(optarg, mac_address, &mac_mask); if (!r) { usage(); return 1; @@ -252,12 +289,29 @@ int main(int argc, char *argv[]) // cancel following on USR1 signal(SIGUSR1, cancel_follow_handler); - if (do_follow && do_promisc) { - printf("Error: must choose either -f or -p, one or the other pal\n"); + if (do_follow + do_no_follow + do_promisc > 1) { + printf("Error: must choose one -f, -n, or -p, pick one pal\n"); return 1; } - if (do_follow || do_promisc) { + // allow user to set target before following + if (do_target) { + r = cmd_btle_set_target(ut->devh, mac_address, mac_mask); + if (r == 0) { + if (mac_mask == 0) { + printf("target cleared\n"); + } else { + printf("target set to: "); + print_mac(mac_address, mac_mask); + printf("\n"); + } + } else { + printf("Unable to set target\n"); + return 1; + } + } + + if (do_follow || do_no_follow || do_promisc) { usb_pkt_rx rx; r = cmd_set_jam_mode(ut->devh, jam_mode); @@ -267,7 +321,7 @@ int main(int argc, char *argv[]) } cmd_set_modulation(ut->devh, MOD_BT_LOW_ENERGY); - if (do_follow) { + if (do_follow || do_no_follow) { u16 channel; if (do_adv_index == 37) channel = 2402; @@ -276,7 +330,7 @@ int main(int argc, char *argv[]) else channel = 2480; cmd_set_channel(ut->devh, channel); - cmd_btle_sniffing(ut->devh, 2); + cmd_btle_sniffing(ut->devh, do_follow); } else { cmd_btle_promisc(ut->devh); } @@ -336,18 +390,7 @@ int main(int argc, char *argv[]) cmd_btle_slave(ut->devh, mac_address); } - if (do_target) { - r = cmd_btle_set_target(ut->devh, mac_address); - if (r == 0) { - int i; - printf("target set to: "); - for (i = 0; i < 5; ++i) - printf("%02x:", mac_address[i]); - printf("%02x\n", mac_address[5]); - } - } - - if (!(do_follow || do_promisc || do_get_aa || do_set_aa || + if (!(do_follow || do_no_follow || do_promisc || do_get_aa || do_set_aa || do_crc >= 0 || do_slave_mode || do_target)) usage(); diff --git a/tools/RELEASENOTES b/tools/RELEASENOTES index 2b4adaa..ed64d7f 100644 --- a/tools/RELEASENOTES +++ b/tools/RELEASENOTES @@ -1,7 +1,7 @@ -Ubertooth 2018-06-R1 Release Notes +Ubertooth 2018-08-R1 Release Notes ============================== -The Ubertooth host utilities in this release require libbtbb-2018-06-R1 -(https://github.com/greatscottgadgets/libbtbb/releases/tag/2018-06-R1) or +The Ubertooth host utilities in this release require libbtbb-2018-08-R1 +(https://github.com/greatscottgadgets/libbtbb/releases/tag/2018-08-R1) or greater. Changes @@ -21,22 +21,29 @@ connection is established as well as support for the Channel Map Update Link Layer Procedure. This allows capturing connections from virtually all modern BLE devices. -**Feature degradation** - Support for Connection Update Link Layer -Procedure has been lost as of this update. This is a relatively rare -occurrence, and it will be added in an upcoming release once it has been -fully debugged. If you encounter a device that uses this feature, please -file a bug on the project as it will help with our implementation -testing. +**Connection update support** - Support for Connection Update Link Layer +Procedure has been reimplemented as of this update. This was a feature +degradation in 2018-06-R1 but has been fixed. + +**Improved filtering** - LE filtering now applies to all advertising +packets, not just connections. Packets that do not match the filter are +silently dropped. Filters can include a CIDR-style netmask, allowing as +few as 1 or as many as 48 bits to be included in the BD ADDR filter. + +**No-follow mode** - In LE, it is now a first-class operation to only +log advertising packets (inhibit connection following). The previous +mechanism of using a filter of 00:00:00:00:00:00 is no longer +functional, and this new feature should be used instead. **USB API version** - As with the previous release, we are using USB API versioning to improve the experience of failures due to mismatched firmware and host code. As of this release, the USB API has been bumped -to 1.03. If the Ubertooth tools complain that your firmware is out of +to 1.04. If the Ubertooth tools complain that your firmware is out of date, please update your firmware. Updating firmware is simple and reliable, please follow the instructions on the wiki https://github.com/greatscottgadgets/ubertooth/wiki/Firmware A release archive with precompiled firmware is available from -https://github.com/greatscottgadgets/ubertooth/releases/download/2018-06-R1/ubertooth-2018-06-R1.tar.xz +https://github.com/greatscottgadgets/ubertooth/releases/download/2018-08-R1/ubertooth-2018-08-R1.tar.xz Support ------- |