MeshPRT_v1.1, chapter 7 states that GATT provisioning service and GATT proxy service must NOT be active simultaneously. This patch only implements the GATT proxy itself (so that a GATT proxy client can exchange network messages with server). Relaying / retransmission of network messages and propagation of beacons will be handled in later patches. --- Makefile.mesh | 3 +- mesh/gatt-proxy-svc.c | 327 ++++++++++++++++++++++++++++++++++++++++++ mesh/gatt-proxy-svc.h | 28 ++++ mesh/main.c | 3 + mesh/net-keys.c | 61 ++++++++ mesh/net-keys.h | 4 + mesh/net.c | 72 +++++++++- mesh/net.h | 3 + mesh/prov-acceptor.c | 26 +++- 9 files changed, 518 insertions(+), 9 deletions(-) create mode 100644 mesh/gatt-proxy-svc.c create mode 100644 mesh/gatt-proxy-svc.h diff --git a/Makefile.mesh b/Makefile.mesh index 700d64fe9293..8a190f75de9d 100644 --- a/Makefile.mesh +++ b/Makefile.mesh @@ -40,7 +40,8 @@ mesh_sources = mesh/mesh.h mesh/mesh.c \ mesh/rpl.h mesh/rpl.c \ mesh/prv-beacon.h mesh/prvbeac-server.c \ mesh/mesh-defs.h \ - mesh/gatt-service.h mesh/gatt-service.c + mesh/gatt-service.h mesh/gatt-service.c \ + mesh/gatt-proxy-svc.h mesh/gatt-proxy-svc.c pkglibexec_PROGRAMS += mesh/bluetooth-meshd mesh/mesh.$(OBJEXT): ell/internal diff --git a/mesh/gatt-proxy-svc.c b/mesh/gatt-proxy-svc.c new file mode 100644 index 000000000000..27cc22c0572a --- /dev/null +++ b/mesh/gatt-proxy-svc.c @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2025 ARRI Lighting. All rights reserved. + * + * + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> // memcpy() + +#include <ell/dbus.h> +#include <ell/log.h> // l_warn() +#include <ell/queue.h> +#include <ell/timeout.h> +#include <ell/util.h> // ell_new(), l_free(), l_malloc() + +#include "mesh/gatt-service.h" +#include "mesh/mesh-io.h" // mesh_io_recv_func_t +#include "mesh/net.h" // mesh_net_attach_gatt(), + // mesh_net_detach_gatt() +#include "mesh/net-keys.h" // net_key_fill_adv_service_data(), + // net_key_get_next_id() +#include "mesh/util.h" // print_packet() +#include "mesh/gatt-proxy-svc.h" + +#define MESH_GATT_PROXY_SVC_UUID "0x1828" +#define MESH_GATT_PROXY_CHRC_DATA_IN "0x2ADD" +#define MESH_GATT_PROXY_CHRC_DATA_OUT "0x2ADE" + +#define MAX_PROXY_PDU_LEN 66 /* MshPRT_v1.1, section 7.2.2.2.7 */ + +struct gatt_io_reg { + mesh_io_recv_func_t cb; + void *user_data; + enum proxy_msg_type msg_type; +}; + +struct gatt_proxy_svc { + struct gatt_service *gatt_service; + uint32_t current_adv_key_id; + struct l_timeout *adv_key_cycle_to; + bool connected; + bool txing; + struct l_queue *tx_deferred; + struct l_queue *rx_regs; +}; + +struct process_data { + enum proxy_msg_type msg_type; + const uint8_t *data; + uint8_t len; +}; + +static struct gatt_proxy_svc *gatt_proxy_svc; + +struct tx_deferred { + enum proxy_msg_type msg_type; + uint16_t len; + uint8_t data[]; +}; + +static struct gatt_io_reg *find_by_filter(struct l_queue *rx_regs, + enum proxy_msg_type msg_type) +{ + const struct l_queue_entry *entry; + + entry = l_queue_get_entries(rx_regs); + + for (; entry; entry = entry->next) { + struct gatt_io_reg *rx_reg = entry->data; + + if (rx_reg->msg_type == msg_type) + return rx_reg; + } + + return NULL; +} + +void gatt_proxy_svc_register_recv_cb(struct gatt_proxy_svc *gatt_proxy, + enum proxy_msg_type msg_type, + mesh_io_recv_func_t cb, + void *user_data) +{ + struct gatt_io_reg *rx_reg; + + if (gatt_proxy != gatt_proxy_svc || !cb) + return; + + rx_reg = find_by_filter(gatt_proxy->rx_regs, msg_type); + + l_free(rx_reg); + l_queue_remove(gatt_proxy->rx_regs, rx_reg); + + rx_reg = l_malloc(sizeof(struct gatt_io_reg)); + rx_reg->cb = cb; + rx_reg->msg_type = msg_type; + rx_reg->user_data = user_data; + + l_queue_push_head(gatt_proxy->rx_regs, rx_reg); +} + +void gatt_proxy_svc_deregister_recv_cb(struct gatt_proxy_svc *gatt_proxy, + enum proxy_msg_type msg_type) +{ + struct gatt_io_reg *rx_reg; + + if (gatt_proxy != gatt_proxy_svc) + return; + + rx_reg = find_by_filter(gatt_proxy->rx_regs, msg_type); + + l_queue_remove(gatt_proxy->rx_regs, rx_reg); + l_free(rx_reg); +} + +static void gatt_proxy_svc_send(enum proxy_msg_type msg_type, const void *data, + uint8_t len) +{ + if (!gatt_proxy_svc) + return; + + if (!gatt_proxy_svc->connected) { + l_warn("Not connected, dropping TX message..."); + return; + } + + if (!gatt_proxy_svc->txing) { + gatt_proxy_svc->txing = true; + gatt_service_tx(gatt_proxy_svc->gatt_service, msg_type, + data, len); + } else { + struct tx_deferred *tx_deferred; + +// print_packet("TX-Defer", data, len); + tx_deferred = l_malloc(len + sizeof(struct tx_deferred)); + tx_deferred->msg_type = msg_type; + tx_deferred->len = len; + memcpy(tx_deferred->data, data, len); + l_queue_push_tail(gatt_proxy_svc->tx_deferred, tx_deferred); + } +} + +void gatt_proxy_svc_send_net(const void *data, uint8_t len) +{ + gatt_proxy_svc_send(PROXY_MSG_TYPE_NETWORK_PDU, data, len); +} + +static void gatt_service_notify_acquired(void *user_data) +{ + struct gatt_proxy_svc *gatt_proxy = user_data; + + if (gatt_proxy != gatt_proxy_svc) + return; + + gatt_proxy->connected = true; +} + +static void gatt_service_notify_stopped(void *user_data) +{ + struct gatt_proxy_svc *gatt_proxy = user_data; + + if (gatt_proxy != gatt_proxy_svc) + return; + + gatt_proxy->connected = false; + gatt_proxy->txing = false; + l_queue_clear(gatt_proxy->tx_deferred, l_free); +} + +static void process_rx_callbacks(void *a, void *b) +{ + struct gatt_io_reg *rx_reg = a; + struct process_data *rx = b; + + if (rx->msg_type == rx_reg->msg_type) + rx_reg->cb(rx_reg->user_data, NULL, rx->data, rx->len); +} + +static void gatt_service_rx(void *user_data, enum proxy_msg_type msg_type, + const void *data, uint16_t len) +{ + struct gatt_proxy_svc *gatt_proxy = user_data; + struct process_data rx = { + .msg_type = msg_type, + .data = data, + .len = len, + }; + + if (gatt_proxy != gatt_proxy_svc) + return; + + l_queue_foreach(gatt_proxy->rx_regs, process_rx_callbacks, &rx); +} + +static bool gatt_service_tx_cmplt(void *user_data) +{ + struct gatt_proxy_svc *gatt_proxy = user_data; + struct tx_deferred *tx_deferred; + +// l_info("gatt_service_tx_cmplt"); + + if (gatt_proxy_svc != gatt_proxy) + return false; + + if (!gatt_proxy->connected || !gatt_proxy->txing) + return false; + + gatt_proxy->txing = false; + + tx_deferred = l_queue_pop_head(gatt_proxy->tx_deferred); + if (!tx_deferred) + return false; + + gatt_proxy_svc_send(tx_deferred->msg_type, tx_deferred->data, + tx_deferred->len); + l_free(tx_deferred); + return true; +} + +static bool gatt_service_fill_adv_service_data(void *user_data, + struct l_dbus_message_builder *builder) +{ + struct gatt_proxy_svc *gatt_service = user_data; + + if (gatt_service != gatt_proxy_svc) + return false; + + return net_key_fill_adv_service_data(gatt_service->current_adv_key_id, + builder); +} + +static void gatt_proxy_svc_cycle_adv(struct l_timeout *timeout, + void *user_data) +{ + struct gatt_proxy_svc *gatt_proxy = user_data; + uint32_t next_adv_key_id; + + if (gatt_proxy_svc != gatt_proxy) + return; + + next_adv_key_id = net_key_get_next_id(gatt_proxy->current_adv_key_id); + if (!next_adv_key_id) + return; + + if (gatt_proxy->current_adv_key_id != next_adv_key_id) { + gatt_proxy->current_adv_key_id = next_adv_key_id; + gatt_service_adv_updated(gatt_proxy_svc->gatt_service); + } + + l_timeout_modify(gatt_proxy->adv_key_cycle_to, 3); +} + +void gatt_proxy_svc_set_current_adv_key(uint32_t id) +{ + if (!gatt_proxy_svc) + return; + + gatt_proxy_svc->current_adv_key_id = id; + gatt_service_adv_updated(gatt_proxy_svc->gatt_service); +} + +void gatt_proxy_svc_start(void) +{ + if (!gatt_proxy_svc || gatt_proxy_svc->gatt_service) + return; + + gatt_proxy_svc->gatt_service = gatt_service_create( + MESH_GATT_PROXY_SVC_UUID, + MESH_GATT_PROXY_CHRC_DATA_IN, + MESH_GATT_PROXY_CHRC_DATA_OUT, + MAX_PROXY_PDU_LEN, + gatt_service_notify_acquired, + gatt_service_notify_stopped, + gatt_service_rx, + gatt_service_tx_cmplt, + gatt_service_fill_adv_service_data, + gatt_proxy_svc); + + gatt_proxy_svc->adv_key_cycle_to = l_timeout_create(3, + gatt_proxy_svc_cycle_adv, + gatt_proxy_svc, NULL); + + mesh_net_attach_gatt(gatt_proxy_svc); +} + +void gatt_proxy_svc_stop(void) +{ + if (!gatt_proxy_svc || !gatt_proxy_svc->gatt_service) + return; + + mesh_net_detach_gatt(gatt_proxy_svc); + l_timeout_remove(gatt_proxy_svc->adv_key_cycle_to); + gatt_service_destroy(gatt_proxy_svc->gatt_service, NULL, NULL); +} + +void gatt_proxy_svc_create(void) +{ + if (gatt_proxy_svc) + return; + + gatt_proxy_svc = l_new(struct gatt_proxy_svc, 1); + gatt_proxy_svc->tx_deferred = l_queue_new(); + gatt_proxy_svc->rx_regs = l_queue_new(); + + /* Check whether we have at least one key */ + if (!net_key_get_next_id(0)) + return; + + gatt_proxy_svc_start(); +} + +void gatt_proxy_svc_destroy(void) +{ + if (!gatt_proxy_svc) + return; + + gatt_proxy_svc_stop(); + + l_queue_destroy(gatt_proxy_svc->rx_regs, l_free); + l_queue_destroy(gatt_proxy_svc->tx_deferred, l_free); + l_free(gatt_proxy_svc); + gatt_proxy_svc = NULL; +} diff --git a/mesh/gatt-proxy-svc.h b/mesh/gatt-proxy-svc.h new file mode 100644 index 000000000000..2b0c9d7ec21b --- /dev/null +++ b/mesh/gatt-proxy-svc.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2025 ARRI Lighting. All rights reserved. + * + * + */ + +#include <stdint.h> + +enum proxy_msg_type; +struct gatt_proxy_svc; + +void gatt_proxy_svc_create(void); +void gatt_proxy_svc_destroy(void); +void gatt_proxy_svc_start(void); +void gatt_proxy_svc_stop(void); +void gatt_proxy_svc_set_current_adv_key(uint32_t id); +void gatt_proxy_svc_register_recv_cb(struct gatt_proxy_svc *gatt_proxy, + enum proxy_msg_type msg_type, + mesh_io_recv_func_t cb, + void *user_data); +void gatt_proxy_svc_deregister_recv_cb(struct gatt_proxy_svc *gatt_proxy, + enum proxy_msg_type msg_type); +void gatt_proxy_svc_send_net(const void *data, uint8_t len); + diff --git a/mesh/main.c b/mesh/main.c index 5b8af4bc7345..079b3cbcad36 100644 --- a/mesh/main.c +++ b/mesh/main.c @@ -31,6 +31,7 @@ #include "mesh/crypto.h" #include "mesh/dbus.h" #include "mesh/mesh-io.h" +#include "mesh/gatt-proxy-svc.h" #include "mesh/util.h" static const char *storage_dir; @@ -94,6 +95,8 @@ static void mesh_ready_callback(void *user_data, bool success) l_error("Failed to initialize mesh D-Bus resources"); l_main_quit(); } + + gatt_proxy_svc_create(); } static void request_name_callback(struct l_dbus *dbus, bool success, diff --git a/mesh/net-keys.c b/mesh/net-keys.c index 98e6d23d3f87..ab724f9cfa1e 100644 --- a/mesh/net-keys.c +++ b/mesh/net-keys.c @@ -22,6 +22,7 @@ #include "mesh/util.h" #include "mesh/crypto.h" #include "mesh/mesh-io.h" +#include "mesh/gatt-proxy-svc.h" #include "mesh/net.h" #include "mesh/net-keys.h" @@ -31,6 +32,12 @@ /* This allows daemon to skip decryption on recently seen beacons */ #define BEACON_CACHE_MAX 10 +/* MshPRT_v1.1, section 7.2.2.2.1 */ +#define IDENTIFICATION_TYPE_NETWORK_ID 0x00 +#define IDENTIFICATION_TYPE_NODE_ID 0x01 +#define IDENTIFICATION_TYPE_PRV_NETWORK_ID 0x02 +#define IDENTIFICATION_TYPE_PRV_NODE_ID 0x03 + struct beacon_rx { uint8_t data[BEACON_LEN_MAX]; uint32_t id; @@ -146,6 +153,9 @@ uint32_t net_key_add(const uint8_t flooding[16]) goto fail; key->id = ++last_flooding_id; + if (l_queue_isempty(keys)) + gatt_proxy_svc_start(); + l_queue_push_tail(keys, key); return key->id; @@ -198,6 +208,9 @@ void net_key_unref(uint32_t id) l_timeout_remove(key->observe.timeout); l_queue_remove(keys, key); l_free(key); + + if (l_queue_isempty(keys)) + gatt_proxy_svc_stop(); } } } @@ -662,6 +675,7 @@ bool net_key_beacon_refresh(uint32_t id, uint32_t ivi, bool kr, bool ivu, return false; print_packet("Set SNB to", key->snb, BEACON_LEN_SNB); + gatt_proxy_svc_set_current_adv_key(key->id); } l_debug("Set Beacon: IVI: %8.8x, IVU: %d, KR: %d", ivi, ivu, kr); @@ -797,3 +811,50 @@ void net_key_cleanup(void) l_queue_destroy(beacons, l_free); beacons = NULL; } + +bool net_key_fill_adv_service_data(uint32_t id, + struct l_dbus_message_builder *builder) +{ + uint8_t identification_type = IDENTIFICATION_TYPE_NETWORK_ID; + struct net_key *key; + int i; + + key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); + if (!key) + return false; + + l_dbus_message_builder_enter_array(builder, "y"); + l_dbus_message_builder_append_basic(builder, 'y', &identification_type); + + for (i = 0; i < sizeof(key->net_id); i++) + l_dbus_message_builder_append_basic(builder, 'y', + &(key->net_id[i])); + l_dbus_message_builder_leave_array(builder); + + return true; +} + +uint32_t net_key_get_next_id(uint32_t id) +{ + const struct l_queue_entry *entry; + struct net_key *key; + bool found = false; + + /* Try to find next key (after the given key id) */ + for (entry = l_queue_get_entries(keys); entry; entry = entry->next) { + key = entry->data; + + if (!found) + if (key->id == id) + found = true; + else + return key->id; + } + + /* If not found, return id of first key */ + key = l_queue_peek_head(keys); + if (key) + return key->id; + + return 0; +} diff --git a/mesh/net-keys.h b/mesh/net-keys.h index 49e01132cbf2..512347521547 100644 --- a/mesh/net-keys.h +++ b/mesh/net-keys.h @@ -38,3 +38,7 @@ bool net_key_beacon_refresh(uint32_t id, uint32_t iv_index, bool kr, bool ivu, void net_key_beacon_enable(uint32_t id, bool mpb, uint8_t refresh_count); void net_key_beacon_disable(uint32_t id, bool mpb); uint32_t net_key_beacon_last_seen(uint32_t id); + +bool net_key_fill_adv_service_data(uint32_t id, + struct l_dbus_message_builder *builder); +uint32_t net_key_get_next_id(uint32_t id); diff --git a/mesh/net.c b/mesh/net.c index b29e24f5d4a9..911f781ef75c 100644 --- a/mesh/net.c +++ b/mesh/net.c @@ -29,6 +29,8 @@ #include "mesh/net.h" #include "mesh/mesh-io.h" #include "mesh/friend.h" +#include "mesh/gatt-service.h" // PROXY_MSG_TYPE_NETWORK_PDU +#include "mesh/gatt-proxy-svc.h" // gatt_proxy_svc_send_net() #include "mesh/mesh-config.h" #include "mesh/model.h" #include "mesh/appkey.h" @@ -177,6 +179,7 @@ struct mesh_destination { }; struct net_queue_data { + struct gatt_proxy_svc *gatt_proxy; struct mesh_io_recv_info *info; struct mesh_net *net; const uint8_t *data; @@ -192,6 +195,7 @@ struct net_queue_data { struct oneshot_tx { struct mesh_net *net; uint16_t interval; + bool frnd; uint8_t cnt; uint8_t size; uint8_t packet[MESH_AD_MAX_LEN]; @@ -2288,17 +2292,30 @@ static void send_msg_pkt_oneshot(void *user_data) /* No extra randomization when sending regular mesh messages */ info.u.gen.max_delay = DEFAULT_MIN_DELAY; + /* + * MshPrt_v1.1, section 3.4.6.4 - Transmitting a network PDU + * If [...], and the Network PDU is secured using the friendship + * security credentials, the Network PDU shall be delivered to the + * advertising bearer network interface. + * If [...], and the Network PDU is not secured using the friendship + * security credentials, the Network PDU shall be delivered to all + * network interfaces. + */ mesh_io_send(net->io, &info, tx->packet, tx->size); + if (!tx->frnd) + gatt_proxy_svc_send_net(tx->packet + 1, tx->size - 1); l_free(tx); } static void send_msg_pkt(struct mesh_net *net, uint8_t cnt, uint16_t interval, - const uint8_t *packet, uint8_t size) + const uint8_t *packet, uint8_t size, + bool frnd) { struct oneshot_tx *tx = l_new(struct oneshot_tx, 1); tx->net = net; tx->interval = interval; + tx->frnd = frnd; tx->cnt = cnt; tx->size = size; memcpy(tx->packet, packet, size); @@ -2482,6 +2499,15 @@ static void net_rx(void *net_ptr, void *user_data) if (net_idx == NET_IDX_INVALID) return; + /* + * MshPRT_v1.1, section 3.4.5.1 - Interface input filter + * The input filter of the interface connected to the GATT bearer shall + * drop all Network PDUs that have been secured using the friendship + * security credentials. + */ + if (data->gatt_proxy && frnd) + return; + relay_advice = packet_received(net, net_key_id, net_idx, frnd, iv_index, out, out_size, rssi); if (relay_advice > data->relay_advice) { @@ -2506,7 +2532,9 @@ static void net_msg_recv(void *user_data, struct mesh_io_recv_info *info, { uint64_t hash; bool isNew; + struct gatt_proxy_svc *gatt_proxy = user_data; struct net_queue_data net_data = { + .gatt_proxy = gatt_proxy, .info = info, .data = data + 1, .len = len - 1, @@ -3047,6 +3075,21 @@ struct mesh_io *mesh_net_detach(struct mesh_net *net) return io; } +void mesh_net_attach_gatt(struct gatt_proxy_svc *gatt_proxy) +{ + gatt_proxy_svc_register_recv_cb(gatt_proxy, PROXY_MSG_TYPE_NETWORK_PDU, + net_msg_recv, + gatt_proxy); +} + +void mesh_net_detach_gatt(struct gatt_proxy_svc *gatt_proxy) +{ +// mesh_io_send_cancel(net->io, &type, 1); + + gatt_proxy_svc_deregister_recv_cb(gatt_proxy, + PROXY_MSG_TYPE_NETWORK_PDU); +} + bool mesh_net_iv_index_update(struct mesh_net *net) { if (net->iv_upd_state != IV_UPD_NORMAL) @@ -3171,7 +3214,7 @@ static bool send_seg(struct mesh_net *net, uint8_t cnt, uint16_t interval, return false; } - send_msg_pkt(net, cnt, interval, packet, packet_len + 1); + send_msg_pkt(net, cnt, interval, packet, packet_len + 1, false); msg->last_seg = segO; @@ -3191,6 +3234,7 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id, uint16_t seqZero = (hdr >> SEQ_ZERO_HDR_SHIFT) & SEQ_ZERO_MASK; uint8_t segO = (hdr >> SEGO_HDR_SHIFT) & SEG_MASK; uint8_t segN = (hdr >> SEGN_HDR_SHIFT) & SEG_MASK; + bool frnd; /* * MshPRFv1.0.1 section 3.4.5.2, Interface output filter: @@ -3219,8 +3263,13 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id, return; } + if (key_id_to_net_idx(net, net_key_id, &frnd) == NET_IDX_INVALID) { + l_error("Failed to determine friend security material"); + return; + } + send_msg_pkt(net, net->tx_cnt, net->tx_interval, packet, - packet_len + 1); + packet_len + 1, frnd); l_debug("TX: Friend Seg-%d %04x -> %04x : len %u) : TTL %d : SEQ %06x", segO, src, dst, packet_len, ttl, seq); @@ -3345,6 +3394,7 @@ void mesh_net_ack_send(struct mesh_net *net, uint32_t net_key_id, uint8_t data[7]; uint8_t pkt_len; uint8_t pkt[MESH_AD_MAX_LEN]; + bool frnd; /* * MshPRFv1.0.1 section 3.4.5.2, Interface output filter: @@ -3378,7 +3428,13 @@ void mesh_net_ack_send(struct mesh_net *net, uint32_t net_key_id, return; } - send_msg_pkt(net, net->tx_cnt, net->tx_interval, pkt, pkt_len + 1); + if (key_id_to_net_idx(net, net_key_id, &frnd) == NET_IDX_INVALID) { + l_error("Failed to determine friend security material"); + return; + } + + send_msg_pkt(net, net->tx_cnt, net->tx_interval, pkt, pkt_len + 1, + frnd); l_debug("TX: Friend ACK %04x -> %04x : len %u : TTL %d : SEQ %06x", src, dst, pkt_len, ttl, seq); @@ -3394,6 +3450,7 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id, uint8_t pkt_len; uint8_t pkt[MESH_AD_MAX_LEN]; bool result = false; + bool frnd; if (!net->src_addr) return; @@ -3459,9 +3516,14 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id, return; } + if (key_id_to_net_idx(net, net_key_id, &frnd) == NET_IDX_INVALID) { + l_error("Failed to determine friend security material"); + return; + } + if (!(IS_UNASSIGNED(dst))) send_msg_pkt(net, net->tx_cnt, net->tx_interval, pkt, - pkt_len + 1); + pkt_len + 1, frnd); } int mesh_net_key_refresh_phase_set(struct mesh_net *net, uint16_t idx, diff --git a/mesh/net.h b/mesh/net.h index 5200beb2fada..af581478412c 100644 --- a/mesh/net.h +++ b/mesh/net.h @@ -14,6 +14,7 @@ struct mesh_io; struct mesh_node; +struct gatt_proxy_svc; #define DEV_ID 0 @@ -249,6 +250,8 @@ bool mesh_net_get_key(struct mesh_net *net, bool new_key, uint16_t idx, uint32_t *net_key_id); bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io); struct mesh_io *mesh_net_detach(struct mesh_net *net); +void mesh_net_attach_gatt(struct gatt_proxy_svc *gatt_proxy); +void mesh_net_detach_gatt(struct gatt_proxy_svc *gatt_proxy); struct l_queue *mesh_net_get_app_keys(struct mesh_net *net); void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id, diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c index b3c538359a66..a374abb92083 100644 --- a/mesh/prov-acceptor.c +++ b/mesh/prov-acceptor.c @@ -22,6 +22,8 @@ #include "mesh/mesh-defs.h" #include "mesh/util.h" #include "mesh/crypto.h" +#include "mesh/mesh-io.h" +#include "mesh/gatt-proxy-svc.h" #include "mesh/net.h" #include "mesh/prov.h" #include "mesh/provision.h" @@ -89,6 +91,11 @@ struct mesh_prov_acceptor { static struct mesh_prov_acceptor *prov = NULL; +static void gatt_unreg_finished(void *user_data) +{ + gatt_proxy_svc_create(); +} + static void acceptor_free(void) { if (!prov) @@ -101,7 +108,7 @@ static void acceptor_free(void) mesh_send_cancel(&pkt_filter, sizeof(pkt_filter)); pb_adv_unreg(prov); - pb_gatt_unreg(prov, NULL, NULL); + pb_gatt_unreg(prov, gatt_unreg_finished, NULL); l_free(prov); prov = NULL; @@ -705,8 +712,13 @@ failure: cleanup: l_timeout_remove(prov->timeout); - /* Give PB Link 5 seconds to end session */ - prov->timeout = l_timeout_create(5, prov_to, prov, NULL); + if (prov->transport == PB_ADV) { + /* Give PB Link 5 seconds to end session */ + prov->timeout = l_timeout_create(5, prov_to, prov, NULL); + } else { + prov->timeout = NULL; + prov_to(NULL, prov); + } } static void acp_prov_ack(void *user_data, uint8_t msg_num) @@ -804,6 +816,14 @@ bool acceptor_start(uint8_t num_ele, uint8_t *uuid, result = pb_adv_reg(false, acp_prov_open, acp_prov_close, acp_prov_rx, acp_prov_ack, uuid, prov); + /* + * MeshPRT_v1.1, chapter 7: "A device may support the Mesh + * Provisioning Service or the Mesh Proxy Service or both. If + * both are supported, only one of these services shall be + * exposed in the GATT database at a time." + */ + gatt_proxy_svc_destroy(); + result = pb_gatt_reg(acp_prov_open, acp_prov_close, acp_prov_rx, acp_prov_ack, uuid, caps->oob_info, prov); -- 2.43.0