Re: [PATCH BlueZ v5 03/14] mesh: Infrastructure for Mesh daemon

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Marcel,

On Fri, 2018-07-06 at 20:20 +0200, Marcel Holtmann wrote:
> Hi Brian,
> 
> > ---
> > mesh/display.c         |  67 +++++
> > mesh/hci.c             | 699 +++++++++++++++++++++++++++++++++++++++++++++++++
> > mesh/mesh-io-generic.c | 660 ++++++++++++++++++++++++++++++++++++++++++++++
> > mesh/mesh-io.c         | 187 +++++++++++++
> > 4 files changed, 1613 insertions(+)
> > create mode 100644 mesh/display.c
> > create mode 100644 mesh/hci.c
> > create mode 100644 mesh/mesh-io-generic.c
> > create mode 100644 mesh/mesh-io.c
> > 
> > diff --git a/mesh/display.c b/mesh/display.c
> > new file mode 100644
> > index 000000000..adf92cae0
> > --- /dev/null
> > +++ b/mesh/display.c
> > @@ -0,0 +1,67 @@
> > +/*
> > + *
> > + *  BlueZ - Bluetooth protocol stack for Linux
> > + *
> > + *  Copyright (C) 2018  Intel Corporation. All rights reserved.++++
> > + *
> > + *
> > + *  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.
> > + *
> > + */
> > +
> > +#include <stdio.h>
> > +#include <unistd.h>
> > +#include <termios.h>
> > +#include <sys/ioctl.h>
> > +#include <sys/time.h>
> > +#include <ell/ell.h>
> > +
> > +#include "display.h"
> > +
> > +#define likely(x)   __builtin_expect(!!(x), 1)
> > +#define unlikely(x) __builtin_expect(!!(x), 0)
> 
> I highly doubt we will make good use of likely and unlikely. Just remove that. We can measure that at some
> point, but right now it seems useless. On a side note, I am not convinced that our usage in ELL is actually
> worth while doing.

This will be removed for v6 of patch-set

> 
> > +
> > +static unsigned int cached_num_columns;
> > +
> > +unsigned int num_columns(void)
> > +{
> > +	struct winsize ws;
> > +
> > +	if (likely(cached_num_columns > 0))
> > +		return cached_num_columns;
> > +
> > +	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0 || ws.ws_col == 0)
> > +		cached_num_columns = 80;
> > +	else
> > +		cached_num_columns = ws.ws_col;
> > +
> > +	return cached_num_columns;
> > +}
> > +
> > +void print_packet(const char *label, const void *data, uint16_t size)
> > +{
> > +	struct timeval pkt_time;
> > +
> > +	gettimeofday(&pkt_time, NULL);
> > +
> > +	if (size > 0) {
> > +		char *str;
> > +
> > +		str = l_util_hexstring(data, size);
> > +		l_info("%05d.%03d %s: %s",
> > +				(uint32_t) pkt_time.tv_sec % 100000,
> > +				(uint32_t) pkt_time.tv_usec/1000, label, str);
> > +		l_free(str);
> > +	} else
> > +		l_info("%05d.%03d %s: empty",
> > +				(uint32_t) pkt_time.tv_sec % 100000,
> > +				(uint32_t) pkt_time.tv_usec/1000, label);
> > +}
> 
> I have no idea why we are not using util_hexdump() or l_util_hexdump() since they are hooked up properly with
> debug defines etc.

l_util_hexdump does not create strings in the format we most use, which is a form that can be fed back into
l_util_from_hexstring. l_util_hexdump adds whitespace between each octet, and ascii gorp at the end of the
line, while l_util_hexstring returns a tightly packed octets-to-asciihex.

We can then use the output from this function to copy/paste strings between instances for example to:
1. simulate "Out Of Band" public and static key exchange
2. trade via email long ascii-hex strings to IOP and UPF partners
3. paste repeated over-the-air packets to repeat exact test runs without preconditioning sequence numbers and
IV Indexs etc.

If you like, I can rework this to use l_debug, but the current output format of the data is more useful in this
form, than it is in hexdump format.


> > diff --git a/mesh/hci.c b/mesh/hci.c
> > new file mode 100644
> > index 000000000..da6838a55
> > --- /dev/null
> > +++ b/mesh/hci.c
> > @@ -0,0 +1,699 @@
> > +/*
> > + *
> > + *  BlueZ - Bluetooth protocol stack for Linux
> > + *
> > + *  Copyright (C) 2018  Intel Corporation. All rights reserved.
> > + *
> > + *
> > + *  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.
> > + *
> > + */
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include <config.h>
> > +#endif
> > +
> > +#include <unistd.h>
> > +#include <stdlib.h>
> > +#include <sys/uio.h>
> > +#include <sys/socket.h>
> > +#include <ell/ell.h>
> > +
> > +#include "monitor/bt.h"
> > +
> > +#include "mesh/hci.h"
> > +
> > +#define BTPROTO_HCI	1
> > +struct sockaddr_hci {
> > +	sa_family_t	hci_family;
> > +	unsigned short	hci_dev;
> > +	unsigned short  hci_channel;
> > +};
> > +#define HCI_CHANNEL_USER	1
> > +
> > +struct bt_hci {
> > +	int ref_count;
> > +	struct l_io *io;
> > +	bool is_stream;
> > +	bool writer_active;
> > +	uint8_t num_cmds;
> > +	uint8_t num_pkts;
> > +	unsigned int next_cmd_id;
> > +	unsigned int next_evt_id;
> > +	struct l_queue *cmd_queue;
> > +	struct l_queue *rsp_queue;
> > +	struct l_queue *evt_list;
> > +	struct l_queue *pkt_queue;
> > +	bt_hci_receive_func_t receive_callback;
> > +	bt_hci_destroy_func_t receive_destroy;
> > +	void *receive_data;
> > +};
> 
> What is wrong with src/shared/hci.[ch] instead having a copy here?

The main barrier to this is that the src/shared/hci.[ch] uses glib conventions, and the mesh versions use ELL.
I agree that these should be a single hci.[ch], but it may need to wait until the rest of bluez is transitioned
to ELL.

I can add a /* TODO */ to the mesh version to ensure that this is eventually addressed (?).
 
> > +
> > +struct cmd {
> > +	unsigned int id;
> > +	uint16_t opcode;
> > +	void *data;
> > +	uint8_t size;
> > +	bt_hci_callback_func_t callback;
> > +	bt_hci_destroy_func_t destroy;
> > +	void *user_data;
> > +};
> > +
> > +struct evt {
> > +	unsigned int id;
> > +	uint8_t event;
> > +	bt_hci_callback_func_t callback;
> > +	bt_hci_destroy_func_t destroy;
> > +	void *user_data;
> > +};
> > +
> > +struct pkt {
> > +	uint16_t handle;
> > +	uint8_t flags;
> > +	void *data;
> > +	uint16_t size;
> > +};
> > +
> > +static void cmd_free(void *data)
> > +{
> > +	struct cmd *cmd = data;
> > +
> > +	if (cmd->destroy)
> > +		cmd->destroy(cmd->user_data);
> > +
> > +	l_free(cmd->data);
> > +	l_free(cmd);
> > +}
> > +
> > +static void evt_free(void *data)
> > +{
> > +	struct evt *evt = data;
> > +
> > +	if (evt->destroy)
> > +		evt->destroy(evt->user_data);
> > +
> > +	l_free(evt);
> > +}
> > +
> > +static void pkt_free(void *data)
> > +{
> > +	struct pkt *pkt = data;
> > +
> > +	l_free(pkt->data);
> > +	l_free(pkt);
> > +}
> > +
> > +static void send_command(struct bt_hci *hci, uint16_t opcode,
> > +						void *data, uint8_t size)
> > +{
> > +	uint8_t type = BT_H4_CMD_PKT;
> > +	struct bt_hci_cmd_hdr hdr;
> > +	struct iovec iov[3];
> > +	int fd, iovcnt;
> > +
> > +	hdr.opcode = L_CPU_TO_LE16(opcode);
> > +	hdr.plen = size;
> > +
> > +	iov[0].iov_base = &type;
> > +	iov[0].iov_len  = 1;
> > +	iov[1].iov_base = &hdr;
> > +	iov[1].iov_len  = sizeof(hdr);
> > +
> > +	if (size > 0) {
> > +		iov[2].iov_base = data;
> > +		iov[2].iov_len  = size;
> > +		iovcnt = 3;
> > +	} else
> > +		iovcnt = 2;
> > +
> > +	fd = l_io_get_fd(hci->io);
> > +	if (fd < 0) {
> > +		l_error("hci->io Bad");
> > +		return;
> > +	}
> > +
> > +	if (writev(fd, iov, iovcnt) < 0) {
> > +		l_error("writev Bad");
> > +		return;
> > +	}
> > +
> > +	hci->num_cmds--;
> > +}
> > +
> > +static void send_packet(struct bt_hci *hci, uint16_t handle, uint8_t flags,
> > +						void *data, uint8_t size)
> > +{
> > +	uint8_t type = BT_H4_ACL_PKT;
> > +	struct bt_hci_acl_hdr hdr;
> > +	struct iovec iov[3];
> > +	int fd, iovcnt;
> > +
> > +	hdr.handle = L_CPU_TO_LE16(flags << 12 | handle);
> > +	hdr.dlen = L_CPU_TO_LE16(size);
> > +
> > +	iov[0].iov_base = &type;
> > +	iov[0].iov_len  = 1;
> > +	iov[1].iov_base = &hdr;
> > +	iov[1].iov_len  = sizeof(hdr);
> > +
> > +	if (size > 0) {
> > +		iov[2].iov_base = data;
> > +		iov[2].iov_len  = size;
> > +		iovcnt = 3;
> > +	} else
> > +		iovcnt = 2;
> > +
> > +	fd = l_io_get_fd(hci->io);
> > +	if (fd < 0) {
> > +		l_error("hci->io Bad");
> > +		return;
> > +	}
> > +
> > +	if (writev(fd, iov, iovcnt) < 0) {
> > +		l_error("writev Bad");
> > +		return;
> > +	}
> > +
> > +	hci->num_pkts--;
> > +}
> > +
> > +static bool io_write_callback(struct l_io *io, void *user_data)
> > +{
> > +	struct bt_hci *hci = user_data;
> > +	struct cmd *cmd;
> > +
> > +	if (hci->num_cmds > 0)
> > +		cmd = l_queue_pop_head(hci->cmd_queue);
> > +	else
> > +		cmd = NULL;
> > +
> > +	if (cmd) {
> > +		send_command(hci, cmd->opcode, cmd->data, cmd->size);
> > +		l_queue_push_tail(hci->rsp_queue, cmd);
> > +	} else {
> > +		struct pkt *pkt;
> > +
> > +		if (hci->num_pkts < 1)
> > +			goto done;
> > +
> > +		pkt = l_queue_pop_head(hci->pkt_queue);
> > +		if (pkt) {
> > +			send_packet(hci, pkt->handle, pkt->flags,
> > +							pkt->data, pkt->size);
> > +			pkt_free(pkt);
> > +		}
> > +	}
> > +
> > +	if (!l_queue_isempty(hci->pkt_queue))
> > +		return true;
> > +
> > +done:
> > +	hci->writer_active = false;
> > +
> > +	return false;
> > +}
> > +
> > +static void wakeup_writer(struct bt_hci *hci)
> > +{
> > +	if (hci->writer_active)
> > +		return;
> > +
> > +	if (l_queue_isempty(hci->cmd_queue) && l_queue_isempty(hci->pkt_queue))
> > +		return;
> > +
> > +	if (!l_io_set_write_handler(hci->io, io_write_callback, hci, NULL))
> > +		return;
> > +
> > +	hci->writer_active = true;
> > +}
> > +
> > +static bool match_cmd_opcode(const void *a, const void *b)
> > +{
> > +	const struct cmd *cmd = a;
> > +	uint16_t opcode = L_PTR_TO_UINT(b);
> > +
> > +	return cmd->opcode == opcode;
> > +}
> > +
> > +static void process_response(struct bt_hci *hci, uint16_t opcode,
> > +					const void *data, size_t size)
> > +{
> > +	struct cmd *cmd;
> > +
> > +	if (opcode == BT_HCI_CMD_NOP)
> > +		goto done;
> > +
> > +	cmd = l_queue_remove_if(hci->rsp_queue, match_cmd_opcode,
> > +						L_UINT_TO_PTR(opcode));
> > +	if (!cmd)
> > +		goto done;
> > +
> > +	if (cmd->callback)
> > +		cmd->callback(data, size, cmd->user_data);
> > +
> > +	cmd_free(cmd);
> > +
> > +done:
> > +	wakeup_writer(hci);
> > +}
> > +
> > +static void process_notify(void *data, void *user_data)
> > +{
> > +	struct bt_hci_evt_hdr *hdr = user_data;
> > +	struct evt *evt = data;
> > +
> > +	if (evt->event == hdr->evt)
> > +		evt->callback(user_data + sizeof(struct bt_hci_evt_hdr),
> > +						hdr->plen, evt->user_data);
> > +}
> > +
> > +static void process_event(struct bt_hci *hci, const void *data, size_t size)
> > +{
> > +	const struct bt_hci_evt_hdr *hdr = data;
> > +	const struct bt_hci_evt_cmd_complete *cc;
> > +	const struct bt_hci_evt_cmd_status *cs;
> > +	const struct bt_hci_evt_num_completed_packets *cp;
> > +
> > +	if (size < sizeof(struct bt_hci_evt_hdr))
> > +		return;
> > +
> > +	data += sizeof(struct bt_hci_evt_hdr);
> > +	size -= sizeof(struct bt_hci_evt_hdr);
> > +
> > +	if (hdr->plen != size)
> > +		return;
> > +
> > +	switch (hdr->evt) {
> > +	case BT_HCI_EVT_CMD_COMPLETE:
> > +		if (size < sizeof(*cc))
> > +			return;
> > +		cc = data;
> > +		hci->num_cmds = cc->ncmd;
> > +		process_response(hci, L_LE16_TO_CPU(cc->opcode),
> > +						data + sizeof(*cc),
> > +						size - sizeof(*cc));
> > +		break;
> > +
> > +	case BT_HCI_EVT_CMD_STATUS:
> > +		if (size < sizeof(*cs))
> > +			return;
> > +		cs = data;
> > +		hci->num_cmds = cs->ncmd;
> > +		process_response(hci, L_LE16_TO_CPU(cs->opcode),
> > +							&cs->status, 1);
> > +		break;
> > +
> > +	case BT_HCI_EVT_NUM_COMPLETED_PACKETS:
> > +		if (size < sizeof(*cp))
> > +			return;
> > +		cp = data;
> > +		l_debug("BT_HCI_EVT_NUM_COMPLETED_PACKETS:%d", cp->count);
> > +		/* Ignoring handle information for now */
> > +		hci->num_pkts = cp->count;
> > +		wakeup_writer(hci);
> > +		break;
> > +
> > +	default:
> > +		l_queue_foreach(hci->evt_list, process_notify, (void *) hdr);
> > +		break;
> > +	}
> > +}
> > +
> > +static void process_acl(struct bt_hci *hci, const void *data, size_t size)
> > +{
> > +	const struct bt_hci_acl_hdr *hdr = data;
> > +	uint16_t handle;
> > +
> > +	if (size < sizeof(struct bt_hci_acl_hdr))
> > +		return;
> > +
> > +	data += sizeof(struct bt_hci_acl_hdr);
> > +	size -= sizeof(struct bt_hci_acl_hdr);
> > +
> > +	if (L_LE16_TO_CPU(hdr->dlen) != size)
> > +		return;
> > +
> > +	handle = L_LE16_TO_CPU(hdr->handle);
> > +
> > +	if (hci->receive_callback)
> > +		hci->receive_callback(handle & 0x0fff, handle >> 12,
> > +					data, size, hci->receive_data);
> > +}
> > +
> > +static bool io_read_callback(struct l_io *io, void *user_data)
> > +{
> > +	struct bt_hci *hci = user_data;
> > +	uint8_t buf[512];
> > +	ssize_t len;
> > +	int fd;
> > +
> > +	fd = l_io_get_fd(hci->io);
> > +	if (fd < 0)
> > +		return false;
> > +
> > +	if (hci->is_stream)
> > +		return false;
> > +
> > +	len = read(fd, buf, sizeof(buf));
> > +	if (len < 0)
> > +		return false;
> > +
> > +	if (len < 1)
> > +		return true;
> > +
> > +	switch (buf[0]) {
> > +	case BT_H4_EVT_PKT:
> > +		process_event(hci, buf + 1, len - 1);
> > +		break;
> > +	case BT_H4_ACL_PKT:
> > +		process_acl(hci, buf + 1, len - 1);
> > +		break;
> > +	default:
> > +		l_info("%2.2x-RXed", buf[0]);
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static struct bt_hci *create_hci(int fd)
> > +{
> > +	struct bt_hci *hci;
> > +
> > +	if (fd < 0)
> > +		return NULL;
> > +
> > +	hci = l_new(struct bt_hci, 1);
> > +
> > +	hci->io = l_io_new(fd);
> > +
> > +	hci->is_stream = true;
> > +	hci->writer_active = false;
> > +	hci->num_cmds = 1;
> > +	hci->num_pkts = 1;
> > +	hci->next_cmd_id = 1;
> > +	hci->next_evt_id = 1;
> > +
> > +	hci->cmd_queue = l_queue_new();
> > +	hci->rsp_queue = l_queue_new();
> > +	hci->evt_list = l_queue_new();
> > +	hci->pkt_queue = l_queue_new();
> > +
> > +	if (!l_io_set_read_handler(hci->io, io_read_callback, hci, NULL)) {
> > +		l_queue_destroy(hci->pkt_queue, NULL);
> > +		l_queue_destroy(hci->evt_list, NULL);
> > +		l_queue_destroy(hci->rsp_queue, NULL);
> > +		l_queue_destroy(hci->cmd_queue, NULL);
> > +		l_io_destroy(hci->io);
> > +		l_free(hci);
> > +		return NULL;
> > +	}
> > +
> > +	return bt_hci_ref(hci);
> > +}
> > +
> > +struct bt_hci *bt_hci_new(int fd)
> > +{
> > +	struct bt_hci *hci;
> > +
> > +	hci = create_hci(fd);
> > +	if (!hci)
> > +		return NULL;
> > +
> > +	return hci;
> > +}
> > +
> > +static int create_socket(uint16_t index, uint16_t channel)
> > +{
> > +	struct sockaddr_hci addr;
> > +	int fd;
> > +
> > +	fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
> > +								BTPROTO_HCI);
> > +	if (fd < 0)
> > +		return -1;
> > +
> > +	memset(&addr, 0, sizeof(addr));
> > +	addr.hci_family = AF_BLUETOOTH;
> > +	addr.hci_dev = index;
> > +	addr.hci_channel = channel;
> > +
> > +	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> > +		close(fd);
> > +		return -1;
> > +	}
> > +
> > +	return fd;
> > +}
> > +
> > +struct bt_hci *bt_hci_new_user_channel(uint16_t index)
> > +{
> > +	struct bt_hci *hci;
> > +	int fd;
> > +
> > +	fd = create_socket(index, HCI_CHANNEL_USER);
> > +	if (fd < 0)
> > +		return NULL;
> > +
> > +	hci = create_hci(fd);
> > +	if (!hci) {
> > +		close(fd);
> > +		return NULL;
> > +	}
> > +
> > +	hci->is_stream = false;
> > +
> > +	bt_hci_set_close_on_unref(hci, true);
> > +
> > +	return hci;
> > +}
> > +
> > +struct bt_hci *bt_hci_ref(struct bt_hci *hci)
> > +{
> > +	if (!hci)
> > +		return NULL;
> > +
> > +	__sync_fetch_and_add(&hci->ref_count, 1);
> > +
> > +	return hci;
> > +}
> > +
> > +void bt_hci_unref(struct bt_hci *hci)
> > +{
> > +	if (!hci)
> > +		return;
> > +
> > +	if (__sync_sub_and_fetch(&hci->ref_count, 1))
> > +		return;
> > +
> > +	if (hci->receive_destroy)
> > +		hci->receive_destroy(hci->receive_data);
> > +
> > +	l_queue_destroy(hci->pkt_queue, pkt_free);
> > +	l_queue_destroy(hci->evt_list, evt_free);
> > +	l_queue_destroy(hci->cmd_queue, cmd_free);
> > +	l_queue_destroy(hci->rsp_queue, cmd_free);
> > +
> > +	l_io_destroy(hci->io);
> > +
> > +	l_free(hci);
> > +}
> > +
> > +bool bt_hci_set_close_on_unref(struct bt_hci *hci, bool do_close)
> > +{
> > +	if (!hci)
> > +		return false;
> > +
> > +	return l_io_set_close_on_destroy(hci->io, do_close);
> > +}
> > +
> > +unsigned int bt_hci_send(struct bt_hci *hci, uint16_t opcode,
> > +				const void *data, uint8_t size,
> > +				bt_hci_callback_func_t callback,
> > +				void *user_data, bt_hci_destroy_func_t destroy)
> > +{
> > +	struct cmd *cmd;
> > +
> > +	if (!hci)
> > +		return 0;
> > +
> > +	cmd = l_new(struct cmd, 1);
> > +
> > +	cmd->opcode = opcode;
> > +	cmd->size = size;
> > +
> > +	if (cmd->size > 0)
> > +		cmd->data = l_memdup(data, cmd->size);
> > +
> > +	if (hci->next_cmd_id < 1)
> > +		hci->next_cmd_id = 1;
> > +
> > +	cmd->id = hci->next_cmd_id++;
> > +
> > +	cmd->callback = callback;
> > +	cmd->destroy = destroy;
> > +	cmd->user_data = user_data;
> > +
> > +	if (!l_queue_push_tail(hci->cmd_queue, cmd)) {
> > +		l_free(cmd->data);
> > +		l_free(cmd);
> > +		return 0;
> > +	}
> > +
> > +	wakeup_writer(hci);
> > +
> > +	return cmd->id;
> > +}
> > +
> > +static bool match_cmd_id(const void *a, const void *b)
> > +{
> > +	const struct cmd *cmd = a;
> > +	unsigned int id = L_PTR_TO_UINT(b);
> > +
> > +	return cmd->id == id;
> > +}
> > +
> > +bool bt_hci_cancel(struct bt_hci *hci, unsigned int id)
> > +{
> > +	struct cmd *cmd;
> > +
> > +	if (!hci || !id)
> > +		return false;
> > +
> > +	cmd = l_queue_remove_if(hci->cmd_queue, match_cmd_id,
> > +						L_UINT_TO_PTR(id));
> > +	if (!cmd) {
> > +		cmd = l_queue_remove_if(hci->rsp_queue, match_cmd_id,
> > +							L_UINT_TO_PTR(id));
> > +		if (!cmd)
> > +			return false;
> > +	}
> > +
> > +	cmd_free(cmd);
> > +
> > +	wakeup_writer(hci);
> > +
> > +	return true;
> > +}
> > +
> > +bool bt_hci_flush(struct bt_hci *hci)
> > +{
> > +	if (!hci)
> > +		return false;
> > +
> > +	if (hci->writer_active) {
> > +		l_io_set_write_handler(hci->io, NULL, NULL, NULL);
> > +		hci->writer_active = false;
> > +	}
> > +
> > +	l_queue_clear(hci->cmd_queue, cmd_free);
> > +	l_queue_clear(hci->rsp_queue, cmd_free);
> > +
> > +	return true;
> > +}
> > +
> > +unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
> > +				bt_hci_callback_func_t callback,
> > +				void *user_data, bt_hci_destroy_func_t destroy)
> > +{
> > +	struct evt *evt;
> > +
> > +	if (!hci)
> > +		return 0;
> > +
> > +	evt = l_new(struct evt, 1);
> > +
> > +	evt->event = event;
> > +
> > +	if (hci->next_evt_id < 1)
> > +		hci->next_evt_id = 1;
> > +
> > +	evt->id = hci->next_evt_id++;
> > +
> > +	evt->callback = callback;
> > +	evt->destroy = destroy;
> > +	evt->user_data = user_data;
> > +
> > +	if (!l_queue_push_tail(hci->evt_list, evt)) {
> > +		l_free(evt);
> > +		return 0;
> > +	}
> > +
> > +	return evt->id;
> > +}
> > +
> > +static bool match_evt_id(const void *a, const void *b)
> > +{
> > +	const struct evt *evt = a;
> > +	unsigned int id = L_PTR_TO_UINT(b);
> > +
> > +	return evt->id == id;
> > +}
> > +
> > +bool bt_hci_unregister(struct bt_hci *hci, unsigned int id)
> > +{
> > +	struct evt *evt;
> > +
> > +	if (!hci || !id)
> > +		return false;
> > +
> > +	evt = l_queue_remove_if(hci->evt_list, match_evt_id,
> > +						L_UINT_TO_PTR(id));
> > +	if (!evt)
> > +		return false;
> > +
> > +	evt_free(evt);
> > +
> > +	return true;
> > +}
> > +
> > +bool bt_hci_receive(struct bt_hci *hci, bt_hci_receive_func_t callback,
> > +				void *user_data, bt_hci_destroy_func_t destroy)
> > +{
> > +	if (!hci)
> > +		return false;
> > +
> > +	if (hci->receive_destroy)
> > +		hci->receive_destroy(hci->receive_data);
> > +
> > +	hci->receive_callback = callback;
> > +	hci->receive_destroy = destroy;
> > +	hci->receive_data = user_data;
> > +
> > +	return true;
> > +}
> > +
> > +bool bt_hci_write(struct bt_hci *hci, uint16_t handle, uint8_t flags,
> > +				const void *data, uint16_t size)
> > +{
> > +	struct pkt *pkt;
> > +
> > +	if (!hci)
> > +		return false;
> > +
> > +	pkt = l_new(struct pkt, 1);
> > +
> > +	pkt->handle = handle;
> > +	pkt->flags = flags;
> > +	pkt->size = size;
> > +
> > +	if (pkt->size > 0)
> > +		pkt->data = l_memdup(data, pkt->size);
> > +
> > +	if (!l_queue_push_tail(hci->pkt_queue, pkt)) {
> > +		l_free(pkt->data);
> > +		l_free(pkt);
> > +		return false;
> > +	}
> > +
> > +	wakeup_writer(hci);
> > +
> > +	return true;
> > +}
> > diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c
> > new file mode 100644
> > index 000000000..7a974cff3
> > --- /dev/null
> > +++ b/mesh/mesh-io-generic.c
> > @@ -0,0 +1,660 @@
> > +/*
> > + *
> > + *  BlueZ - Bluetooth protocol stack for Linux
> > + *
> > + *  Copyright (C) 2018  Intel Corporation. All rights reserved.
> > + *
> > + *
> > + *  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.
> > + *
> > + */
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include <config.h>
> > +#endif
> > +
> > +#include <sys/time.h>
> > +#include <ell/ell.h>
> > +
> > +#include "lib/bluetooth.h"
> > +#include "lib/hci.h"
> > +
> > +#include "monitor/bt.h"
> > +
> > +#include "mesh/hci.h"
> > +#include "mesh/display.h"
> > +#include "mesh/mesh-io.h"
> > +#include "mesh/mesh-io-api.h"
> > +
> > +#include "mesh/mesh-io-generic.h"
> > +
> > +struct mesh_io_private {
> > +	uint16_t index;
> > +	struct bt_hci *hci;
> > +	struct l_timeout *tx_timeout;
> > +	struct l_queue *rx_regs;
> > +	struct l_queue *tx_pkts;
> > +	uint8_t filters[3]; /* Simple filtering on AD type only */
> > +	bool sending;
> > +	struct tx_pkt *tx;
> > +	uint16_t interval;
> > +};
> > +
> > +struct pvt_rx_reg {
> > +	uint8_t filter_id;
> > +	mesh_io_recv_func_t cb;
> > +	void *user_data;
> > +};
> > +
> > +struct process_data {
> > +	struct mesh_io_private		*pvt;
> > +	const uint8_t			*data;
> > +	uint8_t				len;
> > +	struct mesh_io_recv_info	info;
> > +};
> > +
> > +struct tx_pkt {
> > +	struct mesh_io_send_info	info;
> > +	bool				delete;
> > +	uint8_t				len;
> > +	uint8_t				pkt[30];
> > +};
> > +
> > +struct tx_pattern {
> > +	const uint8_t			*data;
> > +	uint8_t				len;
> > +};
> > +
> > +static uint32_t get_instant(void)
> > +{
> > +	struct timeval tm;
> > +	uint32_t instant;
> > +
> > +	gettimeofday(&tm, NULL);
> > +	instant = tm.tv_sec * 1000;
> > +	instant += tm.tv_usec / 1000;
> > +
> > +	return instant;
> > +}
> > +
> > +static uint32_t instant_remaining_ms(uint32_t instant)
> > +{
> > +	instant -= get_instant();
> > +	return instant;
> > +}
> > +
> > +static void process_rx_callbacks(void *v_rx, void *v_reg)
> > +{
> > +	struct pvt_rx_reg *rx_reg = v_rx;
> > +	struct process_data *rx = v_reg;
> > +	uint8_t ad_type;
> > +
> > +	ad_type = rx->pvt->filters[rx_reg->filter_id - 1];
> > +
> > +	if (rx->data[0] == ad_type && rx_reg->cb)
> > +		rx_reg->cb(rx_reg->user_data, &rx->info, rx->data, rx->len);
> > +}
> > +
> > +static void process_rx(struct mesh_io_private *pvt, int8_t rssi,
> > +					uint32_t instant,
> > +					const uint8_t *data, uint8_t len)
> > +{
> > +	struct process_data rx = {
> > +		.pvt = pvt,
> > +		.data = data,
> > +		.len = len,
> > +		.info.instant = instant,
> > +		.info.chan = 7,
> > +		.info.rssi = rssi,
> > +	};
> > +
> > +	l_queue_foreach(pvt->rx_regs, process_rx_callbacks, &rx);
> > +}
> > +
> > +static void event_adv_report(struct mesh_io *io, const void *buf, uint8_t size)
> > +{
> > +	const struct bt_hci_evt_le_adv_report *evt = buf;
> > +	const uint8_t *adv;
> > +	uint32_t instant;
> > +	uint8_t adv_len;
> > +	uint16_t len = 0;
> > +	int8_t rssi;
> > +
> > +	if (evt->event_type != 0x03)
> > +		return;
> > +
> > +	if (evt->addr_type != BDADDR_LE_PUBLIC &&
> > +			evt->addr_type != BDADDR_LE_RANDOM)
> > +		return;
> > +
> > +	instant = get_instant();
> > +	adv = evt->data;
> > +	adv_len = evt->data_len;
> > +
> > +	/* rssi is just beyond last byte of data */
> > +	rssi = (int8_t) adv[adv_len];
> > +
> > +	while (len < adv_len - 1) {
> > +		uint8_t field_len = adv[0];
> > +
> > +		/* Check for the end of advertising data */
> > +		if (field_len == 0)
> > +			break;
> > +
> > +		len += field_len + 1;
> > +
> > +		/* Do not continue data parsing if got incorrect length */
> > +		if (len > adv_len)
> > +			break;
> > +
> > +		/* TODO: Create an Instant to use */
> > +		process_rx(io->pvt, rssi, instant, adv + 1, adv[0]);
> > +
> > +		adv += field_len + 1;
> > +	}
> > +}
> > +
> > +static void event_callback(const void *buf, uint8_t size, void *user_data)
> > +{
> > +	uint8_t event = l_get_u8(buf);
> > +	struct mesh_io *io = user_data;
> > +
> > +	switch (event) {
> > +	case BT_HCI_EVT_LE_ADV_REPORT:
> > +		event_adv_report(io, buf + 1, size - 1);
> > +		break;
> > +
> > +	default:
> > +		l_info("Other Meta Evt - %d", event);
> > +	}
> > +}
> > +
> > +static bool dev_init(uint16_t index, struct mesh_io *io)
> > +{
> > +	struct mesh_io_private *tmp;
> > +
> > +	if (!io || io->pvt)
> > +		return false;
> > +
> > +	tmp = l_new(struct mesh_io_private, 1);
> > +
> > +	if (tmp == NULL)
> > +		return false;
> > +
> > +	tmp->rx_regs = l_queue_new();
> > +	tmp->tx_pkts = l_queue_new();
> > +	if (!tmp->rx_regs || !tmp->tx_pkts)
> > +		goto fail;
> > +
> > +	tmp->hci = bt_hci_new_user_channel(index);
> > +	if (!tmp->hci)
> > +		goto fail;
> > +
> > +	bt_hci_register(tmp->hci, BT_HCI_EVT_LE_META_EVENT,
> > +						event_callback, io, NULL);
> > +
> > +	io->pvt = tmp;
> > +	return true;
> > +
> > +fail:
> > +	l_queue_destroy(tmp->rx_regs, l_free);
> > +	l_queue_destroy(tmp->tx_pkts, l_free);
> > +	l_free(tmp);
> > +	return false;
> > +}
> > +
> > +static bool dev_destroy(struct mesh_io *io)
> > +{
> > +	struct mesh_io_private *pvt = io->pvt;
> > +
> > +	if (!pvt)
> > +		return true;
> > +
> > +	bt_hci_unref(pvt->hci);
> > +	l_timeout_remove(pvt->tx_timeout);
> > +	l_queue_destroy(pvt->rx_regs, l_free);
> > +	l_queue_destroy(pvt->tx_pkts, l_free);
> > +	l_free(pvt);
> > +	io->pvt = NULL;
> > +
> > +	return true;
> > +}
> > +
> > +static bool dev_caps(struct mesh_io *io, struct mesh_io_caps *caps)
> > +{
> > +	struct mesh_io_private *pvt = io->pvt;
> > +
> > +	if (!pvt || !caps)
> > +		return false;
> > +
> > +	caps->max_num_filters = sizeof(pvt->filters);
> > +	caps->window_accuracy = 50;
> > +
> > +	return true;
> > +}
> > +
> > +static void send_cancel_done(const void *buf, uint8_t size,
> > +							void *user_data)
> > +{
> > +	struct mesh_io_private *pvt = user_data;
> > +	struct bt_hci_cmd_le_set_random_address cmd;
> > +
> > +	if (!pvt)
> > +		return;
> > +
> > +	pvt->sending = false;
> > +
> > +	/* At end of any burst of ADVs, change random address */
> > +	l_getrandom(cmd.addr, 6);
> > +	cmd.addr[5] |= 0xc0;
> > +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_RANDOM_ADDRESS,
> > +				&cmd, sizeof(cmd), NULL, NULL, NULL);
> > +}
> > +
> > +static void send_cancel(struct mesh_io_private *pvt)
> > +{
> > +	struct bt_hci_cmd_le_set_adv_enable cmd;
> > +
> > +	if (!pvt)
> > +		return;
> > +
> > +	if (!pvt->sending) {
> > +		send_cancel_done(NULL, 0, pvt);
> > +		return;
> > +	}
> > +
> > +	cmd.enable = 0x00;	/* Disable advertising */
> > +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_ENABLE,
> > +				&cmd, sizeof(cmd),
> > +				send_cancel_done, pvt, NULL);
> > +}
> > +
> > +static void set_send_adv_enable(const void *buf, uint8_t size,
> > +							void *user_data)
> > +{
> > +	struct mesh_io_private *pvt = user_data;
> > +	struct bt_hci_cmd_le_set_adv_enable cmd;
> > +
> > +	if (!pvt)
> > +		return;
> > +
> > +	pvt->sending = true;
> > +	cmd.enable = 0x01;	/* Enable advertising */
> > +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_ENABLE,
> > +				&cmd, sizeof(cmd), NULL, NULL, NULL);
> > +}
> > +
> > +static void set_send_adv_data(const void *buf, uint8_t size,
> > +							void *user_data)
> > +{
> > +	struct mesh_io_private *pvt = user_data;
> > +	struct tx_pkt *tx;
> > +	struct bt_hci_cmd_le_set_adv_data cmd;
> > +
> > +	if (!pvt || !pvt->tx)
> > +		return;
> > +
> > +	tx = pvt->tx;
> > +	if (tx->len >= sizeof(cmd.data))
> > +		goto done;
> > +
> > +	memset(&cmd, 0, sizeof(cmd));
> > +
> > +	cmd.len = tx->len + 1;
> > +	cmd.data[0] = tx->len;
> > +	memcpy(cmd.data + 1, tx->pkt, tx->len);
> > +
> > +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_DATA,
> > +					&cmd, sizeof(cmd),
> > +					set_send_adv_enable, pvt, NULL);
> > +done:
> > +	if (tx->delete)
> > +		l_free(tx);
> > +
> > +	pvt->tx = NULL;
> > +}
> > +
> > +static void set_send_adv_params(const void *buf, uint8_t size,
> > +							void *user_data)
> > +{
> > +	struct mesh_io_private *pvt = user_data;
> > +	struct bt_hci_cmd_le_set_adv_parameters cmd;
> > +	uint16_t hci_interval;
> > +
> > +	if (!pvt)
> > +		return;
> > +
> > +	hci_interval = (pvt->interval * 16) / 10;
> > +	cmd.min_interval = L_CPU_TO_LE16(hci_interval);
> > +	cmd.max_interval = L_CPU_TO_LE16(hci_interval);
> > +	cmd.type = 0x03; /* ADV_NONCONN_IND */
> > +	cmd.own_addr_type = 0x01; /* ADDR_TYPE_RANDOM */
> > +	cmd.direct_addr_type = 0x00;
> > +	memset(cmd.direct_addr, 0, 6);
> > +	cmd.channel_map = 0x07;
> > +	cmd.filter_policy = 0x03;
> > +
> > +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
> > +				&cmd, sizeof(cmd),
> > +				set_send_adv_data, pvt, NULL);
> > +}
> > +
> > +static void send_pkt(struct mesh_io_private *pvt, struct tx_pkt *tx,
> > +							uint16_t interval)
> > +{
> > +	struct bt_hci_cmd_le_set_adv_enable cmd;
> > +
> > +	pvt->tx = tx;
> > +	pvt->interval = interval;
> > +
> > +	if (!pvt->sending) {
> > +		set_send_adv_params(NULL, 0, pvt);
> > +		return;
> > +	}
> > +
> > +	cmd.enable = 0x00;	/* Disable advertising */
> > +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_ENABLE,
> > +				&cmd, sizeof(cmd),
> > +				set_send_adv_params, pvt, NULL);
> > +}
> > +
> > +static void tx_timeout(struct l_timeout *timeout, void *user_data)
> > +{
> > +	struct mesh_io_private *pvt = user_data;
> > +	struct tx_pkt *tx;
> > +	uint16_t ms;
> > +	uint8_t count;
> > +
> > +	if (!pvt)
> > +		return;
> > +
> > +	tx = l_queue_pop_head(pvt->tx_pkts);
> > +	if (!tx) {
> > +		l_timeout_remove(timeout);
> > +		pvt->tx_timeout = NULL;
> > +		send_cancel(pvt);
> > +		return;
> > +	}
> > +
> > +	if (tx->info.type == MESH_IO_TIMING_TYPE_GENERAL) {
> > +		ms = tx->info.u.gen.interval;
> > +		count = tx->info.u.gen.cnt;
> > +		if (count != MESH_IO_TX_COUNT_UNLIMITED)
> > +			tx->info.u.gen.cnt--;
> > +	} else {
> > +		ms = 25;
> > +		count = 1;
> > +	}
> > +
> > +	tx->delete = !!(count == 1);
> > +
> > +	send_pkt(pvt, tx, ms);
> > +
> > +	if (count == 1) {
> > +		/* send_pkt will delete when done */
> > +		tx = l_queue_peek_head(pvt->tx_pkts);
> > +		if (tx && tx->info.type == MESH_IO_TIMING_TYPE_POLL_RSP) {
> > +			ms = instant_remaining_ms(tx->info.u.poll_rsp.instant +
> > +						tx->info.u.poll_rsp.delay);
> > +		}
> > +	} else
> > +		l_queue_push_tail(pvt->tx_pkts, tx);
> > +
> > +	if (timeout) {
> > +		pvt->tx_timeout = timeout;
> > +		l_timeout_modify_ms(timeout, ms);
> > +	} else
> > +		pvt->tx_timeout = l_timeout_create_ms(ms, tx_timeout,
> > +								pvt, NULL);
> > +}
> > +
> > +static void tx_worker(void *user_data)
> > +{
> > +	struct mesh_io_private *pvt = user_data;
> > +	struct tx_pkt *tx;
> > +	uint32_t delay;
> > +
> > +	tx = l_queue_peek_head(pvt->tx_pkts);
> > +	if (!tx)
> > +		return;
> > +
> > +	switch (tx->info.type) {
> > +	case MESH_IO_TIMING_TYPE_GENERAL:
> > +		if (tx->info.u.gen.min_delay == tx->info.u.gen.max_delay)
> > +			delay = tx->info.u.gen.min_delay;
> > +		else {
> > +			l_getrandom(&delay, sizeof(delay));
> > +			delay %= tx->info.u.gen.max_delay -
> > +						tx->info.u.gen.min_delay;
> > +			delay += tx->info.u.gen.min_delay;
> > +		}
> > +		break;
> > +
> > +	case MESH_IO_TIMING_TYPE_POLL:
> > +		if (tx->info.u.poll.min_delay == tx->info.u.poll.max_delay)
> > +			delay = tx->info.u.poll.min_delay;
> > +		else {
> > +			l_getrandom(&delay, sizeof(delay));
> > +			delay %= tx->info.u.poll.max_delay -
> > +						tx->info.u.poll.min_delay;
> > +			delay += tx->info.u.poll.min_delay;
> > +		}
> > +		break;
> > +
> > +	case MESH_IO_TIMING_TYPE_POLL_RSP:
> > +		/* Delay until Instant + Delay */
> > +		delay = instant_remaining_ms(tx->info.u.poll_rsp.instant +
> > +						tx->info.u.poll_rsp.delay);
> > +		if (delay > 255)
> > +			delay = 0;
> > +		break;
> > +
> > +	default:
> > +		return;
> > +	}
> > +
> > +	if (!delay)
> > +		tx_timeout(pvt->tx_timeout, pvt);
> > +	else if (pvt->tx_timeout)
> > +		l_timeout_modify_ms(pvt->tx_timeout, delay);
> > +	else
> > +		pvt->tx_timeout = l_timeout_create_ms(delay, tx_timeout,
> > +								pvt, NULL);
> > +}
> > +
> > +static bool send_tx(struct mesh_io *io, struct mesh_io_send_info *info,
> > +					const uint8_t *data, uint16_t len)
> > +{
> > +	struct mesh_io_private *pvt = io->pvt;
> > +	struct tx_pkt *tx;
> > +	bool sending = false;
> > +
> > +	if (!info || !data || !len || len > sizeof(tx->pkt))
> > +		return false;
> > +
> > +
> > +	tx = l_new(struct tx_pkt, 1);
> > +	if (!tx)
> > +		return false;
> > +
> > +	memcpy(&tx->info, info, sizeof(tx->info));
> > +	memcpy(&tx->pkt, data, len);
> > +	tx->len = len;
> > +
> > +	if (info->type == MESH_IO_TIMING_TYPE_POLL_RSP)
> > +		l_queue_push_head(pvt->tx_pkts, tx);
> > +	else {
> > +		sending = !l_queue_isempty(pvt->tx_pkts);
> > +		l_queue_push_tail(pvt->tx_pkts, tx);
> > +	}
> > +
> > +	if (!sending) {
> > +		l_timeout_remove(pvt->tx_timeout);
> > +		pvt->tx_timeout = NULL;
> > +		l_idle_oneshot(tx_worker, pvt, NULL);
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static bool find_by_ad_type(const void *a, const void *b)
> > +{
> > +	const struct tx_pkt *tx = a;
> > +	uint8_t ad_type = L_PTR_TO_UINT(b);
> > +
> > +	return !ad_type || ad_type == tx->pkt[0];
> > +}
> > +
> > +static bool find_by_pattern(const void *a, const void *b)
> > +{
> > +	const struct tx_pkt *tx = a;
> > +	const struct tx_pattern *pattern = b;
> > +
> > +	if (tx->len < pattern->len)
> > +		return false;
> > +
> > +	return (!memcmp(tx->pkt, pattern->data, pattern->len));
> > +}
> > +
> > +static bool tx_cancel(struct mesh_io *io, uint8_t *data, uint8_t len)
> > +{
> > +	struct mesh_io_private *pvt = io->pvt;
> > +	struct tx_pkt *tx;
> > +
> > +	if (!data)
> > +		return false;
> > +
> > +	if (len == 1) {
> > +		do {
> > +			tx = l_queue_remove_if(pvt->tx_pkts, find_by_ad_type,
> > +							L_UINT_TO_PTR(data[0]));
> > +			l_free(tx);
> > +		} while (tx);
> > +	}  else {
> > +		struct tx_pattern pattern = {
> > +			.data = data,
> > +			.len = len
> > +		};
> > +
> > +		do {
> > +			tx = l_queue_remove_if(pvt->tx_pkts, find_by_pattern,
> > +								&pattern);
> > +			l_free(tx);
> > +		} while (tx);
> > +	}
> > +
> > +	if (l_queue_isempty(pvt->tx_pkts)) {
> > +		send_cancel(pvt);
> > +		l_timeout_remove(pvt->tx_timeout);
> > +		pvt->tx_timeout = NULL;
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static bool find_by_filter_id(const void *a, const void *b)
> > +{
> > +	const struct pvt_rx_reg *rx_reg = a;
> > +	uint8_t filter_id = L_PTR_TO_UINT(b);
> > +
> > +	return rx_reg->filter_id == filter_id;
> > +}
> > +
> > +static bool recv_register(struct mesh_io *io, uint8_t filter_id,
> > +				mesh_io_recv_func_t cb, void *user_data)
> > +{
> > +	struct bt_hci_cmd_le_set_scan_enable cmd;
> > +	struct mesh_io_private *pvt = io->pvt;
> > +	struct pvt_rx_reg *rx_reg;
> > +	bool scanning;
> > +
> > +	l_info("%s %d", __func__, filter_id);
> > +	if (!cb || !filter_id || filter_id > sizeof(pvt->filters))
> > +		return false;
> > +
> > +	rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter_id,
> > +						L_UINT_TO_PTR(filter_id));
> > +
> > +	if (!rx_reg) {
> > +		rx_reg = l_new(struct pvt_rx_reg, 1);
> > +		if (!rx_reg)
> > +			return false;
> > +	}
> > +
> > +	rx_reg->filter_id = filter_id;
> > +	rx_reg->cb = cb;
> > +	rx_reg->user_data = user_data;
> > +
> > +	scanning = !l_queue_isempty(pvt->rx_regs);
> > +
> > +	l_queue_push_head(pvt->rx_regs, rx_reg);
> > +
> > +	if (!scanning) {
> > +		cmd.enable = 0x01;	/* Enable scanning */
> > +		cmd.filter_dup = 0x00;	/* Report duplicates */
> > +		bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
> > +				&cmd, sizeof(cmd), NULL, NULL, NULL);
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static bool recv_deregister(struct mesh_io *io, uint8_t filter_id)
> > +{
> > +	struct bt_hci_cmd_le_set_scan_enable cmd;
> > +	struct mesh_io_private *pvt = io->pvt;
> > +
> > +	struct pvt_rx_reg *rx_reg;
> > +
> > +	rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter_id,
> > +						L_UINT_TO_PTR(filter_id));
> > +
> > +	if (rx_reg)
> > +		l_free(rx_reg);
> > +
> > +	if (l_queue_isempty(pvt->rx_regs)) {
> > +		cmd.enable = 0x00;	/* Disable scanning */
> > +		cmd.filter_dup = 0x00;	/* Report duplicates */
> > +		bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
> > +				&cmd, sizeof(cmd), NULL, NULL, NULL);
> > +
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static bool filter_set(struct mesh_io *io,
> > +		uint8_t filter_id, const uint8_t *data, uint8_t len,
> > +		mesh_io_status_func_t callback, void *user_data)
> > +{
> > +	struct mesh_io_private *pvt = io->pvt;
> > +
> > +	l_info("%s id: %d, --> %2.2x", __func__, filter_id, data[0]);
> > +	if (!data || !len || !filter_id || filter_id > sizeof(pvt->filters))
> > +		return false;
> > +
> > +	pvt->filters[filter_id - 1] = data[0];
> > +
> > +	/* TODO: Delayed Call to successful status */
> > +
> > +	return true;
> > +}
> > +
> > +const struct mesh_io_api mesh_io_generic = {
> > +	.init = dev_init,
> > +	.destroy = dev_destroy,
> > +	.caps = dev_caps,
> > +	.send = send_tx,
> > +	.reg = recv_register,
> > +	.dereg = recv_deregister,
> > +	.set = filter_set,
> > +	.cancel = tx_cancel,
> > +};
> > diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c
> > new file mode 100644
> > index 000000000..762eb2c6f
> > --- /dev/null
> > +++ b/mesh/mesh-io.c
> > @@ -0,0 +1,187 @@
> > +/*
> > + *
> > + *  BlueZ - Bluetooth protocol stack for Linux
> > + *
> > + *  Copyright (C) 2018  Intel Corporation. All rights reserved.
> > + *
> > + *
> > + *  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.
> > + *
> > + */
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include <config.h>
> > +#endif
> > +
> > +#include <ell/ell.h>
> > +
> > +#include "lib/bluetooth.h"
> > +#include "lib/hci.h"
> > +
> > +#include "mesh/mesh-defs.h"
> > +
> > +#include "mesh/mesh-io.h"
> > +#include "mesh/mesh-io-api.h"
> > +
> > +/* List of Mesh-IO Type headers */
> > +#include "mesh/mesh-io-generic.h"
> > +
> > +/* List of Supported Mesh-IO Types */
> > +static const struct mesh_io_table table[] = {
> > +	{MESH_IO_TYPE_GENERIC,	&mesh_io_generic},
> > +};
> 
> 	{ MESH.., &mesh.. }

Fixed in v6

> > +
> > +static struct l_queue *io_list;
> > +
> > +static bool match_by_io(const void *a, const void *b)
> > +{
> > +	return a == b;
> > +}
> > +
> > +static bool match_by_index(const void *a, const void *b)
> > +{
> > +	const struct mesh_io *io = a;
> > +
> > +	return io->index == L_PTR_TO_UINT(b);
> > +}
> > +
> > +struct mesh_io *mesh_io_new(uint16_t index, enum mesh_io_type type)
> > +{
> > +	const struct mesh_io_api	*api = NULL;
> > +	struct mesh_io			*io;
> > +	uint16_t			i;
> 
> No alignment of variable names please.

Fixed in v6

> > +
> > +	l_info("%s %d\n", __func__, type);
> 
> Empty line here.

Fixed in v6

> > +	for (i = 0; i < L_ARRAY_SIZE(table); i++) {
> > +		if (table[i].type == type) {
> > +			api = table[i].api;
> > +			break;
> > +		}
> > +	}
> > +
> > +	io = l_queue_find(io_list, match_by_index, L_UINT_TO_PTR(index));
> > +
> > +	if (api == NULL || api->init == NULL || io != NULL)
> > +		return NULL;
> > +
> > +	io = l_new(struct mesh_io, 1);
> > +
> > +	if (io == NULL)
> > +		return NULL;
> 
> Use if (!io).

Fixed in v6

> > +
> > +	io->type = type;
> > +	io->index = index;
> > +	io->api = api;
> > +	if (!api->init(index, io))
> > +		goto fail;
> > +
> > +	if (io_list == NULL)
> > +		io_list = l_queue_new();
> > +
> > +	if (api->set) {
> > +		uint8_t pkt = MESH_AD_TYPE_NETWORK;
> > +		uint8_t bec = MESH_AD_TYPE_BEACON;
> > +		uint8_t prv = MESH_AD_TYPE_PROVISION;
> > +
> > +		api->set(io, 1, &bec, 1, NULL, NULL);
> > +		api->set(io, 2, &prv, 1, NULL, NULL);
> > +		api->set(io, 3, &pkt, 1, NULL, NULL);
> > +	}
> > +
> > +	if (l_queue_push_head(io_list, io))
> > +		return io;
> > +
> > +fail:
> > +	if (api->destroy)
> > +		api->destroy(io);
> > +
> > +	l_free(io);
> > +	return NULL;
> > +}
> > +
> > +void mesh_io_destroy(struct mesh_io *io)
> > +{
> > +	io = l_queue_remove_if(io_list, match_by_io, io);
> > +
> > +	if (io && io->api && io->api->destroy)
> > +		io->api->destroy(io);
> > +
> > +	l_free(io);
> > +
> > +	if (l_queue_isempty(io_list)) {
> > +		l_queue_destroy(io_list, NULL);
> > +		io_list = NULL;
> > +	}
> > +}
> > +
> > +bool mesh_io_get_caps(struct mesh_io *io, struct mesh_io_caps *caps)
> > +{
> > +	io = l_queue_find(io_list, match_by_io, io);
> > +
> > +	if (io && io->api && io->api->caps)
> > +		return io->api->caps(io, caps);
> > +
> > +	return false;
> > +}
> > +
> > +bool mesh_io_register_recv_cb(struct mesh_io *io, uint8_t filter_id,
> > +				mesh_io_recv_func_t cb, void *user_data)
> > +{
> > +	io = l_queue_find(io_list, match_by_io, io);
> > +
> > +	if (io && io->api && io->api->reg)
> > +		return io->api->reg(io, filter_id, cb, user_data);
> > +
> > +	return false;
> > +}
> > +
> > +bool mesh_io_deregister_recv_cb(struct mesh_io *io, uint8_t filter_id)
> > +{
> > +	io = l_queue_find(io_list, match_by_io, io);
> > +
> > +	if (io && io->api && io->api->dereg)
> > +		return io->api->dereg(io, filter_id);
> > +
> > +	return false;
> > +}
> > +
> > +bool mesh_set_filter(struct mesh_io *io, uint8_t filter_id,
> > +				const uint8_t *data, uint8_t len,
> > +				mesh_io_status_func_t cb, void *user_data)
> > +{
> > +	io = l_queue_find(io_list, match_by_io, io);
> > +
> > +	if (io && io->api && io->api->set)
> > +		return io->api->set(io, filter_id, data, len, cb, user_data);
> > +
> > +	return false;
> > +}
> > +
> > +bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info,
> > +					const uint8_t *data, uint16_t len)
> > +{
> > +	io = l_queue_find(io_list, match_by_io, io);
> > +
> > +	if (io && io->api && io->api->send)
> > +		return io->api->send(io, info, data, len);
> > +
> > +	return false;
> > +}
> > +
> > +bool mesh_io_send_cancel(struct mesh_io *io, uint8_t *pattern, uint8_t len)
> > +{
> > +	io = l_queue_find(io_list, match_by_io, io);
> > +
> > +	if (io && io->api && io->api->cancel)
> > +		return io->api->cancel(io, pattern, len);
> > +
> > +	return false;
> > +}
> 
> Regards
> 
> Marcel
> ��.n��������+%������w��{.n�����{����^n�r������&��z�ޗ�zf���h���~����������_��+v���)ߣ�


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux