mynewt-nimble
mynewt-nimble copied to clipboard
fixed bug of find cli with CONTAINER_OF() in bt_mesh_proxy_addr_add
the ptr of CONTAINER_OF() macro should be field position address of type, so, the buf parameter of bt_mesh_proxy_addr_add should be position address.
Style check summary
Our coding style is here!
nimble/host/mesh/src/adv.c
@@ -45,205 +45,212 @@
static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT];
-static struct bt_mesh_adv *adv_alloc(int id)
-{
- return &adv_pool[id];
-}
-
-struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
- bt_mesh_adv_alloc_t get_id,
- enum bt_mesh_adv_type type,
- uint8_t xmit, int32_t timeout)
-{
- struct bt_mesh_adv *adv;
- struct os_mbuf *buf;
-
- if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
- BT_WARN("Refusing to allocate buffer while suspended");
- return NULL;
- }
-
- buf = os_mbuf_get_pkthdr(pool, BT_MESH_ADV_USER_DATA_SIZE);
- if (!buf) {
- return NULL;
- }
-
- adv = get_id(net_buf_id(buf));
- BT_MESH_ADV(buf) = adv;
-
- memset(adv, 0, sizeof(*adv));
-
- adv->type = type;
- adv->xmit = xmit;
-
- adv->ref_cnt = 1;
- ble_npl_event_set_arg(&adv->ev, buf);
-
- return buf;
-}
-
-struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit,
- int32_t timeout)
-{
- return bt_mesh_adv_create_from_pool(&adv_os_mbuf_pool, adv_alloc, type,
- xmit, timeout);
-}
-
-void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
- void *cb_data)
-{
- BT_DBG("buf %p, type 0x%02x len %u: %s", buf, BT_MESH_ADV(buf)->type, buf->om_len,
- bt_hex(buf->om_data, buf->om_len));
-
- BT_MESH_ADV(buf)->cb = cb;
- BT_MESH_ADV(buf)->cb_data = cb_data;
- BT_MESH_ADV(buf)->busy = 1;
-
- net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf));
- bt_mesh_adv_buf_ready();
-}
-
-static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
- uint8_t adv_type, struct os_mbuf *buf)
-{
- if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
- return;
- }
+static struct bt_mesh_adv *
+adv_alloc(int id)
+{
+ return &adv_pool[id];
+}
+
+struct os_mbuf *
+bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
+ bt_mesh_adv_alloc_t get_id,
+ enum bt_mesh_adv_type type,
+ uint8_t xmit, int32_t timeout)
+{
+ struct bt_mesh_adv *adv;
+ struct os_mbuf *buf;
+
+ if (atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
+ BT_WARN("Refusing to allocate buffer while suspended");
+ return NULL;
+ }
+
+ buf = os_mbuf_get_pkthdr(pool, BT_MESH_ADV_USER_DATA_SIZE);
+ if (!buf) {
+ return NULL;
+ }
+
+ adv = get_id(net_buf_id(buf));
+ BT_MESH_ADV(buf) = adv;
+
+ memset(adv, 0, sizeof(*adv));
+
+ adv->type = type;
+ adv->xmit = xmit;
+
+ adv->ref_cnt = 1;
+ ble_npl_event_set_arg(&adv->ev, buf);
+
+ return buf;
+}
+
+struct os_mbuf *
+bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit,
+ int32_t timeout)
+{
+ return bt_mesh_adv_create_from_pool(&adv_os_mbuf_pool, adv_alloc, type,
+ xmit, timeout);
+}
+
+void
+bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
+ void *cb_data)
+{
+ BT_DBG("buf %p, type 0x%02x len %u: %s", buf, BT_MESH_ADV(buf)->type, buf->om_len,
+ bt_hex(buf->om_data, buf->om_len));
+
+ BT_MESH_ADV(buf)->cb = cb;
+ BT_MESH_ADV(buf)->cb_data = cb_data;
+ BT_MESH_ADV(buf)->busy = 1;
+
+ net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf));
+ bt_mesh_adv_buf_ready();
+}
+
+static void
+bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
+ uint8_t adv_type, struct os_mbuf *buf)
+{
+ if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
+ return;
+ }
#if BT_MESH_EXTENDED_DEBUG
- BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
-#endif
-
- while (buf->om_len > 1) {
- struct net_buf_simple_state state;
- uint8_t len, type;
-
- len = net_buf_simple_pull_u8(buf);
- /* Check for early termination */
- if (len == 0) {
- return;
- }
-
- if (len > buf->om_len) {
- BT_WARN("AD malformed");
- return;
- }
-
- net_buf_simple_save(buf, &state);
-
- type = net_buf_simple_pull_u8(buf);
-
- switch (type) {
- case BLE_HS_ADV_TYPE_MESH_MESSAGE:
- bt_mesh_net_recv(&buf, rssi, BT_MESH_NET_IF_ADV);
- break;
+ BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
+#endif
+
+ while (buf->om_len > 1) {
+ struct net_buf_simple_state state;
+ uint8_t len, type;
+
+ len = net_buf_simple_pull_u8(buf);
+ /* Check for early termination */
+ if (len == 0) {
+ return;
+ }
+
+ if (len > buf->om_len) {
+ BT_WARN("AD malformed");
+ return;
+ }
+
+ net_buf_simple_save(buf, &state);
+
+ type = net_buf_simple_pull_u8(buf);
+
+ switch (type) {
+ case BLE_HS_ADV_TYPE_MESH_MESSAGE:
+ bt_mesh_net_recv(&buf, rssi, BT_MESH_NET_IF_ADV);
+ break;
#if MYNEWT_VAL(BLE_MESH_PB_ADV)
- case BLE_HS_ADV_TYPE_MESH_PROV:
- bt_mesh_pb_adv_recv(buf);
- break;
-#endif
- case BLE_HS_ADV_TYPE_MESH_BEACON:
- bt_mesh_beacon_recv(buf);
- break;
- default:
- break;
- }
-
- net_buf_simple_restore(buf, &state);
- net_buf_simple_pull_mem(buf, len);
- }
+ case BLE_HS_ADV_TYPE_MESH_PROV:
+ bt_mesh_pb_adv_recv(buf);
+ break;
+#endif
+ case BLE_HS_ADV_TYPE_MESH_BEACON:
+ bt_mesh_beacon_recv(buf);
+ break;
+ default:
+ break;
+ }
+
+ net_buf_simple_restore(buf, &state);
+ net_buf_simple_pull_mem(buf, len);
+ }
}
int
ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg)
{
#if MYNEWT_VAL(BLE_EXT_ADV)
- struct ble_gap_ext_disc_desc *ext_desc;
-#endif
- struct ble_gap_disc_desc *desc;
- struct os_mbuf *buf = NULL;
+ struct ble_gap_ext_disc_desc *ext_desc;
+#endif
+ struct ble_gap_disc_desc *desc;
+ struct os_mbuf *buf = NULL;
#if BT_MESH_EXTENDED_DEBUG
- BT_DBG("event->type %d", event->type);
-#endif
-
- switch (event->type) {
+ BT_DBG("event->type %d", event->type);
+#endif
+
+ switch (event->type) {
#if MYNEWT_VAL(BLE_EXT_ADV)
- case BLE_GAP_EVENT_EXT_DISC:
- ext_desc = &event->ext_disc;
- buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
- if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) {
- BT_ERR("Could not append data");
- goto done;
- }
- bt_mesh_scan_cb(&ext_desc->addr, ext_desc->rssi,
- ext_desc->legacy_event_type, buf);
- break;
-#endif
- case BLE_GAP_EVENT_DISC:
- desc = &event->disc;
- buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
- if (!buf || os_mbuf_append(buf, desc->data, desc->length_data)) {
- BT_ERR("Could not append data");
- goto done;
- }
-
- bt_mesh_scan_cb(&desc->addr, desc->rssi, desc->event_type, buf);
- break;
- default:
- break;
- }
+ case BLE_GAP_EVENT_EXT_DISC:
+ ext_desc = &event->ext_disc;
+ buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
+ if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) {
+ BT_ERR("Could not append data");
+ goto done;
+ }
+ bt_mesh_scan_cb(&ext_desc->addr, ext_desc->rssi,
+ ext_desc->legacy_event_type, buf);
+ break;
+#endif
+ case BLE_GAP_EVENT_DISC:
+ desc = &event->disc;
+ buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
+ if (!buf || os_mbuf_append(buf, desc->data, desc->length_data)) {
+ BT_ERR("Could not append data");
+ goto done;
+ }
+
+ bt_mesh_scan_cb(&desc->addr, desc->rssi, desc->event_type, buf);
+ break;
+ default:
+ break;
+ }
done:
- if (buf) {
- os_mbuf_free_chain(buf);
- }
-
- return 0;
-}
-
-int bt_mesh_scan_enable(void)
-{
- int err;
+ if (buf) {
+ os_mbuf_free_chain(buf);
+ }
+
+ return 0;
+}
+
+int
+bt_mesh_scan_enable(void)
+{
+ int err;
#if MYNEWT_VAL(BLE_EXT_ADV)
- struct ble_gap_ext_disc_params uncoded_params =
- { .itvl = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW,
- .passive = 1 };
-
- BT_DBG("");
-
- err = ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0,
- &uncoded_params, NULL, NULL, NULL);
+ struct ble_gap_ext_disc_params uncoded_params =
+ { .itvl = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW,
+ .passive = 1 };
+
+ BT_DBG("");
+
+ err = ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0,
+ &uncoded_params, NULL, NULL, NULL);
#else
- struct ble_gap_disc_params scan_param =
- { .passive = 1, .filter_duplicates = 0, .itvl =
- MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW };
-
- BT_DBG("");
-
- err = ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param,
- NULL, NULL);
-#endif
- if (err && err != BLE_HS_EALREADY) {
- BT_ERR("starting scan failed (err %d)", err);
- return err;
- }
-
- return 0;
-}
-
-int bt_mesh_scan_disable(void)
-{
- int err;
-
- BT_DBG("");
-
- err = ble_gap_disc_cancel();
- if (err && err != BLE_HS_EALREADY) {
- BT_ERR("stopping scan failed (err %d)", err);
- return err;
- }
-
- return 0;
-}
+ struct ble_gap_disc_params scan_param =
+ { .passive = 1, .filter_duplicates = 0, .itvl =
+ MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW };
+
+ BT_DBG("");
+
+ err = ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param,
+ NULL, NULL);
+#endif
+ if (err && err != BLE_HS_EALREADY) {
+ BT_ERR("starting scan failed (err %d)", err);
+ return err;
+ }
+
+ return 0;
+}
+
+int
+bt_mesh_scan_disable(void)
+{
+ int err;
+
+ BT_DBG("");
+
+ err = ble_gap_disc_cancel();
+ if (err && err != BLE_HS_EALREADY) {
+ BT_ERR("stopping scan failed (err %d)", err);
+ return err;
+ }
+
+ return 0;
+}
nimble/host/mesh/src/net.c
@@ -640,584 +659,603 @@
* get sent to the advertising bearer. If the packet came in through GATT,
* then we should only relay it if the GATT Proxy state is enabled.
*/
-static bool relay_to_adv(enum bt_mesh_net_if net_if)
-{
- switch (net_if) {
- case BT_MESH_NET_IF_ADV:
- return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED);
- case BT_MESH_NET_IF_PROXY:
- return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
- default:
- return false;
- }
-}
-
-static void bt_mesh_net_relay(struct os_mbuf *sbuf,
- struct bt_mesh_net_rx *rx)
-{
- const struct bt_mesh_net_cred *cred;
- struct os_mbuf *buf;
- uint8_t transmit;
-
- if (rx->ctx.recv_ttl <= 1U) {
- return;
- }
-
- if (rx->net_if == BT_MESH_NET_IF_ADV &&
- !rx->friend_cred &&
- bt_mesh_relay_get() != BT_MESH_RELAY_ENABLED &&
- bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_ENABLED) {
- return;
- }
-
- BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl,
- rx->ctx.recv_dst);
-
- /* The Relay Retransmit state is only applied to adv-adv relaying.
- * Anything else (like GATT to adv, or locally originated packets)
- * use the Network Transmit state.
- */
- if (rx->net_if == BT_MESH_NET_IF_ADV && !rx->friend_cred) {
- transmit = bt_mesh_relay_retransmit_get();
- } else {
- transmit = bt_mesh_net_transmit_get();
- }
-
- buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, transmit, K_NO_WAIT);
- if (!buf) {
- BT_ERR("Out of relay buffers");
- return;
- }
-
- /* Leave CTL bit intact */
- sbuf->om_data[1] &= 0x80;
- sbuf->om_data[1] |= rx->ctx.recv_ttl - 1U;
-
- net_buf_add_mem(buf, sbuf->om_data, sbuf->om_len);
-
- cred = &rx->sub->keys[SUBNET_KEY_TX_IDX(rx->sub)].msg;
-
- BT_DBG("Relaying packet. TTL is now %u", TTL(buf->om_data));
-
- /* Update NID if RX or RX was with friend credentials */
- if (rx->friend_cred) {
- buf->om_data[0] &= 0x80; /* Clear everything except IVI */
- buf->om_data[0] |= cred->nid;
- }
-
- /* We re-encrypt and obfuscate using the received IVI rather than
- * the normal TX IVI (which may be different) since the transport
- * layer nonce includes the IVI.
- */
- if (net_encrypt(buf, cred, BT_MESH_NET_IVI_RX(rx), false)) {
- BT_ERR("Re-encrypting failed");
- goto done;
- }
-
- BT_DBG("encoded %u bytes: %s", buf->om_len,
- bt_hex(buf->om_data, buf->om_len));
-
- /* When the Friend node relays message for lpn, the message will be
- * retransmitted using the managed flooding security credentials and
- * the Network PDU shall be retransmitted to all network interfaces.
- */
- if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
- (rx->friend_cred ||
- bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) {
- bt_mesh_proxy_relay(buf, rx->ctx.recv_dst);
- }
-
- if (relay_to_adv(rx->net_if) || rx->friend_cred) {
- bt_mesh_adv_send(buf, NULL, NULL);
- }
+static bool
+relay_to_adv(enum bt_mesh_net_if net_if)
+{
+ switch (net_if) {
+ case BT_MESH_NET_IF_ADV:
+ return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED);
+ case BT_MESH_NET_IF_PROXY:
+ return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
+ default:
+ return false;
+ }
+}
+
+static void
+bt_mesh_net_relay(struct os_mbuf *sbuf,
+ struct bt_mesh_net_rx *rx)
+{
+ const struct bt_mesh_net_cred *cred;
+ struct os_mbuf *buf;
+ uint8_t transmit;
+
+ if (rx->ctx.recv_ttl <= 1U) {
+ return;
+ }
+
+ if (rx->net_if == BT_MESH_NET_IF_ADV &&
+ !rx->friend_cred &&
+ bt_mesh_relay_get() != BT_MESH_RELAY_ENABLED &&
+ bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_ENABLED) {
+ return;
+ }
+
+ BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl,
+ rx->ctx.recv_dst);
+
+ /* The Relay Retransmit state is only applied to adv-adv relaying.
+ * Anything else (like GATT to adv, or locally originated packets)
+ * use the Network Transmit state.
+ */
+ if (rx->net_if == BT_MESH_NET_IF_ADV && !rx->friend_cred) {
+ transmit = bt_mesh_relay_retransmit_get();
+ } else {
+ transmit = bt_mesh_net_transmit_get();
+ }
+
+ buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, transmit, K_NO_WAIT);
+ if (!buf) {
+ BT_ERR("Out of relay buffers");
+ return;
+ }
+
+ /* Leave CTL bit intact */
+ sbuf->om_data[1] &= 0x80;
+ sbuf->om_data[1] |= rx->ctx.recv_ttl - 1U;
+
+ net_buf_add_mem(buf, sbuf->om_data, sbuf->om_len);
+
+ cred = &rx->sub->keys[SUBNET_KEY_TX_IDX(rx->sub)].msg;
+
+ BT_DBG("Relaying packet. TTL is now %u", TTL(buf->om_data));
+
+ /* Update NID if RX or RX was with friend credentials */
+ if (rx->friend_cred) {
+ buf->om_data[0] &= 0x80; /* Clear everything except IVI */
+ buf->om_data[0] |= cred->nid;
+ }
+
+ /* We re-encrypt and obfuscate using the received IVI rather than
+ * the normal TX IVI (which may be different) since the transport
+ * layer nonce includes the IVI.
+ */
+ if (net_encrypt(buf, cred, BT_MESH_NET_IVI_RX(rx), false)) {
+ BT_ERR("Re-encrypting failed");
+ goto done;
+ }
+
+ BT_DBG("encoded %u bytes: %s", buf->om_len,
+ bt_hex(buf->om_data, buf->om_len));
+
+ /* When the Friend node relays message for lpn, the message will be
+ * retransmitted using the managed flooding security credentials and
+ * the Network PDU shall be retransmitted to all network interfaces.
+ */
+ if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
+ (rx->friend_cred ||
+ bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) {
+ bt_mesh_proxy_relay(buf, rx->ctx.recv_dst);
+ }
+
+ if (relay_to_adv(rx->net_if) || rx->friend_cred) {
+ bt_mesh_adv_send(buf, NULL, NULL);
+ }
done:
- net_buf_unref(buf);
-}
-
-void bt_mesh_net_header_parse(struct os_mbuf *buf,
- struct bt_mesh_net_rx *rx)
-{
- rx->old_iv = (IVI(buf->om_data) != (bt_mesh.iv_index & 0x01));
- rx->ctl = CTL(buf->om_data);
- rx->ctx.recv_ttl = TTL(buf->om_data);
- rx->seq = SEQ(buf->om_data);
- rx->ctx.addr = SRC(buf->om_data);
- rx->ctx.recv_dst = DST(buf->om_data);
-}
-
-int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if,
- struct bt_mesh_net_rx *rx, struct os_mbuf *out)
-{
- if (in->om_len < BT_MESH_NET_MIN_PDU_LEN) {
- BT_WARN("Dropping too short mesh packet (len %u)", in->om_len);
- BT_WARN("%s", bt_hex(in->om_data, in->om_len));
- return -EINVAL;
- }
-
- if (in->om_len > BT_MESH_NET_MAX_PDU_LEN) {
- BT_WARN("Dropping too long mesh packet (len %u)", in->om_len);
- return -EINVAL;
- }
-
- if (net_if == BT_MESH_NET_IF_ADV && check_dup(in)) {
- BT_DBG("duplicate packet; dropping %u bytes: %s", in->om_len,
- bt_hex(in->om_data, in->om_len));
- return -EINVAL;
- }
-
- BT_DBG("%u bytes: %s", in->om_len, bt_hex(in->om_data, in->om_len));
-
- rx->net_if = net_if;
-
- if (!bt_mesh_net_cred_find(rx, in, out, net_decrypt)) {
- BT_DBG("Unable to find matching net for packet");
- return -ENOENT;
- }
-
- /* Initialize AppIdx to a sane value */
- rx->ctx.app_idx = BT_MESH_KEY_UNUSED;
-
- rx->ctx.recv_ttl = TTL(out->om_data);
-
- /* Default to responding with TTL 0 for non-routed messages */
- if (rx->ctx.recv_ttl == 0) {
- rx->ctx.send_ttl = 0;
- } else {
- rx->ctx.send_ttl = BT_MESH_TTL_DEFAULT;
- }
-
- rx->ctl = CTL(out->om_data);
- rx->seq = SEQ(out->om_data);
- rx->ctx.recv_dst = DST(out->om_data);
-
- BT_DBG("Decryption successful. Payload len %u: %s", out->om_len,
- bt_hex(out->om_data, out->om_len));
-
- if (net_if != BT_MESH_NET_IF_PROXY_CFG &&
- rx->ctx.recv_dst == BT_MESH_ADDR_UNASSIGNED) {
- BT_ERR("Destination address is unassigned; dropping packet");
- return -EBADMSG;
- }
-
- BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst,
- rx->ctx.recv_ttl);
- BT_DBG("PDU: %s", bt_hex(out->om_data, out->om_len));
-
- msg_cache_add(rx);
-
- return 0;
-}
-
-void bt_mesh_net_recv(struct os_mbuf **data, int8_t rssi,
- enum bt_mesh_net_if net_if)
-{
- struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN);
- struct bt_mesh_net_rx rx = { .ctx.recv_rssi = rssi };
- struct net_buf_simple_state state;
-
- BT_DBG("rssi %d net_if %u", rssi, net_if);
-
- if (!bt_mesh_is_provisioned()) {
- BT_ERR("Not provisioned; dropping packet");
- goto done;
- }
-
- if (bt_mesh_net_decode(*data, net_if, &rx, buf)) {
- goto done;
- }
-
- /* Save the state so the buffer can later be relayed */
- net_buf_simple_save(buf, &state);
-
- rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) ||
- bt_mesh_has_addr(rx.ctx.recv_dst));
-
- if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY)) &&
- net_if == BT_MESH_NET_IF_PROXY) {
- bt_mesh_proxy_addr_add(data, rx.ctx.addr);
-
- if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_DISABLED &&
- !rx.local_match) {
- BT_INFO("Proxy is disabled; ignoring message");
- goto done;
- }
- }
-
- /* The transport layer has indicated that it has rejected the message,
- * but would like to see it again if it is received in the future.
- * This can happen if a message is received when the device is in
- * Low Power mode, but the message was not encrypted with the friend
- * credentials. Remove it from the message cache so that we accept
- * it again in the future.
- */
- if (bt_mesh_trans_recv(buf, &rx) == -EAGAIN) {
- BT_WARN("Removing rejected message from Network Message Cache");
- msg_cache[rx.msg_cache_idx].src = BT_MESH_ADDR_UNASSIGNED;
- /* Rewind the next index now that we're not using this entry */
- msg_cache_next = rx.msg_cache_idx;
- }
-
- /* Relay if this was a group/virtual address, or if the destination
- * was neither a local element nor an LPN we're Friends for.
- */
- if (!BT_MESH_ADDR_IS_UNICAST(rx.ctx.recv_dst) ||
- (!rx.local_match && !rx.friend_match)) {
- net_buf_simple_restore(buf, &state);
- bt_mesh_net_relay(buf, &rx);
- }
+ net_buf_unref(buf);
+}
+
+void
+bt_mesh_net_header_parse(struct os_mbuf *buf,
+ struct bt_mesh_net_rx *rx)
+{
+ rx->old_iv = (IVI(buf->om_data) != (bt_mesh.iv_index & 0x01));
+ rx->ctl = CTL(buf->om_data);
+ rx->ctx.recv_ttl = TTL(buf->om_data);
+ rx->seq = SEQ(buf->om_data);
+ rx->ctx.addr = SRC(buf->om_data);
+ rx->ctx.recv_dst = DST(buf->om_data);
+}
+
+int
+bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if,
+ struct bt_mesh_net_rx *rx, struct os_mbuf *out)
+{
+ if (in->om_len < BT_MESH_NET_MIN_PDU_LEN) {
+ BT_WARN("Dropping too short mesh packet (len %u)", in->om_len);
+ BT_WARN("%s", bt_hex(in->om_data, in->om_len));
+ return -EINVAL;
+ }
+
+ if (in->om_len > BT_MESH_NET_MAX_PDU_LEN) {
+ BT_WARN("Dropping too long mesh packet (len %u)", in->om_len);
+ return -EINVAL;
+ }
+
+ if (net_if == BT_MESH_NET_IF_ADV && check_dup(in)) {
+ BT_DBG("duplicate packet; dropping %u bytes: %s", in->om_len,
+ bt_hex(in->om_data, in->om_len));
+ return -EINVAL;
+ }
+
+ BT_DBG("%u bytes: %s", in->om_len, bt_hex(in->om_data, in->om_len));
+
+ rx->net_if = net_if;
+
+ if (!bt_mesh_net_cred_find(rx, in, out, net_decrypt)) {
+ BT_DBG("Unable to find matching net for packet");
+ return -ENOENT;
+ }
+
+ /* Initialize AppIdx to a sane value */
+ rx->ctx.app_idx = BT_MESH_KEY_UNUSED;
+
+ rx->ctx.recv_ttl = TTL(out->om_data);
+
+ /* Default to responding with TTL 0 for non-routed messages */
+ if (rx->ctx.recv_ttl == 0) {
+ rx->ctx.send_ttl = 0;
+ } else {
+ rx->ctx.send_ttl = BT_MESH_TTL_DEFAULT;
+ }
+
+ rx->ctl = CTL(out->om_data);
+ rx->seq = SEQ(out->om_data);
+ rx->ctx.recv_dst = DST(out->om_data);
+
+ BT_DBG("Decryption successful. Payload len %u: %s", out->om_len,
+ bt_hex(out->om_data, out->om_len));
+
+ if (net_if != BT_MESH_NET_IF_PROXY_CFG &&
+ rx->ctx.recv_dst == BT_MESH_ADDR_UNASSIGNED) {
+ BT_ERR("Destination address is unassigned; dropping packet");
+ return -EBADMSG;
+ }
+
+ BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst,
+ rx->ctx.recv_ttl);
+ BT_DBG("PDU: %s", bt_hex(out->om_data, out->om_len));
+
+ msg_cache_add(rx);
+
+ return 0;
+}
+
+void
+bt_mesh_net_recv(struct os_mbuf **data, int8_t rssi,
+ enum bt_mesh_net_if net_if)
+{
+ struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN);
+ struct bt_mesh_net_rx rx = { .ctx.recv_rssi = rssi };
+ struct net_buf_simple_state state;
+
+ BT_DBG("rssi %d net_if %u", rssi, net_if);
+
+ if (!bt_mesh_is_provisioned()) {
+ BT_ERR("Not provisioned; dropping packet");
+ goto done;
+ }
+
+ if (bt_mesh_net_decode(*data, net_if, &rx, buf)) {
+ goto done;
+ }
+
+ /* Save the state so the buffer can later be relayed */
+ net_buf_simple_save(buf, &state);
+
+ rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) ||
+ bt_mesh_has_addr(rx.ctx.recv_dst));
+
+ if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY)) &&
+ net_if == BT_MESH_NET_IF_PROXY) {
+ bt_mesh_proxy_addr_add(data, rx.ctx.addr);
+
+ if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_DISABLED &&
+ !rx.local_match) {
+ BT_INFO("Proxy is disabled; ignoring message");
+ goto done;
+ }
+ }
+
+ /* The transport layer has indicated that it has rejected the message,
+ * but would like to see it again if it is received in the future.
+ * This can happen if a message is received when the device is in
+ * Low Power mode, but the message was not encrypted with the friend
+ * credentials. Remove it from the message cache so that we accept
+ * it again in the future.
+ */
+ if (bt_mesh_trans_recv(buf, &rx) == -EAGAIN) {
+ BT_WARN("Removing rejected message from Network Message Cache");
+ msg_cache[rx.msg_cache_idx].src = BT_MESH_ADDR_UNASSIGNED;
+ /* Rewind the next index now that we're not using this entry */
+ msg_cache_next = rx.msg_cache_idx;
+ }
+
+ /* Relay if this was a group/virtual address, or if the destination
+ * was neither a local element nor an LPN we're Friends for.
+ */
+ if (!BT_MESH_ADDR_IS_UNICAST(rx.ctx.recv_dst) ||
+ (!rx.local_match && !rx.friend_match)) {
+ net_buf_simple_restore(buf, &state);
+ bt_mesh_net_relay(buf, &rx);
+ }
done:
os_mbuf_free_chain(buf);
}
-static void ivu_refresh(struct ble_npl_event *work)
-{
- if (!bt_mesh_is_provisioned()) {
- return;
- }
-
- bt_mesh.ivu_duration = MIN(UINT8_MAX,
- bt_mesh.ivu_duration + BT_MESH_IVU_HOURS);
-
- BT_DBG("%s for %u hour%s",
- atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ?
- "IVU in Progress" : "IVU Normal mode",
- bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1 ? "" : "s");
-
- if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
- if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
- store_iv(true);
- }
-
- k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
- return;
- }
-
- if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) {
- bt_mesh_beacon_ivu_initiator(true);
- bt_mesh_net_iv_update(bt_mesh.iv_index, false);
- } else if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
- store_iv(true);
- }
+static void
+ivu_refresh(struct ble_npl_event *work)
+{
+ if (!bt_mesh_is_provisioned()) {
+ return;
+ }
+
+ bt_mesh.ivu_duration = MIN(UINT8_MAX,
+ bt_mesh.ivu_duration + BT_MESH_IVU_HOURS);
+
+ BT_DBG("%s for %u hour%s",
+ atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ?
+ "IVU in Progress" : "IVU Normal mode",
+ bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1 ? "" : "s");
+
+ if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
+ if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
+ store_iv(true);
+ }
+
+ k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
+ return;
+ }
+
+ if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) {
+ bt_mesh_beacon_ivu_initiator(true);
+ bt_mesh_net_iv_update(bt_mesh.iv_index, false);
+ } else if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
+ store_iv(true);
+ }
}
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
-static int net_set(int argc, char **argv, char *val)
-{
- struct net_val net;
- int len, err;
-
- BT_DBG("val %s", val ? val : "(null)");
-
- if (!val) {
- bt_mesh_comp_unprovision();
- memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
- return 0;
- }
-
- len = sizeof(net);
- err = settings_bytes_from_str(val, &net, &len);
- if (err) {
- BT_ERR("Failed to decode value %s (err %d)", val, err);
- return err;
- }
-
- if (len != sizeof(net)) {
- BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(net));
- return -EINVAL;
- }
-
- memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key));
- bt_mesh_comp_provision(net.primary_addr);
-
- BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr);
- BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16));
-
- return 0;
-}
-
-static int iv_set(int argc, char **argv, char *val)
-{
- struct iv_val iv;
- int len, err;
-
- BT_DBG("val %s", val ? val : "(null)");
-
- if (!val) {
- bt_mesh.iv_index = 0U;
- atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
- return 0;
- }
-
- len = sizeof(iv);
- err = settings_bytes_from_str(val, &iv, &len);
- if (err) {
- BT_ERR("Failed to decode value %s (err %d)", val, err);
- return err;
- }
-
- if (len != sizeof(iv)) {
- BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(iv));
- return -EINVAL;
- }
-
- bt_mesh.iv_index = iv.iv_index;
- atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv.iv_update);
- bt_mesh.ivu_duration = iv.iv_duration;
-
- BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours",
- (unsigned) iv.iv_index, iv.iv_update, iv.iv_duration);
-
- return 0;
-}
-
-static int seq_set(int argc, char **argv, char *val)
-{
- struct seq_val seq;
- int len, err;
-
- BT_DBG("val %s", val ? val : "(null)");
-
- if (!val) {
- bt_mesh.seq = 0;
- return 0;
- }
-
- len = sizeof(seq);
- err = settings_bytes_from_str(val, &seq, &len);
- if (err) {
- BT_ERR("Failed to decode value %s (err %d)", val, err);
- return err;
- }
-
- if (len != sizeof(seq)) {
- BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(seq));
- return -EINVAL;
- }
-
- bt_mesh.seq = sys_get_le24(seq.val);
-
- if (CONFIG_BT_MESH_SEQ_STORE_RATE > 0) {
- /* Make sure we have a large enough sequence number. We
- * subtract 1 so that the first transmission causes a write
- * to the settings storage.
- */
- bt_mesh.seq += (CONFIG_BT_MESH_SEQ_STORE_RATE -
- (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE));
- bt_mesh.seq--;
- }
-
- BT_DBG("Sequence Number 0x%06x", bt_mesh.seq);
-
- return 0;
+static int
+net_set(int argc, char **argv, char *val)
+{
+ struct net_val net;
+ int len, err;
+
+ BT_DBG("val %s", val ? val : "(null)");
+
+ if (!val) {
+ bt_mesh_comp_unprovision();
+ memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
+ return 0;
+ }
+
+ len = sizeof(net);
+ err = settings_bytes_from_str(val, &net, &len);
+ if (err) {
+ BT_ERR("Failed to decode value %s (err %d)", val, err);
+ return err;
+ }
+
+ if (len != sizeof(net)) {
+ BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(net));
+ return -EINVAL;
+ }
+
+ memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key));
+ bt_mesh_comp_provision(net.primary_addr);
+
+ BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr);
+ BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16));
+
+ return 0;
+}
+
+static int
+iv_set(int argc, char **argv, char *val)
+{
+ struct iv_val iv;
+ int len, err;
+
+ BT_DBG("val %s", val ? val : "(null)");
+
+ if (!val) {
+ bt_mesh.iv_index = 0U;
+ atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
+ return 0;
+ }
+
+ len = sizeof(iv);
+ err = settings_bytes_from_str(val, &iv, &len);
+ if (err) {
+ BT_ERR("Failed to decode value %s (err %d)", val, err);
+ return err;
+ }
+
+ if (len != sizeof(iv)) {
+ BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(iv));
+ return -EINVAL;
+ }
+
+ bt_mesh.iv_index = iv.iv_index;
+ atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv.iv_update);
+ bt_mesh.ivu_duration = iv.iv_duration;
+
+ BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours",
+ (unsigned) iv.iv_index, iv.iv_update, iv.iv_duration);
+
+ return 0;
+}
+
+static int
+seq_set(int argc, char **argv, char *val)
+{
+ struct seq_val seq;
+ int len, err;
+
+ BT_DBG("val %s", val ? val : "(null)");
+
+ if (!val) {
+ bt_mesh.seq = 0;
+ return 0;
+ }
+
+ len = sizeof(seq);
+ err = settings_bytes_from_str(val, &seq, &len);
+ if (err) {
+ BT_ERR("Failed to decode value %s (err %d)", val, err);
+ return err;
+ }
+
+ if (len != sizeof(seq)) {
+ BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(seq));
+ return -EINVAL;
+ }
+
+ bt_mesh.seq = sys_get_le24(seq.val);
+
+ if (CONFIG_BT_MESH_SEQ_STORE_RATE > 0) {
+ /* Make sure we have a large enough sequence number. We
+ * subtract 1 so that the first transmission causes a write
+ * to the settings storage.
+ */
+ bt_mesh.seq += (CONFIG_BT_MESH_SEQ_STORE_RATE -
+ (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE));
+ bt_mesh.seq--;
+ }
+
+ BT_DBG("Sequence Number 0x%06x", bt_mesh.seq);
+
+ return 0;
}
static struct conf_handler bt_mesh_net_conf_handler = {
- .ch_name = "bt_mesh",
- .ch_get = NULL,
- .ch_set = net_set,
- .ch_commit = NULL,
- .ch_export = NULL,
+ .ch_name = "bt_mesh",
+ .ch_get = NULL,
+ .ch_set = net_set,
+ .ch_commit = NULL,
+ .ch_export = NULL,
};
static struct conf_handler bt_mesh_iv_conf_handler = {
- .ch_name = "bt_mesh",
- .ch_get = NULL,
- .ch_set = iv_set,
- .ch_commit = NULL,
- .ch_export = NULL,
+ .ch_name = "bt_mesh",
+ .ch_get = NULL,
+ .ch_set = iv_set,
+ .ch_commit = NULL,
+ .ch_export = NULL,
};
static struct conf_handler bt_mesh_seq_conf_handler = {
- .ch_name = "bt_mesh",
- .ch_get = NULL,
- .ch_set = seq_set,
- .ch_commit = NULL,
- .ch_export = NULL,
+ .ch_name = "bt_mesh",
+ .ch_get = NULL,
+ .ch_set = seq_set,
+ .ch_commit = NULL,
+ .ch_export = NULL,
};
#endif
-void bt_mesh_net_init(void)
-{
- int rc;
+void
+bt_mesh_net_init(void)
+{
+ int rc;
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
- rc = conf_register(&bt_mesh_net_conf_handler);
-
- SYSINIT_PANIC_ASSERT_MSG(rc == 0,
- "Failed to register bt_mesh_net conf");
-
-
- rc = conf_register(&bt_mesh_iv_conf_handler);
-
- SYSINIT_PANIC_ASSERT_MSG(rc == 0,
- "Failed to register bt_mesh_iv conf");
-
- rc = conf_register(&bt_mesh_seq_conf_handler);
-
- SYSINIT_PANIC_ASSERT_MSG(rc == 0,
- "Failed to register bt_mesh_seq conf");
+ rc = conf_register(&bt_mesh_net_conf_handler);
+
+ SYSINIT_PANIC_ASSERT_MSG(rc == 0,
+ "Failed to register bt_mesh_net conf");
+
+
+ rc = conf_register(&bt_mesh_iv_conf_handler);
+
+ SYSINIT_PANIC_ASSERT_MSG(rc == 0,
+ "Failed to register bt_mesh_iv conf");
+
+ rc = conf_register(&bt_mesh_seq_conf_handler);
+
+ SYSINIT_PANIC_ASSERT_MSG(rc == 0,
+ "Failed to register bt_mesh_seq conf");
#endif
- k_work_init_delayable(&bt_mesh.ivu_timer, ivu_refresh);
-
- k_work_init(&bt_mesh.local_work, bt_mesh_net_local);
- net_buf_slist_init(&bt_mesh.local_queue);
-
- rc = os_mempool_init(&loopback_buf_mempool, MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS),
- LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE,
- &loopback_mbuf_membuf[0], "loopback_buf_pool");
- assert(rc == 0);
-
- rc = os_mbuf_pool_init(&loopback_os_mbuf_pool, &loopback_buf_mempool,
- LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE,
- MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS));
- assert(rc == 0);
+ k_work_init_delayable(&bt_mesh.ivu_timer, ivu_refresh);
+
+ k_work_init(&bt_mesh.local_work, bt_mesh_net_local);
+ net_buf_slist_init(&bt_mesh.local_queue);
+
+ rc = os_mempool_init(&loopback_buf_mempool, MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS),
+ LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE,
+ &loopback_mbuf_membuf[0], "loopback_buf_pool");
+ assert(rc == 0);
+
+ rc = os_mbuf_pool_init(&loopback_os_mbuf_pool, &loopback_buf_mempool,
+ LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE,
+ MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS));
+ assert(rc == 0);
}
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
-static void clear_iv(void)
-{
- int err;
-
- err = settings_save_one("bt_mesh/IV", NULL);
- if (err) {
- BT_ERR("Failed to clear IV");
- } else {
- BT_DBG("Cleared IV");
- }
-}
-
-static void store_pending_iv(void)
-{
- char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))];
- struct iv_val iv;
- char *str;
- int err;
-
- iv.iv_index = bt_mesh.iv_index;
- iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
- iv.iv_duration = bt_mesh.ivu_duration;
-
- str = settings_str_from_bytes(&iv, sizeof(iv), buf, sizeof(buf));
- if (!str) {
- BT_ERR("Unable to encode IV as value");
- return;
- }
-
- BT_DBG("Saving IV as value %s", str);
- err = settings_save_one("bt_mesh/IV", str);
- if (err) {
- BT_ERR("Failed to store IV");
- } else {
- BT_DBG("Stored IV");
- }
-}
-
-void bt_mesh_net_pending_iv_store(void)
-{
- if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
- store_pending_iv();
- } else {
- clear_iv();
- }
-}
-
-static void clear_net(void)
-{
- int err;
-
- err = settings_save_one("bt_mesh/Net", NULL);
- if (err) {
- BT_ERR("Failed to clear Network");
- } else {
- BT_DBG("Cleared Network");
- }
-}
-
-static void store_pending_net(void)
-{
- char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))];
- struct net_val net;
- char *str;
- int err;
-
- BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(),
- bt_hex(bt_mesh.dev_key, 16));
-
- net.primary_addr = bt_mesh_primary_addr();
- memcpy(net.dev_key, bt_mesh.dev_key, 16);
-
- str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf));
- if (!str) {
- BT_ERR("Unable to encode Network as value");
- return;
- }
-
- BT_DBG("Saving Network as value %s", str);
- err = settings_save_one("bt_mesh/Net", str);
- if (err) {
- BT_ERR("Failed to store Network");
- } else {
- BT_DBG("Stored Network");
- }
-}
-
-void bt_mesh_net_pending_net_store(void)
-{
- if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
- store_pending_net();
- } else {
- clear_net();
- }
-}
-
-void bt_mesh_net_pending_seq_store(void)
-{
- char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))];
- char *str;
- struct seq_val seq;
- int err;
-
- if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
- sys_put_le24(bt_mesh.seq, seq.val);
-
- str = settings_str_from_bytes(&seq, sizeof(seq), buf, sizeof(buf));
- if (!str) {
- BT_ERR("Unable to encode Network as value");
- return;
- }
-
- BT_DBG("Saving Network as value %s", str);
- err = settings_save_one("bt_mesh/Seq", str);
- if (err) {
- BT_ERR("Failed to stor Seq value");
- } else {
- BT_DBG("Stored Seq value");
- }
- } else {
- err = settings_save_one("bt_mesh/Seq", NULL);
- if (err) {
- BT_ERR("Failed to clear Seq value");
- } else {
- BT_DBG("Cleared Seq value");
- }
- }
-}
-
-void bt_mesh_net_clear(void)
-{
- bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_PENDING);
- bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING);
- bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
- bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING);
+static void
+clear_iv(void)
+{
+ int err;
+
+ err = settings_save_one("bt_mesh/IV", NULL);
+ if (err) {
+ BT_ERR("Failed to clear IV");
+ } else {
+ BT_DBG("Cleared IV");
+ }
+}
+
+static void
+store_pending_iv(void)
+{
+ char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))];
+ struct iv_val iv;
+ char *str;
+ int err;
+
+ iv.iv_index = bt_mesh.iv_index;
+ iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
+ iv.iv_duration = bt_mesh.ivu_duration;
+
+ str = settings_str_from_bytes(&iv, sizeof(iv), buf, sizeof(buf));
+ if (!str) {
+ BT_ERR("Unable to encode IV as value");
+ return;
+ }
+
+ BT_DBG("Saving IV as value %s", str);
+ err = settings_save_one("bt_mesh/IV", str);
+ if (err) {
+ BT_ERR("Failed to store IV");
+ } else {
+ BT_DBG("Stored IV");
+ }
+}
+
+void
+bt_mesh_net_pending_iv_store(void)
+{
+ if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
+ store_pending_iv();
+ } else {
+ clear_iv();
+ }
+}
+
+static void
+clear_net(void)
+{
+ int err;
+
+ err = settings_save_one("bt_mesh/Net", NULL);
+ if (err) {
+ BT_ERR("Failed to clear Network");
+ } else {
+ BT_DBG("Cleared Network");
+ }
+}
+
+static void
+store_pending_net(void)
+{
+ char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))];
+ struct net_val net;
+ char *str;
+ int err;
+
+ BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(),
+ bt_hex(bt_mesh.dev_key, 16));
+
+ net.primary_addr = bt_mesh_primary_addr();
+ memcpy(net.dev_key, bt_mesh.dev_key, 16);
+
+ str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf));
+ if (!str) {
+ BT_ERR("Unable to encode Network as value");
+ return;
+ }
+
+ BT_DBG("Saving Network as value %s", str);
+ err = settings_save_one("bt_mesh/Net", str);
+ if (err) {
+ BT_ERR("Failed to store Network");
+ } else {
+ BT_DBG("Stored Network");
+ }
+}
+
+void
+bt_mesh_net_pending_net_store(void)
+{
+ if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
+ store_pending_net();
+ } else {
+ clear_net();
+ }
+}
+
+void
+bt_mesh_net_pending_seq_store(void)
+{
+ char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))];
+ char *str;
+ struct seq_val seq;
+ int err;
+
+ if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
+ sys_put_le24(bt_mesh.seq, seq.val);
+
+ str = settings_str_from_bytes(&seq, sizeof(seq), buf, sizeof(buf));
+ if (!str) {
+ BT_ERR("Unable to encode Network as value");
+ return;
+ }
+
+ BT_DBG("Saving Network as value %s", str);
+ err = settings_save_one("bt_mesh/Seq", str);
+ if (err) {
+ BT_ERR("Failed to stor Seq value");
+ } else {
+ BT_DBG("Stored Seq value");
+ }
+ } else {
+ err = settings_save_one("bt_mesh/Seq", NULL);
+ if (err) {
+ BT_ERR("Failed to clear Seq value");
+ } else {
+ BT_DBG("Cleared Seq value");
+ }
+ }
+}
+
+void
+bt_mesh_net_clear(void)
+{
+ bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_PENDING);
+ bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING);
+ bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
+ bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING);
}
#endif
-void bt_mesh_net_settings_commit(void)
-{
- if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
- k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
- }
-}
+void
+bt_mesh_net_settings_commit(void)
+{
+ if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
+ k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
+ }
+}
nimble/host/mesh/src/net.h
@@ -280,21 +281,21 @@
}
int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16],
- uint32_t iv_index);
+ uint32_t iv_index);
bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update);
int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
- bool proxy);
+ bool proxy);
int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if,
- struct bt_mesh_net_rx *rx, struct os_mbuf *out);
+ struct bt_mesh_net_rx *rx, struct os_mbuf *out);
int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
- const struct bt_mesh_send_cb *cb, void *cb_data);
+ const struct bt_mesh_send_cb *cb, void *cb_data);
void bt_mesh_net_recv(struct os_mbuf **data, int8_t rssi,
- enum bt_mesh_net_if net_if);
+ enum bt_mesh_net_if net_if);
void bt_mesh_net_loopback_clear(uint16_t net_idx);
nimble/host/mesh/src/proxy_srv.c
@@ -60,325 +60,342 @@
static int conn_count;
-struct bt_mesh_proxy_client *find_client(uint16_t conn_handle)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(clients); i++) {
- if (clients[i].conn_handle == conn_handle) {
- return &clients[i];
- }
- }
- return NULL;
-}
-
-static struct bt_mesh_proxy_client *get_client(uint16_t conn_handle)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(clients); i++) {
- if (clients[i].conn_handle == 0xffff) {
- clients[i].conn_handle = conn_handle;
- return &clients[i];
- }
- }
- return NULL;
+struct bt_mesh_proxy_client *
+find_client(uint16_t conn_handle)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clients); i++) {
+ if (clients[i].conn_handle == conn_handle) {
+ return &clients[i];
+ }
+ }
+ return NULL;
+}
+
+static struct bt_mesh_proxy_client *
+get_client(uint16_t conn_handle)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clients); i++) {
+ if (clients[i].conn_handle == 0xffff) {
+ clients[i].conn_handle = conn_handle;
+ return &clients[i];
+ }
+ }
+ return NULL;
}
/* Next subnet in queue to be advertised */
static struct bt_mesh_subnet *beacon_sub;
-static int filter_set(struct bt_mesh_proxy_client *client,
- struct os_mbuf *buf)
-{
- uint8_t type;
-
- if (buf->om_len < 1) {
- BT_WARN("Too short Filter Set message");
- return -EINVAL;
- }
-
- type = net_buf_simple_pull_u8(buf);
- BT_DBG("type 0x%02x", type);
-
- switch (type) {
- case 0x00:
- (void)memset(client->filter, 0, sizeof(client->filter));
- client->filter_type = ACCEPT;
- break;
- case 0x01:
- (void)memset(client->filter, 0, sizeof(client->filter));
- client->filter_type = REJECT;
- break;
- default:
- BT_WARN("Prohibited Filter Type 0x%02x", type);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void filter_add(struct bt_mesh_proxy_client *client, uint16_t addr)
-{
- int i;
-
- BT_DBG("addr 0x%04x", addr);
-
- if (addr == BT_MESH_ADDR_UNASSIGNED) {
- return;
- }
-
- for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
- if (client->filter[i] == addr) {
- return;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
- if (client->filter[i] == BT_MESH_ADDR_UNASSIGNED) {
- client->filter[i] = addr;
- return;
- }
- }
-}
-
-static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr)
-{
- int i;
-
- BT_DBG("addr 0x%04x", addr);
-
- if (addr == BT_MESH_ADDR_UNASSIGNED) {
- return;
- }
-
- for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
- if (client->filter[i] == addr) {
- client->filter[i] = BT_MESH_ADDR_UNASSIGNED;
- return;
- }
- }
-}
-
-static void send_filter_status(struct bt_mesh_proxy_client *client,
- struct bt_mesh_net_rx *rx,
- struct os_mbuf *buf)
-{
- struct bt_mesh_net_tx tx = {
- .sub = rx->sub,
- .ctx = &rx->ctx,
- .src = bt_mesh_primary_addr(),
- };
- uint16_t filter_size;
- int i, err;
-
- /* Configuration messages always have dst unassigned */
- tx.ctx->addr = BT_MESH_ADDR_UNASSIGNED;
-
- net_buf_simple_init(buf, 10);
-
- net_buf_simple_add_u8(buf, CFG_FILTER_STATUS);
-
- if (client->filter_type == ACCEPT) {
- net_buf_simple_add_u8(buf, 0x00);
- } else {
- net_buf_simple_add_u8(buf, 0x01);
- }
-
- for (filter_size = 0U, i = 0; i < ARRAY_SIZE(client->filter); i++) {
- if (client->filter[i] != BT_MESH_ADDR_UNASSIGNED) {
- filter_size++;
- }
- }
-
- net_buf_simple_add_be16(buf, filter_size);
-
- BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
-
- err = bt_mesh_net_encode(&tx, buf, true);
- if (err) {
- BT_ERR("Encoding Proxy cfg message failed (err %d)", err);
- return;
- }
-
- err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_CONFIG, buf);
- if (err) {
- BT_ERR("Failed to send proxy cfg message (err %d)", err);
- }
-}
-
-static void proxy_filter_recv(uint16_t conn_handle,
- struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
-{
- struct bt_mesh_proxy_client *client;
- uint8_t opcode;
-
- client = find_client(conn_handle);
-
- opcode = net_buf_simple_pull_u8(buf);
- switch (opcode) {
- case CFG_FILTER_SET:
- filter_set(client, buf);
- send_filter_status(client, rx, buf);
- break;
- case CFG_FILTER_ADD:
- while (buf->om_len >= 2) {
- uint16_t addr;
-
- addr = net_buf_simple_pull_be16(buf);
- filter_add(client, addr);
- }
- send_filter_status(client, rx, buf);
- break;
- case CFG_FILTER_REMOVE:
- while (buf->om_len >= 2) {
- uint16_t addr;
-
- addr = net_buf_simple_pull_be16(buf);
- filter_remove(client, addr);
- }
- send_filter_status(client, rx, buf);
- break;
- default:
- BT_WARN("Unhandled configuration OpCode 0x%02x", opcode);
- break;
- }
-}
-
-static void proxy_cfg(struct bt_mesh_proxy_role *role)
-{
- struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN);
- struct bt_mesh_net_rx rx;
- int err;
-
- err = bt_mesh_net_decode(role->buf, BT_MESH_NET_IF_PROXY_CFG,
- &rx, buf);
- if (err) {
- BT_ERR("Failed to decode Proxy Configuration (err %d)", err);
- return;
- }
-
- rx.local_match = 1U;
-
- if (bt_mesh_rpl_check(&rx, NULL)) {
- BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x",
- rx.ctx.addr, rx.ctx.recv_dst, rx.seq);
- return;
- }
-
- /* Remove network headers */
- net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN);
-
- BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
-
- if (buf->om_len < 1) {
- BT_WARN("Too short proxy configuration PDU");
- return;
- }
-
- proxy_filter_recv(role->conn_handle, &rx, buf);
-}
-
-static void proxy_msg_recv(struct bt_mesh_proxy_role *role)
-{
- switch (role->msg_type) {
- case BT_MESH_PROXY_NET_PDU:
- BT_DBG("Mesh Network PDU");
- bt_mesh_net_recv(&(role->buf), 0, BT_MESH_NET_IF_PROXY);
- break;
- case BT_MESH_PROXY_BEACON:
- BT_DBG("Mesh Beacon PDU");
- bt_mesh_beacon_recv(role->buf);
- break;
- case BT_MESH_PROXY_CONFIG:
- BT_DBG("Mesh Configuration PDU");
- proxy_cfg(role);
- break;
- default:
- BT_WARN("Unhandled Message Type 0x%02x", role->msg_type);
- break;
- }
-}
-
-static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subnet *sub)
-{
- struct os_mbuf *buf = NET_BUF_SIMPLE(23);
- int rc;
-
- net_buf_simple_init(buf, 1);
- bt_mesh_beacon_create(sub, buf);
-
- rc = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_BEACON, buf);
- os_mbuf_free_chain(buf);
- return rc;
-}
-
-static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data)
-{
- struct bt_mesh_proxy_client *client = cb_data;
-
- return beacon_send(client, sub);
-}
-
-static void proxy_send_beacons(struct ble_npl_event *work)
-{
- struct bt_mesh_proxy_client *client;
-
- client = ble_npl_event_get_arg(work);
-
- (void)bt_mesh_subnet_find(send_beacon_cb, client);
-}
-
-void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub)
-{
- int i;
-
- if (!sub) {
- /* NULL means we send on all subnets */
- bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send);
- return;
- }
-
- for (i = 0; i < ARRAY_SIZE(clients); i++) {
- if (clients[i].cli) {
- beacon_send(&clients[i], sub);
- }
- }
-}
-
-static void node_id_start(struct bt_mesh_subnet *sub)
-{
- sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING;
- sub->node_id_start = k_uptime_get_32();
-}
-
-void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub)
-{
- node_id_start(sub);
-
- /* Prioritize the recently enabled subnet */
- beacon_sub = sub;
-}
-
-void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub)
- {
- sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
- sub->node_id_start = 0U;
-}
-
-int bt_mesh_proxy_identity_enable(void)
-{
- BT_DBG("");
-
- if (!bt_mesh_is_provisioned()) {
- return -EAGAIN;
- }
-
- if (bt_mesh_subnet_foreach(node_id_start)) {
- bt_mesh_adv_update();
- }
-
- return 0;
+static int
+filter_set(struct bt_mesh_proxy_client *client,
+ struct os_mbuf *buf)
+{
+ uint8_t type;
+
+ if (buf->om_len < 1) {
+ BT_WARN("Too short Filter Set message");
+ return -EINVAL;
+ }
+
+ type = net_buf_simple_pull_u8(buf);
+ BT_DBG("type 0x%02x", type);
+
+ switch (type) {
+ case 0x00:
+ (void)memset(client->filter, 0, sizeof(client->filter));
+ client->filter_type = ACCEPT;
+ break;
+ case 0x01:
+ (void)memset(client->filter, 0, sizeof(client->filter));
+ client->filter_type = REJECT;
+ break;
+ default:
+ BT_WARN("Prohibited Filter Type 0x%02x", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void
+filter_add(struct bt_mesh_proxy_client *client, uint16_t addr)
+{
+ int i;
+
+ BT_DBG("addr 0x%04x", addr);
+
+ if (addr == BT_MESH_ADDR_UNASSIGNED) {
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+ if (client->filter[i] == addr) {
+ return;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+ if (client->filter[i] == BT_MESH_ADDR_UNASSIGNED) {
+ client->filter[i] = addr;
+ return;
+ }
+ }
+}
+
+static void
+filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr)
+{
+ int i;
+
+ BT_DBG("addr 0x%04x", addr);
+
+ if (addr == BT_MESH_ADDR_UNASSIGNED) {
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+ if (client->filter[i] == addr) {
+ client->filter[i] = BT_MESH_ADDR_UNASSIGNED;
+ return;
+ }
+ }
+}
+
+static void
+send_filter_status(struct bt_mesh_proxy_client *client,
+ struct bt_mesh_net_rx *rx,
+ struct os_mbuf *buf)
+{
+ struct bt_mesh_net_tx tx = {
+ .sub = rx->sub,
+ .ctx = &rx->ctx,
+ .src = bt_mesh_primary_addr(),
+ };
+ uint16_t filter_size;
+ int i, err;
+
+ /* Configuration messages always have dst unassigned */
+ tx.ctx->addr = BT_MESH_ADDR_UNASSIGNED;
+
+ net_buf_simple_init(buf, 10);
+
+ net_buf_simple_add_u8(buf, CFG_FILTER_STATUS);
+
+ if (client->filter_type == ACCEPT) {
+ net_buf_simple_add_u8(buf, 0x00);
+ } else {
+ net_buf_simple_add_u8(buf, 0x01);
+ }
+
+ for (filter_size = 0U, i = 0; i < ARRAY_SIZE(client->filter); i++) {
+ if (client->filter[i] != BT_MESH_ADDR_UNASSIGNED) {
+ filter_size++;
+ }
+ }
+
+ net_buf_simple_add_be16(buf, filter_size);
+
+ BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
+
+ err = bt_mesh_net_encode(&tx, buf, true);
+ if (err) {
+ BT_ERR("Encoding Proxy cfg message failed (err %d)", err);
+ return;
+ }
+
+ err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_CONFIG, buf);
+ if (err) {
+ BT_ERR("Failed to send proxy cfg message (err %d)", err);
+ }
+}
+
+static void
+proxy_filter_recv(uint16_t conn_handle,
+ struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
+{
+ struct bt_mesh_proxy_client *client;
+ uint8_t opcode;
+
+ client = find_client(conn_handle);
+
+ opcode = net_buf_simple_pull_u8(buf);
+ switch (opcode) {
+ case CFG_FILTER_SET:
+ filter_set(client, buf);
+ send_filter_status(client, rx, buf);
+ break;
+ case CFG_FILTER_ADD:
+ while (buf->om_len >= 2) {
+ uint16_t addr;
+
+ addr = net_buf_simple_pull_be16(buf);
+ filter_add(client, addr);
+ }
+ send_filter_status(client, rx, buf);
+ break;
+ case CFG_FILTER_REMOVE:
+ while (buf->om_len >= 2) {
+ uint16_t addr;
+
+ addr = net_buf_simple_pull_be16(buf);
+ filter_remove(client, addr);
+ }
+ send_filter_status(client, rx, buf);
+ break;
+ default:
+ BT_WARN("Unhandled configuration OpCode 0x%02x", opcode);
+ break;
+ }
+}
+
+static void
+proxy_cfg(struct bt_mesh_proxy_role *role)
+{
+ struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN);
+ struct bt_mesh_net_rx rx;
+ int err;
+
+ err = bt_mesh_net_decode(role->buf, BT_MESH_NET_IF_PROXY_CFG,
+ &rx, buf);
+ if (err) {
+ BT_ERR("Failed to decode Proxy Configuration (err %d)", err);
+ return;
+ }
+
+ rx.local_match = 1U;
+
+ if (bt_mesh_rpl_check(&rx, NULL)) {
+ BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x",
+ rx.ctx.addr, rx.ctx.recv_dst, rx.seq);
+ return;
+ }
+
+ /* Remove network headers */
+ net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN);
+
+ BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
+
+ if (buf->om_len < 1) {
+ BT_WARN("Too short proxy configuration PDU");
+ return;
+ }
+
+ proxy_filter_recv(role->conn_handle, &rx, buf);
+}
+
+static void
+proxy_msg_recv(struct bt_mesh_proxy_role *role)
+{
+ switch (role->msg_type) {
+ case BT_MESH_PROXY_NET_PDU:
+ BT_DBG("Mesh Network PDU");
+ bt_mesh_net_recv(&(role->buf), 0, BT_MESH_NET_IF_PROXY);
+ break;
+ case BT_MESH_PROXY_BEACON:
+ BT_DBG("Mesh Beacon PDU");
+ bt_mesh_beacon_recv(role->buf);
+ break;
+ case BT_MESH_PROXY_CONFIG:
+ BT_DBG("Mesh Configuration PDU");
+ proxy_cfg(role);
+ break;
+ default:
+ BT_WARN("Unhandled Message Type 0x%02x", role->msg_type);
+ break;
+ }
+}
+
+static int
+beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subnet *sub)
+{
+ struct os_mbuf *buf = NET_BUF_SIMPLE(23);
+ int rc;
+
+ net_buf_simple_init(buf, 1);
+ bt_mesh_beacon_create(sub, buf);
+
+ rc = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_BEACON, buf);
+ os_mbuf_free_chain(buf);
+ return rc;
+}
+
+static int
+send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data)
+{
+ struct bt_mesh_proxy_client *client = cb_data;
+
+ return beacon_send(client, sub);
+}
+
+static void
+proxy_send_beacons(struct ble_npl_event *work)
+{
+ struct bt_mesh_proxy_client *client;
+
+ client = ble_npl_event_get_arg(work);
+
+ (void)bt_mesh_subnet_find(send_beacon_cb, client);
+}
+
+void
+bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub)
+{
+ int i;
+
+ if (!sub) {
+ /* NULL means we send on all subnets */
+ bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send);
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(clients); i++) {
+ if (clients[i].cli) {
+ beacon_send(&clients[i], sub);
+ }
+ }
+}
+
+static void
+node_id_start(struct bt_mesh_subnet *sub)
+{
+ sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING;
+ sub->node_id_start = k_uptime_get_32();
+}
+
+void
+bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub)
+{
+ node_id_start(sub);
+
+ /* Prioritize the recently enabled subnet */
+ beacon_sub = sub;
+}
+
+void
+bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub)
+{
+ sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
+ sub->node_id_start = 0U;
+}
+
+int
+bt_mesh_proxy_identity_enable(void)
+{
+ BT_DBG("");
+
+ if (!bt_mesh_is_provisioned()) {
+ return -EAGAIN;
+ }
+
+ if (bt_mesh_subnet_foreach(node_id_start)) {
+ bt_mesh_adv_update();
+ }
+
+ return 0;
}
#define ID_TYPE_NET 0x00
@@ -390,616 +407,639 @@
#define NODE_ID_TIMEOUT (CONFIG_BT_MESH_NODE_ID_TIMEOUT * MSEC_PER_SEC)
static uint8_t proxy_svc_data[NODE_ID_LEN] = {
- BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL),
+ BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL),
};
static const struct bt_data node_id_ad[] = {
- BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
- BT_DATA_BYTES(BT_DATA_UUID16_ALL,
- BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
- BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN),
+ BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
+ BT_DATA_BYTES(BT_DATA_UUID16_ALL,
+ BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
+ BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN),
};
static const struct bt_data net_id_ad[] = {
- BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
- BT_DATA_BYTES(BT_DATA_UUID16_ALL,
- BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
- BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN),
+ BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
+ BT_DATA_BYTES(BT_DATA_UUID16_ALL,
+ BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
+ BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN),
};
-static int node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
-{
- struct ble_gap_adv_params fast_adv_param = {
- ADV_OPT_PROXY
- ADV_FAST_INT
- };
+static int
+node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
+{
+ struct ble_gap_adv_params fast_adv_param = {
+ ADV_OPT_PROXY
+ ADV_FAST_INT
+ };
#if ADV_OPT_USE_NAME
- const char *name = CONFIG_BT_DEVICE_NAME;
- size_t name_len = strlen(name);
- struct bt_data sd = {
- .type = BT_DATA_NAME_COMPLETE,
- .data_len = name_len,
- .data = (void *)name
- };
+ const char *name = CONFIG_BT_DEVICE_NAME;
+ size_t name_len = strlen(name);
+ struct bt_data sd = {
+ .type = BT_DATA_NAME_COMPLETE,
+ .data_len = name_len,
+ .data = (void *)name
+ };
#else
- struct bt_data *sd = NULL;
+ struct bt_data *sd = NULL;
#endif
- uint8_t tmp[16];
- int err;
-
- BT_DBG("");
-
- proxy_svc_data[2] = ID_TYPE_NODE;
-
- err = bt_rand(proxy_svc_data + 11, 8);
- if (err) {
- return err;
- }
-
- (void)memset(tmp, 0, 6);
- memcpy(tmp + 6, proxy_svc_data + 11, 8);
- sys_put_be16(bt_mesh_primary_addr(), tmp + 14);
-
- err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp,
- tmp);
- if (err) {
- return err;
- }
-
- memcpy(proxy_svc_data + 3, tmp + 8, 8);
-
- err = bt_mesh_adv_start(&fast_adv_param, duration, node_id_ad,
- ARRAY_SIZE(node_id_ad), sd, 0);
- if (err) {
- BT_WARN("Failed to advertise using Node ID (err %d)", err);
- return err;
- }
-
- return 0;
-}
-
-static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
-{
- struct ble_gap_adv_params slow_adv_param = {
- ADV_OPT_PROXY
- ADV_SLOW_INT
- };
+ uint8_t tmp[16];
+ int err;
+
+ BT_DBG("");
+
+ proxy_svc_data[2] = ID_TYPE_NODE;
+
+ err = bt_rand(proxy_svc_data + 11, 8);
+ if (err) {
+ return err;
+ }
+
+ (void)memset(tmp, 0, 6);
+ memcpy(tmp + 6, proxy_svc_data + 11, 8);
+ sys_put_be16(bt_mesh_primary_addr(), tmp + 14);
+
+ err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp,
+ tmp);
+ if (err) {
+ return err;
+ }
+
+ memcpy(proxy_svc_data + 3, tmp + 8, 8);
+
+ err = bt_mesh_adv_start(&fast_adv_param, duration, node_id_ad,
+ ARRAY_SIZE(node_id_ad), sd, 0);
+ if (err) {
+ BT_WARN("Failed to advertise using Node ID (err %d)", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
+{
+ struct ble_gap_adv_params slow_adv_param = {
+ ADV_OPT_PROXY
+ ADV_SLOW_INT
+ };
#if ADV_OPT_USE_NAME
- const char *name = CONFIG_BT_DEVICE_NAME;
- size_t name_len = strlen(name);
- struct bt_data sd = {
- .type = BT_DATA_NAME_COMPLETE,
- .data_len = name_len,
- .data = (void *)name
- };
+ const char *name = CONFIG_BT_DEVICE_NAME;
+ size_t name_len = strlen(name);
+ struct bt_data sd = {
+ .type = BT_DATA_NAME_COMPLETE,
+ .data_len = name_len,
+ .data = (void *)name
+ };
#else
- struct bt_data *sd = NULL;
+ struct bt_data *sd = NULL;
#endif
- int err;
-
- BT_DBG("");
-
- proxy_svc_data[2] = ID_TYPE_NET;
-
- BT_DBG("Advertising with NetId %s",
- bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));
-
- memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8);
-
- err = bt_mesh_adv_start(&slow_adv_param, duration, net_id_ad,
- ARRAY_SIZE(net_id_ad), sd, 0);
- if (err) {
- BT_WARN("Failed to advertise using Network ID (err %d)", err);
- return err;
- }
-
- return 0;
-}
-
-static bool advertise_subnet(struct bt_mesh_subnet *sub)
-{
- if (sub->net_idx == BT_MESH_KEY_UNUSED) {
- return false;
- }
-
- return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING ||
- bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
-}
-
-static struct bt_mesh_subnet *next_sub(void)
-{
- struct bt_mesh_subnet *sub = NULL;
-
- if (!beacon_sub) {
- beacon_sub = bt_mesh_subnet_next(NULL);
- if (!beacon_sub) {
- /* No valid subnets */
- return NULL;
- }
- }
-
- sub = beacon_sub;
- do {
- if (advertise_subnet(sub)) {
- beacon_sub = sub;
- return sub;
- }
-
- sub = bt_mesh_subnet_next(sub);
- } while (sub != beacon_sub);
-
- /* No subnets to advertise on */
- return NULL;
-}
-
-static int sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data)
-{
- int *count = cb_data;
-
- if (advertise_subnet(sub)) {
- (*count)++;
- }
-
- return 0;
-}
-
-static int sub_count(void)
-{
- int count = 0;
-
- (void)bt_mesh_subnet_find(sub_count_cb, &count);
-
- return count;
-}
-
-static int gatt_proxy_advertise(struct bt_mesh_subnet *sub)
-{
- int32_t remaining = K_FOREVER;
- int subnet_count;
- int err = -EBUSY;
-
- BT_DBG("");
-
- if (conn_count == CONFIG_BT_MAX_CONN) {
- BT_DBG("Connectable advertising deferred (max connections %d)", conn_count);
- return -ENOMEM;
- }
-
- sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub);
- if (!sub) {
- BT_WARN("No subnets to advertise on");
- return -ENOENT;
- }
-
- subnet_count = sub_count();
- BT_DBG("sub_count %u", subnet_count);
- if (subnet_count > 1) {
- int32_t max_timeout;
-
- /* We use NODE_ID_TIMEOUT as a starting point since it may
- * be less than 60 seconds. Divide this period into at least
- * 6 slices, but make sure that a slice is at least one
- * second long (to avoid excessive rotation).
- */
- max_timeout = NODE_ID_TIMEOUT / max(subnet_count, 6);
- max_timeout = max(max_timeout, K_SECONDS(1));
-
- if (remaining > max_timeout || remaining < 0) {
- remaining = max_timeout;
- }
- }
-
- if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
- uint32_t active = k_uptime_get_32() - sub->node_id_start;
-
- if (active < NODE_ID_TIMEOUT) {
- remaining = NODE_ID_TIMEOUT - active;
- BT_DBG("Node ID active for %u ms, %d ms remaining",
- active, remaining);
- err = node_id_adv(sub, remaining);
- } else {
- bt_mesh_proxy_identity_stop(sub);
- BT_DBG("Node ID stopped");
- }
- }
-
- if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
- err = net_id_adv(sub, remaining);
- }
-
- BT_DBG("Advertising %d ms for net_idx 0x%04x",
- (int) remaining, sub->net_idx);
-
- beacon_sub = bt_mesh_subnet_next(beacon_sub);
-
- return err;
-}
-
-static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
-{
- if (evt == BT_MESH_KEY_DELETED) {
- if (sub == beacon_sub) {
- beacon_sub = NULL;
- }
- } else {
- bt_mesh_proxy_beacon_send(sub);
- }
-}
-
-static void proxy_ccc_write(uint16_t conn_handle)
-{
- struct bt_mesh_proxy_client *client;
-
- BT_DBG("conn_handle %d", conn_handle);
-
- client = find_client(conn_handle);
-
- if (client->filter_type == NONE) {
- client->filter_type = ACCEPT;
- k_work_add_arg(&client->send_beacons, client);
- k_work_submit(&client->send_beacons);
- }
-}
-
-int bt_mesh_proxy_gatt_enable(void)
-{
- uint16_t handle;
- int rc;
- int i;
-
- BT_DBG("");
-
- if (!bt_mesh_is_provisioned()) {
- return -ENOTSUP;
- }
-
- if (service_registered) {
- return -EBUSY;
- }
-
- rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
- assert(rc == 0);
- ble_gatts_svc_set_visibility(handle, 1);
- /* FIXME: figure out end handle */
- ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
-
- service_registered = true;
-
- for (i = 0; i < ARRAY_SIZE(clients); i++) {
- if (clients[i].cli) {
- clients[i].filter_type = ACCEPT;
- }
- }
- return 0;
-}
-
-void bt_mesh_proxy_gatt_disconnect(void)
-{
- int rc;
- int i;
-
- BT_DBG("");
-
- for (i = 0; i < ARRAY_SIZE(clients); i++) {
- struct bt_mesh_proxy_client *client = &clients[i];
-
- if ((client->cli) &&
- (client->filter_type == ACCEPT ||
- client->filter_type == REJECT)) {
- client->filter_type = NONE;
- rc = ble_gap_terminate(client->cli->conn_handle,
- BLE_ERR_REM_USER_CONN_TERM);
- assert(rc == 0);
- }
- }
-}
-
-int bt_mesh_proxy_gatt_disable(void)
-{
- uint16_t handle;
- int rc;
- BT_DBG("");
-
- if (!service_registered) {
- return -EALREADY;
- }
-
- bt_mesh_proxy_gatt_disconnect();
-
- rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
- assert(rc == 0);
- ble_gatts_svc_set_visibility(handle, 0);
- /* FIXME: figure out end handle */
- ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
- service_registered = false;
-
- return 0;
-}
-
-void bt_mesh_proxy_addr_add(struct os_mbuf **buf, uint16_t addr)
-{
- struct bt_mesh_proxy_client *client;
- struct bt_mesh_proxy_role *cli =
- CONTAINER_OF(buf, struct bt_mesh_proxy_role, buf);
-
- client = find_client(cli->conn_handle);
-
- BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
-
- if (client->filter_type == ACCEPT) {
- filter_add(client, addr);
- } else if (client->filter_type == REJECT) {
- filter_remove(client, addr);
- }
-}
-
-static bool client_filter_match(struct bt_mesh_proxy_client *client,
- uint16_t addr)
-{
- int i;
-
- BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
-
- if (client->filter_type == REJECT) {
- for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
- if (client->filter[i] == addr) {
- return false;
- }
- }
-
- return true;
- }
-
- if (addr == BT_MESH_ADDR_ALL_NODES) {
- return true;
- }
-
- if (client->filter_type == ACCEPT) {
- for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
- if (client->filter[i] == addr) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst)
-{
- const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
- void *cb_data = BT_MESH_ADV(buf)->cb_data;
- bool relayed = false;
- int i, err;
-
- BT_DBG("%u bytes to dst 0x%04x", buf->om_len, dst);
-
- for (i = 0; i < ARRAY_SIZE(clients); i++) {
- struct bt_mesh_proxy_client *client = &clients[i];
- struct os_mbuf *msg;
-
- if (!client->cli) {
- continue;
- }
-
- if (!client_filter_match(client, dst)) {
- continue;
- }
-
- /* Proxy PDU sending modifies the original buffer,
- * so we need to make a copy.
- */
- msg = NET_BUF_SIMPLE(32);
- net_buf_simple_init(msg, 1);
- net_buf_simple_add_mem(msg, buf->om_data, buf->om_len);
-
- err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_NET_PDU,
- msg);
-
- adv_send_start(0, err, cb, cb_data);
- if (err) {
- BT_ERR("Failed to send proxy message (err %d)", err);
-
- /* If segment_and_send() fails the buf_send_end() callback will
- * not be called, so we need to clear the user data (net_buf,
- * which is just opaque data to segment_and send) reference given
- * to segment_and_send() here.
- */
- net_buf_unref(buf);
- continue;
- }
- os_mbuf_free_chain(msg);
- relayed = true;
- }
-
- return relayed;
-}
-
-static void gatt_connected(uint16_t conn_handle)
-{
- struct bt_mesh_proxy_client *client;
- struct ble_gap_conn_desc info;
- struct ble_hs_conn *conn;
-
- conn = ble_hs_conn_find(conn_handle);
- bt_conn_get_info(conn, &info);
- if (info.role != BLE_GAP_ROLE_SLAVE ||
- !service_registered) {
- return;
- }
- BT_DBG("conn %d", conn_handle);
-
- conn_count++;
-
- client = get_client(conn_handle);
- assert(client);
-
- client->filter_type = NONE;
- (void)memset(client->filter, 0, sizeof(client->filter));
-
- client->cli = bt_mesh_proxy_role_setup(conn_handle, proxy_send,
- proxy_msg_recv);
-
- /* Try to re-enable advertising in case it's possible */
- if (conn_count < CONFIG_BT_MAX_CONN) {
- bt_mesh_adv_update();
- }
-}
-
-static void gatt_disconnected(struct ble_gap_conn_desc conn, uint8_t reason)
-{
- struct bt_mesh_proxy_client *client;
-
- if (conn.role != BLE_GAP_ROLE_SLAVE) {
- return;
- }
-
- if (!service_registered && bt_mesh_is_provisioned()) {
- (void)bt_mesh_proxy_gatt_enable();
- return;
- }
-
- conn_count--;
- client = find_client(conn.conn_handle);
- if (client->cli) {
- bt_mesh_proxy_role_cleanup(client->cli);
- client->cli = NULL;
- }
-
- client->conn_handle = 0xffff;
-}
-
-void notify_complete(void)
-{
- sys_snode_t *n;
-
- if (atomic_dec(&pending_notifications) > 1) {
- return;
- }
-
- BT_DBG("");
-
- while ((n = sys_slist_get(&idle_waiters))) {
- CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb();
- }
-}
-
-static int proxy_send(uint16_t conn_handle,
- const void *data, uint16_t len)
-{
- struct os_mbuf *om;
- int err = 0;
-
- BT_DBG("%u bytes: %s", len, bt_hex(data, len));
-
- om = ble_hs_mbuf_from_flat(data, len);
- assert(om);
- err = ble_gatts_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om);
- notify_complete();
-
- if (!err) {
- atomic_inc(&pending_notifications);
- }
-
- return err;
-}
-
-int bt_mesh_proxy_adv_start(void)
-{
- BT_DBG("");
-
- if (!service_registered || !bt_mesh_is_provisioned()) {
- return -ENOTSUP;
- }
-
- return gatt_proxy_advertise(next_sub());
-}
-
-
-static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg)
+ int err;
+
+ BT_DBG("");
+
+ proxy_svc_data[2] = ID_TYPE_NET;
+
+ BT_DBG("Advertising with NetId %s",
+ bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));
+
+ memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8);
+
+ err = bt_mesh_adv_start(&slow_adv_param, duration, net_id_ad,
+ ARRAY_SIZE(net_id_ad), sd, 0);
+ if (err) {
+ BT_WARN("Failed to advertise using Network ID (err %d)", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static bool
+advertise_subnet(struct bt_mesh_subnet *sub)
+{
+ if (sub->net_idx == BT_MESH_KEY_UNUSED) {
+ return false;
+ }
+
+ return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING ||
+ bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
+}
+
+static struct bt_mesh_subnet *
+next_sub(void)
+{
+ struct bt_mesh_subnet *sub = NULL;
+
+ if (!beacon_sub) {
+ beacon_sub = bt_mesh_subnet_next(NULL);
+ if (!beacon_sub) {
+ /* No valid subnets */
+ return NULL;
+ }
+ }
+
+ sub = beacon_sub;
+ do {
+ if (advertise_subnet(sub)) {
+ beacon_sub = sub;
+ return sub;
+ }
+
+ sub = bt_mesh_subnet_next(sub);
+ } while (sub != beacon_sub);
+
+ /* No subnets to advertise on */
+ return NULL;
+}
+
+static int
+sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data)
+{
+ int *count = cb_data;
+
+ if (advertise_subnet(sub)) {
+ (*count)++;
+ }
+
+ return 0;
+}
+
+static int
+sub_count(void)
+{
+ int count = 0;
+
+ (void)bt_mesh_subnet_find(sub_count_cb, &count);
+
+ return count;
+}
+
+static int
+gatt_proxy_advertise(struct bt_mesh_subnet *sub)
+{
+ int32_t remaining = K_FOREVER;
+ int subnet_count;
+ int err = -EBUSY;
+
+ BT_DBG("");
+
+ if (conn_count == CONFIG_BT_MAX_CONN) {
+ BT_DBG("Connectable advertising deferred (max connections %d)", conn_count);
+ return -ENOMEM;
+ }
+
+ sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub);
+ if (!sub) {
+ BT_WARN("No subnets to advertise on");
+ return -ENOENT;
+ }
+
+ subnet_count = sub_count();
+ BT_DBG("sub_count %u", subnet_count);
+ if (subnet_count > 1) {
+ int32_t max_timeout;
+
+ /* We use NODE_ID_TIMEOUT as a starting point since it may
+ * be less than 60 seconds. Divide this period into at least
+ * 6 slices, but make sure that a slice is at least one
+ * second long (to avoid excessive rotation).
+ */
+ max_timeout = NODE_ID_TIMEOUT / max(subnet_count, 6);
+ max_timeout = max(max_timeout, K_SECONDS(1));
+
+ if (remaining > max_timeout || remaining < 0) {
+ remaining = max_timeout;
+ }
+ }
+
+ if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
+ uint32_t active = k_uptime_get_32() - sub->node_id_start;
+
+ if (active < NODE_ID_TIMEOUT) {
+ remaining = NODE_ID_TIMEOUT - active;
+ BT_DBG("Node ID active for %u ms, %d ms remaining",
+ active, remaining);
+ err = node_id_adv(sub, remaining);
+ } else {
+ bt_mesh_proxy_identity_stop(sub);
+ BT_DBG("Node ID stopped");
+ }
+ }
+
+ if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
+ err = net_id_adv(sub, remaining);
+ }
+
+ BT_DBG("Advertising %d ms for net_idx 0x%04x",
+ (int) remaining, sub->net_idx);
+
+ beacon_sub = bt_mesh_subnet_next(beacon_sub);
+
+ return err;
+}
+
+static void
+subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
+{
+ if (evt == BT_MESH_KEY_DELETED) {
+ if (sub == beacon_sub) {
+ beacon_sub = NULL;
+ }
+ } else {
+ bt_mesh_proxy_beacon_send(sub);
+ }
+}
+
+static void
+proxy_ccc_write(uint16_t conn_handle)
+{
+ struct bt_mesh_proxy_client *client;
+
+ BT_DBG("conn_handle %d", conn_handle);
+
+ client = find_client(conn_handle);
+
+ if (client->filter_type == NONE) {
+ client->filter_type = ACCEPT;
+ k_work_add_arg(&client->send_beacons, client);
+ k_work_submit(&client->send_beacons);
+ }
+}
+
+int
+bt_mesh_proxy_gatt_enable(void)
+{
+ uint16_t handle;
+ int rc;
+ int i;
+
+ BT_DBG("");
+
+ if (!bt_mesh_is_provisioned()) {
+ return -ENOTSUP;
+ }
+
+ if (service_registered) {
+ return -EBUSY;
+ }
+
+ rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
+ assert(rc == 0);
+ ble_gatts_svc_set_visibility(handle, 1);
+ /* FIXME: figure out end handle */
+ ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
+
+ service_registered = true;
+
+ for (i = 0; i < ARRAY_SIZE(clients); i++) {
+ if (clients[i].cli) {
+ clients[i].filter_type = ACCEPT;
+ }
+ }
+ return 0;
+}
+
+void
+bt_mesh_proxy_gatt_disconnect(void)
+{
+ int rc;
+ int i;
+
+ BT_DBG("");
+
+ for (i = 0; i < ARRAY_SIZE(clients); i++) {
+ struct bt_mesh_proxy_client *client = &clients[i];
+
+ if ((client->cli) &&
+ (client->filter_type == ACCEPT ||
+ client->filter_type == REJECT)) {
+ client->filter_type = NONE;
+ rc = ble_gap_terminate(client->cli->conn_handle,
+ BLE_ERR_REM_USER_CONN_TERM);
+ assert(rc == 0);
+ }
+ }
+}
+
+int
+bt_mesh_proxy_gatt_disable(void)
+{
+ uint16_t handle;
+ int rc;
+ BT_DBG("");
+
+ if (!service_registered) {
+ return -EALREADY;
+ }
+
+ bt_mesh_proxy_gatt_disconnect();
+
+ rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle);
+ assert(rc == 0);
+ ble_gatts_svc_set_visibility(handle, 0);
+ /* FIXME: figure out end handle */
+ ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff);
+ service_registered = false;
+
+ return 0;
+}
+
+void
+bt_mesh_proxy_addr_add(struct os_mbuf **buf, uint16_t addr)
+{
+ struct bt_mesh_proxy_client *client;
+ struct bt_mesh_proxy_role *cli =
+ CONTAINER_OF(buf, struct bt_mesh_proxy_role, buf);
+
+ client = find_client(cli->conn_handle);
+
+ BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
+
+ if (client->filter_type == ACCEPT) {
+ filter_add(client, addr);
+ } else if (client->filter_type == REJECT) {
+ filter_remove(client, addr);
+ }
+}
+
+static bool
+client_filter_match(struct bt_mesh_proxy_client *client,
+ uint16_t addr)
+{
+ int i;
+
+ BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
+
+ if (client->filter_type == REJECT) {
+ for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+ if (client->filter[i] == addr) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ if (addr == BT_MESH_ADDR_ALL_NODES) {
+ return true;
+ }
+
+ if (client->filter_type == ACCEPT) {
+ for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
+ if (client->filter[i] == addr) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst)
+{
+ const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
+ void *cb_data = BT_MESH_ADV(buf)->cb_data;
+ bool relayed = false;
+ int i, err;
+
+ BT_DBG("%u bytes to dst 0x%04x", buf->om_len, dst);
+
+ for (i = 0; i < ARRAY_SIZE(clients); i++) {
+ struct bt_mesh_proxy_client *client = &clients[i];
+ struct os_mbuf *msg;
+
+ if (!client->cli) {
+ continue;
+ }
+
+ if (!client_filter_match(client, dst)) {
+ continue;
+ }
+
+ /* Proxy PDU sending modifies the original buffer,
+ * so we need to make a copy.
+ */
+ msg = NET_BUF_SIMPLE(32);
+ net_buf_simple_init(msg, 1);
+ net_buf_simple_add_mem(msg, buf->om_data, buf->om_len);
+
+ err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_NET_PDU,
+ msg);
+
+ adv_send_start(0, err, cb, cb_data);
+ if (err) {
+ BT_ERR("Failed to send proxy message (err %d)", err);
+
+ /* If segment_and_send() fails the buf_send_end() callback will
+ * not be called, so we need to clear the user data (net_buf,
+ * which is just opaque data to segment_and send) reference given
+ * to segment_and_send() here.
+ */
+ net_buf_unref(buf);
+ continue;
+ }
+ os_mbuf_free_chain(msg);
+ relayed = true;
+ }
+
+ return relayed;
+}
+
+static void
+gatt_connected(uint16_t conn_handle)
+{
+ struct bt_mesh_proxy_client *client;
+ struct ble_gap_conn_desc info;
+ struct ble_hs_conn *conn;
+
+ conn = ble_hs_conn_find(conn_handle);
+ bt_conn_get_info(conn, &info);
+ if (info.role != BLE_GAP_ROLE_SLAVE ||
+ !service_registered) {
+ return;
+ }
+ BT_DBG("conn %d", conn_handle);
+
+ conn_count++;
+
+ client = get_client(conn_handle);
+ assert(client);
+
+ client->filter_type = NONE;
+ (void)memset(client->filter, 0, sizeof(client->filter));
+
+ client->cli = bt_mesh_proxy_role_setup(conn_handle, proxy_send,
+ proxy_msg_recv);
+
+ /* Try to re-enable advertising in case it's possible */
+ if (conn_count < CONFIG_BT_MAX_CONN) {
+ bt_mesh_adv_update();
+ }
+}
+
+static void
+gatt_disconnected(struct ble_gap_conn_desc conn, uint8_t reason)
+{
+ struct bt_mesh_proxy_client *client;
+
+ if (conn.role != BLE_GAP_ROLE_SLAVE) {
+ return;
+ }
+
+ if (!service_registered && bt_mesh_is_provisioned()) {
+ (void)bt_mesh_proxy_gatt_enable();
+ return;
+ }
+
+ conn_count--;
+ client = find_client(conn.conn_handle);
+ if (client->cli) {
+ bt_mesh_proxy_role_cleanup(client->cli);
+ client->cli = NULL;
+ }
+
+ client->conn_handle = 0xffff;
+}
+
+void
+notify_complete(void)
+{
+ sys_snode_t *n;
+
+ if (atomic_dec(&pending_notifications) > 1) {
+ return;
+ }
+
+ BT_DBG("");
+
+ while ((n = sys_slist_get(&idle_waiters))) {
+ CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb();
+ }
+}
+
+static int
+proxy_send(uint16_t conn_handle,
+ const void *data, uint16_t len)
+{
+ struct os_mbuf *om;
+ int err = 0;
+
+ BT_DBG("%u bytes: %s", len, bt_hex(data, len));
+
+ om = ble_hs_mbuf_from_flat(data, len);
+ assert(om);
+ err = ble_gatts_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om);
+ notify_complete();
+
+ if (!err) {
+ atomic_inc(&pending_notifications);
+ }
+
+ return err;
+}
+
+int
+bt_mesh_proxy_adv_start(void)
+{
+ BT_DBG("");
+
+ if (!service_registered || !bt_mesh_is_provisioned()) {
+ return -ENOTSUP;
+ }
+
+ return gatt_proxy_advertise(next_sub());
+}
+
+
+static void
+ble_mesh_handle_connect(struct ble_gap_event *event, void *arg)
{
#if MYNEWT_VAL(BLE_EXT_ADV)
- /* When EXT ADV is enabled then mesh proxy is connected
- * when proxy advertising instance is completed.
- * Therefore no need to handle BLE_GAP_EVENT_CONNECT
- */
- if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) {
- /* Reason 0 means advertising has been completed because
- * connection has been established
- */
- if (event->adv_complete.reason != 0) {
- return;
- }
-
- if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) {
- return;
- }
-
- gatt_connected(event->adv_complete.conn_handle);
+ /* When EXT ADV is enabled then mesh proxy is connected
+ * when proxy advertising instance is completed.
+ * Therefore no need to handle BLE_GAP_EVENT_CONNECT
+ */
+ if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) {
+ /* Reason 0 means advertising has been completed because
+ * connection has been established
+ */
+ if (event->adv_complete.reason != 0) {
+ return;
+ }
+
+ if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) {
+ return;
+ }
+
+ gatt_connected(event->adv_complete.conn_handle);
#if MYNEWT_VAL(BLE_MESH_PB_GATT)
- gatt_connected_pb_gatt(event->adv_complete.conn_handle,
- event->adv_complete.reason);
+ gatt_connected_pb_gatt(event->adv_complete.conn_handle,
+ event->adv_complete.reason);
#endif
- }
+ }
#else
- if (event->type == BLE_GAP_EVENT_CONNECT) {
- gatt_connected(event->connect.conn_handle);
+ if (event->type == BLE_GAP_EVENT_CONNECT) {
+ gatt_connected(event->connect.conn_handle);
#if MYNEWT_VAL(BLE_MESH_PB_GATT)
- gatt_connected_pb_gatt(event->connect.conn_handle, event->connect.status);
+ gatt_connected_pb_gatt(event->connect.conn_handle, event->connect.status);
#endif
- }
+ }
#endif
}
-int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg)
-{
- if ((event->type == BLE_GAP_EVENT_CONNECT) ||
- (event->type == BLE_GAP_EVENT_ADV_COMPLETE)) {
- ble_mesh_handle_connect(event, arg);
- } else if (event->type == BLE_GAP_EVENT_DISCONNECT) {
- gatt_disconnected(event->disconnect.conn,
- event->disconnect.reason);
+int
+ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg)
+{
+ if ((event->type == BLE_GAP_EVENT_CONNECT) ||
+ (event->type == BLE_GAP_EVENT_ADV_COMPLETE)) {
+ ble_mesh_handle_connect(event, arg);
+ } else if (event->type == BLE_GAP_EVENT_DISCONNECT) {
+ gatt_disconnected(event->disconnect.conn,
+ event->disconnect.reason);
#if MYNEWT_VAL(BLE_MESH_PB_GATT)
- gatt_disconnected_pb_gatt(event->disconnect.conn,
- event->disconnect.reason);
+ gatt_disconnected_pb_gatt(event->disconnect.conn,
+ event->disconnect.reason);
#endif
- } else if (event->type == BLE_GAP_EVENT_SUBSCRIBE) {
- if (event->subscribe.attr_handle == svc_handles.proxy_data_out_h) {
+ } else if (event->type == BLE_GAP_EVENT_SUBSCRIBE) {
+ if (event->subscribe.attr_handle == svc_handles.proxy_data_out_h) {
#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
- proxy_ccc_write(event->subscribe.conn_handle);
+ proxy_ccc_write(event->subscribe.conn_handle);
#endif
- } else if (event->subscribe.attr_handle ==
- svc_handles.prov_data_out_h) {
+ } else if (event->subscribe.attr_handle ==
+ svc_handles.prov_data_out_h) {
#if (MYNEWT_VAL(BLE_MESH_PB_GATT))
- prov_ccc_write(event->subscribe.conn_handle, event->type);
+ prov_ccc_write(event->subscribe.conn_handle, event->type);
#endif
- }
- }
-
- return 0;
-}
-
-int bt_mesh_proxy_init(void)
-{
- int i;
+ }
+ }
+
+ return 0;
+}
+
+int
+bt_mesh_proxy_init(void)
+{
+ int i;
#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
- if (!bt_mesh_subnet_cb_list[4]) {
- bt_mesh_subnet_cb_list[4] = subnet_evt;
- }
+ if (!bt_mesh_subnet_cb_list[4]) {
+ bt_mesh_subnet_cb_list[4] = subnet_evt;
+ }
#endif
- for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) {
+ for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) {
#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
- k_work_init(&clients[i].send_beacons, proxy_send_beacons);
+ k_work_init(&clients[i].send_beacons, proxy_send_beacons);
#endif
- clients[i].conn_handle = 0xffff;
- }
-
- resolve_svc_handles();
-
- ble_gatts_svc_set_visibility(svc_handles.proxy_h, 0);
- ble_gatts_svc_set_visibility(svc_handles.prov_h, 0);
-
- return 0;
-}
+ clients[i].conn_handle = 0xffff;
+ }
+
+ resolve_svc_handles();
+
+ ble_gatts_svc_set_visibility(svc_handles.proxy_h, 0);
+ ble_gatts_svc_set_visibility(svc_handles.prov_h, 0);
+
+ return 0;
+}