Blame mesh/mesh-io-generic.c

Packit Service 8264ee
/*
Packit Service 8264ee
 *
Packit Service 8264ee
 *  BlueZ - Bluetooth protocol stack for Linux
Packit Service 8264ee
 *
Packit Service 8264ee
 *  Copyright (C) 2018-2019  Intel Corporation. All rights reserved.
Packit Service 8264ee
 *
Packit Service 8264ee
 *
Packit Service 8264ee
 *  This library is free software; you can redistribute it and/or
Packit Service 8264ee
 *  modify it under the terms of the GNU Lesser General Public
Packit Service 8264ee
 *  License as published by the Free Software Foundation; either
Packit Service 8264ee
 *  version 2.1 of the License, or (at your option) any later version.
Packit Service 8264ee
 *
Packit Service 8264ee
 *  This library is distributed in the hope that it will be useful,
Packit Service 8264ee
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 8264ee
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 8264ee
 *  Lesser General Public License for more details.
Packit Service 8264ee
 *
Packit Service 8264ee
 */
Packit Service 8264ee
Packit Service 8264ee
#ifdef HAVE_CONFIG_H
Packit Service 8264ee
#include <config.h>
Packit Service 8264ee
#endif
Packit Service 8264ee
Packit Service 8264ee
#include <errno.h>
Packit Service 8264ee
#include <string.h>
Packit Service 8264ee
#include <sys/time.h>
Packit Service 8264ee
#include <ell/ell.h>
Packit Service 8264ee
Packit Service 8264ee
#include "monitor/bt.h"
Packit Service 8264ee
#include "src/shared/hci.h"
Packit Service 8264ee
#include "lib/bluetooth.h"
Packit Service 8264ee
#include "lib/mgmt.h"
Packit Service 8264ee
Packit Service 8264ee
#include "mesh/mesh-mgmt.h"
Packit Service 8264ee
#include "mesh/mesh-io.h"
Packit Service 8264ee
#include "mesh/mesh-io-api.h"
Packit Service 8264ee
#include "mesh/mesh-io-generic.h"
Packit Service 8264ee
Packit Service 8264ee
struct mesh_io_private {
Packit Service 8264ee
	uint16_t index;
Packit Service 8264ee
	struct bt_hci *hci;
Packit Service 8264ee
	struct l_timeout *tx_timeout;
Packit Service 8264ee
	struct l_queue *rx_regs;
Packit Service 8264ee
	struct l_queue *tx_pkts;
Packit Service 8264ee
	uint8_t filters[4];
Packit Service 8264ee
	bool sending;
Packit Service 8264ee
	struct tx_pkt *tx;
Packit Service 8264ee
	uint16_t interval;
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
struct pvt_rx_reg {
Packit Service 8264ee
	uint8_t filter_id;
Packit Service 8264ee
	mesh_io_recv_func_t cb;
Packit Service 8264ee
	void *user_data;
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
struct process_data {
Packit Service 8264ee
	struct mesh_io_private		*pvt;
Packit Service 8264ee
	const uint8_t			*data;
Packit Service 8264ee
	uint8_t				len;
Packit Service 8264ee
	struct mesh_io_recv_info	info;
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
struct tx_pkt {
Packit Service 8264ee
	struct mesh_io_send_info	info;
Packit Service 8264ee
	bool				delete;
Packit Service 8264ee
	uint8_t				len;
Packit Service 8264ee
	uint8_t				pkt[30];
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
struct tx_pattern {
Packit Service 8264ee
	const uint8_t			*data;
Packit Service 8264ee
	uint8_t				len;
Packit Service 8264ee
};
Packit Service 8264ee
Packit Service 8264ee
static uint32_t get_instant(void)
Packit Service 8264ee
{
Packit Service 8264ee
	struct timeval tm;
Packit Service 8264ee
	uint32_t instant;
Packit Service 8264ee
Packit Service 8264ee
	gettimeofday(&tm, NULL);
Packit Service 8264ee
	instant = tm.tv_sec * 1000;
Packit Service 8264ee
	instant += tm.tv_usec / 1000;
Packit Service 8264ee
Packit Service 8264ee
	return instant;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static uint32_t instant_remaining_ms(uint32_t instant)
Packit Service 8264ee
{
Packit Service 8264ee
	instant -= get_instant();
Packit Service 8264ee
	return instant;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void process_rx_callbacks(void *v_rx, void *v_reg)
Packit Service 8264ee
{
Packit Service 8264ee
	struct pvt_rx_reg *rx_reg = v_rx;
Packit Service 8264ee
	struct process_data *rx = v_reg;
Packit Service 8264ee
	uint8_t ad_type;
Packit Service 8264ee
Packit Service 8264ee
	ad_type = rx->pvt->filters[rx_reg->filter_id - 1];
Packit Service 8264ee
Packit Service 8264ee
	if (rx->data[0] == ad_type && rx_reg->cb)
Packit Service 8264ee
		rx_reg->cb(rx_reg->user_data, &rx->info, rx->data, rx->len);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void process_rx(struct mesh_io_private *pvt, int8_t rssi,
Packit Service 8264ee
					uint32_t instant,
Packit Service 8264ee
					const uint8_t *data, uint8_t len)
Packit Service 8264ee
{
Packit Service 8264ee
	struct process_data rx = {
Packit Service 8264ee
		.pvt = pvt,
Packit Service 8264ee
		.data = data,
Packit Service 8264ee
		.len = len,
Packit Service 8264ee
		.info.instant = instant,
Packit Service 8264ee
		.info.chan = 7,
Packit Service 8264ee
		.info.rssi = rssi,
Packit Service 8264ee
	};
Packit Service 8264ee
Packit Service 8264ee
	l_queue_foreach(pvt->rx_regs, process_rx_callbacks, &rx);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void event_adv_report(struct mesh_io *io, const void *buf, uint8_t size)
Packit Service 8264ee
{
Packit Service 8264ee
	const struct bt_hci_evt_le_adv_report *evt = buf;
Packit Service 8264ee
	const uint8_t *adv;
Packit Service 8264ee
	uint32_t instant;
Packit Service 8264ee
	uint8_t adv_len;
Packit Service 8264ee
	uint16_t len = 0;
Packit Service 8264ee
	int8_t rssi;
Packit Service 8264ee
Packit Service 8264ee
	if (evt->event_type != 0x03)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	instant = get_instant();
Packit Service 8264ee
	adv = evt->data;
Packit Service 8264ee
	adv_len = evt->data_len;
Packit Service 8264ee
Packit Service 8264ee
	/* rssi is just beyond last byte of data */
Packit Service 8264ee
	rssi = (int8_t) adv[adv_len];
Packit Service 8264ee
Packit Service 8264ee
	while (len < adv_len - 1) {
Packit Service 8264ee
		uint8_t field_len = adv[0];
Packit Service 8264ee
Packit Service 8264ee
		/* Check for the end of advertising data */
Packit Service 8264ee
		if (field_len == 0)
Packit Service 8264ee
			break;
Packit Service 8264ee
Packit Service 8264ee
		len += field_len + 1;
Packit Service 8264ee
Packit Service 8264ee
		/* Do not continue data parsing if got incorrect length */
Packit Service 8264ee
		if (len > adv_len)
Packit Service 8264ee
			break;
Packit Service 8264ee
Packit Service 8264ee
		/* TODO: Create an Instant to use */
Packit Service 8264ee
		process_rx(io->pvt, rssi, instant, adv + 1, adv[0]);
Packit Service 8264ee
Packit Service 8264ee
		adv += field_len + 1;
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void event_callback(const void *buf, uint8_t size, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	uint8_t event = l_get_u8(buf);
Packit Service 8264ee
	struct mesh_io *io = user_data;
Packit Service 8264ee
Packit Service 8264ee
	switch (event) {
Packit Service 8264ee
	case BT_HCI_EVT_LE_ADV_REPORT:
Packit Service 8264ee
		event_adv_report(io, buf + 1, size - 1);
Packit Service 8264ee
		break;
Packit Service 8264ee
Packit Service 8264ee
	default:
Packit Service 8264ee
		l_info("Other Meta Evt - %d", event);
Packit Service 8264ee
	}
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void local_commands_callback(const void *data, uint8_t size,
Packit Service 8264ee
							void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	const struct bt_hci_rsp_read_local_commands *rsp = data;
Packit Service 8264ee
Packit Service 8264ee
	if (rsp->status)
Packit Service 8264ee
		l_error("Failed to read local commands");
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void local_features_callback(const void *data, uint8_t size,
Packit Service 8264ee
							void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	const struct bt_hci_rsp_read_local_features *rsp = data;
Packit Service 8264ee
Packit Service 8264ee
	if (rsp->status)
Packit Service 8264ee
		l_error("Failed to read local features");
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void hci_generic_callback(const void *data, uint8_t size,
Packit Service 8264ee
								void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	uint8_t status = l_get_u8(data);
Packit Service 8264ee
Packit Service 8264ee
	if (status)
Packit Service 8264ee
		l_error("Failed to initialize HCI");
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void configure_hci(struct mesh_io_private *io)
Packit Service 8264ee
{
Packit Service 8264ee
	struct bt_hci_cmd_le_set_scan_parameters cmd;
Packit Service 8264ee
	struct bt_hci_cmd_set_event_mask cmd_sem;
Packit Service 8264ee
	struct bt_hci_cmd_le_set_event_mask cmd_slem;
Packit Service 8264ee
Packit Service 8264ee
	/* Set scan parameters */
Packit Service 8264ee
	cmd.type = 0x00; /* Passive Scanning. No scanning PDUs shall be sent */
Packit Service 8264ee
	cmd.interval = 0x0030; /* Scan Interval = N * 0.625ms */
Packit Service 8264ee
	cmd.window = 0x0030; /* Scan Window = N * 0.625ms */
Packit Service 8264ee
	cmd.own_addr_type = 0x00; /* Public Device Address */
Packit Service 8264ee
	/* Accept all advertising packets except directed advertising packets
Packit Service 8264ee
	 * not addressed to this device (default).
Packit Service 8264ee
	 */
Packit Service 8264ee
	cmd.filter_policy = 0x00;
Packit Service 8264ee
Packit Service 8264ee
	/* Set event mask
Packit Service 8264ee
	 *
Packit Service 8264ee
	 * Mask: 0x2000800002008890
Packit Service 8264ee
	 *   Disconnection Complete
Packit Service 8264ee
	 *   Encryption Change
Packit Service 8264ee
	 *   Read Remote Version Information Complete
Packit Service 8264ee
	 *   Hardware Error
Packit Service 8264ee
	 *   Data Buffer Overflow
Packit Service 8264ee
	 *   Encryption Key Refresh Complete
Packit Service 8264ee
	 *   LE Meta
Packit Service 8264ee
	 */
Packit Service 8264ee
	cmd_sem.mask[0] = 0x90;
Packit Service 8264ee
	cmd_sem.mask[1] = 0x88;
Packit Service 8264ee
	cmd_sem.mask[2] = 0x00;
Packit Service 8264ee
	cmd_sem.mask[3] = 0x02;
Packit Service 8264ee
	cmd_sem.mask[4] = 0x00;
Packit Service 8264ee
	cmd_sem.mask[5] = 0x80;
Packit Service 8264ee
	cmd_sem.mask[6] = 0x00;
Packit Service 8264ee
	cmd_sem.mask[7] = 0x20;
Packit Service 8264ee
Packit Service 8264ee
	/* Set LE event mask
Packit Service 8264ee
	 *
Packit Service 8264ee
	 * Mask: 0x000000000000087f
Packit Service 8264ee
	 *   LE Connection Complete
Packit Service 8264ee
	 *   LE Advertising Report
Packit Service 8264ee
	 *   LE Connection Update Complete
Packit Service 8264ee
	 *   LE Read Remote Used Features Complete
Packit Service 8264ee
	 *   LE Long Term Key Request
Packit Service 8264ee
	 *   LE Remote Connection Parameter Request
Packit Service 8264ee
	 *   LE Data Length Change
Packit Service 8264ee
	 *   LE PHY Update Complete
Packit Service 8264ee
	 */
Packit Service 8264ee
	cmd_slem.mask[0] = 0x7f;
Packit Service 8264ee
	cmd_slem.mask[1] = 0x08;
Packit Service 8264ee
	cmd_slem.mask[2] = 0x00;
Packit Service 8264ee
	cmd_slem.mask[3] = 0x00;
Packit Service 8264ee
	cmd_slem.mask[4] = 0x00;
Packit Service 8264ee
	cmd_slem.mask[5] = 0x00;
Packit Service 8264ee
	cmd_slem.mask[6] = 0x00;
Packit Service 8264ee
	cmd_slem.mask[7] = 0x00;
Packit Service 8264ee
Packit Service 8264ee
	/* TODO: Move to suitable place. Set suitable masks */
Packit Service 8264ee
	/* Reset Command */
Packit Service 8264ee
	bt_hci_send(io->hci, BT_HCI_CMD_RESET, NULL, 0, hci_generic_callback,
Packit Service 8264ee
								NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
	/* Read local supported commands */
Packit Service 8264ee
	bt_hci_send(io->hci, BT_HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0,
Packit Service 8264ee
					local_commands_callback, NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
	/* Read local supported features */
Packit Service 8264ee
	bt_hci_send(io->hci, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0,
Packit Service 8264ee
					local_features_callback, NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
	/* Set event mask */
Packit Service 8264ee
	bt_hci_send(io->hci, BT_HCI_CMD_SET_EVENT_MASK, &cmd_sem,
Packit Service 8264ee
			sizeof(cmd_sem), hci_generic_callback, NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
	/* Set LE event mask */
Packit Service 8264ee
	bt_hci_send(io->hci, BT_HCI_CMD_LE_SET_EVENT_MASK, &cmd_slem,
Packit Service 8264ee
			sizeof(cmd_slem), hci_generic_callback, NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
	/* Scan Params */
Packit Service 8264ee
	bt_hci_send(io->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS, &cmd,
Packit Service 8264ee
				sizeof(cmd), hci_generic_callback, NULL, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool hci_init(struct mesh_io *io)
Packit Service 8264ee
{
Packit Service 8264ee
	io->pvt->hci = bt_hci_new_user_channel(io->pvt->index);
Packit Service 8264ee
	if (!io->pvt->hci) {
Packit Service 8264ee
		l_error("Failed to start mesh io (hci %u): %s", io->pvt->index,
Packit Service 8264ee
							strerror(errno));
Packit Service 8264ee
		return false;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	configure_hci(io->pvt);
Packit Service 8264ee
Packit Service 8264ee
	bt_hci_register(io->pvt->hci, BT_HCI_EVT_LE_META_EVENT,
Packit Service 8264ee
						event_callback, io, NULL);
Packit Service 8264ee
Packit Service 8264ee
	l_debug("Started mesh on hci %u", io->pvt->index);
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void read_info(int index, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io *io = user_data;
Packit Service 8264ee
Packit Service 8264ee
	if (io->pvt->index != MGMT_INDEX_NONE &&
Packit Service 8264ee
					index != io->pvt->index) {
Packit Service 8264ee
		l_debug("Ignore index %d", index);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	io->pvt->index = index;
Packit Service 8264ee
	hci_init(io);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool dev_init(struct mesh_io *io, void *opts)
Packit Service 8264ee
{
Packit Service 8264ee
	if (!io || io->pvt)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	io->pvt = l_new(struct mesh_io_private, 1);
Packit Service 8264ee
	io->pvt->index = *(int *)opts;
Packit Service 8264ee
Packit Service 8264ee
	io->pvt->rx_regs = l_queue_new();
Packit Service 8264ee
	io->pvt->tx_pkts = l_queue_new();
Packit Service 8264ee
Packit Service 8264ee
	if (io->pvt->index == MGMT_INDEX_NONE)
Packit Service 8264ee
		return mesh_mgmt_list(read_info, io);
Packit Service 8264ee
	else
Packit Service 8264ee
		return hci_init(io);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool dev_destroy(struct mesh_io *io)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = io->pvt;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt)
Packit Service 8264ee
		return true;
Packit Service 8264ee
Packit Service 8264ee
	bt_hci_unref(pvt->hci);
Packit Service 8264ee
	l_timeout_remove(pvt->tx_timeout);
Packit Service 8264ee
	l_queue_destroy(pvt->rx_regs, l_free);
Packit Service 8264ee
	l_queue_destroy(pvt->tx_pkts, l_free);
Packit Service 8264ee
	l_free(pvt);
Packit Service 8264ee
	io->pvt = NULL;
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool dev_caps(struct mesh_io *io, struct mesh_io_caps *caps)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = io->pvt;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt || !caps)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	caps->max_num_filters = sizeof(pvt->filters);
Packit Service 8264ee
	caps->window_accuracy = 50;
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void send_cancel_done(const void *buf, uint8_t size,
Packit Service 8264ee
							void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = user_data;
Packit Service 8264ee
	struct bt_hci_cmd_le_set_random_address cmd;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	pvt->sending = false;
Packit Service 8264ee
Packit Service 8264ee
	/* At end of any burst of ADVs, change random address */
Packit Service 8264ee
	l_getrandom(cmd.addr, 6);
Packit Service 8264ee
	cmd.addr[5] |= 0xc0;
Packit Service 8264ee
	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_RANDOM_ADDRESS,
Packit Service 8264ee
				&cmd, sizeof(cmd), NULL, NULL, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void send_cancel(struct mesh_io_private *pvt)
Packit Service 8264ee
{
Packit Service 8264ee
	struct bt_hci_cmd_le_set_adv_enable cmd;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt->sending) {
Packit Service 8264ee
		send_cancel_done(NULL, 0, pvt);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	cmd.enable = 0x00;	/* Disable advertising */
Packit Service 8264ee
	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_ENABLE,
Packit Service 8264ee
				&cmd, sizeof(cmd),
Packit Service 8264ee
				send_cancel_done, pvt, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void set_send_adv_enable(const void *buf, uint8_t size,
Packit Service 8264ee
							void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = user_data;
Packit Service 8264ee
	struct bt_hci_cmd_le_set_adv_enable cmd;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	pvt->sending = true;
Packit Service 8264ee
	cmd.enable = 0x01;	/* Enable advertising */
Packit Service 8264ee
	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_ENABLE,
Packit Service 8264ee
				&cmd, sizeof(cmd), NULL, NULL, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void set_send_adv_data(const void *buf, uint8_t size,
Packit Service 8264ee
							void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = user_data;
Packit Service 8264ee
	struct tx_pkt *tx;
Packit Service 8264ee
	struct bt_hci_cmd_le_set_adv_data cmd;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt || !pvt->tx)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	tx = pvt->tx;
Packit Service 8264ee
	if (tx->len >= sizeof(cmd.data))
Packit Service 8264ee
		goto done;
Packit Service 8264ee
Packit Service 8264ee
	memset(&cmd, 0, sizeof(cmd));
Packit Service 8264ee
Packit Service 8264ee
	cmd.len = tx->len + 1;
Packit Service 8264ee
	cmd.data[0] = tx->len;
Packit Service 8264ee
	memcpy(cmd.data + 1, tx->pkt, tx->len);
Packit Service 8264ee
Packit Service 8264ee
	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_DATA,
Packit Service 8264ee
					&cmd, sizeof(cmd),
Packit Service 8264ee
					set_send_adv_enable, pvt, NULL);
Packit Service 8264ee
done:
Packit Service 8264ee
	if (tx->delete)
Packit Service 8264ee
		l_free(tx);
Packit Service 8264ee
Packit Service 8264ee
	pvt->tx = NULL;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void set_send_adv_params(const void *buf, uint8_t size,
Packit Service 8264ee
							void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = user_data;
Packit Service 8264ee
	struct bt_hci_cmd_le_set_adv_parameters cmd;
Packit Service 8264ee
	uint16_t hci_interval;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	hci_interval = (pvt->interval * 16) / 10;
Packit Service 8264ee
	cmd.min_interval = L_CPU_TO_LE16(hci_interval);
Packit Service 8264ee
	cmd.max_interval = L_CPU_TO_LE16(hci_interval);
Packit Service 8264ee
	cmd.type = 0x03; /* ADV_NONCONN_IND */
Packit Service 8264ee
	cmd.own_addr_type = 0x01; /* ADDR_TYPE_RANDOM */
Packit Service 8264ee
	cmd.direct_addr_type = 0x00;
Packit Service 8264ee
	memset(cmd.direct_addr, 0, 6);
Packit Service 8264ee
	cmd.channel_map = 0x07;
Packit Service 8264ee
	cmd.filter_policy = 0x03;
Packit Service 8264ee
Packit Service 8264ee
	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
Packit Service 8264ee
				&cmd, sizeof(cmd),
Packit Service 8264ee
				set_send_adv_data, pvt, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void send_pkt(struct mesh_io_private *pvt, struct tx_pkt *tx,
Packit Service 8264ee
							uint16_t interval)
Packit Service 8264ee
{
Packit Service 8264ee
	struct bt_hci_cmd_le_set_adv_enable cmd;
Packit Service 8264ee
Packit Service 8264ee
	pvt->tx = tx;
Packit Service 8264ee
	pvt->interval = interval;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt->sending) {
Packit Service 8264ee
		set_send_adv_params(NULL, 0, pvt);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	cmd.enable = 0x00;	/* Disable advertising */
Packit Service 8264ee
	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_ADV_ENABLE,
Packit Service 8264ee
				&cmd, sizeof(cmd),
Packit Service 8264ee
				set_send_adv_params, pvt, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void tx_timeout(struct l_timeout *timeout, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = user_data;
Packit Service 8264ee
	struct tx_pkt *tx;
Packit Service 8264ee
	uint16_t ms;
Packit Service 8264ee
	uint8_t count;
Packit Service 8264ee
Packit Service 8264ee
	if (!pvt)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	tx = l_queue_pop_head(pvt->tx_pkts);
Packit Service 8264ee
	if (!tx) {
Packit Service 8264ee
		l_timeout_remove(timeout);
Packit Service 8264ee
		pvt->tx_timeout = NULL;
Packit Service 8264ee
		send_cancel(pvt);
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (tx->info.type == MESH_IO_TIMING_TYPE_GENERAL) {
Packit Service 8264ee
		ms = tx->info.u.gen.interval;
Packit Service 8264ee
		count = tx->info.u.gen.cnt;
Packit Service 8264ee
		if (count != MESH_IO_TX_COUNT_UNLIMITED)
Packit Service 8264ee
			tx->info.u.gen.cnt--;
Packit Service 8264ee
	} else {
Packit Service 8264ee
		ms = 25;
Packit Service 8264ee
		count = 1;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	tx->delete = !!(count == 1);
Packit Service 8264ee
Packit Service 8264ee
	send_pkt(pvt, tx, ms);
Packit Service 8264ee
Packit Service 8264ee
	if (count == 1) {
Packit Service 8264ee
		/* send_pkt will delete when done */
Packit Service 8264ee
		tx = l_queue_peek_head(pvt->tx_pkts);
Packit Service 8264ee
		if (tx && tx->info.type == MESH_IO_TIMING_TYPE_POLL_RSP) {
Packit Service 8264ee
			ms = instant_remaining_ms(tx->info.u.poll_rsp.instant +
Packit Service 8264ee
						tx->info.u.poll_rsp.delay);
Packit Service 8264ee
		}
Packit Service 8264ee
	} else
Packit Service 8264ee
		l_queue_push_tail(pvt->tx_pkts, tx);
Packit Service 8264ee
Packit Service 8264ee
	if (timeout) {
Packit Service 8264ee
		pvt->tx_timeout = timeout;
Packit Service 8264ee
		l_timeout_modify_ms(timeout, ms);
Packit Service 8264ee
	} else
Packit Service 8264ee
		pvt->tx_timeout = l_timeout_create_ms(ms, tx_timeout,
Packit Service 8264ee
								pvt, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void tx_worker(void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = user_data;
Packit Service 8264ee
	struct tx_pkt *tx;
Packit Service 8264ee
	uint32_t delay;
Packit Service 8264ee
Packit Service 8264ee
	tx = l_queue_peek_head(pvt->tx_pkts);
Packit Service 8264ee
	if (!tx)
Packit Service 8264ee
		return;
Packit Service 8264ee
Packit Service 8264ee
	switch (tx->info.type) {
Packit Service 8264ee
	case MESH_IO_TIMING_TYPE_GENERAL:
Packit Service 8264ee
		if (tx->info.u.gen.min_delay == tx->info.u.gen.max_delay)
Packit Service 8264ee
			delay = tx->info.u.gen.min_delay;
Packit Service 8264ee
		else {
Packit Service 8264ee
			l_getrandom(&delay, sizeof(delay));
Packit Service 8264ee
			delay %= tx->info.u.gen.max_delay -
Packit Service 8264ee
						tx->info.u.gen.min_delay;
Packit Service 8264ee
			delay += tx->info.u.gen.min_delay;
Packit Service 8264ee
		}
Packit Service 8264ee
		break;
Packit Service 8264ee
Packit Service 8264ee
	case MESH_IO_TIMING_TYPE_POLL:
Packit Service 8264ee
		if (tx->info.u.poll.min_delay == tx->info.u.poll.max_delay)
Packit Service 8264ee
			delay = tx->info.u.poll.min_delay;
Packit Service 8264ee
		else {
Packit Service 8264ee
			l_getrandom(&delay, sizeof(delay));
Packit Service 8264ee
			delay %= tx->info.u.poll.max_delay -
Packit Service 8264ee
						tx->info.u.poll.min_delay;
Packit Service 8264ee
			delay += tx->info.u.poll.min_delay;
Packit Service 8264ee
		}
Packit Service 8264ee
		break;
Packit Service 8264ee
Packit Service 8264ee
	case MESH_IO_TIMING_TYPE_POLL_RSP:
Packit Service 8264ee
		/* Delay until Instant + Delay */
Packit Service 8264ee
		delay = instant_remaining_ms(tx->info.u.poll_rsp.instant +
Packit Service 8264ee
						tx->info.u.poll_rsp.delay);
Packit Service 8264ee
		if (delay > 255)
Packit Service 8264ee
			delay = 0;
Packit Service 8264ee
		break;
Packit Service 8264ee
Packit Service 8264ee
	default:
Packit Service 8264ee
		return;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!delay)
Packit Service 8264ee
		tx_timeout(pvt->tx_timeout, pvt);
Packit Service 8264ee
	else if (pvt->tx_timeout)
Packit Service 8264ee
		l_timeout_modify_ms(pvt->tx_timeout, delay);
Packit Service 8264ee
	else
Packit Service 8264ee
		pvt->tx_timeout = l_timeout_create_ms(delay, tx_timeout,
Packit Service 8264ee
								pvt, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool send_tx(struct mesh_io *io, struct mesh_io_send_info *info,
Packit Service 8264ee
					const uint8_t *data, uint16_t len)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = io->pvt;
Packit Service 8264ee
	struct tx_pkt *tx;
Packit Service 8264ee
	bool sending = false;
Packit Service 8264ee
Packit Service 8264ee
	if (!info || !data || !len || len > sizeof(tx->pkt))
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	tx = l_new(struct tx_pkt, 1);
Packit Service 8264ee
	if (!tx)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	memcpy(&tx->info, info, sizeof(tx->info));
Packit Service 8264ee
	memcpy(&tx->pkt, data, len);
Packit Service 8264ee
	tx->len = len;
Packit Service 8264ee
Packit Service 8264ee
	if (info->type == MESH_IO_TIMING_TYPE_POLL_RSP)
Packit Service 8264ee
		l_queue_push_head(pvt->tx_pkts, tx);
Packit Service 8264ee
	else {
Packit Service 8264ee
		sending = !l_queue_isempty(pvt->tx_pkts);
Packit Service 8264ee
		l_queue_push_tail(pvt->tx_pkts, tx);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (!sending) {
Packit Service 8264ee
		l_timeout_remove(pvt->tx_timeout);
Packit Service 8264ee
		pvt->tx_timeout = NULL;
Packit Service 8264ee
		l_idle_oneshot(tx_worker, pvt, NULL);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool find_by_ad_type(const void *a, const void *b)
Packit Service 8264ee
{
Packit Service 8264ee
	const struct tx_pkt *tx = a;
Packit Service 8264ee
	uint8_t ad_type = L_PTR_TO_UINT(b);
Packit Service 8264ee
Packit Service 8264ee
	return !ad_type || ad_type == tx->pkt[0];
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool find_by_pattern(const void *a, const void *b)
Packit Service 8264ee
{
Packit Service 8264ee
	const struct tx_pkt *tx = a;
Packit Service 8264ee
	const struct tx_pattern *pattern = b;
Packit Service 8264ee
Packit Service 8264ee
	if (tx->len < pattern->len)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	return (!memcmp(tx->pkt, pattern->data, pattern->len));
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool tx_cancel(struct mesh_io *io, const uint8_t *data, uint8_t len)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = io->pvt;
Packit Service 8264ee
	struct tx_pkt *tx;
Packit Service 8264ee
Packit Service 8264ee
	if (!data)
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	if (len == 1) {
Packit Service 8264ee
		do {
Packit Service 8264ee
			tx = l_queue_remove_if(pvt->tx_pkts, find_by_ad_type,
Packit Service 8264ee
							L_UINT_TO_PTR(data[0]));
Packit Service 8264ee
			l_free(tx);
Packit Service 8264ee
Packit Service 8264ee
			if (tx == pvt->tx)
Packit Service 8264ee
				pvt->tx = NULL;
Packit Service 8264ee
Packit Service 8264ee
		} while (tx);
Packit Service 8264ee
	} else {
Packit Service 8264ee
		struct tx_pattern pattern = {
Packit Service 8264ee
			.data = data,
Packit Service 8264ee
			.len = len
Packit Service 8264ee
		};
Packit Service 8264ee
Packit Service 8264ee
		do {
Packit Service 8264ee
			tx = l_queue_remove_if(pvt->tx_pkts, find_by_pattern,
Packit Service 8264ee
								&pattern);
Packit Service 8264ee
			l_free(tx);
Packit Service 8264ee
Packit Service 8264ee
			if (tx == pvt->tx)
Packit Service 8264ee
				pvt->tx = NULL;
Packit Service 8264ee
Packit Service 8264ee
		} while (tx);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	if (l_queue_isempty(pvt->tx_pkts)) {
Packit Service 8264ee
		send_cancel(pvt);
Packit Service 8264ee
		l_timeout_remove(pvt->tx_timeout);
Packit Service 8264ee
		pvt->tx_timeout = NULL;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool find_by_filter_id(const void *a, const void *b)
Packit Service 8264ee
{
Packit Service 8264ee
	const struct pvt_rx_reg *rx_reg = a;
Packit Service 8264ee
	uint8_t filter_id = L_PTR_TO_UINT(b);
Packit Service 8264ee
Packit Service 8264ee
	return rx_reg->filter_id == filter_id;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static void set_recv_scan_enable(const void *buf, uint8_t size,
Packit Service 8264ee
							void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = user_data;
Packit Service 8264ee
	struct bt_hci_cmd_le_set_scan_enable cmd;
Packit Service 8264ee
Packit Service 8264ee
	cmd.enable = 0x01;	/* Enable scanning */
Packit Service 8264ee
	cmd.filter_dup = 0x00;	/* Report duplicates */
Packit Service 8264ee
	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
Packit Service 8264ee
			&cmd, sizeof(cmd), NULL, NULL, NULL);
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool recv_register(struct mesh_io *io, uint8_t filter_id,
Packit Service 8264ee
				mesh_io_recv_func_t cb, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct bt_hci_cmd_le_set_scan_parameters cmd;
Packit Service 8264ee
	struct mesh_io_private *pvt = io->pvt;
Packit Service 8264ee
	struct pvt_rx_reg *rx_reg;
Packit Service 8264ee
	bool already_scanning;
Packit Service 8264ee
Packit Service 8264ee
	l_info("%s %d", __func__, filter_id);
Packit Service 8264ee
	if (!cb || !filter_id || filter_id > sizeof(pvt->filters))
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter_id,
Packit Service 8264ee
						L_UINT_TO_PTR(filter_id));
Packit Service 8264ee
Packit Service 8264ee
	if (!rx_reg) {
Packit Service 8264ee
		rx_reg = l_new(struct pvt_rx_reg, 1);
Packit Service 8264ee
		if (!rx_reg)
Packit Service 8264ee
			return false;
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	rx_reg->filter_id = filter_id;
Packit Service 8264ee
	rx_reg->cb = cb;
Packit Service 8264ee
	rx_reg->user_data = user_data;
Packit Service 8264ee
Packit Service 8264ee
	already_scanning = !l_queue_isempty(pvt->rx_regs);
Packit Service 8264ee
Packit Service 8264ee
	l_queue_push_head(pvt->rx_regs, rx_reg);
Packit Service 8264ee
Packit Service 8264ee
	if (!already_scanning) {
Packit Service 8264ee
		cmd.type = 0x00;			/* Passive scanning */
Packit Service 8264ee
		cmd.interval = L_CPU_TO_LE16(0x0010);	/* 10 ms */
Packit Service 8264ee
		cmd.window = L_CPU_TO_LE16(0x0010);	/* 10 ms */
Packit Service 8264ee
		cmd.own_addr_type = 0x01;		/* ADDR_TYPE_RANDOM */
Packit Service 8264ee
		cmd.filter_policy = 0x00;		/* Accept all */
Packit Service 8264ee
Packit Service 8264ee
		bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS,
Packit Service 8264ee
				&cmd, sizeof(cmd),
Packit Service 8264ee
				set_recv_scan_enable, pvt, NULL);
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool recv_deregister(struct mesh_io *io, uint8_t filter_id)
Packit Service 8264ee
{
Packit Service 8264ee
	struct bt_hci_cmd_le_set_scan_enable cmd;
Packit Service 8264ee
	struct mesh_io_private *pvt = io->pvt;
Packit Service 8264ee
Packit Service 8264ee
	struct pvt_rx_reg *rx_reg;
Packit Service 8264ee
Packit Service 8264ee
	rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter_id,
Packit Service 8264ee
						L_UINT_TO_PTR(filter_id));
Packit Service 8264ee
Packit Service 8264ee
	if (rx_reg)
Packit Service 8264ee
		l_free(rx_reg);
Packit Service 8264ee
Packit Service 8264ee
	if (l_queue_isempty(pvt->rx_regs)) {
Packit Service 8264ee
		cmd.enable = 0x00;	/* Disable scanning */
Packit Service 8264ee
		cmd.filter_dup = 0x00;	/* Report duplicates */
Packit Service 8264ee
		bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
Packit Service 8264ee
				&cmd, sizeof(cmd), NULL, NULL, NULL);
Packit Service 8264ee
Packit Service 8264ee
	}
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
static bool filter_set(struct mesh_io *io,
Packit Service 8264ee
		uint8_t filter_id, const uint8_t *data, uint8_t len,
Packit Service 8264ee
		mesh_io_status_func_t callback, void *user_data)
Packit Service 8264ee
{
Packit Service 8264ee
	struct mesh_io_private *pvt = io->pvt;
Packit Service 8264ee
Packit Service 8264ee
	l_info("%s id: %d, --> %2.2x", __func__, filter_id, data[0]);
Packit Service 8264ee
	if (!data || !len || !filter_id || filter_id > sizeof(pvt->filters))
Packit Service 8264ee
		return false;
Packit Service 8264ee
Packit Service 8264ee
	pvt->filters[filter_id - 1] = data[0];
Packit Service 8264ee
Packit Service 8264ee
	/* TODO: Delayed Call to successful status */
Packit Service 8264ee
Packit Service 8264ee
	return true;
Packit Service 8264ee
}
Packit Service 8264ee
Packit Service 8264ee
const struct mesh_io_api mesh_io_generic = {
Packit Service 8264ee
	.init = dev_init,
Packit Service 8264ee
	.destroy = dev_destroy,
Packit Service 8264ee
	.caps = dev_caps,
Packit Service 8264ee
	.send = send_tx,
Packit Service 8264ee
	.reg = recv_register,
Packit Service 8264ee
	.dereg = recv_deregister,
Packit Service 8264ee
	.set = filter_set,
Packit Service 8264ee
	.cancel = tx_cancel,
Packit Service 8264ee
};