| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2018-2019 Intel Corporation. All rights reserved.
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <errno.h>
- #include <string.h>
- #include <sys/time.h>
- #include <ell/ell.h>
- #include "monitor/bt.h"
- #include "src/shared/hci.h"
- #include "lib/bluetooth.h"
- #include "lib/mgmt.h"
- #include "mesh/mesh-defs.h"
- #include "mesh/mesh-mgmt.h"
- #include "mesh/mesh-io.h"
- #include "mesh/mesh-io-api.h"
- #include "mesh/mesh-io-generic.h"
- struct mesh_io_private {
- struct bt_hci *hci;
- void *user_data;
- mesh_io_ready_func_t ready_callback;
- struct l_timeout *tx_timeout;
- struct l_queue *rx_regs;
- struct l_queue *tx_pkts;
- struct tx_pkt *tx;
- uint16_t index;
- uint16_t interval;
- bool sending;
- bool active;
- };
- struct pvt_rx_reg {
- mesh_io_recv_func_t cb;
- void *user_data;
- uint8_t len;
- uint8_t filter[0];
- };
- 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_reg, void *v_rx)
- {
- struct pvt_rx_reg *rx_reg = v_reg;
- struct process_data *rx = v_rx;
- if (!memcmp(rx->data, rx_reg->filter, rx_reg->len))
- 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 *addr,
- const uint8_t *data, uint8_t len)
- {
- struct process_data rx = {
- .pvt = pvt,
- .data = data,
- .len = len,
- .info.instant = instant,
- .info.addr = addr,
- .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;
- const uint8_t *addr;
- uint32_t instant;
- uint8_t adv_len;
- uint16_t len = 0;
- int8_t rssi;
- if (evt->event_type != 0x03)
- return;
- instant = get_instant();
- adv = evt->data;
- adv_len = evt->data_len;
- addr = evt->addr;
- /* 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, addr, 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_debug("Other Meta Evt - %d", event);
- }
- }
- static void local_commands_callback(const void *data, uint8_t size,
- void *user_data)
- {
- const struct bt_hci_rsp_read_local_commands *rsp = data;
- if (rsp->status)
- l_error("Failed to read local commands");
- }
- static void local_features_callback(const void *data, uint8_t size,
- void *user_data)
- {
- const struct bt_hci_rsp_read_local_features *rsp = data;
- if (rsp->status)
- l_error("Failed to read local features");
- }
- static void hci_generic_callback(const void *data, uint8_t size,
- void *user_data)
- {
- uint8_t status = l_get_u8(data);
- if (status)
- l_error("Failed to initialize HCI");
- }
- static void configure_hci(struct mesh_io_private *io)
- {
- struct bt_hci_cmd_le_set_scan_parameters cmd;
- struct bt_hci_cmd_set_event_mask cmd_sem;
- struct bt_hci_cmd_le_set_event_mask cmd_slem;
- struct bt_hci_cmd_le_set_random_address cmd_raddr;
- /* Set scan parameters */
- cmd.type = 0x00; /* Passive Scanning. No scanning PDUs shall be sent */
- cmd.interval = 0x0030; /* Scan Interval = N * 0.625ms */
- cmd.window = 0x0030; /* Scan Window = N * 0.625ms */
- cmd.own_addr_type = 0x00; /* Public Device Address */
- /* Accept all advertising packets except directed advertising packets
- * not addressed to this device (default).
- */
- cmd.filter_policy = 0x00;
- /* Set event mask
- *
- * Mask: 0x2000800002008890
- * Disconnection Complete
- * Encryption Change
- * Read Remote Version Information Complete
- * Hardware Error
- * Data Buffer Overflow
- * Encryption Key Refresh Complete
- * LE Meta
- */
- cmd_sem.mask[0] = 0x90;
- cmd_sem.mask[1] = 0x88;
- cmd_sem.mask[2] = 0x00;
- cmd_sem.mask[3] = 0x02;
- cmd_sem.mask[4] = 0x00;
- cmd_sem.mask[5] = 0x80;
- cmd_sem.mask[6] = 0x00;
- cmd_sem.mask[7] = 0x20;
- /* Set LE event mask
- *
- * Mask: 0x000000000000087f
- * LE Connection Complete
- * LE Advertising Report
- * LE Connection Update Complete
- * LE Read Remote Used Features Complete
- * LE Long Term Key Request
- * LE Remote Connection Parameter Request
- * LE Data Length Change
- * LE PHY Update Complete
- */
- cmd_slem.mask[0] = 0x7f;
- cmd_slem.mask[1] = 0x08;
- cmd_slem.mask[2] = 0x00;
- cmd_slem.mask[3] = 0x00;
- cmd_slem.mask[4] = 0x00;
- cmd_slem.mask[5] = 0x00;
- cmd_slem.mask[6] = 0x00;
- cmd_slem.mask[7] = 0x00;
- /* Set LE random address */
- l_getrandom(cmd_raddr.addr, 6);
- cmd_raddr.addr[5] |= 0xc0;
- /* TODO: Move to suitable place. Set suitable masks */
- /* Reset Command */
- bt_hci_send(io->hci, BT_HCI_CMD_RESET, NULL, 0, hci_generic_callback,
- NULL, NULL);
- /* Read local supported commands */
- bt_hci_send(io->hci, BT_HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0,
- local_commands_callback, NULL, NULL);
- /* Read local supported features */
- bt_hci_send(io->hci, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0,
- local_features_callback, NULL, NULL);
- /* Set event mask */
- bt_hci_send(io->hci, BT_HCI_CMD_SET_EVENT_MASK, &cmd_sem,
- sizeof(cmd_sem), hci_generic_callback, NULL, NULL);
- /* Set LE event mask */
- bt_hci_send(io->hci, BT_HCI_CMD_LE_SET_EVENT_MASK, &cmd_slem,
- sizeof(cmd_slem), hci_generic_callback, NULL, NULL);
- /* Set LE random address */
- bt_hci_send(io->hci, BT_HCI_CMD_LE_SET_RANDOM_ADDRESS, &cmd_raddr,
- sizeof(cmd_raddr), hci_generic_callback, NULL, NULL);
- /* Scan Params */
- bt_hci_send(io->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS, &cmd,
- sizeof(cmd), hci_generic_callback, NULL, NULL);
- }
- static void scan_enable_rsp(const void *buf, uint8_t size,
- void *user_data)
- {
- uint8_t status = *((uint8_t *) buf);
- if (status)
- l_error("LE Scan enable failed (0x%02x)", status);
- }
- static void set_recv_scan_enable(const void *buf, uint8_t size,
- void *user_data)
- {
- struct mesh_io_private *pvt = user_data;
- struct bt_hci_cmd_le_set_scan_enable cmd;
- 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), scan_enable_rsp, pvt, NULL);
- }
- static void scan_disable_rsp(const void *buf, uint8_t size,
- void *user_data)
- {
- struct bt_hci_cmd_le_set_scan_parameters cmd;
- struct mesh_io_private *pvt = user_data;
- uint8_t status = *((uint8_t *) buf);
- if (status)
- l_error("LE Scan disable failed (0x%02x)", status);
- cmd.type = pvt->active ? 0x01 : 0x00; /* Passive/Active scanning */
- cmd.interval = L_CPU_TO_LE16(0x0010); /* 10 ms */
- cmd.window = L_CPU_TO_LE16(0x0010); /* 10 ms */
- cmd.own_addr_type = 0x01; /* ADDR_TYPE_RANDOM */
- cmd.filter_policy = 0x00; /* Accept all */
- bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS,
- &cmd, sizeof(cmd),
- set_recv_scan_enable, pvt, NULL);
- }
- static bool simple_match(const void *a, const void *b)
- {
- return a == b;
- }
- 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 find_active(const void *a, const void *b)
- {
- const struct pvt_rx_reg *rx_reg = a;
- /* Mesh specific AD types do *not* require active scanning,
- * so do not turn on Active Scanning on their account.
- */
- if (rx_reg->filter[0] < MESH_AD_TYPE_PROVISION ||
- rx_reg->filter[0] > MESH_AD_TYPE_BEACON)
- return true;
- return false;
- }
- static void restart_scan(struct mesh_io_private *pvt)
- {
- struct bt_hci_cmd_le_set_scan_enable cmd;
- if (l_queue_isempty(pvt->rx_regs))
- return;
- pvt->active = l_queue_find(pvt->rx_regs, find_active, NULL);
- 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), scan_disable_rsp, pvt, NULL);
- }
- static void hci_init(void *user_data)
- {
- struct mesh_io *io = user_data;
- bool result = true;
- bool restarted = false;
- if (io->pvt->hci) {
- restarted = true;
- bt_hci_unref(io->pvt->hci);
- }
- io->pvt->hci = bt_hci_new_user_channel(io->pvt->index);
- if (!io->pvt->hci) {
- l_error("Failed to start mesh io (hci %u): %s", io->pvt->index,
- strerror(errno));
- result = false;
- }
- if (result) {
- configure_hci(io->pvt);
- bt_hci_register(io->pvt->hci, BT_HCI_EVT_LE_META_EVENT,
- event_callback, io, NULL);
- l_debug("Started mesh on hci %u", io->pvt->index);
- if (restarted)
- restart_scan(io->pvt);
- }
- if (io->pvt->ready_callback)
- io->pvt->ready_callback(io->pvt->user_data, result);
- }
- static void read_info(int index, void *user_data)
- {
- struct mesh_io *io = user_data;
- if (io->pvt->index != MGMT_INDEX_NONE &&
- index != io->pvt->index) {
- l_debug("Ignore index %d", index);
- return;
- }
- io->pvt->index = index;
- hci_init(io);
- }
- static bool dev_init(struct mesh_io *io, void *opts,
- mesh_io_ready_func_t cb, void *user_data)
- {
- if (!io || io->pvt)
- return false;
- io->pvt = l_new(struct mesh_io_private, 1);
- io->pvt->index = *(int *)opts;
- io->pvt->rx_regs = l_queue_new();
- io->pvt->tx_pkts = l_queue_new();
- io->pvt->ready_callback = cb;
- io->pvt->user_data = user_data;
- if (io->pvt->index == MGMT_INDEX_NONE)
- return mesh_mgmt_list(read_info, io);
- l_idle_oneshot(hci_init, io, NULL);
- return true;
- }
- 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_remove_if(pvt->tx_pkts, simple_match, pvt->tx);
- l_queue_destroy(pvt->tx_pkts, l_free);
- l_free(pvt->tx);
- 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 = 255;
- 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_queue_remove_if(pvt->tx_pkts, simple_match, tx);
- 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;
- /* Delete superseded packet in favor of new packet */
- if (pvt->tx && pvt->tx != tx && pvt->tx->delete) {
- l_queue_remove_if(pvt->tx_pkts, simple_match, pvt->tx);
- l_free(pvt->tx);
- }
- 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_to(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) {
- /* Recalculate wakeup if we are responding to POLL */
- 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_to, 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_to(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_to, 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);
- 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 {
- if (pvt->tx)
- sending = true;
- else
- sending = !l_queue_isempty(pvt->tx_pkts);
- l_queue_push_tail(pvt->tx_pkts, tx);
- /*
- * If transmitter is idle, send packets at least twice to
- * guard against in-line cancelation of HCI command chain.
- */
- if (info->type == MESH_IO_TIMING_TYPE_GENERAL && !sending &&
- tx->info.u.gen.cnt == 1)
- tx->info.u.gen.cnt++;
- }
- if (!sending) {
- l_timeout_remove(pvt->tx_timeout);
- pvt->tx_timeout = NULL;
- l_idle_oneshot(tx_worker, pvt, NULL);
- }
- return true;
- }
- static bool tx_cancel(struct mesh_io *io, const 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);
- if (tx == pvt->tx)
- pvt->tx = NULL;
- } 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);
- if (tx == pvt->tx)
- pvt->tx = NULL;
- } 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(const void *a, const void *b)
- {
- const struct pvt_rx_reg *rx_reg = a;
- const uint8_t *filter = b;
- return !memcmp(rx_reg->filter, filter, rx_reg->len);
- }
- static bool recv_register(struct mesh_io *io, const uint8_t *filter,
- uint8_t len, 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 already_scanning;
- bool active = false;
- if (!cb || !filter || !len)
- return false;
- rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter, filter);
- l_free(rx_reg);
- rx_reg = l_malloc(sizeof(*rx_reg) + len);
- memcpy(rx_reg->filter, filter, len);
- rx_reg->len = len;
- rx_reg->cb = cb;
- rx_reg->user_data = user_data;
- already_scanning = !l_queue_isempty(pvt->rx_regs);
- l_queue_push_head(pvt->rx_regs, rx_reg);
- /* Look for any AD types requiring Active Scanning */
- if (l_queue_find(pvt->rx_regs, find_active, NULL))
- active = true;
- if (!already_scanning || pvt->active != active) {
- pvt->active = active;
- 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), scan_disable_rsp, pvt, NULL);
- }
- return true;
- }
- static bool recv_deregister(struct mesh_io *io, const uint8_t *filter,
- uint8_t len)
- {
- struct bt_hci_cmd_le_set_scan_enable cmd = {0, 0};
- struct mesh_io_private *pvt = io->pvt;
- struct pvt_rx_reg *rx_reg;
- bool active = false;
- rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter, filter);
- if (rx_reg)
- l_free(rx_reg);
- /* Look for any AD types requiring Active Scanning */
- if (l_queue_find(pvt->rx_regs, find_active, NULL))
- active = true;
- if (l_queue_isempty(pvt->rx_regs)) {
- bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
- &cmd, sizeof(cmd), NULL, NULL, NULL);
- } else if (active != pvt->active) {
- pvt->active = active;
- bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
- &cmd, sizeof(cmd), scan_disable_rsp, pvt, NULL);
- }
- 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,
- .cancel = tx_cancel,
- };
|