/* Bluetooth Mesh */ /* * Copyright (c) 2017 Intel Corporation * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #define MESH_LOG_MODULE BLE_MESH_PROV_LOG #include "mesh/mesh.h" #include "prov.h" #include "net.h" #include "proxy.h" #include "adv.h" #include "nimble_syscfg.h" #include "pb_gatt_srv.h" #if MYNEWT_VAL(BLE_MESH_PB_GATT) struct prov_bearer_send_cb { prov_bearer_send_complete_t cb; void *cb_data; }; struct prov_link { uint16_t conn_handle; const struct prov_bearer_cb *cb; void *cb_data; struct prov_bearer_send_cb comp; struct { uint8_t id; /* Transaction ID */ uint8_t prev_id; /* Previous Transaction ID */ uint8_t seg; /* Bit-field of unreceived segments */ uint8_t last_seg; /* Last segment (to check length) */ uint8_t fcs; /* Expected FCS value */ } rx; struct k_work_delayable prot_timer; }; static struct prov_link link; static void reset_state(void) { link.conn_handle = BLE_HS_CONN_HANDLE_NONE; /* If this fails, the protocol timeout handler will exit early. */ (void)k_work_cancel_delayable(&link.prot_timer); } static void link_closed(enum prov_bearer_link_status status) { const struct prov_bearer_cb *cb = link.cb; void *cb_data = link.cb_data; reset_state(); cb->link_closed(&pb_gatt, cb_data, status); } static void protocol_timeout(struct ble_npl_event *work) { if (!link.conn_handle) { /* Already disconnected */ return; } BT_DBG("Protocol timeout"); link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT); } int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf) { BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); if (link.conn_handle != conn_handle || !link.cb) { BT_WARN("Data for unexpected connection"); return -ENOTCONN; } if (buf->om_len < 1) { BT_WARN("Too short provisioning packet (len %u)", buf->om_len); return -EINVAL; } k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); link.cb->recv(&pb_gatt, link.cb_data, buf); return 0; } int bt_mesh_pb_gatt_open(uint16_t conn_handle) { BT_DBG("conn %p", conn_handle); if (link.conn_handle) { return -EBUSY; } link.conn_handle = conn_handle; k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); link.cb->link_opened(&pb_gatt, link.cb_data); return 0; } int bt_mesh_pb_gatt_close(uint16_t conn_handle) { BT_DBG("conn %p", conn_handle); if (link.conn_handle != conn_handle) { BT_DBG("Not connected"); return -ENOTCONN; } link.cb->link_closed(&pb_gatt, link.cb_data, PROV_BEARER_LINK_STATUS_SUCCESS); reset_state(); return 0; } static int link_accept(const struct prov_bearer_cb *cb, void *cb_data) { (void)bt_mesh_pb_gatt_enable(); bt_mesh_adv_update(); link.cb = cb; link.cb_data = cb_data; return 0; } static int buf_send(struct os_mbuf *buf, prov_bearer_send_complete_t cb, void *cb_data) { if (!link.conn_handle) { return -ENOTCONN; } link.comp.cb = cb; link.comp.cb_data = cb_data; k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); return bt_mesh_pb_gatt_send(link.conn_handle, buf); } static void clear_tx(void) { /* No action */ } void pb_gatt_init(void) { k_work_init_delayable(&link.prot_timer, protocol_timeout); } void pb_gatt_reset(void) { reset_state(); } const struct prov_bearer pb_gatt = { .type = BT_MESH_PROV_GATT, .link_accept = link_accept, .send = buf_send, .clear_tx = clear_tx, }; #endif