2012-05-22 05:40:24

by Gustavo Padovan

[permalink] [raw]
Subject: [PATCH 1/4] monitor: add include <stdint.h>

From: Gustavo Padovan <[email protected]>

---
monitor/packet.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/monitor/packet.h b/monitor/packet.h
index 90fc7ec..4c8b698 100644
--- a/monitor/packet.h
+++ b/monitor/packet.h
@@ -23,6 +23,7 @@
*/

#include <stdbool.h>
+#include <stdint.h>
#include <sys/time.h>

#define PACKET_FILTER_SHOW_INDEX (1 << 0)
--
1.7.10.1



2012-05-22 15:30:18

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH 3/4] monitor: add filter support

Hi Vinicius,

* Vinicius Costa Gomes <[email protected]> [2012-05-22 12:02:39 -0300]:

> Hi Gustavo,
>
> Here are some nitpicks, feel free to ignore them.
>
> On 02:40 Tue 22 May, Gustavo Padovan wrote:
> > From: Gustavo Padovan <[email protected]>
>
> The title "add filter support" is not totally correct, there was some
> support for filters, but it was quite basic, right?

Quite basic, and there wasn't any option to set it from command line so I
decided to call this "add filter support"

>
> >
> > the packet code receives the data parsed from the filter file and apply
> > the proper filters to the devices.
> > ---
> > monitor/config_file.c | 4 +-
> > monitor/config_file.h | 1 +
> > monitor/main.c | 21 +++++-----
> > monitor/packet.c | 108 ++++++++++++++++++++++++++++++++++++++++---------
> > monitor/packet.h | 4 +-
> > 5 files changed, 106 insertions(+), 32 deletions(-)
> >
> > diff --git a/monitor/config_file.c b/monitor/config_file.c
> > index 6fb50f9..464fe4f 100644
> > --- a/monitor/config_file.c
> > +++ b/monitor/config_file.c
> > @@ -79,7 +79,7 @@ static struct filter_options {
> >
> > struct controller *controller;
> >
> > -static void free_controllers_list(struct list *controllers_l)
> > +void controllers_list_free(struct list *controllers_l)
>
> This change is somewhat unrelated.

Kind of, I had to export this function for this patch and I changed the name
to some that makes more sense.

Gustavo

2012-05-22 15:02:39

by Vinicius Costa Gomes

[permalink] [raw]
Subject: Re: [PATCH 3/4] monitor: add filter support

Hi Gustavo,

Here are some nitpicks, feel free to ignore them.

On 02:40 Tue 22 May, Gustavo Padovan wrote:
> From: Gustavo Padovan <[email protected]>

The title "add filter support" is not totally correct, there was some
support for filters, but it was quite basic, right?

>
> the packet code receives the data parsed from the filter file and apply
> the proper filters to the devices.
> ---
> monitor/config_file.c | 4 +-
> monitor/config_file.h | 1 +
> monitor/main.c | 21 +++++-----
> monitor/packet.c | 108 ++++++++++++++++++++++++++++++++++++++++---------
> monitor/packet.h | 4 +-
> 5 files changed, 106 insertions(+), 32 deletions(-)
>
> diff --git a/monitor/config_file.c b/monitor/config_file.c
> index 6fb50f9..464fe4f 100644
> --- a/monitor/config_file.c
> +++ b/monitor/config_file.c
> @@ -79,7 +79,7 @@ static struct filter_options {
>
> struct controller *controller;
>
> -static void free_controllers_list(struct list *controllers_l)
> +void controllers_list_free(struct list *controllers_l)

This change is somewhat unrelated.

> {
> struct list *l, *tmp;
>
> @@ -318,7 +318,7 @@ struct list *parse_config(char *file)
> return controllers_l;
>
> error:


[snip]

>
> void packet_hexdump(const unsigned char *buf, uint16_t len);
>
> --
> 1.7.10.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


Cheers,
--
Vinicius

2012-05-22 05:40:27

by Gustavo Padovan

[permalink] [raw]
Subject: [PATCH 4/4] monitor: add example filter file

From: Gustavo Padovan <[email protected]>

---
monitor/filter.example | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 monitor/filter.example

diff --git a/monitor/filter.example b/monitor/filter.example
new file mode 100644
index 0000000..e84b07f
--- /dev/null
+++ b/monitor/filter.example
@@ -0,0 +1,31 @@
+#
+# Example filter file for btmon.
+#
+# It should be used with the -f option of btmon:
+#
+# $ btmon -f <filter file>
+#
+#
+# The basic structure of the file is show below, we always need a 'Controller'
+# keyword followed by a Bluetooth pattern, wild card is accepted.
+#
+# Then there is 4 possible configurations you can specify:
+# - 'Timestamps' to show timestamps or not
+# - 'Show' to selects which protocols to show, any protocol not listed here is
+# hided.
+# - 'Hide' to hide specific protocols. All the others are shown. 'Show' and
+# 'Hide' can't be used together.
+# - 'Ignore' to ignore this device in btmon.
+#
+# The available options for 'Show' and 'Hide' are l2cap, sco and hci.
+
+Controller *
+ Timestamps on
+ Show l2cap
+
+Controller 00:11:22:33:44:55
+ Timestamps off
+ Hide sco,hci
+
+Controller CA:FE:CA:FE:*
+ Ignore
--
1.7.10.1


2012-05-22 05:40:26

by Gustavo Padovan

[permalink] [raw]
Subject: [PATCH 3/4] monitor: add filter support

From: Gustavo Padovan <[email protected]>

the packet code receives the data parsed from the filter file and apply
the proper filters to the devices.
---
monitor/config_file.c | 4 +-
monitor/config_file.h | 1 +
monitor/main.c | 21 +++++-----
monitor/packet.c | 108 ++++++++++++++++++++++++++++++++++++++++---------
monitor/packet.h | 4 +-
5 files changed, 106 insertions(+), 32 deletions(-)

diff --git a/monitor/config_file.c b/monitor/config_file.c
index 6fb50f9..464fe4f 100644
--- a/monitor/config_file.c
+++ b/monitor/config_file.c
@@ -79,7 +79,7 @@ static struct filter_options {

struct controller *controller;

-static void free_controllers_list(struct list *controllers_l)
+void controllers_list_free(struct list *controllers_l)
{
struct list *l, *tmp;

@@ -318,7 +318,7 @@ struct list *parse_config(char *file)
return controllers_l;

error:
- free_controllers_list(controllers_l);
+ controllers_list_free(controllers_l);
fclose(f);
return NULL;
}
diff --git a/monitor/config_file.h b/monitor/config_file.h
index 9190e01..dd5fe79 100644
--- a/monitor/config_file.h
+++ b/monitor/config_file.h
@@ -28,3 +28,4 @@ struct controller {
};

struct list *parse_config(char *file);
+void controllers_list_free(struct list *controllers_l);
diff --git a/monitor/main.c b/monitor/main.c
index 1379839..c429333 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -68,8 +68,9 @@ static const struct option main_options[] = {

int main(int argc, char *argv[])
{
- unsigned long filter_mask = 0;
+ struct list *filter_l = NULL;
sigset_t mask;
+ int err;

mainloop_init();

@@ -82,7 +83,8 @@ int main(int argc, char *argv[])

switch (opt) {
case 'f':
- if (!parse_config(optarg))
+ filter_l = parse_config(optarg);
+ if (!filter_l)
return EXIT_FAILURE;
break;
case 'b':
@@ -105,18 +107,19 @@ int main(int argc, char *argv[])

mainloop_set_signal(&mask, signal_callback, NULL, NULL);

- filter_mask |= PACKET_FILTER_SHOW_INDEX;
- filter_mask |= PACKET_FILTER_SHOW_TIME;
- filter_mask |= PACKET_FILTER_SHOW_ACL_DATA;
-
- packet_set_filter(filter_mask);
+ packet_set_filter(filter_l);

printf("Bluetooth monitor ver %s\n", VERSION);

if (control_tracing() < 0) {
- if (hcidump_tracing() < 0)
+ if (hcidump_tracing() < 0) {
+ controllers_list_free(filter_l);
return EXIT_FAILURE;
+ }
}

- return mainloop_run();
+ err = mainloop_run();
+
+ controllers_list_free(filter_l);
+ return err;
}
diff --git a/monitor/packet.c b/monitor/packet.c
index 0f14ea6..bdc9705 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -43,18 +43,74 @@
#include "control.h"
#include "btsnoop.h"
#include "packet.h"
+#include "config_file.h"

-static unsigned long filter_mask = 0;
+#define MAX_INDEX 16
+
+struct monitor_new_index {
+ uint8_t type;
+ uint8_t bus;
+ bdaddr_t bdaddr;
+ char name[8];
+} __attribute__((packed));

-void packet_set_filter(unsigned long filter)
+struct index_filter {
+ unsigned long filter;
+ uint8_t ignore;
+};
+
+static struct monitor_new_index index_list[MAX_INDEX];
+static struct index_filter index_filter[MAX_INDEX];
+static struct list *filter_l;
+
+void packet_set_filter(struct list *filter)
{
- filter_mask = filter;
+ filter_l = filter;
+}
+
+static int filter_bacmp(char *str1, char *str2)
+{
+ int i, max;
+
+ max = strlen(str1) < 18 ? strlen(str1) : 18;
+
+ for (i = 0 ; i < max ; i++) {
+ if (str1[i] == '*')
+ return 1;
+ if (str1[i] != str2[i])
+ return 0;
+ }
+
+ return 1;
+}
+
+static void packet_set_index_filter(int index)
+{
+ char str[18];
+ struct list *l;
+
+ index_filter[index].ignore = 0;
+ index_filter[index].filter = ~0UL;
+
+ ba2str(&index_list[index].bdaddr, str);
+
+ for (l = filter_l->next ; l != filter_l ; l = l->next) {
+ if (filter_bacmp(l->controller->value, str)) {
+ index_filter[index].ignore = l->controller->ignore;
+ index_filter[index].filter = l->controller->filter;
+ }
+ }
+}
+
+static int filter_check_flag(uint16_t index, int flag)
+{
+ return (index_filter[index].filter & flag);
}

static void print_channel_header(struct timeval *tv, uint16_t index,
uint16_t channel)
{
- if (filter_mask & PACKET_FILTER_SHOW_INDEX) {
+ if (filter_check_flag(index, PACKET_FILTER_SHOW_INDEX)) {
switch (channel) {
case HCI_CHANNEL_CONTROL:
printf("{hci%d} ", index);
@@ -71,11 +127,11 @@ static void print_channel_header(struct timeval *tv, uint16_t index,

localtime_r(&t, &tm);

- if (filter_mask & PACKET_FILTER_SHOW_DATE)
+ if (filter_check_flag(index, PACKET_FILTER_SHOW_DATE))
printf("%04d-%02d-%02d ", tm.tm_year + 1900,
tm.tm_mon + 1, tm.tm_mday);

- if (filter_mask & PACKET_FILTER_SHOW_TIME)
+ if (filter_check_flag(index, PACKET_FILTER_SHOW_TIME))
printf("%02d:%02d:%02d.%06lu ", tm.tm_hour,
tm.tm_min, tm.tm_sec, tv->tv_usec);
}
@@ -128,6 +184,9 @@ void packet_hexdump(const unsigned char *buf, uint16_t len)
void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size)
{
+ if (index_filter[index].ignore)
+ return
+
print_channel_header(tv, index, HCI_CHANNEL_CONTROL);

control_message(opcode, data, size);
@@ -142,33 +201,30 @@ void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
#define MONITOR_SCO_TX_PKT 6
#define MONITOR_SCO_RX_PKT 7

-struct monitor_new_index {
- uint8_t type;
- uint8_t bus;
- bdaddr_t bdaddr;
- char name[8];
-} __attribute__((packed));
-
#define MONITOR_NEW_INDEX_SIZE 16

#define MONITOR_DEL_INDEX_SIZE 0

-#define MAX_INDEX 16
-
-static struct monitor_new_index index_list[MAX_INDEX];
-
void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size)
{
const struct monitor_new_index *ni;
char str[18];

+ if (index_filter[index].ignore)
+ return;
+
switch (opcode) {
case MONITOR_NEW_INDEX:
ni = data;

- if (index < MAX_INDEX)
+ if (index < MAX_INDEX) {
memcpy(&index_list[index], ni, MONITOR_NEW_INDEX_SIZE);
+ packet_set_index_filter(index);
+ }
+
+ if (index_filter[index].ignore)
+ break;

ba2str(&ni->bdaddr, str);
packet_new_index(tv, index, str, ni->type, ni->bus, ni->name);
@@ -573,6 +629,9 @@ void packet_hci_command(struct timeval *tv, uint16_t index,

btsnoop_write(tv, index, 0x02, data, size);

+ if (!filter_check_flag(index, PACKET_FILTER_SHOW_HCI))
+ return;
+
print_header(tv, index);

if (size < HCI_COMMAND_HDR_SIZE) {
@@ -596,6 +655,9 @@ void packet_hci_event(struct timeval *tv, uint16_t index,

btsnoop_write(tv, index, 0x03, data, size);

+ if (!filter_check_flag(index, PACKET_FILTER_SHOW_HCI))
+ return;
+
print_header(tv, index);

if (size < HCI_EVENT_HDR_SIZE) {
@@ -622,6 +684,9 @@ void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,

btsnoop_write(tv, index, in ? 0x01 : 0x00, data, size);

+ if (!filter_check_flag(index, PACKET_FILTER_SHOW_ACL))
+ return;
+
print_header(tv, index);

if (size < HCI_ACL_HDR_SIZE) {
@@ -635,7 +700,7 @@ void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
data += HCI_ACL_HDR_SIZE;
size -= HCI_ACL_HDR_SIZE;

- if (filter_mask & PACKET_FILTER_SHOW_ACL_DATA)
+ if (filter_check_flag(index, PACKET_FILTER_SHOW_ACL_DATA))
packet_hexdump(data, size);
}

@@ -646,6 +711,9 @@ void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
uint16_t handle = btohs(hdr->handle);
uint8_t flags = acl_flags(handle);

+ if (!filter_check_flag(index, PACKET_FILTER_SHOW_SCO))
+ return;
+
print_header(tv, index);

if (size < HCI_SCO_HDR_SIZE) {
@@ -659,6 +727,6 @@ void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
data += HCI_SCO_HDR_SIZE;
size -= HCI_SCO_HDR_SIZE;

- if (filter_mask & PACKET_FILTER_SHOW_SCO_DATA)
+ if (filter_check_flag(index, PACKET_FILTER_SHOW_SCO_DATA))
packet_hexdump(data, size);
}
diff --git a/monitor/packet.h b/monitor/packet.h
index c8d011d..aa113df 100644
--- a/monitor/packet.h
+++ b/monitor/packet.h
@@ -26,6 +26,8 @@
#include <stdint.h>
#include <sys/time.h>

+#include "list.h"
+
#define PACKET_FILTER_SHOW_INDEX (1 << 0)
#define PACKET_FILTER_SHOW_DATE (1 << 1)
#define PACKET_FILTER_SHOW_TIME (1 << 2)
@@ -35,7 +37,7 @@
#define PACKET_FILTER_SHOW_ACL_DATA (1 << 6)
#define PACKET_FILTER_SHOW_SCO_DATA (1 << 7)

-void packet_set_filter(unsigned long filter);
+void packet_set_filter(struct list *filter);

void packet_hexdump(const unsigned char *buf, uint16_t len);

--
1.7.10.1


2012-05-22 05:40:25

by Gustavo Padovan

[permalink] [raw]
Subject: [PATCH 2/4] monitor: add config_file parser

From: Gustavo Padovan <[email protected]>

parse_config() returns a list with the filter data for each controller
entry.
---
Makefile.tools | 5 +-
monitor/config_file.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++++
monitor/config_file.h | 30 +++++
monitor/list.c | 44 +++++++
monitor/list.h | 32 +++++
monitor/main.c | 9 +-
monitor/packet.h | 7 +-
7 files changed, 448 insertions(+), 4 deletions(-)
create mode 100644 monitor/config_file.c
create mode 100644 monitor/config_file.h
create mode 100644 monitor/list.c
create mode 100644 monitor/list.h

diff --git a/Makefile.tools b/Makefile.tools
index 4df7453..b82d4bc 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -60,7 +60,10 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
monitor/hcidump.h monitor/hcidump.c \
monitor/btsnoop.h monitor/btsnoop.c \
monitor/control.h monitor/control.c \
- monitor/packet.h monitor/packet.c
+ monitor/packet.h monitor/packet.c \
+ monitor/config_file.h \
+ monitor/config_file.c \
+ monitor/list.h monitor/list.c
monitor_btmon_LDADD = lib/libbluetooth-private.la

emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
diff --git a/monitor/config_file.c b/monitor/config_file.c
new file mode 100644
index 0000000..6fb50f9
--- /dev/null
+++ b/monitor/config_file.c
@@ -0,0 +1,325 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Collabora Ltd.
+ *
+ *
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "config_file.h"
+#include "packet.h"
+
+#define PROTO_FILT (PACKET_FILTER_SHOW_HCI | PACKET_FILTER_SHOW_ACL \
+ | PACKET_FILTER_SHOW_SCO)
+#define TS_MASK (PACKET_FILTER_SHOW_DATE | PACKET_FILTER_SHOW_TIME)
+
+#define error(fmt ,l, arg...) \
+ fprintf(stderr, "line %d: error: " fmt "\n",l, ## arg)
+
+#define SPACE " \n\t\r,"
+
+enum keyword_code {
+ OP_CONTROLLER,
+ OP_IGNORE,
+ OP_SHOW,
+ OP_HIDE,
+ OP_TIMESTAMPS,
+ OP_ERROR,
+};
+
+static struct keyword {
+ const char *string;
+ int code;
+} kw[] = {
+ { "Controller", OP_CONTROLLER },
+ { "Ignore", OP_IGNORE },
+ { "Show", OP_SHOW },
+ { "Hide", OP_HIDE },
+ { "Timestamps", OP_TIMESTAMPS },
+ { NULL, OP_ERROR }
+};
+
+static struct filter_options {
+ const char *string;
+ int bit;
+} filters[] = {
+ { "HCI", PACKET_FILTER_SHOW_HCI },
+ { "L2CAP", PACKET_FILTER_SHOW_ACL },
+ { "SCO", PACKET_FILTER_SHOW_SCO },
+ { NULL, 0 }
+};
+
+struct controller *controller;
+
+static void free_controllers_list(struct list *controllers_l)
+{
+ struct list *l, *tmp;
+
+ for (l = controllers_l->next ; l != controllers_l ; ) {
+ tmp = l;
+
+ list_del(l);
+ l = l->next;
+
+ free(tmp->controller->value);
+ free(tmp->controller);
+ free(tmp);
+ }
+
+ free(controllers_l);
+}
+
+static char *find_token(char *line)
+{
+ int n;
+
+ if (line == NULL)
+ return NULL;
+
+ line += strspn(line, SPACE);
+ if (line[0] == '\0' || line[0] == '\n' || line[0] == '\r')
+ return NULL;
+
+ n = strcspn(line, SPACE);
+ if (n == 0)
+ return NULL;
+
+ line[n] = '\0';
+
+ return line;
+}
+
+static int create_controller(struct list *controllers_l, char *c)
+{
+ struct list *l;
+
+ l = calloc(1, sizeof(*l));
+ if (!l)
+ return -ENOMEM;
+
+ l->controller = calloc(1, sizeof(*l->controller));
+ if (!l->controller) {
+ free(l);
+ return -ENOMEM;
+ }
+
+ l->controller->value = strdup(c);
+
+ l->controller->filter = ~0UL;
+
+ list_append(controllers_l, l);
+
+ controller = l->controller;
+
+ return 0;
+}
+
+static int get_filter(char *s, unsigned long *f, int line)
+{
+ int i, found;
+
+ *f = 0L;
+
+ s = find_token(s + strlen(s) + 1);
+ if (!s)
+ error("no options specified", line);
+
+ do {
+ found = 0;
+ for (i = 0 ; filters[i].string ; i++) {
+ if (!strcasecmp(s, filters[i].string)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ error("invalid filter parameter: %s", line, s);
+ return -EINVAL;
+ }
+
+ *f |= filters[i].bit;
+ s = find_token(s + strlen(s) + 1);
+ } while(s);
+
+ return 0;
+}
+
+static int parse_on_off(char *c, int line)
+{
+ char *state;
+ int ret;
+
+ state = find_token(c + strlen(c) + 1);
+ if (!strcasecmp(state, "on")) {
+ ret = 1;
+ } else if (!strcasecmp(state, "off")) {
+ ret = 0;
+ } else {
+ error("parameter should be 'on' or 'off'", line);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int process_keyword(struct list *controllers_l, char *key, int line)
+{
+ char *value;
+ unsigned long filter;
+ int i, v, err;
+
+ for (i = 0 ; kw[i].string ; i++) {
+ if (!strcasecmp(key, kw[i].string))
+ break;
+ }
+
+ if ((kw[i].code != OP_CONTROLLER) && !controller) {
+ error("no controller specified", line);
+ return -EINVAL;
+ }
+
+ err = 0;
+ switch (kw[i].code) {
+ case OP_CONTROLLER:
+ value = find_token(key + strlen(key) + 1);
+ if (!value) {
+ error("missing expected paramenter for 'Controller'",
+ line);
+ return -EINVAL;
+ }
+
+ err = create_controller(controllers_l, value);
+ break;
+ case OP_IGNORE:
+ controller->ignore = 1;
+ break;
+ case OP_SHOW:
+ if ((controller->filter | TS_MASK) != ~0UL) {
+ error("'Hide' option was specified, can't set 'Show'",
+ line);
+ return -EINVAL;
+ }
+
+ err = get_filter(key, &filter, line);
+ if (err)
+ return err;
+
+ controller->filter &= (0L | TS_MASK);
+
+ controller->filter |= filter;
+
+ break;
+
+ case OP_HIDE:
+ if ((controller->filter | TS_MASK) != ~0UL) {
+ error("'Show' option was specified, can't set 'Hide'",
+ line);
+ return -EINVAL;
+ }
+
+ err = get_filter(key, &filter, line);
+ if (err)
+ return err;
+
+ controller->filter &= ~filter;
+
+ break;
+ case OP_TIMESTAMPS:
+ v = parse_on_off(key, line);
+ if (v < 0)
+ return v;
+
+ if (v == 0)
+ controller->filter &= ~(PACKET_FILTER_SHOW_DATE |
+ PACKET_FILTER_SHOW_TIME);
+
+ break;
+ case OP_ERROR:
+ error("string not recognized: '%s'", line, key);
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+struct list *parse_config(char *file)
+{
+ FILE *f;
+ struct stat s;
+ int line;
+ char buf[1024];
+ struct list *controllers_l;
+
+ if (stat(file, &s) < 0) {
+ fprintf(stderr, "failed to get file status '%s' (%d)\n", file,
+ errno);
+ return NULL;
+
+ }
+
+ f = fopen(file, "r");
+ if (!f) {
+ fprintf(stderr, "failed to open filter file '%s' (%d)\n", file,
+ errno);
+ return NULL;
+ }
+
+ /*Allocate list head */
+ controllers_l = calloc(1, sizeof(*controllers_l));
+ if (!controllers_l)
+ goto error;
+
+ list_init(controllers_l);
+
+ line = 1;
+ memset(buf, 0, sizeof(buf));
+ while (fgets(buf, sizeof(buf), f)) {
+ char *key = find_token(buf);
+
+ if (key && key[0] != '#') {
+ if (process_keyword(controllers_l, key, line) < 0)
+ goto error;
+ }
+
+ line++;
+ memset(buf, 0, sizeof(buf));
+ }
+
+ fclose(f);
+ return controllers_l;
+
+error:
+ free_controllers_list(controllers_l);
+ fclose(f);
+ return NULL;
+}
+
diff --git a/monitor/config_file.h b/monitor/config_file.h
new file mode 100644
index 0000000..9190e01
--- /dev/null
+++ b/monitor/config_file.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Collabora Ltd.
+ *
+ *
+ * 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
+ *
+ */
+
+struct controller {
+ char *value;
+ unsigned long filter;
+ int ignore:1;
+};
+
+struct list *parse_config(char *file);
diff --git a/monitor/list.c b/monitor/list.c
new file mode 100644
index 0000000..8ac4647
--- /dev/null
+++ b/monitor/list.c
@@ -0,0 +1,44 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Collabora Ltd.
+ *
+ *
+ * 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 "list.h"
+
+void list_init(struct list *l)
+{
+ l->next = l;
+ l->prev = l;
+}
+
+void list_append(struct list *head, struct list *l)
+{
+ l->next = head;
+ l->prev = head->prev;
+ head->prev->next = l;
+ head->prev = l;
+}
+
+void list_del(struct list *l)
+{
+ l->next->prev = l->prev;
+ l->prev->next = l->next;
+}
diff --git a/monitor/list.h b/monitor/list.h
new file mode 100644
index 0000000..046811c
--- /dev/null
+++ b/monitor/list.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Collabora Ltd.
+ *
+ *
+ * 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
+ *
+ */
+
+struct list {
+ struct list *next;
+ struct list *prev;
+ struct controller *controller;
+};
+
+void list_init(struct list *l);
+void list_append(struct list *head, struct list *l);
+void list_del(struct list *l);
diff --git a/monitor/main.c b/monitor/main.c
index 90e32c5..1379839 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -35,6 +35,7 @@
#include "control.h"
#include "hcidump.h"
#include "btsnoop.h"
+#include "config_file.h"

static void signal_callback(int signum, void *user_data)
{
@@ -52,11 +53,13 @@ static void usage(void)
"Usage:\n");
printf("\tbtmon [options]\n");
printf("options:\n"
+ "\t-f, --filter <file> Filter file\n"
"\t-b, --btsnoop <file> Save dump in btsnoop format\n"
"\t-h, --help Show help options\n");
}

static const struct option main_options[] = {
+ { "filter", required_argument, NULL, 'f' },
{ "btsnoop", required_argument, NULL, 'b' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
@@ -73,11 +76,15 @@ int main(int argc, char *argv[])
for (;;) {
int opt;

- opt = getopt_long(argc, argv, "bvh", main_options, NULL);
+ opt = getopt_long(argc, argv, "f:bvh", main_options, NULL);
if (opt < 0)
break;

switch (opt) {
+ case 'f':
+ if (!parse_config(optarg))
+ return EXIT_FAILURE;
+ break;
case 'b':
btsnoop_open(optarg);
break;
diff --git a/monitor/packet.h b/monitor/packet.h
index 4c8b698..c8d011d 100644
--- a/monitor/packet.h
+++ b/monitor/packet.h
@@ -29,8 +29,11 @@
#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_ACL_DATA (1 << 3)
-#define PACKET_FILTER_SHOW_SCO_DATA (1 << 4)
+#define PACKET_FILTER_SHOW_HCI (1 << 3)
+#define PACKET_FILTER_SHOW_ACL (1 << 4)
+#define PACKET_FILTER_SHOW_SCO (1 << 5)
+#define PACKET_FILTER_SHOW_ACL_DATA (1 << 6)
+#define PACKET_FILTER_SHOW_SCO_DATA (1 << 7)

void packet_set_filter(unsigned long filter);

--
1.7.10.1