Hi Luiz, >>> This adds -M/--mesh [nid] option to show only mesh advertisements which >>> is very convenient when monitoring noisy environments. >>> --- >>> monitor/main.c | 17 +++++++++++- >>> monitor/packet.c | 80 ++++++++++++++++++++++++++++++++++++++++++++------------ >>> monitor/packet.h | 2 ++ >>> 3 files changed, 82 insertions(+), 17 deletions(-) >>> >>> diff --git a/monitor/main.c b/monitor/main.c >>> index b4e9a6a..fb7d5f5 100644 >>> --- a/monitor/main.c >>> +++ b/monitor/main.c >>> @@ -71,6 +71,7 @@ static void usage(void) >>> "\t-S, --sco Dump SCO traffic\n" >>> "\t-A, --a2dp Dump A2DP stream traffic\n" >>> "\t-E, --ellisys [ip] Send Ellisys HCI Injection\n" >>> + "\t-M, --mesh [nid] Dump Mesh traffic only\n" >>> "\t-h, --help Show help options\n"); >>> } >>> >>> @@ -88,6 +89,7 @@ static const struct option main_options[] = { >>> { "sco", no_argument, NULL, 'S' }, >>> { "a2dp", no_argument, NULL, 'A' }, >>> { "ellisys", required_argument, NULL, 'E' }, >>> + { "mesh", optional_argument, NULL, 'M' }, >>> { "todo", no_argument, NULL, '#' }, >>> { "version", no_argument, NULL, 'v' }, >>> { "help", no_argument, NULL, 'h' }, >>> @@ -104,6 +106,7 @@ int main(int argc, char *argv[]) >>> const char *tty = NULL; >>> unsigned int tty_speed = B115200; >>> unsigned short ellisys_port = 0; >>> + int mesh_nid = -1; >>> const char *str; >>> int exit_status; >>> sigset_t mask; >>> @@ -115,7 +118,7 @@ int main(int argc, char *argv[]) >>> for (;;) { >>> int opt; >>> >>> - opt = getopt_long(argc, argv, "d:r:w:a:s:p:i:tTSAE:vh", >>> + opt = getopt_long(argc, argv, "d:r:w:a:s:p:i:tTSAE:M::vh", >>> main_options, NULL); >>> if (opt < 0) >>> break; >>> @@ -176,6 +179,18 @@ int main(int argc, char *argv[]) >>> ellisys_server = optarg; >>> ellisys_port = 24352; >>> break; >>> + case 'M': >>> + if (optarg) { >>> + mesh_nid = atoi(optarg); >> >> you also need to support hex input here as well. >> >>> + if (mesh_nid < 0 || mesh_nid > 0x7f) { >>> + fprintf(stderr, "Invalid NID: %s\n", >>> + optarg); >>> + return EXIT_FAILURE; >>> + } >>> + packet_set_mesh_nid(mesh_nid); >>> + } >>> + filter_mask |= PACKET_FILTER_MESH_ONLY; >>> + break; >>> case '#': >>> packet_todo(); >>> lmp_todo(); >>> diff --git a/monitor/packet.c b/monitor/packet.c >>> index 678d7a7..c2ba66f 100644 >>> --- a/monitor/packet.c >>> +++ b/monitor/packet.c >>> @@ -111,6 +111,7 @@ static unsigned long filter_mask = 0; >>> static bool index_filter = false; >>> static uint16_t index_number = 0; >>> static uint16_t index_current = 0; >>> +static int mesh_nid = -1; >>> >>> #define UNKNOWN_MANUFACTURER 0xffff >>> >>> @@ -268,6 +269,11 @@ void packet_select_index(uint16_t index) >>> index_number = index; >>> } >>> >>> +void packet_set_mesh_nid(uint8_t nid) >>> +{ >>> + mesh_nid = nid; >>> +} >>> + >>> #define print_space(x) printf("%*c", (x), ' '); >>> >>> #define MAX_INDEX 16 >>> @@ -8850,6 +8856,25 @@ rssi: >>> } >>> } >>> >>> +static bool le_adv_report_filter(uint8_t index, const void *data, uint8_t size) >>> +{ >>> + const struct bt_hci_evt_le_adv_report *evt = data; >>> + >>> + if (!packet_has_filter(PACKET_FILTER_MESH_ONLY)) >>> + return false; >>> + >>> + switch (evt->data[1]) { >>> + case BT_EIR_MESH_DATA: >>> + if (mesh_nid > 0 && ((evt->data[2] & 0xfe) != mesh_nid)) >>> + return true; >> >> fall through comment is missing and also mesh_nid > 0 is wrong. Then using uint8_t mesh_nid would be fine. Which is actually what I think we should be doing anyway in the first place. This a cryptographic hash. Chances are super slim that we get 0x00 here. >> >>> + case BT_EIR_MESH_PROV: >>> + case BT_EIR_MESH_BEACON: >>> + return false; >>> + } >>> + >>> + return true; >>> +} >>> + >>> static void le_conn_update_complete_evt(uint8_t index, const void *data, uint8_t size) >>> { >>> const struct bt_hci_evt_le_conn_update_complete *evt = data; >>> @@ -8998,6 +9023,7 @@ struct subevent_data { >>> void (*func) (uint8_t index, const void *data, uint8_t size); >>> uint8_t size; >>> bool fixed; >>> + bool (*filter) (uint8_t index, const void *data, uint8_t size); >>> }; >>> >>> static void print_subevent(const struct subevent_data *subevent_data, >>> @@ -9039,7 +9065,8 @@ static const struct subevent_data le_meta_event_table[] = { >>> { 0x01, "LE Connection Complete", >>> le_conn_complete_evt, 18, true }, >>> { 0x02, "LE Advertising Report", >>> - le_adv_report_evt, 1, false }, >>> + le_adv_report_evt, 1, false, >>> + le_adv_report_filter }, >>> { 0x03, "LE Connection Update Complete", >>> le_conn_update_complete_evt, 9, true }, >>> { 0x04, "LE Read Remote Used Features", >>> @@ -9072,29 +9099,45 @@ static const struct subevent_data le_meta_event_table[] = { >>> { } >>> }; >>> >>> -static void le_meta_event_evt(uint8_t index, const void *data, uint8_t size) >>> +static const struct subevent_data *le_meta_event_find(uint8_t subevent) >>> { >>> - uint8_t subevent = *((const uint8_t *) data); >>> - struct subevent_data unknown; >>> - const struct subevent_data *subevent_data = &unknown; >>> int i; >>> >>> - unknown.subevent = subevent; >>> - unknown.str = "Unknown"; >>> - unknown.func = NULL; >>> - unknown.size = 0; >>> - unknown.fixed = true; >>> - >>> for (i = 0; le_meta_event_table[i].str; i++) { >>> - if (le_meta_event_table[i].subevent == subevent) { >>> - subevent_data = &le_meta_event_table[i]; >>> - break; >>> - } >>> + if (le_meta_event_table[i].subevent == subevent) >>> + return &le_meta_event_table[i]; >>> + } >>> + >>> + return NULL; >>> +} >>> + >>> +static void le_meta_event_evt(uint8_t index, const void *data, uint8_t size) >>> +{ >>> + uint8_t subevent = *((const uint8_t *) data); >>> + const struct subevent_data *subevent_data; >>> + >>> + subevent_data = le_meta_event_find(subevent); >>> + if (!subevent_data) { >>> + print_indent(6, COLOR_HCI_EVENT_UNKNOWN, "", "", COLOR_OFF, >>> + " (0x%2.2x)", subevent); >>> + return; >>> } >>> >>> print_subevent(subevent_data, index, data + 1, size - 1); >>> } >>> >>> +static bool le_meta_event_filter(uint8_t index, const void *data, uint8_t size) >>> +{ >>> + uint8_t subevent = *((const uint8_t *) data); >>> + const struct subevent_data *subevent_data; >>> + >>> + subevent_data = le_meta_event_find(subevent); >>> + if (!subevent_data || !subevent_data->filter) >>> + return false; >>> + >>> + return subevent_data->filter(index, data + 1, size - 1); >>> +} >>> + >>> static void vendor_evt(uint8_t index, const void *data, uint8_t size) >>> { >>> uint8_t subevent = *((const uint8_t *) data); >>> @@ -9135,6 +9178,7 @@ struct event_data { >>> void (*func) (uint8_t index, const void *data, uint8_t size); >>> uint8_t size; >>> bool fixed; >>> + bool (*filter) (uint8_t index, const void *data, uint8_t size); >>> }; >>> >>> static const struct event_data event_table[] = { >>> @@ -9241,7 +9285,8 @@ static const struct event_data event_table[] = { >>> { 0x3d, "Remote Host Supported Features", >>> remote_host_features_notify_evt, 14, true }, >>> { 0x3e, "LE Meta Event", >>> - le_meta_event_evt, 1, false }, >>> + le_meta_event_evt, 1, false, >>> + le_meta_event_filter }, >> >> I really do not like this. Lets not add another function to these tables. Figure something else out. And frankly, I rather have a btmon --mesh command that focus purely on mesh advertising bearer. If not, then just leave all packets unfiltered. > > I thought about that too, but there could be other related packets, > for example GATT proxy. Frankly, if you care about GATT proxy as well, then accept that you get everything. >> Also we could just figure out on how to use BPF on the monitoring socket. Doing this outside the kernel seems pointless. > > I will look into that, didn't know BPF could be used with any packet > based socket, well if it does then I completely agree with you, if it > doesn't then we might want something that could work with older > kernels. I rather accept that it only works on newer kernels than hacking btmon into some complicated code base. That happened to hcidump and I have no intention to repeat it. Regards Marcel -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html