diff --git a/nimble/host/mesh/include/mesh/glue.h b/nimble/host/mesh/include/mesh/glue.h index 4cb61c5bc..b1050d8c6 100644 --- a/nimble/host/mesh/include/mesh/glue.h +++ b/nimble/host/mesh/include/mesh/glue.h @@ -97,6 +97,7 @@ #define BT_DATA_SOLICIT32 0x1f /* Solicit UUIDs, 32-bit */ #define BT_DATA_SVC_DATA32 0x20 /* Service data, 32-bit UUID */ #define BT_DATA_SVC_DATA128 0x21 /* Service data, 128-bit UUID */ +#define BT_DATA_URI 0x24 /* URI */ #define BT_DATA_MESH_PROV 0x29 /* Mesh Provisioning PDU */ #define BT_DATA_MESH_MESSAGE 0x2a /* Mesh Networking PDU */ #define BT_DATA_MESH_BEACON 0x2b /* Mesh Beacon */ @@ -286,6 +287,7 @@ void k_delayed_work_cancel(struct k_delayed_work *w); void k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms); int64_t k_uptime_get(void); u32_t k_uptime_get_32(void); +void k_sleep(int32_t duration); void k_work_submit(struct os_callout *w); void k_work_add_arg(struct os_callout *w, void *arg); void k_delayed_work_add_arg(struct k_delayed_work *w, void *arg); @@ -356,6 +358,7 @@ static inline unsigned int find_msb_set(u32_t op) #define CONFIG_BT_MESH_MODEL_KEY_COUNT MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT) #define CONFIG_BT_MESH_NODE_ID_TIMEOUT MYNEWT_VAL(BLE_MESH_NODE_ID_TIMEOUT) #define CONFIG_BT_MAX_CONN MYNEWT_VAL(BLE_MAX_CONNECTIONS) +#define CONFIG_BT_DEVICE_NAME "nimble-mesh" #define printk console_printf diff --git a/nimble/host/mesh/include/mesh/main.h b/nimble/host/mesh/include/mesh/main.h index bc3c86f8f..752878fa1 100644 --- a/nimble/host/mesh/include/mesh/main.h +++ b/nimble/host/mesh/include/mesh/main.h @@ -39,11 +39,37 @@ typedef enum { BT_MESH_PROV_GATT = BIT(1), } bt_mesh_prov_bearer_t; +typedef enum { + BT_MESH_PROV_OOB_OTHER = BIT(0), + BT_MESH_PROV_OOB_URI = BIT(1), + BT_MESH_PROV_OOB_2D_CODE = BIT(2), + BT_MESH_PROV_OOB_BAR_CODE = BIT(3), + BT_MESH_PROV_OOB_NFC = BIT(4), + BT_MESH_PROV_OOB_NUMBER = BIT(5), + BT_MESH_PROV_OOB_STRING = BIT(6), + /* 7 - 10 are reserved */ + BT_MESH_PROV_OOB_ON_BOX = BIT(11), + BT_MESH_PROV_OOB_IN_BOX = BIT(12), + BT_MESH_PROV_OOB_ON_PAPER = BIT(13), + BT_MESH_PROV_OOB_IN_MANUAL = BIT(14), + BT_MESH_PROV_OOB_ON_DEV = BIT(15), +} bt_mesh_prov_oob_info_t; + /** Provisioning properties & capabilities. */ struct bt_mesh_prov { /** The UUID that's used when advertising as unprovisioned */ const u8_t *uuid; + /** Optional URI. This will be advertised separately from the + * unprovisioned beacon, however the unprovisioned beacon will + * contain a hash of it so the two can be associated by the + * provisioner. + */ + const char *uri; + + /** Out of Band information field. */ + bt_mesh_prov_oob_info_t oob_info; + /** Static OOB value */ const u8_t *static_val; /** Static OOB value length */ diff --git a/nimble/host/mesh/src/adv.c b/nimble/host/mesh/src/adv.c index c8aced18b..3dce81c9e 100644 --- a/nimble/host/mesh/src/adv.c +++ b/nimble/host/mesh/src/adv.c @@ -1,6 +1,7 @@ /* Bluetooth Mesh */ /* + * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 @@ -23,20 +24,22 @@ #include "prov.h" #include "proxy.h" -/* Window and Interval are equal for continuous scanning */ -#define MESH_SCAN_INTERVAL 0x10 -#define MESH_SCAN_WINDOW 0x10 - /* Convert from ms to 0.625ms units */ -#define ADV_INT(_ms) ((_ms) * 8 / 5) +#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) + +/* Window and Interval are equal for continuous scanning */ +#define MESH_SCAN_INTERVAL_MS 10 +#define MESH_SCAN_WINDOW_MS 10 +#define MESH_SCAN_INTERVAL ADV_SCAN_UNIT(MESH_SCAN_INTERVAL_MS) +#define MESH_SCAN_WINDOW ADV_SCAN_UNIT(MESH_SCAN_WINDOW_MS) /* Pre-5.0 controllers enforce a minimum interval of 100ms * whereas 5.0+ controllers can go down to 20ms. */ -#define ADV_INT_DEFAULT K_MSEC(100) -#define ADV_INT_FAST K_MSEC(20) +#define ADV_INT_DEFAULT_MS 100 +#define ADV_INT_FAST_MS 20 -static s32_t adv_int_min = ADV_INT_DEFAULT; +static s32_t adv_int_min = ADV_INT_DEFAULT_MS; /* TinyCrypt PRNG consumes a lot of stack space, so we need to have * an increased call stack whenever it's used. @@ -55,9 +58,10 @@ struct os_mbuf_pool adv_os_mbuf_pool; static struct os_mempool adv_buf_mempool; static const u8_t adv_type[] = { - [BT_MESH_ADV_PROV] = BLE_HS_ADV_TYPE_MESH_PROV, - [BT_MESH_ADV_DATA] = BLE_HS_ADV_TYPE_MESH_MESSAGE, + [BT_MESH_ADV_PROV] = BLE_HS_ADV_TYPE_MESH_PROV, + [BT_MESH_ADV_DATA] = BLE_HS_ADV_TYPE_MESH_MESSAGE, [BT_MESH_ADV_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON, + [BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI, }; @@ -96,7 +100,7 @@ static inline void adv_send(struct os_mbuf *buf) int err; adv_int = max(adv_int_min, adv->adv_int); - duration = (adv->count + 1) * (adv_int + 10); + duration = MESH_SCAN_WINDOW_MS + (adv->count + 1) * (adv_int + 10); BT_DBG("buf %p, type %u len %u:", buf, adv->type, buf->om_len); @@ -107,7 +111,7 @@ static inline void adv_send(struct os_mbuf *buf) ad.data_len = buf->om_len; ad.data = buf->om_data; - param.itvl_min = ADV_INT(adv_int); + param.itvl_min = ADV_SCAN_UNIT(adv_int); param.itvl_max = param.itvl_min; param.conn_mode = BLE_GAP_CONN_MODE_NON; @@ -121,7 +125,7 @@ static inline void adv_send(struct os_mbuf *buf) BT_DBG("Advertising started. Sleeping %u ms", duration); - os_time_delay(OS_TICKS_PER_SEC * duration / 1000); + k_sleep(K_MSEC(duration)); err = bt_le_adv_stop(); adv_send_end(err, cb, cb_data); @@ -314,7 +318,7 @@ void bt_mesh_adv_init(void) /* For BT5 controllers we can have fast advertising interval */ if (ble_hs_hci_get_hci_version() >= BLE_HCI_VER_BCS_5_0) { - adv_int_min = ADV_INT_FAST; + adv_int_min = ADV_INT_FAST_MS; } } diff --git a/nimble/host/mesh/src/adv.h b/nimble/host/mesh/src/adv.h index 27930d59f..e40d6673b 100644 --- a/nimble/host/mesh/src/adv.h +++ b/nimble/host/mesh/src/adv.h @@ -28,6 +28,7 @@ enum bt_mesh_adv_type BT_MESH_ADV_PROV, BT_MESH_ADV_DATA, BT_MESH_ADV_BEACON, + BT_MESH_ADV_URI, }; typedef void (*bt_mesh_adv_func_t)(struct os_mbuf *buf, u16_t duration, diff --git a/nimble/host/mesh/src/beacon.c b/nimble/host/mesh/src/beacon.c index ace6428fa..34ea6b82a 100644 --- a/nimble/host/mesh/src/beacon.c +++ b/nimble/host/mesh/src/beacon.c @@ -150,7 +150,10 @@ static int secure_beacon_send(void) static int unprovisioned_beacon_send(void) { #if (MYNEWT_VAL(BLE_MESH_PB_ADV)) + const struct bt_mesh_prov *prov; + u8_t uri_hash[16] = { 0 }; struct os_mbuf *buf; + u16_t oob_info; BT_DBG("unprovisioned_beacon_send"); @@ -161,15 +164,44 @@ static int unprovisioned_beacon_send(void) return -ENOBUFS; } - net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED); - net_buf_add_mem(buf, bt_mesh_prov_get_uuid(), 16); + prov = bt_mesh_prov_get(); - /* OOB Info (2 bytes) + URI Hash (4 bytes) */ - net_buf_add_zeros(buf, 2 + 4); + net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED); + net_buf_add_mem(buf, prov->uuid, 16); + + if (prov->uri && bt_mesh_s1(prov->uri, uri_hash) == 0) { + oob_info = prov->oob_info | BT_MESH_PROV_OOB_URI; + } else { + oob_info = prov->oob_info; + } + + net_buf_add_be16(buf, oob_info); + net_buf_add_mem(buf, uri_hash, 4); bt_mesh_adv_send(buf, NULL, NULL); net_buf_unref(buf); + if (prov->uri) { + size_t len; + + buf = bt_mesh_adv_create(BT_MESH_ADV_URI, UNPROV_XMIT_COUNT, + UNPROV_XMIT_INT, K_NO_WAIT); + if (!buf) { + BT_ERR("Unable to allocate URI buffer"); + return -ENOBUFS; + } + + len = strlen(prov->uri); + if (net_buf_tailroom(buf) < len) { + BT_WARN("Too long URI to fit advertising data"); + } else { + net_buf_add_mem(buf, prov->uri, len); + bt_mesh_adv_send(buf, NULL, NULL); + } + + net_buf_unref(buf); + } + #endif /* MYNEWT_VAL(BLE_MESH_PB_ADV) */ return 0; } diff --git a/nimble/host/mesh/src/cfg_cli.c b/nimble/host/mesh/src/cfg_cli.c index 05c302bd1..4d1af2e13 100644 --- a/nimble/host/mesh/src/cfg_cli.c +++ b/nimble/host/mesh/src/cfg_cli.c @@ -1132,8 +1132,7 @@ int bt_mesh_cfg_mod_pub_get_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr, return -EINVAL; } - return mod_pub_get(net_idx, addr, elem_addr, mod_id, CID_NVAL, - pub, status); + return mod_pub_get(net_idx, addr, elem_addr, mod_id, cid, pub, status); } static int mod_pub_set(u16_t net_idx, u16_t addr, u16_t elem_addr, @@ -1205,8 +1204,7 @@ int bt_mesh_cfg_mod_pub_set_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr, return -EINVAL; } - return mod_pub_set(net_idx, addr, elem_addr, mod_id, CID_NVAL, - pub, status); + return mod_pub_set(net_idx, addr, elem_addr, mod_id, cid, pub, status); } int bt_mesh_cfg_hb_sub_set(u16_t net_idx, u16_t addr, diff --git a/nimble/host/mesh/src/friend.c b/nimble/host/mesh/src/friend.c index 9969737e9..42c9384b7 100644 --- a/nimble/host/mesh/src/friend.c +++ b/nimble/host/mesh/src/friend.c @@ -44,6 +44,12 @@ static struct os_mempool friend_buf_mempool; #define FRIEND_ADV(buf) CONTAINER_OF(BT_MESH_ADV(buf), \ struct friend_adv, adv) +/* PDUs from Friend to the LPN should only be transmitted once with the + * smallest possible interval (20ms). + */ +#define FRIEND_XMIT_COUNT 0 +#define FRIEND_XMIT_INT 20 + struct friend_pdu_info { u16_t src; u16_t dst; @@ -87,15 +93,13 @@ static void discard_buffer(void) static struct os_mbuf *friend_buf_alloc(u16_t src) { - u8_t xmit = bt_mesh_net_transmit_get(); struct os_mbuf *buf; do { buf = bt_mesh_adv_create_from_pool(&friend_os_mbuf_pool, adv_alloc, BT_MESH_ADV_DATA, - BT_MESH_TRANSMIT_COUNT(xmit), - BT_MESH_TRANSMIT_INT(xmit), - K_NO_WAIT); + FRIEND_XMIT_COUNT, + FRIEND_XMIT_INT, K_NO_WAIT); if (!buf) { discard_buffer(); } diff --git a/nimble/host/mesh/src/glue.c b/nimble/host/mesh/src/glue.c index 086edaf8c..b93d9dbb9 100644 --- a/nimble/host/mesh/src/glue.c +++ b/nimble/host/mesh/src/glue.c @@ -391,6 +391,11 @@ u32_t k_uptime_get_32(void) return k_uptime_get(); } +void k_sleep(int32_t duration) +{ + os_time_delay(OS_TICKS_PER_SEC * duration / 1000); +} + static uint8_t pub[64]; static uint8_t priv[32]; static bool has_pub = false; diff --git a/nimble/host/mesh/src/prov.c b/nimble/host/mesh/src/prov.c index 695c0fa34..07d3d022b 100644 --- a/nimble/host/mesh/src/prov.c +++ b/nimble/host/mesh/src/prov.c @@ -1179,7 +1179,14 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf) } if (atomic_test_bit(link.flags, LINK_ACTIVE)) { - BT_WARN("Ignoring bearer open: link already active"); + /* Send another link ack if the provisioner missed the last */ + if (link.id == rx->link_id && link.expect == PROV_INVITE) { + BT_DBG("Resending link ack"); + bearer_ctl_send(LINK_ACK, NULL, 0); + } else { + BT_WARN("Ignoring bearer open: link already active"); + } + return; } @@ -1470,6 +1477,7 @@ int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf) type = net_buf_simple_pull_u8(buf); if (type != PROV_FAILED && type != link.expect) { BT_WARN("Unexpected msg 0x%02x != 0x%02x", type, link.expect); + prov_send_fail_msg(PROV_ERR_UNEXP_PDU); return -EINVAL; } @@ -1540,9 +1548,9 @@ int bt_mesh_pb_gatt_close(uint16_t conn_handle) } #endif /* MYNEWT_VAL(BLE_MESH_PB_GATT) */ -const u8_t *bt_mesh_prov_get_uuid(void) +const struct bt_mesh_prov *bt_mesh_prov_get(void) { - return prov->uuid; + return prov; } bool bt_prov_active(void) diff --git a/nimble/host/mesh/src/prov.h b/nimble/host/mesh/src/prov.h index 3270b069d..3675b6cc7 100644 --- a/nimble/host/mesh/src/prov.h +++ b/nimble/host/mesh/src/prov.h @@ -21,7 +21,7 @@ int bt_mesh_pb_gatt_open(uint16_t conn_handle); int bt_mesh_pb_gatt_close(uint16_t conn_handle); int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf); -const u8_t *bt_mesh_prov_get_uuid(void); +const struct bt_mesh_prov *bt_mesh_prov_get(void); int bt_mesh_prov_init(const struct bt_mesh_prov *prov); diff --git a/nimble/host/mesh/src/proxy.c b/nimble/host/mesh/src/proxy.c index dae72e971..1fe531752 100644 --- a/nimble/host/mesh/src/proxy.c +++ b/nimble/host/mesh/src/proxy.c @@ -985,10 +985,8 @@ static const struct bt_data prov_ad[] = { BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), }; -static const struct bt_data prov_sd[] = { - BT_DATA(BT_DATA_NAME_COMPLETE, "mynewtproxy", - (sizeof("mynewtproxy") - 1)), -}; +static struct bt_data prov_sd[2]; +static size_t prov_sd_len; #endif /* PB_GATT */ #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) @@ -1201,7 +1199,7 @@ s32_t bt_mesh_proxy_adv_start(void) } if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad), - prov_sd, ARRAY_SIZE(prov_sd)) == 0) { + prov_sd, prov_sd_len) == 0) { proxy_adv_enabled = true; /* Advertise 60 seconds using fast interval */ @@ -1338,7 +1336,42 @@ int bt_mesh_proxy_init(void) } #if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - memcpy(prov_svc_data + 2, bt_mesh_prov_get_uuid(), 16); + const struct bt_mesh_prov *prov = bt_mesh_prov_get(); + size_t name_len = strlen(CONFIG_BT_DEVICE_NAME); + size_t sd_space = 31; + + memcpy(prov_svc_data + 2, prov->uuid, 16); + sys_put_be16(prov->oob_info, prov_svc_data + 18); + + if (prov->uri) { + size_t uri_len = strlen(prov->uri); + + if (uri_len > 29) { + /* There's no way to shorten an URI */ + BT_WARN("Too long URI to fit advertising packet"); + } else { + prov_sd[0].type = BT_DATA_URI; + prov_sd[0].data_len = uri_len; + prov_sd[0].data = (void *)prov->uri; + sd_space -= 2 + uri_len; + prov_sd_len++; + } + } + + if (sd_space > 2 && name_len > 0) { + sd_space -= 2; + + if (sd_space < name_len) { + prov_sd[prov_sd_len].type = BT_DATA_NAME_SHORTENED; + prov_sd[prov_sd_len].data_len = sd_space; + } else { + prov_sd[prov_sd_len].type = BT_DATA_NAME_COMPLETE; + prov_sd[prov_sd_len].data_len = name_len; + } + + prov_sd[prov_sd_len].data = (void *)CONFIG_BT_DEVICE_NAME; + prov_sd_len++; + } #endif resolve_svc_handles(); diff --git a/nimble/host/mesh/src/transport.c b/nimble/host/mesh/src/transport.c index 9902a6d7c..918af1fe7 100644 --- a/nimble/host/mesh/src/transport.c +++ b/nimble/host/mesh/src/transport.c @@ -46,6 +46,12 @@ /* Number of retransmit attempts (after the initial transmit) per segment */ #define SEG_RETRANSMIT_ATTEMPTS 4 +/* "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds.". + * We use 400 since 300 is a common send duration for standard HCI, and we + * need to have a timeout that's bigger than that. + */ +#define SEG_RETRANSMIT_TIMEOUT(tx) (K_MSEC(400) + 50 * (tx)->ttl) + /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT @@ -191,7 +197,7 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err) seg_tx_reset(tx); } -static void seg_send_start(u16_t duration, int err, void *user_data) +static void seg_first_send_start(u16_t duration, int err, void *user_data) { struct seg_tx *tx = user_data; @@ -200,27 +206,35 @@ static void seg_send_start(u16_t duration, int err, void *user_data) } } +static void seg_send_start(u16_t duration, int err, void *user_data) +{ + struct seg_tx *tx = user_data; + + /* If there's an error in transmitting the 'sent' callback will never + * be called. Make sure that we kick the retransmit timer also in this + * case since otherwise we risk the transmission of becoming stale. + */ + if (err) { + k_delayed_work_submit(&tx->retransmit, + SEG_RETRANSMIT_TIMEOUT(tx)); + } +} + static void seg_sent(int err, void *user_data) { struct seg_tx *tx = user_data; - s32_t timeout; - /* "This timer shall be set to a minimum of 200 + 50 * TTL - * milliseconds.". We use 400 since 300 is a common send - * duration for standard HCI, and we need to have a timeout - * that's bigger than that. - */ - timeout = K_MSEC(400) + 50 * tx->ttl; - - k_delayed_work_submit(&tx->retransmit, timeout); + k_delayed_work_submit(&tx->retransmit, + SEG_RETRANSMIT_TIMEOUT(tx)); } static const struct bt_mesh_send_cb first_sent_cb = { - .start = seg_send_start, + .start = seg_first_send_start, .end = seg_sent, }; static const struct bt_mesh_send_cb seg_sent_cb = { + .start = seg_send_start, .end = seg_sent, }; @@ -995,9 +1009,7 @@ static void seg_ack(struct os_event *work) if (k_uptime_get_32() - rx->last > K_SECONDS(60)) { BT_WARN("Incomplete timer expired"); - send_ack(rx->sub, rx->dst, rx->src, rx->ttl, - &rx->seq_auth, 0, rx->obo); - seg_rx_reset(rx, true); + seg_rx_reset(rx, false); if (IS_ENABLED(CONFIG_BT_TESTING)) { bt_test_mesh_trans_incomp_timer_exp();