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

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

 



---
 mesh/display.c         |  64 +++++
 mesh/mesh-io-generic.c | 660 +++++++++++++++++++++++++++++++++++++++++++++++++
 mesh/mesh-io.c         | 188 ++++++++++++++
 3 files changed, 912 insertions(+)
 create mode 100644 mesh/display.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..8238ae849
--- /dev/null
+++ b/mesh/display.c
@@ -0,0 +1,64 @@
+/*
+ *
+ *  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"
+
+static unsigned int cached_num_columns;
+
+unsigned int num_columns(void)
+{
+	struct winsize ws;
+
+	if (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_debug("%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_debug("%05d.%03d %s: empty",
+				(uint32_t) pkt_time.tv_sec % 100000,
+				(uint32_t) pkt_time.tv_usec/1000, label);
+}
diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c
new file mode 100644
index 000000000..52514e280
--- /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 "src/shared/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..5cdfdc5ff
--- /dev/null
+++ b/mesh/mesh-io.c
@@ -0,0 +1,188 @@
+/*
+ *
+ *  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}
+};
+
+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;
+
+	l_info("%s %d\n", __func__, type);
+
+	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 || !api->init || io)
+		return NULL;
+
+	io = l_new(struct mesh_io, 1);
+
+	if (!io)
+		return NULL;
+
+	io->type = type;
+	io->index = index;
+	io->api = api;
+	if (!api->init(index, io))
+		goto fail;
+
+	if (!io_list)
+		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;
+}
-- 
2.14.4

--
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



[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