diff --git a/.travis.yml b/.travis.yml index 285b81e5d0..185ca35507 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,10 @@ _addons: &addon_conf packages: - gcc-multilib - gcc-7-multilib + - g++-multilib go: - - "1.12" + - "1.16" git: depth: false diff --git a/NOTICE b/NOTICE index 84ecb14d9f..90952ecc53 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache Mynewt NimBLE -Copyright 2015-2020 The Apache Software Foundation +Copyright 2015-2021 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md index 37103be08e..96c636634c 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Features highlight: - Support for up to 32 simultaneous connections. - Legacy and SC (secure connections) SMP support (pairing and bonding). - Advertising Extensions. + - Periodic Advertising. - Coded (aka Long Range) and 2M PHYs. - Bluetooth Mesh. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 3bdd31ad05..99810a718d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,6 @@ # RELEASE NOTES -18 March 2020 - Apache NimBLE v1.3.0 +24 March 2021 - Apache NimBLE v1.4.0 For full release notes, please visit the [Apache Mynewt Wiki](https://cwiki.apache.org/confluence/display/MYNEWT/Release+Notes). @@ -10,23 +10,12 @@ replaces the proprietary SoftDevice on Nordic chipsets. New features in this version of NimBLE include: -* Support for Bluetooth Core Specification 5.1 -* New blestress test application -* Dialog DA1469x CMAC driver -* Support for LE Secure Connections out-of-band (OOB) association model -* Support for automated generation of syscfg for ports -* Qualification related bugfixes -* BLE Mesh improvements - fixes and resync with latest Zephyr code -* RIOT OS port fixes and improvements -* btshell sample application improvements -* improvements for bttester application -* Controller duplicates filtering improvements -* Multi PHY support improvements -* Memory and CPU usage optimizations -* Use of packed structs for HCI (code size reduction) -* Linux sample improvements -* PTS test instructions updates -* Clock managements improvements in controller +* Support for PHY on Dialog Configurable MAC (CMAC) +* Support for PHY on Nordic nRF5340 +* Support for Apache NuttX port of NimBLE +* Controller-to-host flow control support +* Support for USB transport +* Various bugfixes If working on next-generation RTOS and Bluetooth protocol stack sounds exciting to you, get in touch, by sending a mail to the Apache Mynewt diff --git a/apps/blecsc/pkg.yml b/apps/blecsc/pkg.yml index 828ff301ee..a2119c1b35 100644 --- a/apps/blecsc/pkg.yml +++ b/apps/blecsc/pkg.yml @@ -32,7 +32,6 @@ pkg.deps: - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt diff --git a/apps/blecsc/src/main.c b/apps/blecsc/src/main.c index 60f0b3d8f7..5cca6b77ec 100644 --- a/apps/blecsc/src/main.c +++ b/apps/blecsc/src/main.c @@ -58,7 +58,7 @@ static struct os_callout blecsc_measure_timer; /* Variable holds current CSC measurement state */ static struct ble_csc_measurement_state csc_measurement_state; -/* Variable holds simulted speed (kilometers per hour) */ +/* Variable holds simulated speed (kilometers per hour) */ static uint16_t csc_sim_speed_kph = CSC_SIM_SPEED_KPH_MIN; /* Variable holds simulated cadence (RPM) */ diff --git a/apps/blecsc/syscfg.yml b/apps/blecsc/syscfg.yml index ecf4b25f15..abf899691d 100644 --- a/apps/blecsc/syscfg.yml +++ b/apps/blecsc/syscfg.yml @@ -32,7 +32,7 @@ syscfg.vals: CONFIG_FCB: 1 # Set public device address. - BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11}) + BLE_LL_PUBLIC_DEV_ADDR: 0x1122aabb33cc # Set device appearance to Cycling Speed and Cadence Sensor BLE_SVC_GAP_APPEARANCE: BLE_SVC_GAP_APPEARANCE_CYC_SPEED_AND_CADENCE_SENSOR diff --git a/apps/blehcibridge/pkg.yml b/apps/blehcibridge/pkg.yml new file mode 100644 index 0000000000..9d170a89f3 --- /dev/null +++ b/apps/blehcibridge/pkg.yml @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +pkg.name: apps/blehcibridge +pkg.type: app +pkg.description: BLE controller application exposing HCI over external interface +pkg.author: "Jerzy Kasenberg " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/log/stub" + - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/sys/shell" + - nimble/transport + +pkg.req_apis: + - ble_transport + +pkg.deps.'CONSOLE_MODE=="full"': + - "@apache-mynewt-core/sys/console/full" +pkg.deps.'CONSOLE_MODE=="minimal": + - "@apache-mynewt-core/sys/console/minimal" +pkg.deps.'CONSOLE_MODE=="stub": + - "@apache-mynewt-core/sys/console/stub" diff --git a/apps/blehcibridge/src/main.c b/apps/blehcibridge/src/main.c new file mode 100644 index 0000000000..620cc37121 --- /dev/null +++ b/apps/blehcibridge/src/main.c @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +static int +forward_cmd_to_controller(uint8_t *cmdbuf, void *arg) +{ + (void)arg; + + return ble_hci_trans_hs_cmd_tx(cmdbuf); +} + +int +forward_acl_to_controller(struct os_mbuf *om, void *arg) +{ + (void)arg; + + return ble_hci_trans_hs_acl_tx(om); +} + +static int +forward_evt_to_host(uint8_t *hci_ev, void *arg) +{ + (void)arg; + + return ble_hci_trans_ll_evt_tx(hci_ev); +} + +int +forward_acl_to_host(struct os_mbuf *om, void *arg) +{ + (void)arg; + + return ble_hci_trans_ll_acl_tx(om); +} + +int +main(void) +{ + /* Initialize OS */ + sysinit(); + + ble_hci_trans_cfg_hs(forward_evt_to_host, NULL, forward_acl_to_host, NULL); + ble_hci_trans_cfg_ll(forward_cmd_to_controller, NULL, forward_acl_to_controller, NULL); + + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + return 0; +} diff --git a/apps/blehcibridge/syscfg.yml b/apps/blehcibridge/syscfg.yml new file mode 100644 index 0000000000..146ab52642 --- /dev/null +++ b/apps/blehcibridge/syscfg.yml @@ -0,0 +1,36 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + CONSOLE_MODE: + description: Which console to use + value: stub + choices: + - full + - minimal + - stub + +syscfg.vals: + # Default task settings + OS_MAIN_STACK_SIZE: 64 + # Use USB transport by default + BLE_HCI_TRANSPORT: usb + + SHELL_TASK: 1 + + BLE_HCI_BRIDGE: 1 diff --git a/apps/blehr/pkg.yml b/apps/blehr/pkg.yml index b91ba3775b..8212f8f6a2 100644 --- a/apps/blehr/pkg.yml +++ b/apps/blehr/pkg.yml @@ -32,9 +32,8 @@ pkg.deps: - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram + - nimble/transport diff --git a/apps/blehr/syscfg.yml b/apps/blehr/syscfg.yml index 5f047041e1..98cf255428 100644 --- a/apps/blehr/syscfg.yml +++ b/apps/blehr/syscfg.yml @@ -32,7 +32,7 @@ syscfg.vals: CONFIG_FCB: 1 # Set public device address. - BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11}) + BLE_LL_PUBLIC_DEV_ADDR: 0x1122aabb33cc # Whether to save data to sys/config, or just keep it in RAM. BLE_STORE_CONFIG_PERSIST: 0 diff --git a/apps/blemesh/pkg.yml b/apps/blemesh/pkg.yml index c70565423c..afe419b57b 100644 --- a/apps/blemesh/pkg.yml +++ b/apps/blemesh/pkg.yml @@ -29,9 +29,8 @@ pkg.deps: - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/sys/shell" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram + - nimble/transport diff --git a/apps/blemesh/src/main.c b/apps/blemesh/src/main.c index 65270554b3..56d0476f86 100644 --- a/apps/blemesh/src/main.c +++ b/apps/blemesh/src/main.c @@ -144,11 +144,12 @@ static struct bt_mesh_model_pub gen_onoff_pub; static uint8_t gen_on_off_state; static int16_t gen_level_state; -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = NET_BUF_SIMPLE(3); uint8_t *status; + int rc; console_printf("#mesh-onoff STATUS\n"); @@ -156,23 +157,25 @@ static void gen_onoff_status(struct bt_mesh_model *model, status = net_buf_simple_add(msg, 1); *status = gen_on_off_state; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { console_printf("#mesh-onoff STATUS: send status failed\n"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-onoff GET\n"); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -181,10 +184,10 @@ static void gen_onoff_set(struct bt_mesh_model *model, gen_on_off_state = buf->om_data[0]; hal_gpio_write(LED_2, !gen_on_off_state); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -192,6 +195,7 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, gen_on_off_state = buf->om_data[0]; hal_gpio_write(LED_2, !gen_on_off_state); + return 0; } static const struct bt_mesh_model_op gen_onoff_op[] = { @@ -201,48 +205,56 @@ static const struct bt_mesh_model_op gen_onoff_op[] = { BT_MESH_MODEL_OP_END, }; -static void gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = NET_BUF_SIMPLE(4); + int rc; console_printf("#mesh-level STATUS\n"); bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x08)); net_buf_simple_add_le16(msg, gen_level_state); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { console_printf("#mesh-level STATUS: send status failed\n"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-level GET\n"); - gen_level_status(model, ctx); + return gen_level_status(model, ctx); } -static void gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { int16_t level; + int rc; level = (int16_t) net_buf_simple_pull_le16(buf); console_printf("#mesh-level SET: level=%d\n", level); - gen_level_status(model, ctx); + rc = gen_level_status(model, ctx); + if (rc) { + return rc; + } gen_level_state = level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -253,9 +265,10 @@ static void gen_level_set_unack(struct bt_mesh_model *model, gen_level_state = level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_delta_set(struct bt_mesh_model *model, +static int gen_delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -268,9 +281,10 @@ static void gen_delta_set(struct bt_mesh_model *model, gen_level_state += delta_level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_delta_set_unack(struct bt_mesh_model *model, +static int gen_delta_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -281,18 +295,21 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, gen_level_state += delta_level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_move_set(struct bt_mesh_model *model, +static int gen_move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + return 0; } -static void gen_move_set_unack(struct bt_mesh_model *model, +static int gen_move_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + return 0; } static const struct bt_mesh_model_op gen_level_op[] = { @@ -317,11 +334,12 @@ static struct bt_mesh_model root_models[] = { static struct bt_mesh_model_pub vnd_model_pub; -static void vnd_model_recv(struct bt_mesh_model *model, +static int vnd_model_recv(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(3); + int rc; console_printf("#vendor-model-recv\n"); @@ -331,11 +349,13 @@ static void vnd_model_recv(struct bt_mesh_model *model, bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR)); os_mbuf_append(msg, buf->om_data, buf->om_len); + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { console_printf("#vendor-model-recv: send rsp failed\n"); } os_mbuf_free_chain(msg); + return rc; } static const struct bt_mesh_model_op vnd_model_op[] = { diff --git a/apps/blemesh_light/pkg.yml b/apps/blemesh_light/pkg.yml index 75a60df7bb..46b6d6c3d1 100644 --- a/apps/blemesh_light/pkg.yml +++ b/apps/blemesh_light/pkg.yml @@ -29,9 +29,8 @@ pkg.deps: - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/sys/shell" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram + - nimble/transport diff --git a/apps/blemesh_models_example_1/pkg.yml b/apps/blemesh_models_example_1/pkg.yml index 451f37a11c..b8d77c4e47 100644 --- a/apps/blemesh_models_example_1/pkg.yml +++ b/apps/blemesh_models_example_1/pkg.yml @@ -27,8 +27,7 @@ pkg.deps: - "@apache-mynewt-core/sys/console/full" - "@apache-mynewt-core/sys/log/full" - "@apache-mynewt-core/sys/stats/full" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - - nimble/transport/ram + - nimble/transport diff --git a/apps/blemesh_models_example_1/src/main.c b/apps/blemesh_models_example_1/src/main.c index 736d4d32bf..80a69c7052 100644 --- a/apps/blemesh_models_example_1/src/main.c +++ b/apps/blemesh_models_example_1/src/main.c @@ -68,19 +68,19 @@ #define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) #define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); @@ -318,26 +318,29 @@ static uint16_t primary_net_idx; * */ -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4); struct onoff_state *state = model->user_data; + int rc; BT_INFO("addr 0x%04x onoff 0x%02x", bt_mesh_model_elem(model)->addr, state->current); bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(msg, state->current); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { BT_ERR("Unable to send On Off Status response"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -372,23 +375,34 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(msg, state->current); err = bt_mesh_model_publish(model); - if (err) { + if (err != 0) { BT_ERR("bt_mesh_model_publish err %d", err); + return err; } } + return 0; } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_INFO(""); + int rc; + + rc = gen_onoff_set_unack(model, ctx, buf); + if (rc != 0) { + return rc; + } - gen_onoff_set_unack(model, ctx, buf); - gen_onoff_get(model, ctx, buf); + rc = gen_onoff_get(model, ctx, buf); + if (rc != 0) { + return rc; + } + return 0; } -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -398,6 +412,7 @@ static void gen_onoff_status(struct bt_mesh_model *model, BT_INFO("Node 0x%04x OnOff status from 0x%04x with state 0x%02x", bt_mesh_model_elem(model)->addr, ctx->addr, state); + return 0; } static int output_number(bt_mesh_output_action_t action, uint32_t number) diff --git a/apps/blemesh_models_example_2/pkg.yml b/apps/blemesh_models_example_2/pkg.yml index ee2be6da2a..020a9616da 100644 --- a/apps/blemesh_models_example_2/pkg.yml +++ b/apps/blemesh_models_example_2/pkg.yml @@ -29,11 +29,10 @@ pkg.deps: - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/encoding/base64" - "@apache-mynewt-core/sys/config" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - - nimble/transport/ram + - nimble/transport pkg.lflags: - -DFLOAT_SUPPORT diff --git a/apps/blemesh_models_example_2/src/device_composition.c b/apps/blemesh_models_example_2/src/device_composition.c index 5dfeaf8ed5..40ede50126 100644 --- a/apps/blemesh_models_example_2/src/device_composition.c +++ b/apps/blemesh_models_example_2/src/device_composition.c @@ -147,7 +147,7 @@ static struct bt_mesh_elem elements[]; /* message handlers (Start) */ /* Generic OnOff Server message handlers */ -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -168,16 +168,17 @@ static void gen_onoff_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void gen_onoff_publish(struct bt_mesh_model *model) +int gen_onoff_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct generic_onoff_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); @@ -193,21 +194,23 @@ void gen_onoff_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { uint8_t tid, onoff, tt, delay; int64_t now; + int err; struct generic_onoff_state *state = model->user_data; onoff = net_buf_simple_pull_u8(buf); tid = net_buf_simple_pull_u8(buf); if (onoff > STATE_ON) { - return; + return 0; } now = k_uptime_get(); @@ -215,7 +218,7 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -226,13 +229,13 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -247,8 +250,7 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, if (state->target_onoff != state->onoff) { onoff_tt_values(state, tt, delay); } else { - gen_onoff_publish(model); - return; + return gen_onoff_publish(model); } /* For Instantaneous Transition */ @@ -257,23 +259,28 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, } state->transition->just_started = true; - gen_onoff_publish(model); + err = gen_onoff_publish(model); onoff_handler(state); + if (err) { + return err; + } + return 0; } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { uint8_t tid, onoff, tt, delay; int64_t now; + int rc; struct generic_onoff_state *state = model->user_data; onoff = net_buf_simple_pull_u8(buf); tid = net_buf_simple_pull_u8(buf); if (onoff > STATE_ON) { - return; + return 0; } now = k_uptime_get(); @@ -281,8 +288,8 @@ static void gen_onoff_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - gen_onoff_get(model, ctx, buf); - return; + rc = gen_onoff_get(model, ctx, buf); + return rc; } switch (buf->om_len) { @@ -293,13 +300,13 @@ static void gen_onoff_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -315,8 +322,8 @@ static void gen_onoff_set(struct bt_mesh_model *model, onoff_tt_values(state, tt, delay); } else { gen_onoff_get(model, ctx, buf); - gen_onoff_publish(model); - return; + rc = gen_onoff_publish(model); + return rc; } /* For Instantaneous Transition */ @@ -326,12 +333,13 @@ static void gen_onoff_set(struct bt_mesh_model *model, state->transition->just_started = true; gen_onoff_get(model, ctx, buf); - gen_onoff_publish(model); + rc = gen_onoff_publish(model); onoff_handler(state); + return rc; } /* Generic OnOff Client message handlers */ -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -342,10 +350,11 @@ static void gen_onoff_status(struct bt_mesh_model *model, printk("Target OnOff = %02x\n", net_buf_simple_pull_u8(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } /* Generic Level Server message handlers */ -static void gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -366,16 +375,17 @@ static void gen_level_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void gen_level_publish(struct bt_mesh_model *model) +int gen_level_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct generic_level_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); @@ -391,9 +401,10 @@ void gen_level_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -410,7 +421,7 @@ static void gen_level_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -421,13 +432,13 @@ static void gen_level_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -443,7 +454,7 @@ static void gen_level_set_unack(struct bt_mesh_model *model, level_tt_values(state, tt, delay); } else { gen_level_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -463,9 +474,10 @@ static void gen_level_set_unack(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT; level_temp_handler(state); } + return 0; } -static void gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -483,7 +495,7 @@ static void gen_level_set(struct bt_mesh_model *model, state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { gen_level_get(model, ctx, buf); - return; + return 0; } switch (buf->om_len) { @@ -494,13 +506,13 @@ static void gen_level_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -517,7 +529,7 @@ static void gen_level_set(struct bt_mesh_model *model, } else { gen_level_get(model, ctx, buf); gen_level_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -538,9 +550,10 @@ static void gen_level_set(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT; level_temp_handler(state); } + return 0; } -static void gen_delta_set_unack(struct bt_mesh_model *model, +static int gen_delta_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -559,7 +572,7 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, (now - state->last_msg_timestamp <= K_SECONDS(6))) { if (state->last_delta == delta) { - return; + return 0; } tmp32 = state->last_level + delta; @@ -576,13 +589,13 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -605,8 +618,7 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, if (state->target_level != state->level) { level_tt_values(state, tt, delay); } else { - gen_level_publish(model); - return; + return gen_level_publish(model); } /* For Instantaneous Transition */ @@ -627,9 +639,10 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT_DELTA; level_temp_handler(state); } + return 0; } -static void gen_delta_set(struct bt_mesh_model *model, +static int gen_delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -649,7 +662,7 @@ static void gen_delta_set(struct bt_mesh_model *model, if (state->last_delta == delta) { gen_level_get(model, ctx, buf); - return; + return 0; } tmp32 = state->last_level + delta; @@ -666,13 +679,13 @@ static void gen_delta_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -697,7 +710,7 @@ static void gen_delta_set(struct bt_mesh_model *model, } else { gen_level_get(model, ctx, buf); gen_level_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -718,14 +731,16 @@ static void gen_delta_set(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT_DELTA; level_temp_handler(state); } + return 0; } -static void gen_level_move_get(struct bt_mesh_model *model, +static int gen_level_move_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); struct generic_level_state *state = model->user_data; + int rc; bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); net_buf_simple_add_le16(msg, state->level); @@ -740,21 +755,23 @@ static void gen_level_move_get(struct bt_mesh_model *model, net_buf_simple_add_u8(msg, UNKNOWN_VALUE); } - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { printk("Unable to send GEN_LEVEL_SRV Status response\n"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_level_move_publish(struct bt_mesh_model *model) +static int gen_level_move_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct generic_level_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); @@ -774,9 +791,10 @@ static void gen_level_move_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void gen_move_set_unack(struct bt_mesh_model *model, +static int gen_move_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -785,6 +803,7 @@ static void gen_move_set_unack(struct bt_mesh_model *model, int32_t tmp32; int64_t now; struct generic_level_state *state = model->user_data; + int rc; delta = (int16_t) net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -794,7 +813,7 @@ static void gen_move_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -805,13 +824,13 @@ static void gen_move_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -835,16 +854,16 @@ static void gen_move_set_unack(struct bt_mesh_model *model, if (state->target_level != state->level) { level_tt_values(state, tt, delay); } else { - gen_level_move_publish(model); - return; + rc = gen_level_move_publish(model); + return rc; } if (state->transition->counter == 0) { - return; + return 0; } state->transition->just_started = true; - gen_level_move_publish(model); + rc = gen_level_move_publish(model); if (bt_mesh_model_elem(model)->addr == elements[0].addr) { /* Root element */ @@ -855,9 +874,10 @@ static void gen_move_set_unack(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT_MOVE; level_temp_handler(state); } + return rc; } -static void gen_move_set(struct bt_mesh_model *model, +static int gen_move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -866,6 +886,7 @@ static void gen_move_set(struct bt_mesh_model *model, int32_t tmp32; int64_t now; struct generic_level_state *state = model->user_data; + int rc; delta = (int16_t) net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -875,8 +896,8 @@ static void gen_move_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - gen_level_move_get(model, ctx, buf); - return; + rc = gen_level_move_get(model, ctx, buf); + return rc; } switch (buf->om_len) { @@ -887,13 +908,13 @@ static void gen_move_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -918,17 +939,17 @@ static void gen_move_set(struct bt_mesh_model *model, level_tt_values(state, tt, delay); } else { gen_level_move_get(model, ctx, buf); - gen_level_move_publish(model); - return; + rc = gen_level_move_publish(model); + return rc; } if (state->transition->counter == 0) { - return; + return 0; } state->transition->just_started = true; gen_level_move_get(model, ctx, buf); - gen_level_move_publish(model); + rc = gen_level_move_publish(model); if (bt_mesh_model_elem(model)->addr == elements[0].addr) { /* Root element */ @@ -939,10 +960,11 @@ static void gen_move_set(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT_MOVE; level_temp_handler(state); } + return rc; } /* Generic Level Client message handlers */ -static void gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -953,10 +975,11 @@ static void gen_level_status(struct bt_mesh_model *model, printk("Target Level = %04x\n", net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } /* Generic Default Transition Time Server message handlers */ -static void gen_def_trans_time_get(struct bt_mesh_model *model, +static int gen_def_trans_time_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -971,16 +994,17 @@ static void gen_def_trans_time_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void gen_def_trans_time_publish(struct bt_mesh_model *model) +static int gen_def_trans_time_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct gen_def_trans_time_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_DEF_TRANS_TIME_STATUS); @@ -990,6 +1014,7 @@ static void gen_def_trans_time_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool gen_def_trans_time_setunack(struct bt_mesh_model *model, @@ -1017,71 +1042,78 @@ static bool gen_def_trans_time_setunack(struct bt_mesh_model *model, return true; } -static void gen_def_trans_time_set_unack(struct bt_mesh_model *model, +static int gen_def_trans_time_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (gen_def_trans_time_setunack(model, ctx, buf) == true) { - gen_def_trans_time_publish(model); + return gen_def_trans_time_publish(model); } + return 0; } -static void gen_def_trans_time_set(struct bt_mesh_model *model, +static int gen_def_trans_time_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (gen_def_trans_time_setunack(model, ctx, buf) == true) { gen_def_trans_time_get(model, ctx, buf); - gen_def_trans_time_publish(model); + return gen_def_trans_time_publish(model); } + return 0; } /* Generic Default Transition Time Client message handlers */ -static void gen_def_trans_time_status(struct bt_mesh_model *model, +static int gen_def_trans_time_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from GEN_DEF_TT_SRV\n"); printk("Transition Time = %02x\n", net_buf_simple_pull_u8(buf)); + return 0; } /* Generic Power OnOff Server message handlers */ -static void gen_onpowerup_get(struct bt_mesh_model *model, +static int gen_onpowerup_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4); struct generic_onpowerup_state *state = model->user_data; + int rc; bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_ONPOWERUP_STATUS); net_buf_simple_add_u8(msg, state->onpowerup); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { printk("Unable to send GEN_POWER_ONOFF_SRV Status response\n"); } os_mbuf_free_chain(msg); + return rc; } /* Generic Power OnOff Client message handlers */ -static void gen_onpowerup_status(struct bt_mesh_model *model, +static int gen_onpowerup_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from GEN_POWER_ONOFF_SRV\n"); printk("OnPowerUp = %02x\n", net_buf_simple_pull_u8(buf)); + return 0; } /* Generic Power OnOff Setup Server message handlers */ -static void gen_onpowerup_publish(struct bt_mesh_model *model) +static int gen_onpowerup_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct generic_onpowerup_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_ONPOWERUP_STATUS); @@ -1091,6 +1123,7 @@ static void gen_onpowerup_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool gen_onpowerup_setunack(struct bt_mesh_model *model, @@ -1117,32 +1150,35 @@ static bool gen_onpowerup_setunack(struct bt_mesh_model *model, return true; } -static void gen_onpowerup_set_unack(struct bt_mesh_model *model, +static int gen_onpowerup_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (gen_onpowerup_setunack(model, ctx, buf) == true) { - gen_onpowerup_publish(model); + return gen_onpowerup_publish(model); } + return 0; } -static void gen_onpowerup_set(struct bt_mesh_model *model, +static int gen_onpowerup_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (gen_onpowerup_setunack(model, ctx, buf) == true) { gen_onpowerup_get(model, ctx, buf); - gen_onpowerup_publish(model); + return gen_onpowerup_publish(model); } + return 0; } /* Vendor Model message handlers*/ -static void vnd_get(struct bt_mesh_model *model, +static int vnd_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(3 + 6 + 4); struct vendor_state *state = model->user_data; + int err; /* This is dummy response for demo purpose */ state->response = 0xA578FEB3; @@ -1151,14 +1187,16 @@ static void vnd_get(struct bt_mesh_model *model, net_buf_simple_add_le16(msg, state->current); net_buf_simple_add_le32(msg, state->response); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + err = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (err) { printk("Unable to send VENDOR Status response\n"); } os_mbuf_free_chain(msg); + return err; } -static void vnd_set_unack(struct bt_mesh_model *model, +static int vnd_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1175,7 +1213,7 @@ static void vnd_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } state->last_tid = tid; @@ -1193,27 +1231,37 @@ static void vnd_set_unack(struct bt_mesh_model *model, /* LED2 Off */ hal_gpio_write(led_device[1], 1); } + return 0; } -static void vnd_set(struct bt_mesh_model *model, +static int vnd_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - vnd_set_unack(model, ctx, buf); - vnd_get(model, ctx, buf); + int rc; + rc = vnd_set_unack(model, ctx, buf); + if (rc) { + return rc; + } + rc = vnd_get(model, ctx, buf); + if (rc) { + return rc; + } + return 0; } -static void vnd_status(struct bt_mesh_model *model, +static int vnd_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from Vendor\n"); printk("cmd = %04x\n", net_buf_simple_pull_le16(buf)); printk("response = %08lx\n", net_buf_simple_pull_le32(buf)); + return 0; } /* Light Lightness Server message handlers */ -static void light_lightness_get(struct bt_mesh_model *model, +static int light_lightness_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1234,16 +1282,17 @@ static void light_lightness_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void light_lightness_publish(struct bt_mesh_model *model) +int light_lightness_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_STATUS); @@ -1259,9 +1308,10 @@ void light_lightness_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_lightness_set_unack(struct bt_mesh_model *model, +static int light_lightness_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1278,7 +1328,7 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -1289,13 +1339,13 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1318,7 +1368,7 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, light_lightness_actual_tt_values(state, tt, delay); } else { light_lightness_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -1329,9 +1379,10 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, state->transition->just_started = true; light_lightness_publish(model); light_lightness_actual_handler(state); + return 0; } -static void light_lightness_set(struct bt_mesh_model *model, +static int light_lightness_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1339,6 +1390,7 @@ static void light_lightness_set(struct bt_mesh_model *model, uint16_t actual; int64_t now; struct light_lightness_state *state = model->user_data; + int rc; actual = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -1348,8 +1400,7 @@ static void light_lightness_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - light_lightness_get(model, ctx, buf); - return; + return light_lightness_get(model, ctx, buf); } switch (buf->om_len) { @@ -1360,13 +1411,13 @@ static void light_lightness_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1388,9 +1439,9 @@ static void light_lightness_set(struct bt_mesh_model *model, if (state->target_actual != state->actual) { light_lightness_actual_tt_values(state, tt, delay); } else { - light_lightness_get(model, ctx, buf); + rc = light_lightness_get(model, ctx, buf); light_lightness_publish(model); - return; + return rc; } /* For Instantaneous Transition */ @@ -1402,9 +1453,10 @@ static void light_lightness_set(struct bt_mesh_model *model, light_lightness_get(model, ctx, buf); light_lightness_publish(model); light_lightness_actual_handler(state); + return 0; } -static void light_lightness_linear_get(struct bt_mesh_model *model, +static int light_lightness_linear_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1426,16 +1478,17 @@ static void light_lightness_linear_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void light_lightness_linear_publish(struct bt_mesh_model *model) +int light_lightness_linear_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, @@ -1452,9 +1505,10 @@ void light_lightness_linear_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_lightness_linear_set_unack(struct bt_mesh_model *model, +static int light_lightness_linear_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1471,7 +1525,7 @@ static void light_lightness_linear_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -1482,13 +1536,13 @@ static void light_lightness_linear_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1504,7 +1558,7 @@ static void light_lightness_linear_set_unack(struct bt_mesh_model *model, light_lightness_linear_tt_values(state, tt, delay); } else { light_lightness_linear_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -1515,9 +1569,10 @@ static void light_lightness_linear_set_unack(struct bt_mesh_model *model, state->transition->just_started = true; light_lightness_linear_publish(model); light_lightness_linear_handler(state); + return 0; } -static void light_lightness_linear_set(struct bt_mesh_model *model, +static int light_lightness_linear_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1525,6 +1580,7 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, uint16_t linear; int64_t now; struct light_lightness_state *state = model->user_data; + int rc; linear = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -1534,8 +1590,7 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - light_lightness_linear_get(model, ctx, buf); - return; + return light_lightness_linear_get(model, ctx, buf); } switch (buf->om_len) { @@ -1546,13 +1601,13 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1567,9 +1622,9 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, if (state->target_linear != state->linear) { light_lightness_linear_tt_values(state, tt, delay); } else { - light_lightness_linear_get(model, ctx, buf); + rc = light_lightness_linear_get(model, ctx, buf); light_lightness_linear_publish(model); - return; + return rc; } /* For Instantaneous Transition */ @@ -1581,9 +1636,10 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, light_lightness_linear_get(model, ctx, buf); light_lightness_linear_publish(model); light_lightness_linear_handler(state); + return 0; } -static void light_lightness_last_get(struct bt_mesh_model *model, +static int light_lightness_last_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1598,9 +1654,10 @@ static void light_lightness_last_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void light_lightness_default_get(struct bt_mesh_model *model, +static int light_lightness_default_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1616,9 +1673,10 @@ static void light_lightness_default_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void light_lightness_range_get(struct bt_mesh_model *model, +static int light_lightness_range_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1637,18 +1695,19 @@ static void light_lightness_range_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } /* Light Lightness Setup Server message handlers */ -static void light_lightness_default_publish(struct bt_mesh_model *model) +static int light_lightness_default_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, @@ -1659,9 +1718,10 @@ static void light_lightness_default_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_lightness_default_set_unack(struct bt_mesh_model *model, +static int light_lightness_default_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1679,26 +1739,37 @@ static void light_lightness_default_set_unack(struct bt_mesh_model *model, save_on_flash(LIGHTNESS_TEMP_DEF_STATE); } - light_lightness_default_publish(model); + return light_lightness_default_publish(model); } -static void light_lightness_default_set(struct bt_mesh_model *model, +static int light_lightness_default_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - light_lightness_default_set_unack(model, ctx, buf); - light_lightness_default_get(model, ctx, buf); - light_lightness_default_publish(model); + int rc; + rc = light_lightness_default_set_unack(model, ctx, buf); + if (rc) { + return rc; + } + rc = light_lightness_default_get(model, ctx, buf); + if (rc) { + return rc; + } + rc = light_lightness_default_publish(model); + if (rc) { + return rc; + } + return 0; } -static void light_lightness_range_publish(struct bt_mesh_model *model) +static int light_lightness_range_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_RANGE_STATUS); @@ -1710,6 +1781,7 @@ static void light_lightness_range_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool light_lightness_range_setunack(struct bt_mesh_model *model, @@ -1748,27 +1820,36 @@ static bool light_lightness_range_setunack(struct bt_mesh_model *model, return true; } -static void light_lightness_range_set_unack(struct bt_mesh_model *model, +static int light_lightness_range_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_lightness_range_setunack(model, ctx, buf) == true) { - light_lightness_range_publish(model); + return light_lightness_range_publish(model); } + return 0; } -static void light_lightness_range_set(struct bt_mesh_model *model, +static int light_lightness_range_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + int rc; if (light_lightness_range_setunack(model, ctx, buf) == true) { - light_lightness_range_get(model, ctx, buf); - light_lightness_range_publish(model); + rc = light_lightness_range_get(model, ctx, buf); + if (rc) { + return rc; + } + rc = light_lightness_range_publish(model); + if (rc) { + return rc; + } } + return 0; } /* Light Lightness Client message handlers */ -static void light_lightness_status(struct bt_mesh_model *model, +static int light_lightness_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1780,9 +1861,10 @@ static void light_lightness_status(struct bt_mesh_model *model, net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } -static void light_lightness_linear_status(struct bt_mesh_model *model, +static int light_lightness_linear_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1794,25 +1876,28 @@ static void light_lightness_linear_status(struct bt_mesh_model *model, net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } -static void light_lightness_last_status(struct bt_mesh_model *model, +static int light_lightness_last_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Last)\n"); printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } -static void light_lightness_default_status(struct bt_mesh_model *model, +static int light_lightness_default_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Default)\n"); printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } -static void light_lightness_range_status(struct bt_mesh_model *model, +static int light_lightness_range_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1820,10 +1905,11 @@ static void light_lightness_range_status(struct bt_mesh_model *model, printk("Status Code = %02x\n", net_buf_simple_pull_u8(buf)); printk("Range Min = %04x\n", net_buf_simple_pull_le16(buf)); printk("Range Max = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } /* Light CTL Server message handlers */ -static void light_ctl_get(struct bt_mesh_model *model, +static int light_ctl_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1846,16 +1932,17 @@ static void light_ctl_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void light_ctl_publish(struct bt_mesh_model *model) +int light_ctl_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_STATUS); @@ -1877,9 +1964,10 @@ void light_ctl_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_ctl_set_unack(struct bt_mesh_model *model, +static int light_ctl_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1895,7 +1983,7 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return; + return 0; } now = k_uptime_get(); @@ -1903,7 +1991,7 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -1914,13 +2002,13 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1947,7 +2035,7 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, light_ctl_tt_values(state, tt, delay); } else { light_ctl_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -1960,9 +2048,10 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, state->transition->just_started = true; light_ctl_publish(model); light_ctl_handler(state); + return 0; } -static void light_ctl_set(struct bt_mesh_model *model, +static int light_ctl_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1978,7 +2067,7 @@ static void light_ctl_set(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return; + return 0; } now = k_uptime_get(); @@ -1987,7 +2076,7 @@ static void light_ctl_set(struct bt_mesh_model *model, state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { light_ctl_get(model, ctx, buf); - return; + return 0; } switch (buf->om_len) { @@ -1998,13 +2087,13 @@ static void light_ctl_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -2032,7 +2121,7 @@ static void light_ctl_set(struct bt_mesh_model *model, } else { light_ctl_get(model, ctx, buf); light_ctl_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -2046,14 +2135,16 @@ static void light_ctl_set(struct bt_mesh_model *model, light_ctl_get(model, ctx, buf); light_ctl_publish(model); light_ctl_handler(state); + return 0; } -static void light_ctl_temp_range_get(struct bt_mesh_model *model, +static int light_ctl_temp_range_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); struct light_ctl_state *state = model->user_data; + int rc; state->status_code = RANGE_SUCCESSFULLY_UPDATED; @@ -2062,42 +2153,47 @@ static void light_ctl_temp_range_get(struct bt_mesh_model *model, net_buf_simple_add_le16(msg, state->temp_range_min); net_buf_simple_add_le16(msg, state->temp_range_max); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { printk("Unable to send LightCTL Temp Range Status response\n"); } os_mbuf_free_chain(msg); + return rc; } -static void light_ctl_default_get(struct bt_mesh_model *model, +static int light_ctl_default_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 6 + 4); struct light_ctl_state *state = model->user_data; + int rc; bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS); net_buf_simple_add_le16(msg, state->lightness_def); net_buf_simple_add_le16(msg, state->temp_def); net_buf_simple_add_le16(msg, state->delta_uv_def); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { printk("Unable to send LightCTL Default Status response\n"); } os_mbuf_free_chain(msg); + return rc; } /* Light CTL Setup Server message handlers */ -static void light_ctl_default_publish(struct bt_mesh_model *model) +static int light_ctl_default_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS); @@ -2109,6 +2205,7 @@ static void light_ctl_default_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool light_ctl_default_setunack(struct bt_mesh_model *model, @@ -2147,33 +2244,35 @@ static bool light_ctl_default_setunack(struct bt_mesh_model *model, return true; } -static void light_ctl_default_set_unack(struct bt_mesh_model *model, +static int light_ctl_default_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_ctl_default_setunack(model, ctx, buf) == true) { - light_ctl_default_publish(model); + return light_ctl_default_publish(model); } + return 0; } -static void light_ctl_default_set(struct bt_mesh_model *model, +static int light_ctl_default_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_ctl_default_setunack(model, ctx, buf) == true) { light_ctl_default_get(model, ctx, buf); - light_ctl_default_publish(model); + return light_ctl_default_publish(model); } + return 0; } -static void light_ctl_temp_range_publish(struct bt_mesh_model *model) +static int light_ctl_temp_range_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_TEMP_RANGE_STATUS); @@ -2185,6 +2284,7 @@ static void light_ctl_temp_range_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool light_ctl_temp_range_setunack(struct bt_mesh_model *model, @@ -2225,27 +2325,29 @@ static bool light_ctl_temp_range_setunack(struct bt_mesh_model *model, return true; } -static void light_ctl_temp_range_set_unack(struct bt_mesh_model *model, +static int light_ctl_temp_range_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_ctl_temp_range_setunack(model, ctx, buf) == true) { - light_ctl_temp_range_publish(model); + return light_ctl_temp_range_publish(model); } + return 0; } -static void light_ctl_temp_range_set(struct bt_mesh_model *model, +static int light_ctl_temp_range_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_ctl_temp_range_setunack(model, ctx, buf) == true) { light_ctl_temp_range_get(model, ctx, buf); - light_ctl_temp_range_publish(model); + return light_ctl_temp_range_publish(model); } + return 0; } /* Light CTL Client message handlers */ -static void light_ctl_status(struct bt_mesh_model *model, +static int light_ctl_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2261,9 +2363,10 @@ static void light_ctl_status(struct bt_mesh_model *model, net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } -static void light_ctl_temp_range_status(struct bt_mesh_model *model, +static int light_ctl_temp_range_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2271,9 +2374,10 @@ static void light_ctl_temp_range_status(struct bt_mesh_model *model, printk("Status Code = %02x\n", net_buf_simple_pull_u8(buf)); printk("Range Min = %04x\n", net_buf_simple_pull_le16(buf)); printk("Range Max = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } -static void light_ctl_temp_status(struct bt_mesh_model *model, +static int light_ctl_temp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2290,9 +2394,10 @@ static void light_ctl_temp_status(struct bt_mesh_model *model, net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } -static void light_ctl_default_status(struct bt_mesh_model *model, +static int light_ctl_default_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2300,10 +2405,11 @@ static void light_ctl_default_status(struct bt_mesh_model *model, printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); printk("Temperature = %04x\n", net_buf_simple_pull_le16(buf)); printk("Delta UV = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } /* Light CTL Temp. Server message handlers */ -static void light_ctl_temp_get(struct bt_mesh_model *model, +static int light_ctl_temp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2326,16 +2432,17 @@ static void light_ctl_temp_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void light_ctl_temp_publish(struct bt_mesh_model *model) +int light_ctl_temp_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_TEMP_STATUS); @@ -2353,9 +2460,10 @@ void light_ctl_temp_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_ctl_temp_set_unack(struct bt_mesh_model *model, +static int light_ctl_temp_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2370,7 +2478,7 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return; + return 0; } now = k_uptime_get(); @@ -2378,7 +2486,7 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -2389,13 +2497,13 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -2420,7 +2528,7 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, light_ctl_temp_tt_values(state, tt, delay); } else { light_ctl_temp_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -2432,9 +2540,10 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, state->transition->just_started = true; light_ctl_temp_publish(model); light_ctl_temp_handler(state); + return 0; } -static void light_ctl_temp_set(struct bt_mesh_model *model, +static int light_ctl_temp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2449,7 +2558,7 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return; + return 0; } now = k_uptime_get(); @@ -2457,8 +2566,7 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - light_ctl_temp_get(model, ctx, buf); - return; + return light_ctl_temp_get(model, ctx, buf); } switch (buf->om_len) { @@ -2469,13 +2577,13 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -2501,7 +2609,7 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, } else { light_ctl_temp_get(model, ctx, buf); light_ctl_temp_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -2514,6 +2622,7 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, light_ctl_temp_get(model, ctx, buf); light_ctl_temp_publish(model); light_ctl_temp_handler(state); + return 0; } /* message handlers (End) */ diff --git a/apps/blemesh_models_example_2/src/device_composition.h b/apps/blemesh_models_example_2/src/device_composition.h index d0f054ee2b..1b5bf5f72a 100644 --- a/apps/blemesh_models_example_2/src/device_composition.h +++ b/apps/blemesh_models_example_2/src/device_composition.h @@ -167,11 +167,11 @@ extern struct bt_mesh_model s0_models[]; extern const struct bt_mesh_comp comp; -void gen_onoff_publish(struct bt_mesh_model *model); -void gen_level_publish(struct bt_mesh_model *model); -void light_lightness_publish(struct bt_mesh_model *model); -void light_lightness_linear_publish(struct bt_mesh_model *model); -void light_ctl_publish(struct bt_mesh_model *model); -void light_ctl_temp_publish(struct bt_mesh_model *model); +int gen_onoff_publish(struct bt_mesh_model *model); +int gen_level_publish(struct bt_mesh_model *model); +int light_lightness_publish(struct bt_mesh_model *model); +int light_lightness_linear_publish(struct bt_mesh_model *model); +int light_ctl_publish(struct bt_mesh_model *model); +int light_ctl_temp_publish(struct bt_mesh_model *model); #endif diff --git a/apps/blemesh_shell/pkg.yml b/apps/blemesh_shell/pkg.yml index e4852f6fa5..f472fdf2aa 100644 --- a/apps/blemesh_shell/pkg.yml +++ b/apps/blemesh_shell/pkg.yml @@ -29,9 +29,8 @@ pkg.deps: - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/sys/shell" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram + - nimble/transport diff --git a/apps/blestress/pkg.yml b/apps/blestress/pkg.yml index b23358c564..53f99ed944 100644 --- a/apps/blestress/pkg.yml +++ b/apps/blestress/pkg.yml @@ -30,10 +30,9 @@ pkg.deps: - "@apache-mynewt-core/sys/log/full" - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/sys/id" - - "@apache-mynewt-nimble/nimble/controller" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util" - "@apache-mynewt-nimble/nimble/host/services/gap" - "@apache-mynewt-nimble/nimble/host/services/gatt" - "@apache-mynewt-nimble/nimble/host/store/config" - - "@apache-mynewt-nimble/nimble/transport/ram" + - "@apache-mynewt-nimble/nimble/transport" diff --git a/apps/blestress/src/rx_stress.c b/apps/blestress/src/rx_stress.c index 440966adcc..a9d9cda09a 100644 --- a/apps/blestress/src/rx_stress.c +++ b/apps/blestress/src/rx_stress.c @@ -155,7 +155,8 @@ rx_stress_simple_adv(struct rx_stress_adv_set *adv_set) assert (rc == 0); if (own_addr_type == 0) { - memcpy(addr.val, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), 6); + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr.val, NULL); + assert (rc == 0); } else { rc = ble_hs_id_gen_rnd(1, &addr); assert (rc == 0); @@ -1010,12 +1011,24 @@ rx_stress_12_gap_event(struct ble_gap_event *event, void *arg) return 0; } -static int -rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) +static struct ble_npl_event rx_stress_13_notify_ev; + +static void +rx_stress_13_notify_ev_func(struct ble_npl_event *ev) { + struct os_mbuf *om; int rc; - struct os_mbuf *om = NULL; + om = ble_hs_mbuf_from_flat(test_6_pattern, 10); + rc = ble_gattc_notify_custom(rx_stress_ctx->conn_handle, + hrs_hrm_handle, om); + assert(rc == 0); + +} + +static int +rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) +{ switch (event->type) { case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed */ @@ -1026,6 +1039,9 @@ rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) rx_stress_ctx->conn_handle = event->connect.conn_handle; rx_stress_ctx->begin_us = os_get_uptime_usec(); + + ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(), + &rx_stress_13_notify_ev); break; } else { /* Connection failed; resume advertising */ @@ -1045,7 +1061,7 @@ rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) rx_stress_ctx->s13_notif_time = rx_stress_ctx->time_sum / rx_stress_ctx->send_num; - MODLOG_DFLT(INFO, "Average time: %lld us\n", + MODLOG_DFLT(INFO, "Average time: %d us\n", rx_stress_ctx->s13_notif_time); rx_stress_on_test_finish(13); return 0; @@ -1061,6 +1077,9 @@ rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) BLE_ERR_REM_USER_CONN_TERM); return 0; } + + ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(), + &rx_stress_13_notify_ev); break; default: @@ -1068,10 +1087,6 @@ rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) return 0; } - om = ble_hs_mbuf_from_flat(test_6_pattern, 10); - rc = ble_gattc_notify_custom(rx_stress_ctx->conn_handle, - hrs_hrm_handle, om); - assert(rc == 0); return 0; } @@ -1377,6 +1392,8 @@ rx_stress_start(int test_num) break; case 13: console_printf("Stress GATT notification\033[0m\n"); + ble_npl_event_init(&rx_stress_13_notify_ev, + rx_stress_13_notify_ev_func, NULL); rx_stress_simple_adv(&rx_stress_adv_sets[13]); break; case 14: diff --git a/apps/blestress/src/tx_stress.c b/apps/blestress/src/tx_stress.c index 4416c568cb..1711f9fbf8 100644 --- a/apps/blestress/src/tx_stress.c +++ b/apps/blestress/src/tx_stress.c @@ -1271,7 +1271,6 @@ tx_stress_13_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_NOTIFY_RX: MODLOG_DFLT(INFO, "Notify RX event\n"); console_printf("\033[0;32m>\033[0m"); - os_mbuf_free_chain(event->notify_rx.om); ++tx_stress_ctx->rcv_num; return 0; @@ -1390,7 +1389,7 @@ tx_stress_14_gap_event(struct ble_gap_event *event, void *arg) if (++tx_stress_ctx->rcv_num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rc = ble_gap_terminate(event->notify_rx.conn_handle, BLE_ERR_REM_USER_CONN_TERM); - MODLOG_DFLT(INFO, "rc=%d\n"); + MODLOG_DFLT(INFO, "rc=%d\n", rc); assert(rc == 0); return 0; } diff --git a/apps/btshell/src/cmd.c b/apps/btshell/src/cmd.c index a0452d22eb..6cb2713518 100644 --- a/apps/btshell/src/cmd.c +++ b/apps/btshell/src/cmd.c @@ -98,16 +98,19 @@ parse_dev_addr(const char *prefix, const struct kv_pair *addr_types, { char name[32]; int rc; + int written = 0; if (!prefix) { name[0] = '\0'; } else { - if (strlcpy(name, prefix, sizeof(name)) >= sizeof(name)) { + written = snprintf(name, sizeof(name) - 1, "%s", prefix); + if (written >= sizeof(name) || written < 0) { return EINVAL; } } - if (strlcat(name, "addr", sizeof(name)) >= sizeof(name)) { + written = snprintf(name + written, sizeof(name) - written - 1, "%s", "addr"); + if (written >= sizeof(name) || written < 0) { return EINVAL; } rc = parse_arg_addr(name, addr); @@ -116,7 +119,8 @@ parse_dev_addr(const char *prefix, const struct kv_pair *addr_types, return rc; } else if (rc == EAGAIN) { /* address found, but no type provided */ - if (strlcat(name, "_type", sizeof(name)) >= sizeof(name)) { + written = snprintf(name + written, sizeof(name) - written - 1, "%s", "_type"); + if (written >= sizeof(name) || written < 0) { return EINVAL; } addr->type = parse_arg_kv(name, addr_types, &rc); @@ -130,7 +134,8 @@ parse_dev_addr(const char *prefix, const struct kv_pair *addr_types, return rc; } else { /* full address found, but let's just make sure there is no type arg */ - if (strlcat(name, "_type", sizeof(name)) >= sizeof(name)) { + written = snprintf(name + written, sizeof(name) - written, "%s", "_type"); + if (written >= sizeof(name) || written < 0) { return EINVAL; } if (parse_arg_extract(name)) { diff --git a/apps/btshell/src/parse.c b/apps/btshell/src/parse.c index a2e2ae5217..e4dbade420 100644 --- a/apps/btshell/src/parse.c +++ b/apps/btshell/src/parse.c @@ -301,7 +301,7 @@ parse_time_us(const char *str, int *out_status) uint32_t val_mult = 1; uint32_t val_us; - while (isdigit(*str)) { + while (isdigit((unsigned char)*str)) { val *= 10; val += *str - '0'; str++; @@ -309,7 +309,7 @@ parse_time_us(const char *str, int *out_status) if (*str == '.') { str++; - while (isdigit(*str)) { + while (isdigit((unsigned char)*str)) { val *= 10; val += *str - '0'; val_div *= 10; diff --git a/apps/bttester/pkg.yml b/apps/bttester/pkg.yml index ba2b7fb1be..270dc7e882 100644 --- a/apps/bttester/pkg.yml +++ b/apps/bttester/pkg.yml @@ -31,14 +31,13 @@ pkg.deps: - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/sys/shell" - - "@apache-mynewt-nimble/nimble/controller" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util" - "@apache-mynewt-nimble/nimble/host/services/gap" - "@apache-mynewt-nimble/nimble/host/services/gatt" - "@apache-mynewt-nimble/nimble/host/services/dis" - "@apache-mynewt-nimble/nimble/host/store/config" - - "@apache-mynewt-nimble/nimble/transport/ram" + - "@apache-mynewt-nimble/nimble/transport" - "@apache-mynewt-core/hw/drivers/uart" - "@apache-mynewt-core/hw/drivers/rtt" diff --git a/apps/bttester/src/bttester.h b/apps/bttester/src/bttester.h index 6761681e15..4a8fc47142 100644 --- a/apps/bttester/src/bttester.h +++ b/apps/bttester/src/bttester.h @@ -997,6 +997,27 @@ struct mesh_invalid_bearer_ev { #define MESH_EV_INCOMP_TIMER_EXP 0x88 +#define MESH_EV_LPN_ESTABLISHED 0x8b +struct mesh_lpn_established_ev { + uint16_t net_idx; + uint16_t friend_addr; + uint8_t queue_size; + uint8_t recv_win; +} __packed; + +#define MESH_EV_LPN_TERMINATED 0x8c +struct mesh_lpn_terminated_ev { + uint16_t net_idx; + uint16_t friend_addr; +} __packed; + +#define MESH_EV_LPN_POLLED 0x8d +struct mesh_lpn_polled_ev { + uint16_t net_idx; + uint16_t friend_addr; + uint8_t retry; +} __packed; + void tester_init(void); void tester_rsp(uint8_t service, uint8_t opcode, uint8_t index, uint8_t status); void tester_send(uint8_t service, uint8_t opcode, uint8_t index, uint8_t *data, diff --git a/apps/bttester/src/gap.c b/apps/bttester/src/gap.c index acac9989f0..75adeb9fc0 100644 --- a/apps/bttester/src/gap.c +++ b/apps/bttester/src/gap.c @@ -63,6 +63,10 @@ static struct os_callout connected_ev_co; static struct gap_device_connected_ev connected_ev; #define CONNECTED_EV_DELAY_MS(itvl) 8 * BLE_HCI_CONN_ITVL * itvl / 1000 static int connection_attempts; +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) +static int64_t advertising_start; +static struct os_callout bttester_nrpa_rotate_timer; +#endif static const struct ble_gap_conn_params dflt_conn_params = { .scan_itvl = 0x0010, @@ -162,18 +166,6 @@ static void controller_index_list(uint8_t *data, uint16_t len) BTP_INDEX_NONE, (uint8_t *) rp, sizeof(buf)); } -static int check_pub_addr_unassigned(void) -{ -#ifdef ARCH_sim - return 0; -#else - uint8_t zero_addr[BLE_DEV_ADDR_LEN] = { 0 }; - - return memcmp(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), - zero_addr, BLE_DEV_ADDR_LEN) == 0; -#endif -} - static void controller_info(uint8_t *data, uint16_t len) { struct gap_read_controller_info_rp rp; @@ -208,15 +200,14 @@ static void controller_info(uint8_t *data, uint16_t len) supported_settings |= BIT(GAP_SETTINGS_PRIVACY); memcpy(rp.address, addr.val, sizeof(rp.address)); } else { - if (check_pub_addr_unassigned()) { + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, rp.address, NULL); + if (rc) { own_addr_type = BLE_OWN_ADDR_RANDOM; memcpy(rp.address, addr.val, sizeof(rp.address)); supported_settings |= BIT(GAP_SETTINGS_STATIC_ADDRESS); current_settings |= BIT(GAP_SETTINGS_STATIC_ADDRESS); } else { own_addr_type = BLE_OWN_ADDR_PUBLIC; - memcpy(rp.address, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), - sizeof(rp.address)); } } @@ -248,6 +239,38 @@ static struct ble_gap_adv_params adv_params = { .disc_mode = BLE_GAP_DISC_MODE_NON, }; +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) +static void rotate_nrpa_cb(struct os_event *ev) +{ + int rc; + ble_addr_t addr; + int32_t duration_ms = BLE_HS_FOREVER; + int32_t remaining_time; + os_time_t remaining_ticks; + + if (adv_params.disc_mode == BLE_GAP_DISC_MODE_LTD) { + duration_ms = MYNEWT_VAL(BTTESTER_LTD_ADV_TIMEOUT); + } + + ble_gap_adv_stop(); + rc = ble_hs_id_gen_rnd(1, &addr); + assert(rc == 0); + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); + + ble_gap_adv_start(own_addr_type, NULL, duration_ms, + &adv_params, gap_event_cb, NULL); + + remaining_time = os_get_uptime_usec() - advertising_start; + if (remaining_time > 0) { + advertising_start = os_get_uptime_usec(); + os_time_ms_to_ticks(remaining_time, &remaining_ticks); + os_callout_reset(&bttester_nrpa_rotate_timer, + remaining_ticks); + } +} +#endif + static void set_connectable(uint8_t *data, uint16_t len) { const struct gap_set_connectable_cmd *cmd = (void *) data; @@ -418,6 +441,13 @@ static void start_advertising(const uint8_t *data, uint16_t len) duration_ms = MYNEWT_VAL(BTTESTER_LTD_ADV_TIMEOUT); } +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) + if (MYNEWT_VAL(BTTESTER_NRPA_TIMEOUT) < duration_ms / 1000) { + advertising_start = os_get_uptime_usec(); + os_callout_reset(&bttester_nrpa_rotate_timer, + OS_TICKS_PER_SEC * MYNEWT_VAL(BTTESTER_NRPA_TIMEOUT)); + } +#endif err = ble_gap_adv_start(own_addr_type, NULL, duration_ms, &adv_params, gap_event_cb, NULL); if (err) { @@ -1675,7 +1705,10 @@ uint8_t tester_init_gap(void) return BTP_STATUS_FAILED; } #endif - +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) + os_callout_init(&bttester_nrpa_rotate_timer, os_eventq_dflt_get(), + rotate_nrpa_cb, NULL); +#endif adv_buf = NET_BUF_SIMPLE(ADV_BUF_LEN); tester_init_gap_cb(BTP_STATUS_SUCCESS); diff --git a/apps/bttester/src/l2cap.c b/apps/bttester/src/l2cap.c index 5c4fc71297..27cc6a9a6e 100644 --- a/apps/bttester/src/l2cap.c +++ b/apps/bttester/src/l2cap.c @@ -249,6 +249,7 @@ tester_l2cap_event(struct ble_l2cap_event *event, void *arg) { struct ble_l2cap_chan_info chan_info; int accept_response; + struct ble_gap_conn_desc conn; switch (event->type) { case BLE_L2CAP_EVENT_COC_CONNECTED: @@ -258,8 +259,6 @@ tester_l2cap_event(struct ble_l2cap_event *event, void *arg) if (event->connect.status) { console_printf("LE COC error: %d\n", event->connect.status); - disconnected_cb(event->connect.conn_handle, - event->connect.chan, &chan_info, arg); return 0; } @@ -288,6 +287,28 @@ tester_l2cap_event(struct ble_l2cap_event *event, void *arg) event->disconnect.chan, &chan_info, arg); return 0; case BLE_L2CAP_EVENT_COC_ACCEPT: + ble_l2cap_get_chan_info(event->accept.chan, &chan_info); + if (chan_info.psm == 0x00F2) { + /* TSPX_psm_authentication_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (!conn.sec_state.authenticated) { + return BLE_HS_EAUTHEN; + } + } else if (chan_info.psm == 0x00F3) { + /* TSPX_psm_authorization_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (!conn.sec_state.encrypted) { + return BLE_HS_EAUTHOR; + } + return BLE_HS_EAUTHOR; + } else if (chan_info.psm == 0x00F4) { + /* TSPX_psm_encryption_key_size_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (conn.sec_state.key_size < 16) { + return BLE_HS_EENCRYPT_KEY_SZ; + } + } + accept_response = POINTER_TO_INT(arg); if (accept_response) { return accept_response; @@ -375,7 +396,7 @@ static void connect(uint8_t *data, uint16_t len) ble_addr_t *addr = (void *) data; uint16_t mtu = htole16(cmd->mtu); int rc; - int i; + int i, j; SYS_LOG_DBG("connect: type: %d addr: %s", addr->type, bt_hex(addr->val, 6)); @@ -397,6 +418,8 @@ static void connect(uint8_t *data, uint16_t len) SYS_LOG_ERR("No free channels"); goto fail; } + /* temporarily mark channel as used to select next one */ + chan->state = 1; rp->chan_ids[i] = chan->chan_id; @@ -407,6 +430,15 @@ static void connect(uint8_t *data, uint16_t len) } } + /* mark selected channels as unused again */ + for (i = 0; i < cmd->num; i++) { + for (j = 0; j < CHANNELS; j++) { + if (rp->chan_ids[i] == channels[j].chan_id) { + channels[j].state = 0; + } + } + } + if (cmd->num == 1) { rc = ble_l2cap_connect(desc.conn_handle, htole16(cmd->psm), mtu, sdu_rx[0], diff --git a/apps/bttester/src/mesh.c b/apps/bttester/src/mesh.c index 8226fe99e1..46bf7699c3 100644 --- a/apps/bttester/src/mesh.c +++ b/apps/bttester/src/mesh.c @@ -41,7 +41,7 @@ extern uint8_t own_addr_type; #define CONTROLLER_INDEX 0 -#define CID_LOCAL 0xffff +#define CID_LOCAL 0x0002 /* Health server data */ #define CUR_FAULTS_MAX 4 @@ -599,7 +599,7 @@ static void net_send(uint8_t *data, uint16_t len) SYS_LOG_DBG("ttl 0x%02x dst 0x%04x payload_len %d", ctx.send_ttl, ctx.addr, cmd->payload_len); - if (!bt_mesh_app_key_get(vnd_app_key_idx)) { + if (!bt_mesh_app_key_exists(vnd_app_key_idx)) { (void)bt_mesh_app_key_add(vnd_app_key_idx, net.net_idx, vnd_app_key); vnd_models[0].keys[0] = vnd_app_key_idx; @@ -937,11 +937,48 @@ static struct bt_test_cb bt_test_cb = { .mesh_trans_incomp_timer_exp = incomp_timer_exp_cb, }; +static void lpn_established(uint16_t friend_addr) +{ + + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + struct mesh_lpn_established_ev ev = { lpn->sub->net_idx, friend_addr, lpn->queue_size, + lpn->recv_win }; + + SYS_LOG_DBG("Friendship (as LPN) established with " + "Friend 0x%04x Queue Size %d Receive Window %d", + friend_addr, lpn->queue_size, lpn->recv_win); + + tester_send(BTP_SERVICE_ID_MESH, MESH_EV_LPN_ESTABLISHED, + CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); +} + +static void lpn_terminated(uint16_t friend_addr) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + struct mesh_lpn_terminated_ev ev = { lpn->sub->net_idx, friend_addr }; + + SYS_LOG_DBG("Friendship (as LPN) lost with Friend " + "0x%04x", friend_addr); + + tester_send(BTP_SERVICE_ID_MESH, MESH_EV_LPN_TERMINATED, + CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); +} + +void lpn_cb(uint16_t friend_addr, bool established) +{ + if (established) { + lpn_established(friend_addr); + } else { + lpn_terminated(friend_addr); + } +} + uint8_t tester_init_mesh(void) { health_pub_init(); if (IS_ENABLED(CONFIG_BT_TESTING)) { + bt_mesh_lpn_set_cb(lpn_cb); bt_test_cb_register(&bt_test_cb); } diff --git a/apps/bttester/syscfg.yml b/apps/bttester/syscfg.yml index db869c341b..f00afeb10f 100644 --- a/apps/bttester/syscfg.yml +++ b/apps/bttester/syscfg.yml @@ -75,12 +75,16 @@ syscfg.defs: description: Maximum MTU size the application can handle value: 230 + BTTESTER_NRPA_TIMEOUT: + description: NRPA rotation timeout in seconds + value: 5 + syscfg.vals: OS_MAIN_STACK_SIZE: 512 SHELL_TASK: 0 SHELL_NEWTMGR: 0 LOG_LEVEL: 12 - MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_COUNT: 100 BLE_MONITOR_RTT: 1 CONSOLE_RTT: 0 @@ -127,7 +131,8 @@ syscfg.vals: BLE_MESH_CFG_CLI: 1 BLE_MESH_RX_SDU_MAX: 110 BLE_MESH_HEALTH_CLI: 1 - BLE_MESH_FRIEND_QUEUE_SIZE: 32 + BLE_MESH_FRIEND_QUEUE_SIZE: 16 + BLE_MESH_SEG_RETRANSMIT_ATTEMPTS: 6 BLE_MESH_RX_SEG_MAX: 13 BLE_MESH_TX_SEG_MSG_COUNT: 2 BLE_MAX_CONNECTIONS: 8 diff --git a/apps/ext_advertiser/pkg.yml b/apps/ext_advertiser/pkg.yml index 097764b206..5a60b2270b 100644 --- a/apps/ext_advertiser/pkg.yml +++ b/apps/ext_advertiser/pkg.yml @@ -25,13 +25,12 @@ pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: pkg.deps: - - nimble/controller - nimble/host - nimble/host/util - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram + - nimble/transport - "@apache-mynewt-core/kernel/os" - "@apache-mynewt-core/sys/console/full" - "@apache-mynewt-core/sys/log/full" diff --git a/apps/ext_advertiser/src/main.c b/apps/ext_advertiser/src/main.c index 6bbc23d598..9cb6c6fe57 100644 --- a/apps/ext_advertiser/src/main.c +++ b/apps/ext_advertiser/src/main.c @@ -86,7 +86,7 @@ start_ext_max_events(uint8_t pattern, bool configure) params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_1M; params.tx_power = 127; - params.sid = pattern % 16; + params.sid = 4; /* allow larger interval, 400 * 0.625ms with 100 events will give up to * ~2.5 seconds for instance @@ -94,7 +94,7 @@ start_ext_max_events(uint8_t pattern, bool configure) params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; params.itvl_max = 400; - /* configure instance 0 */ + /* configure instance 4 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, start_ext_max_events_gap_event, NULL); assert (rc == 0); @@ -184,9 +184,9 @@ start_legacy_duration(uint8_t pattern, bool configure) params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_1M; params.tx_power = 127; - params.sid = pattern % 16; + params.sid = 3; - /* configure instance 0 */ + /* configure instance 3 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, start_legacy_duration_gap_event, NULL); assert (rc == 0); @@ -251,7 +251,7 @@ start_scannable_legacy_ext(void) params.tx_power = 127; params.sid = 2; - /* configure instance 0 */ + /* configure instance 2 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, NULL, NULL); assert (rc == 0); @@ -335,7 +335,7 @@ start_scannable_ext(void) params.tx_power = 127; params.sid = 1; - /* configure instance 0 */ + /* configure instance 1 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, scannable_ext_gap_event, NULL); assert (rc == 0); @@ -387,7 +387,7 @@ start_non_connectable_ext(void) params.tx_power = 127; params.sid = 0; - /* configure instance */ + /* configure instance 0 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, NULL, NULL); assert (rc == 0); @@ -411,6 +411,84 @@ start_non_connectable_ext(void) console_printf("instance %u started (non-con non-scan)\n", instance); } +static void start_periodic(void) +{ + struct ble_gap_periodic_adv_params pparams; + struct ble_gap_ext_adv_params params; + struct ble_hs_adv_fields adv_fields; + struct os_mbuf *data; + uint8_t instance = 5; + ble_addr_t addr; + int rc; + + /* For periodic we use nstance with non-connectable advertising */ + memset (¶ms, 0, sizeof(params)); + + /* advertise using random addr */ + params.own_addr_type = BLE_OWN_ADDR_RANDOM; + + params.primary_phy = BLE_HCI_LE_PHY_1M; + params.secondary_phy = BLE_HCI_LE_PHY_1M; + params.tx_power = 127; + params.sid = 5; + + /* configure instance 5 */ + rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, NULL, NULL); + assert (rc == 0); + + /* set random (NRPA) address for instance */ + rc = ble_hs_id_gen_rnd(1, &addr); + assert (rc == 0); + + rc = ble_gap_ext_adv_set_addr(instance, &addr ); + assert (rc == 0); + + memset(&adv_fields, 0, sizeof(adv_fields)); + adv_fields.name = (const uint8_t *)"nimble with periodic"; + adv_fields.name_len = strlen((char *)adv_fields.name); + + /* Default to legacy PDUs size, mbuf chain will be increased if needed + */ + data = os_msys_get_pkthdr(BLE_HCI_MAX_ADV_DATA_LEN, 0); + assert(data); + + rc = ble_hs_adv_set_fields_mbuf(&adv_fields, data); + assert(rc == 0); + + rc = ble_gap_ext_adv_set_data(instance, data); + assert(rc == 0); + + /* configure periodic advertising */ + memset(&pparams, 0, sizeof(pparams)); + pparams.include_tx_power = 1; + pparams.itvl_min = 160; + pparams.itvl_max = 240; + + rc = ble_gap_periodic_adv_configure(instance, &pparams); + assert(rc == 0); + + /* get mbuf for periodic data */ + data = os_msys_get_pkthdr(sizeof(ext_adv_pattern_1), 0); + assert(data); + + /* fill mbuf with periodic data */ + rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1)); + assert(rc == 0); + + rc = ble_gap_periodic_adv_set_data(instance, data); + assert (rc == 0); + + /* start periodic advertising */ + rc = ble_gap_periodic_adv_start(instance); + assert (rc == 0); + + /* start advertising */ + rc = ble_gap_ext_adv_start(instance, 0, 0); + assert (rc == 0); + + console_printf("instance %u started (periodic)\n", instance); +} + static void on_sync(void) { @@ -435,6 +513,8 @@ on_sync(void) start_legacy_duration(0, true); start_ext_max_events(0, true); + + start_periodic(); } /* diff --git a/apps/ext_advertiser/syscfg.yml b/apps/ext_advertiser/syscfg.yml index 5f5fb54b95..f157ab82b0 100644 --- a/apps/ext_advertiser/syscfg.yml +++ b/apps/ext_advertiser/syscfg.yml @@ -30,6 +30,9 @@ syscfg.vals: # Enable Extended Advertising BLE_EXT_ADV: 1 + # Enable Periodic Advertising + BLE_PERIODIC_ADV: 1 + # Max advertising data size BLE_EXT_ADV_MAX_SIZE: 1650 @@ -37,12 +40,12 @@ syscfg.vals: # to historical reasonds total number of advertising # instances is BLE_MULTI_ADV_INSTANCES + 1 as instance # 0 is always available - BLE_MULTI_ADV_INSTANCES: 4 + BLE_MULTI_ADV_INSTANCES: 5 # Controller uses msys pool for storing advertising data and scan responses. - # Since we advertise a lot of data (~4k in total) at the same time we need + # Since we advertise a lot of data (~6k in total) at the same time we need # to increase block count. - MSYS_1_BLOCK_COUNT: 24 + MSYS_1_BLOCK_COUNT: 32 # Whether to save data to sys/config, or just keep it in RAM. BLE_STORE_CONFIG_PERSIST: 0 diff --git a/apps/mesh_badge/pkg.yml b/apps/mesh_badge/pkg.yml index 0718236f6a..96a42ba6a7 100644 --- a/apps/mesh_badge/pkg.yml +++ b/apps/mesh_badge/pkg.yml @@ -31,9 +31,8 @@ pkg.deps: - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-core/sys/stats/full" - "@apache-mynewt-core/sys/shell" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram + - nimble/transport diff --git a/apps/mesh_badge/src/reel_board.c b/apps/mesh_badge/src/reel_board.c index bc8229377f..5e5f6b4088 100644 --- a/apps/mesh_badge/src/reel_board.c +++ b/apps/mesh_badge/src/reel_board.c @@ -49,8 +49,8 @@ struct font_info { static struct os_dev *epd_dev; static bool pressed; static bool stats_view; -static struct k_delayed_work epd_work; -static struct k_delayed_work long_press_work; +static struct k_work_delayable epd_work; +static struct k_work_delayable long_press_work; static struct { int pin; @@ -61,7 +61,7 @@ static struct { { .pin = RGB_LED_BLU, }, }; -struct k_delayed_work led_timer; +struct k_work_delayable led_timer; static size_t print_line(enum font_size font_size, int row, const char *text, size_t len, bool center) @@ -121,7 +121,7 @@ static size_t get_len(enum font_size font, const char *text) void board_blink_leds(void) { - k_delayed_work_submit(&led_timer, K_MSEC(100)); + k_work_reschedule(&led_timer, K_MSEC(100)); } void board_show_text(const char *text, bool center, int32_t duration) @@ -151,7 +151,7 @@ void board_show_text(const char *text, bool center, int32_t duration) cfb_framebuffer_finalize(epd_dev); if (duration != K_FOREVER) { - k_delayed_work_submit(&epd_work, duration); + k_work_reschedule(&epd_work, duration); } } @@ -381,11 +381,11 @@ static void button_interrupt(struct os_event *ev) printk("Button %s\n", pressed ? "pressed" : "released"); if (pressed) { - k_delayed_work_submit(&long_press_work, LONG_PRESS_TIMEOUT); + k_work_reschedule(&long_press_work, LONG_PRESS_TIMEOUT); return; } - k_delayed_work_cancel(&long_press_work); + k_work_cancel_delayable(&long_press_work); if (!mesh_is_initialized()) { return; @@ -441,7 +441,7 @@ static void led_timeout(struct ble_npl_event *work) i = led_cntr++ % ARRAY_SIZE(leds); hal_gpio_write(leds[i].pin, 0); - k_delayed_work_submit(&led_timer, K_MSEC(100)); + k_work_reschedule(&led_timer, K_MSEC(100)); } static int configure_leds(void) @@ -452,7 +452,7 @@ static int configure_leds(void) hal_gpio_init_out(leds[i].pin, 1); } - k_delayed_work_init(&led_timer, led_timeout); + k_work_init_delayable(&led_timer, led_timeout); return 0; } @@ -466,7 +466,7 @@ static int erase_storage(void) void board_refresh_display(void) { - k_delayed_work_submit(&epd_work, K_NO_WAIT); + k_work_reschedule(&epd_work, K_NO_WAIT); } int board_init(void) @@ -494,8 +494,8 @@ int board_init(void) return -EIO; } - k_delayed_work_init(&epd_work, epd_update); - k_delayed_work_init(&long_press_work, long_press); + k_work_init_delayable(&epd_work, epd_update); + k_work_init_delayable(&long_press_work, long_press); pressed = button_is_pressed(); if (pressed) { diff --git a/docs/btshell/btshell_GAP.rst b/docs/btshell/btshell_GAP.rst index ce6475554d..738d146c5b 100644 --- a/docs/btshell/btshell_GAP.rst +++ b/docs/btshell/btshell_GAP.rst @@ -411,7 +411,7 @@ Advertising with Extended Advertising enabled +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ | | scan\_req\_notif | [``0``-1] | Enable SCAN\_REQ notifications | +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **advertise-set-addr** | | | Configure *random* adress for instance | +| **advertise-set-addr** | | | Configure *random* address for instance | +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ | | instance | [``0``-UINT8\_MAX] | Advertising instance | +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ diff --git a/docs/index.rst b/docs/index.rst index b41b1b283e..b07f1f88d0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -46,7 +46,7 @@ ideal wireless technology for the Internet of Things (IoT). - LE Secure Connections featuring FIPS-compliant algorithms. - LE Data Length Extension for higher throughput - **Coming Soon**: Assigning an Internet Protocol (IP) address - (complaint with the IPv6 or 6LoWPAN standard) to a Bluetooth device + (compliant with the IPv6 or 6LoWPAN standard) to a Bluetooth device through Internet Protocol Support Profile (IPSP) The Bluetooth 5 is backward compatible with previous Bluetooth version diff --git a/nimble/controller/include/controller/ble_ll.h b/nimble/controller/include/controller/ble_ll.h index 24d7db3003..898907a19d 100644 --- a/nimble/controller/include/controller/ble_ll.h +++ b/nimble/controller/include/controller/ble_ll.h @@ -48,7 +48,7 @@ extern "C" { if (hal_debugger_connected()) { \ assert(0);\ } else {\ - ble_ll_hci_ev_send_vendor_err(__FILE__, __LINE__); \ + ble_ll_hci_ev_send_vs_assert(__FILE__, __LINE__); \ while(1) {}\ }\ } @@ -108,11 +108,13 @@ struct ble_ll_obj /* Current Link Layer state */ uint8_t ll_state; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Number of ACL data packets supported */ uint8_t ll_num_acl_pkts; /* ACL data packet size */ uint16_t ll_acl_pkt_size; +#endif /* Preferred PHY's */ uint8_t ll_pref_tx_phys; @@ -129,14 +131,18 @@ struct ble_ll_obj struct ble_ll_pkt_q ll_rx_pkt_q; /* Packet transmit queue */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) struct ble_npl_event ll_tx_pkt_ev; +#endif struct ble_ll_pkt_q ll_tx_pkt_q; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Data buffer overflow event */ struct ble_npl_event ll_dbuf_overflow_ev; /* Number of completed packets event */ struct ble_npl_event ll_comp_pkt_ev; +#endif /* HW error callout */ struct ble_npl_callout ll_hw_err_timer; @@ -214,12 +220,24 @@ extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats; /* States */ #define BLE_LL_STATE_STANDBY (0) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #define BLE_LL_STATE_ADV (1) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) #define BLE_LL_STATE_SCANNING (2) -#define BLE_LL_STATE_INITIATING (3) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_LL_STATE_CONNECTION (4) +#endif +#if MYNEWT_VAL(BLE_LL_DTM) #define BLE_LL_STATE_DTM (5) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) #define BLE_LL_STATE_SYNC (6) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#define BLE_LL_STATE_SCAN_AUX (7) +#endif /* LL Features */ #define BLE_LL_FEAT_LE_ENCRYPTION (0x0000000001) @@ -354,6 +372,7 @@ struct ble_dev_addr #define BLE_LL_EXT_ADV_FLAGS_SIZE (1) #define BLE_LL_EXT_ADV_ADVA_SIZE (6) #define BLE_LL_EXT_ADV_TARGETA_SIZE (6) +#define BLE_LL_EXT_ADV_CTE_INFO_SIZE (1) #define BLE_LL_EXT_ADV_DATA_INFO_SIZE (2) #define BLE_LL_EXT_ADV_AUX_PTR_SIZE (3) #define BLE_LL_EXT_ADV_SYNC_INFO_SIZE (18) diff --git a/nimble/controller/include/controller/ble_ll_conn.h b/nimble/controller/include/controller/ble_ll_conn.h index d7db6878a1..c3073c6e7d 100644 --- a/nimble/controller/include/controller/ble_ll_conn.h +++ b/nimble/controller/include/controller/ble_ll_conn.h @@ -34,8 +34,13 @@ extern "C" { /* Roles */ #define BLE_LL_CONN_ROLE_NONE (0) + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_LL_CONN_ROLE_MASTER (1) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) #define BLE_LL_CONN_ROLE_SLAVE (2) +#endif /* Connection states */ #define BLE_LL_CONN_STATE_IDLE (0) @@ -45,16 +50,6 @@ extern "C" { /* Channel map size */ #define BLE_LL_CONN_CHMAP_LEN (5) -/* Definitions for source clock accuracy */ -#define BLE_MASTER_SCA_251_500_PPM (0) -#define BLE_MASTER_SCA_151_250_PPM (1) -#define BLE_MASTER_SCA_101_150_PPM (2) -#define BLE_MASTER_SCA_76_100_PPM (3) -#define BLE_MASTER_SCA_51_75_PPM (4) -#define BLE_MASTER_SCA_31_50_PPM (5) -#define BLE_MASTER_SCA_21_30_PPM (6) -#define BLE_MASTER_SCA_0_20_PPM (7) - /* Definition for RSSI when the RSSI is unknown */ #define BLE_LL_CONN_UNKNOWN_RSSI (127) @@ -188,28 +183,6 @@ struct hci_conn_update uint16_t max_ce_len; }; -struct hci_ext_conn_params -{ - uint16_t scan_itvl; - uint16_t scan_window; - uint16_t conn_itvl_min; - uint16_t conn_itvl_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -}; - -struct hci_ext_create_conn -{ - uint8_t filter_policy; - uint8_t own_addr_type; - uint8_t peer_addr_type; - uint8_t peer_addr[BLE_DEV_ADDR_LEN]; - uint8_t init_phy_mask; - struct hci_ext_conn_params params[3]; -}; - /* Connection state machine */ struct ble_ll_conn_sm { @@ -224,9 +197,6 @@ struct ble_ll_conn_sm /* RSSI */ int8_t conn_rssi; - /* For privacy */ - int8_t rpa_index; - /* Connection data length management */ uint8_t max_tx_octets; uint8_t max_rx_octets; @@ -240,7 +210,6 @@ struct ble_ll_conn_sm uint16_t rem_max_rx_time; uint16_t eff_max_tx_time; uint16_t eff_max_rx_time; - uint8_t max_tx_octets_phy_mode[BLE_PHY_NUM_MODE]; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) uint16_t host_req_max_tx_time; #endif @@ -327,6 +296,9 @@ struct ble_ll_conn_sm uint8_t own_addr_type; uint8_t peer_addr_type; uint8_t peer_addr[BLE_DEV_ADDR_LEN]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + uint8_t peer_addr_resolved; +#endif /* * XXX: TODO. Could save memory. Have single event at LL and put these @@ -378,11 +350,6 @@ struct ble_ll_conn_sm /* XXX: for now, just store them all */ struct ble_ll_conn_params conn_cp; - struct ble_ll_scan_sm *scansm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct hci_ext_create_conn initial_params; -#endif - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) uint8_t sync_transfer_mode; uint16_t sync_transfer_skip; @@ -408,8 +375,17 @@ struct ble_ll_conn_sm #define CONN_F_AUX_CONN_REQ(csm) ((csm)->csmflags.cfbit.aux_conn_req) /* Role */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define CONN_IS_MASTER(csm) (csm->conn_role == BLE_LL_CONN_ROLE_MASTER) +#else +#define CONN_IS_MASTER(csm) (false) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) #define CONN_IS_SLAVE(csm) (csm->conn_role == BLE_LL_CONN_ROLE_SLAVE) +#else +#define CONN_IS_SLAVE(csm) (false) +#endif /* * Given a handle, returns an active connection state machine (or NULL if the @@ -425,6 +401,34 @@ uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency); void ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event, uint32_t *anchor, uint8_t *anchor_usecs); +struct ble_ll_scan_addr_data; +struct ble_ll_scan_pdu_data; + +uint8_t ble_ll_conn_tx_connect_ind_pducb(uint8_t *dptr, void *pducb_arg, + uint8_t *hdr_byte); +void ble_ll_conn_prepare_connect_ind(struct ble_ll_conn_sm *connsm, + struct ble_ll_scan_pdu_data *pdu_data, + uint8_t adva_type, uint8_t *adva, + uint8_t inita_type, uint8_t *inita, + int rpa_index, uint8_t channel); + +/* Send CONNECT_IND/AUX_CONNECT_REQ */ +int ble_ll_conn_send_connect_req(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t ext); +/* Cancel connection after AUX_CONNECT_REQ was sent */ +void ble_ll_conn_send_connect_req_cancel(void); +/* Signal connection created via CONNECT_IND */ +void ble_ll_conn_created_on_legacy(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t *targeta); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +/* Signal connection created via AUX_CONNECT_REQ */ +void ble_ll_conn_created_on_aux(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t *targeta); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_ctrl.h b/nimble/controller/include/controller/ble_ll_ctrl.h index 15a45b2a08..62e1a53569 100644 --- a/nimble/controller/include/controller/ble_ll_ctrl.h +++ b/nimble/controller/include/controller/ble_ll_ctrl.h @@ -315,7 +315,9 @@ int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status); void ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm); void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm); void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm); -void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line); +void ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line); +void ble_ll_hci_ev_send_vs_llcp_trace(uint8_t type, uint16_t handle, uint16_t count, + void *pdu, size_t length); uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask); uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask); diff --git a/nimble/controller/include/controller/ble_ll_hci.h b/nimble/controller/include/controller/ble_ll_hci.h index 6a9e48e537..a9ea3bb055 100644 --- a/nimble/controller/include/controller/ble_ll_hci.h +++ b/nimble/controller/include/controller/ble_ll_hci.h @@ -43,6 +43,20 @@ extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN]; typedef void (*ble_ll_hci_post_cmd_complete_cb)(void); +#if MYNEWT_VAL(BLE_LL_HCI_VS) +typedef int (* ble_ll_hci_vs_cb_t)(uint16_t ocf, + const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen); + +#define BLE_LL_HCI_VS_CMD(_ocf, _cb) { .ocf = (_ocf), .cb = (_cb) } + +struct ble_ll_hci_vs_cmd { + uint16_t ocf; + ble_ll_hci_vs_cb_t cb; + SLIST_ENTRY(ble_ll_hci_vs_cmd) link; +}; +#endif + /* Initialize LL HCI */ void ble_ll_hci_init(void); @@ -68,6 +82,10 @@ bool ble_ll_hci_adv_mode_ext(void); /* Get TX power compensation rounded to integer dB */ int8_t ble_ll_get_tx_pwr_compensation(void); +#if MYNEWT_VAL(BLE_LL_HCI_VS) +void ble_ll_hci_vs_register(struct ble_ll_hci_vs_cmd *cmds, uint32_t num_cmds); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_plna.h b/nimble/controller/include/controller/ble_ll_plna.h new file mode 100644 index 0000000000..c4fb65ea98 --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_plna.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_PLNA_ +#define H_BLE_LL_PLNA_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_LL_PA) +void ble_ll_plna_pa_init(void); +void ble_ll_plna_pa_enable(void); +void ble_ll_plna_pa_disable(void); +#endif + +#if MYNEWT_VAL(BLE_LL_LNA) +void ble_ll_plna_lna_init(void); +void ble_ll_plna_lna_enable(void); +void ble_ll_plna_lna_disable(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_PLNA_ */ diff --git a/nimble/controller/include/controller/ble_ll_resolv.h b/nimble/controller/include/controller/ble_ll_resolv.h index 228e0a3703..b9ca7fd387 100644 --- a/nimble/controller/include/controller/ble_ll_resolv.h +++ b/nimble/controller/include/controller/ble_ll_resolv.h @@ -72,6 +72,12 @@ int ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len, struct ble_ll_resolv_entry * ble_ll_resolv_list_find(const uint8_t *addr, uint8_t addr_type); +static inline int8_t +ble_ll_resolv_get_idx(struct ble_ll_resolv_entry *rl) +{ + return rl - g_ble_ll_resolv_list; +} + /* Returns true if address resolution is enabled */ uint8_t ble_ll_resolv_enabled(void); diff --git a/nimble/controller/include/controller/ble_ll_rfmgmt.h b/nimble/controller/include/controller/ble_ll_rfmgmt.h index 37b81a88be..5e2d636ff8 100644 --- a/nimble/controller/include/controller/ble_ll_rfmgmt.h +++ b/nimble/controller/include/controller/ble_ll_rfmgmt.h @@ -51,7 +51,7 @@ static inline void ble_ll_rfmgmt_reset(void) { } static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { } static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { } static inline void ble_ll_rfmgmt_release(void) { } -static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; } +static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return os_cputime_get32(); } static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; } #endif diff --git a/nimble/controller/include/controller/ble_ll_scan.h b/nimble/controller/include/controller/ble_ll_scan.h index 139ad5e1f7..a44e431379 100644 --- a/nimble/controller/include/controller/ble_ll_scan.h +++ b/nimble/controller/include/controller/ble_ll_scan.h @@ -80,67 +80,15 @@ struct ble_ll_scan_timing { uint32_t start_time; }; -struct ble_ll_scan_params +struct ble_ll_scan_phy { uint8_t phy; - uint8_t own_addr_type; - uint8_t scan_filt_policy; uint8_t configured; uint8_t scan_type; uint8_t scan_chan; struct ble_ll_scan_timing timing; }; -#define BLE_LL_AUX_HAS_ADVA 0x01 -#define BLE_LL_AUX_HAS_TARGETA 0x02 -#define BLE_LL_AUX_HAS_ADI 0x04 -#define BLE_LL_AUX_IS_MATCHED 0x08 -#define BLE_LL_AUX_IS_TARGETA_RESOLVED 0x10 - -#define BLE_LL_AUX_FLAG_HCI_SENT_ANY 0x02 -#define BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED 0x04 -#define BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED 0x08 -#define BLE_LL_AUX_FLAG_SCAN_COMPLETE 0x10 -#define BLE_LL_AUX_FLAG_SCAN_ERROR 0x20 -#define BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED 0x40 -#define BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED 0x80 - -struct ble_ll_aux_data { - uint8_t flags; - - /* - * Since aux_data can be accessed from ISR and LL, we have separate copies - * of flags to make sure that ISR does not modify flags while LL uses them. - * ISR updates 'flags_isr' and LL adds these to 'flags_ll' which it then - * uses for further processing allowing to update 'flags_isr' if another - * scan for given 'aux_data' is scheduled. Note that flags must not be unset - * while aux_data is valid. - */ - uint8_t flags_isr; - uint8_t flags_ll; - - uint8_t ref_cnt; - uint8_t chan; - uint8_t aux_phy; - uint8_t aux_primary_phy; - uint8_t mode; - uint8_t scanning; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int8_t rpa_index; -#endif - uint16_t adi; - uint32_t offset; - uint8_t offset_units; - uint8_t adva[6]; - uint8_t adva_type; - uint8_t targeta[6]; - uint8_t targeta_type; - uint16_t evt_type; - struct ble_ll_sched_item sch; - struct ble_hci_ev *evt; - struct ble_npl_event ev; -}; - struct ble_ll_scan_pdu_data { uint8_t hdr_byte; /* ScanA for SCAN_REQ and InitA for CONNECT_IND */ @@ -151,10 +99,26 @@ struct ble_ll_scan_pdu_data { uint8_t adva[BLE_DEV_ADDR_LEN]; }; +struct ble_ll_scan_addr_data { + uint8_t *adva; + uint8_t *targeta; + uint8_t *adv_addr; + uint8_t adva_type : 1; + uint8_t targeta_type : 1; + uint8_t adv_addr_type : 1; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + uint8_t adva_resolved : 1; + uint8_t targeta_resolved : 1; + int8_t rpa_index; +#endif +}; + struct ble_ll_scan_sm { uint8_t scan_enabled; + uint8_t own_addr_type; + uint8_t scan_filt_policy; uint8_t scan_filt_dups; uint8_t scan_rsp_pending; uint8_t scan_rsp_cons_fails; @@ -175,36 +139,42 @@ struct ble_ll_scan_sm struct ble_npl_event scan_interrupted_ev; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct hal_timer duration_timer; - struct hal_timer period_timer; - uint32_t duration_ticks; - uint32_t period_ticks; + struct ble_npl_callout duration_timer; + struct ble_npl_callout period_timer; + ble_npl_time_t duration_ticks; + ble_npl_time_t period_ticks; uint8_t ext_scanning; #endif uint8_t restart_timer_needed; - struct ble_ll_aux_data *cur_aux_data; - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_next; - struct ble_ll_scan_params scanp_phys[BLE_LL_SCAN_PHY_NUMBER]; + struct ble_ll_scan_phy *scanp; + struct ble_ll_scan_phy *scanp_next; + struct ble_ll_scan_phy scan_phys[BLE_LL_SCAN_PHY_NUMBER]; + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + /* Connection sm for initiator scan */ + struct ble_ll_conn_sm *connsm; +#endif }; /* Scan types */ #define BLE_SCAN_TYPE_PASSIVE (BLE_HCI_SCAN_TYPE_PASSIVE) #define BLE_SCAN_TYPE_ACTIVE (BLE_HCI_SCAN_TYPE_ACTIVE) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SCAN_TYPE_INITIATE (2) +#endif /*---- HCI ----*/ /* Set scanning parameters */ -int ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_scan_hci_set_params(const uint8_t *cmdbuf, uint8_t len); /* Turn scanning on/off */ -int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_hci_ext_scan_set_enable(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_scan_hci_set_enable(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_scan_hci_set_ext_enable(const uint8_t *cmdbuf, uint8_t len); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_scan_hci_set_ext_params(const uint8_t *cmdbuf, uint8_t len); #endif /*--- Controller Internal API ---*/ @@ -230,13 +200,12 @@ int ble_ll_scan_can_chg_whitelist(void); /* Boolean function returning true if scanning enabled */ int ble_ll_scan_enabled(void); -/* Boolean function returns true if whitelist is enabled for scanning */ -int ble_ll_scan_whitelist_enabled(void); - /* Initialize the scanner when we start initiating */ -struct hci_create_conn; -int ble_ll_scan_initiator_start(struct hci_create_conn *hcc, - struct ble_ll_scan_sm **sm); +struct ble_ll_conn_create_scan; +struct ble_ll_conn_create_params; +int +ble_ll_scan_initiator_start(struct ble_ll_conn_sm *connsm, uint8_t ext, + struct ble_ll_conn_create_scan *cc_scan); /* Returns storage for PDU data (for SCAN_REQ or CONNECT_IND) */ struct ble_ll_scan_pdu_data *ble_ll_scan_get_pdu_data(void); @@ -254,7 +223,11 @@ uint8_t *ble_ll_scan_get_local_rpa(void); void ble_ll_scan_sm_stop(int chk_disable); /* Resume scanning */ +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) void ble_ll_scan_chk_resume(void); +#else +static inline void ble_ll_scan_chk_resume(void) { }; +#endif /* Called when wait for response timer expires in scanning mode */ void ble_ll_scan_wfr_timer_exp(void); @@ -262,30 +235,35 @@ void ble_ll_scan_wfr_timer_exp(void); /* Called when scan could be interrupted */ void ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm); -int ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *init_addr_type, - int *ext_mode); - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_scan_update_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf, - bool *adva_present); - -/* Initialize the extended scanner when we start initiating */ -struct hci_ext_create_conn; -int ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, - struct ble_ll_scan_sm **sm); - /* Called to parse extended advertising*/ -struct ble_ll_aux_data *ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_scan); -void ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_scan); void ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data); #endif /* Called to halt currently running scan */ void ble_ll_scan_halt(void); +uint8_t *ble_ll_get_scan_nrpa(void); +uint8_t ble_ll_scan_get_own_addr_type(void); +uint8_t ble_ll_scan_get_filt_policy(void); +uint8_t ble_ll_scan_get_filt_dups(void); +uint8_t ble_ll_scan_backoff_kick(void); +void ble_ll_scan_backoff_update(int success); + +int ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, bool has_aux, + uint16_t adi); +int ble_ll_scan_dup_update_ext(uint8_t addr_type, uint8_t *addr, bool has_aux, + uint16_t adi); +int ble_ll_scan_have_rxd_scan_rsp(uint8_t *addr, uint8_t txadd, uint8_t ext_adv, + uint16_t adi); +void ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd, uint8_t ext_adv, + uint16_t adi); + +int +ble_ll_scan_rx_filter(uint8_t own_addr_type, uint8_t scan_filt_policy, + struct ble_ll_scan_addr_data *addrd, uint8_t *scan_ok); +int ble_ll_scan_rx_check_init(struct ble_ll_scan_addr_data *addrd); + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_scan_aux.h b/nimble/controller/include/controller/ble_ll_scan_aux.h new file mode 100644 index 0000000000..c7d63b8449 --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_scan_aux.h @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_SCAN_AUX_ +#define H_BLE_LL_SCAN_AUX_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + +struct ble_ll_scan_aux_data; + +void ble_ll_scan_aux_init(void); +int ble_ll_scan_aux_sched(struct ble_ll_scan_aux_data *aux, uint32_t pdu_time, + uint8_t pdu_time_rem, uint32_t aux_ptr); +int ble_ll_scan_aux_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr); +int ble_ll_scan_aux_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok); +void ble_ll_scan_aux_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr); + +void ble_ll_scan_aux_break(struct ble_ll_scan_aux_data *aux); +void ble_ll_scan_aux_wfr_timer_exp(void); +void ble_ll_scan_aux_halt(void); +void ble_ll_scan_aux_sched_remove(struct ble_ll_sched_item *sch); + +int ble_ll_scan_aux_rx_isr_end_on_ext(struct ble_ll_scan_sm *scansm, + struct os_mbuf *rxpdu); +void ble_ll_scan_aux_pkt_in_on_ext(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_SCAN_AUX_ */ diff --git a/nimble/controller/include/controller/ble_ll_sched.h b/nimble/controller/include/controller/ble_ll_sched.h index a614cf0905..45e148cbd6 100644 --- a/nimble/controller/include/controller/ble_ll_sched.h +++ b/nimble/controller/include/controller/ble_ll_sched.h @@ -25,8 +25,8 @@ extern "C" { #endif /* Time per BLE scheduler slot */ -#define BLE_LL_SCHED_USECS_PER_SLOT (1250) -#define BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT (41) /* 1 tick = 30.517 usecs */ +#define BLE_LL_SCHED_USECS_PER_SLOT (1250) +#define BLE_LL_SCHED_TICKS_PER_SLOT (41) /* 1 tick = 30.517 usecs */ /* * Worst case time needed for scheduled advertising item. This is the longest @@ -67,10 +67,10 @@ extern uint8_t g_ble_ll_sched_offset_ticks; #define BLE_LL_SCHED_TYPE_ADV (1) #define BLE_LL_SCHED_TYPE_SCAN (2) #define BLE_LL_SCHED_TYPE_CONN (3) -#define BLE_LL_SCHED_TYPE_AUX_SCAN (4) #define BLE_LL_SCHED_TYPE_DTM (5) #define BLE_LL_SCHED_TYPE_PERIODIC (6) #define BLE_LL_SCHED_TYPE_SYNC (7) +#define BLE_LL_SCHED_TYPE_SCAN_AUX (8) /* Return values for schedule callback. */ #define BLE_LL_SCHED_STATE_RUNNING (0) @@ -159,8 +159,7 @@ int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, ble_ll_sched_adv_new_cb cb, void *arg); /* Schedule periodic advertising event */ -int ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start, - bool after_overlap); +int ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, bool first_event); int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, uint32_t anchor_point, @@ -171,7 +170,7 @@ int ble_ll_sched_sync(struct ble_ll_sched_item *sch, int8_t phy_mode); /* Reschedule an advertising event */ -int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start, +int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t max_delay_ticks); /* Reschedule and advertising pdu */ @@ -199,7 +198,8 @@ int ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, struct ble_ll_scan_sm *scansm, struct ble_ll_aux_data *aux_scan); -int ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode); +int ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch, uint32_t pdu_time, + uint8_t pdu_time_rem, uint32_t offset_us); #endif /* Stop the scheduler */ diff --git a/nimble/controller/include/controller/ble_ll_sync.h b/nimble/controller/include/controller/ble_ll_sync.h index 712af6dffc..8002d2a317 100644 --- a/nimble/controller/include/controller/ble_ll_sync.h +++ b/nimble/controller/include/controller/ble_ll_sync.h @@ -30,6 +30,7 @@ extern "C" { #endif +struct ble_ll_scan_addr_data; struct ble_ll_sync_sm; int ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len); @@ -48,8 +49,7 @@ void ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, uint16_t max_skip, uint32_t sync_timeout); void ble_ll_sync_transfer_disconnected(struct ble_ll_conn_sm *connsm); -void ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, - int rpa_index, uint8_t sid, +void ble_ll_sync_info_event(struct ble_ll_scan_addr_data *addrd, uint8_t sid, struct ble_mbuf_hdr *rxhdr, const uint8_t *syncinfo); diff --git a/nimble/controller/include/controller/ble_phy.h b/nimble/controller/include/controller/ble_phy.h index cd8350d657..47f3afd4ec 100644 --- a/nimble/controller/include/controller/ble_phy.h +++ b/nimble/controller/include/controller/ble_phy.h @@ -202,6 +202,11 @@ void ble_phy_resolv_list_disable(void); #define BLE_PHY_MASK_2M (BLE_HCI_LE_PHY_2M_PREF_MASK) #define BLE_PHY_MASK_CODED (BLE_HCI_LE_PHY_CODED_PREF_MASK) +/* PHY indices (for a zero-based array) */ +#define BLE_PHY_IDX_1M (0) +#define BLE_PHY_IDX_2M (1) +#define BLE_PHY_IDX_CODED (2) + #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)) uint32_t ble_phy_mode_pdu_start_off(int phy); void ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode); diff --git a/nimble/controller/pkg.yml b/nimble/controller/pkg.yml index 96c636798b..9661bb31e8 100644 --- a/nimble/controller/pkg.yml +++ b/nimble/controller/pkg.yml @@ -29,6 +29,10 @@ pkg.req_apis: - ble_driver - ble_transport - stats +pkg.req_apis.BLE_LL_PA: + - ble_ll_pa +pkg.req_apis.BLE_LL_LNA: + - ble_ll_lna pkg.deps: - "@apache-mynewt-core/kernel/os" diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c index cf83b79c38..1e378bc61b 100644 --- a/nimble/controller/src/ble_ll.c +++ b/nimble/controller/src/ble_ll.c @@ -37,13 +37,17 @@ #include "controller/ble_ll_adv.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_scan.h" +#include "controller/ble_ll_scan_aux.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" #include "controller/ble_ll_rfmgmt.h" #include "controller/ble_ll_trace.h" #include "controller/ble_ll_sync.h" +#include "controller/ble_ll_plna.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_hci_priv.h" +#include "ble_ll_priv.h" #if MYNEWT_VAL(BLE_LL_DTM) #include "ble_ll_dtm_priv.h" @@ -61,49 +65,174 @@ * right thing to do. */ +int8_t g_ble_ll_tx_power = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); + /* Supported states */ -#define BLE_LL_S_NCA (0x00000000001) -#define BLE_LL_S_SA (0x00000000002) -#define BLE_LL_S_CA (0x00000000004) -#define BLE_LL_S_HDCA (0x00000000008) -#define BLE_LL_S_PS (0x00000000010) -#define BLE_LL_S_AS (0x00000000020) -#define BLE_LL_S_INIT (0x00000000040) -#define BLE_LL_S_SLAVE (0x00000000080) -#define BLE_LL_S_NCA_PS (0x00000000100) -#define BLE_LL_S_SA_PS (0x00000000200) -#define BLE_LL_S_CA_PS (0x00000000400) -#define BLE_LL_S_HDCA_PS (0x00000000800) -#define BLE_LL_S_NCA_AS (0x00000001000) -#define BLE_LL_S_SA_AS (0x00000002000) -#define BLE_LL_S_CA_AS (0x00000004000) -#define BLE_LL_S_HDCA_AS (0x00000008000) -#define BLE_LL_S_NCA_INIT (0x00000010000) -#define BLE_LL_S_SA_INIT (0x00000020000) -#define BLE_LL_S_NCA_MASTER (0x00000040000) -#define BLE_LL_S_SA_MASTER (0x00000080000) -#define BLE_LL_S_NCA_SLAVE (0x00000100000) -#define BLE_LL_S_SA_SLAVE (0x00000200000) -#define BLE_LL_S_PS_INIT (0x00000400000) -#define BLE_LL_S_AS_INIT (0x00000800000) -#define BLE_LL_S_PS_MASTER (0x00001000000) -#define BLE_LL_S_AS_MASTER (0x00002000000) -#define BLE_LL_S_PS_SLAVE (0x00004000000) -#define BLE_LL_S_AS_SLAVE (0x00008000000) -#define BLE_LL_S_INIT_MASTER (0x00010000000) -#define BLE_LL_S_LDCA (0x00020000000) -#define BLE_LL_S_LDCA_PS (0x00040000000) -#define BLE_LL_S_LDCA_AS (0x00080000000) -#define BLE_LL_S_CA_INIT (0x00100000000) -#define BLE_LL_S_HDCA_INIT (0x00200000000) -#define BLE_LL_S_LDCA_INIT (0x00400000000) -#define BLE_LL_S_CA_MASTER (0x00800000000) -#define BLE_LL_S_HDCA_MASTER (0x01000000000) -#define BLE_LL_S_LDCA_MASTER (0x02000000000) -#define BLE_LL_S_CA_SLAVE (0x04000000000) -#define BLE_LL_S_HDCA_SLAVE (0x08000000000) -#define BLE_LL_S_LDCA_SLAVE (0x10000000000) -#define BLE_LL_S_INIT_SLAVE (0x20000000000) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) +#define BLE_LL_S_NCA ((uint64_t)1 << 0) +#define BLE_LL_S_SA ((uint64_t)1 << 1) +#else +#define BLE_LL_S_NCA ((uint64_t)0 << 0) +#define BLE_LL_S_SA ((uint64_t)0 << 1) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_CA ((uint64_t)1 << 2) +#define BLE_LL_S_HDCA ((uint64_t)1 << 3) +#else +#define BLE_LL_S_CA ((uint64_t)0 << 2) +#define BLE_LL_S_HDCA ((uint64_t)0 << 3) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_PS ((uint64_t)1 << 4) +#define BLE_LL_S_AS ((uint64_t)1 << 5) +#else +#define BLE_LL_S_PS ((uint64_t)0 << 4) +#define BLE_LL_S_AS ((uint64_t)0 << 5) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_INIT ((uint64_t)1 << 6) +#else +#define BLE_LL_S_INIT ((uint64_t)0 << 6) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_SLAVE ((uint64_t)1 << 7) +#else +#define BLE_LL_S_SLAVE ((uint64_t)0 << 7) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_NCA_PS ((uint64_t)1 << 8) +#define BLE_LL_S_SA_PS ((uint64_t)1 << 9) +#else +#define BLE_LL_S_NCA_PS ((uint64_t)0 << 8) +#define BLE_LL_S_SA_PS ((uint64_t)0 << 9) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_CA_PS ((uint64_t)1 << 10) +#define BLE_LL_S_HDCA_PS ((uint64_t)1 << 11) +#else +#define BLE_LL_S_CA_PS ((uint64_t)0 << 10) +#define BLE_LL_S_HDCA_PS ((uint64_t)0 << 11) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_NCA_AS ((uint64_t)1 << 12) +#define BLE_LL_S_SA_AS ((uint64_t)1 << 13) +#else +#define BLE_LL_S_NCA_AS ((uint64_t)0 << 12) +#define BLE_LL_S_SA_AS ((uint64_t)0 << 13) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_CA_AS ((uint64_t)1 << 14) +#define BLE_LL_S_HDCA_AS ((uint64_t)1 << 15) +#else +#define BLE_LL_S_CA_AS ((uint64_t)0 << 14) +#define BLE_LL_S_HDCA_AS ((uint64_t)0 << 15) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_NCA_INIT ((uint64_t)1 << 16) +#define BLE_LL_S_SA_INIT ((uint64_t)1 << 17) +#define BLE_LL_S_NCA_MASTER ((uint64_t)1 << 18) +#define BLE_LL_S_SA_MASTER ((uint64_t)1 << 19) +#else +#define BLE_LL_S_NCA_INIT ((uint64_t)0 << 16) +#define BLE_LL_S_SA_INIT ((uint64_t)0 << 17) +#define BLE_LL_S_NCA_MASTER ((uint64_t)0 << 18) +#define BLE_LL_S_SA_MASTER ((uint64_t)0 << 19) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_NCA_SLAVE ((uint64_t)1 << 20) +#define BLE_LL_S_SA_SLAVE ((uint64_t)1 << 21) +#else +#define BLE_LL_S_NCA_SLAVE ((uint64_t)0 << 20) +#define BLE_LL_S_SA_SLAVE ((uint64_t)0 << 21) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +/* We do not support passive scanning while initiating yet */ +#define BLE_LL_S_PS_INIT ((uint64_t)0 << 22) +/* We do not support active scanning while initiating yet */ +#define BLE_LL_S_AS_INIT ((uint64_t)0 << 23) +#define BLE_LL_S_PS_MASTER ((uint64_t)1 << 24) +#define BLE_LL_S_AS_MASTER ((uint64_t)1 << 25) +#else +#define BLE_LL_S_PS_INIT ((uint64_t)0 << 22) +#define BLE_LL_S_AS_INIT ((uint64_t)0 << 23) +#define BLE_LL_S_PS_MASTER ((uint64_t)0 << 24) +#define BLE_LL_S_AS_MASTER ((uint64_t)0 << 25) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_PS_SLAVE ((uint64_t)1 << 26) +#define BLE_LL_S_AS_SLAVE ((uint64_t)1 << 27) +#else +#define BLE_LL_S_PS_SLAVE ((uint64_t)0 << 26) +#define BLE_LL_S_AS_SLAVE ((uint64_t)0 << 27) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_INIT_MASTER ((uint64_t)1 << 28) +#else +#define BLE_LL_S_INIT_MASTER ((uint64_t)0 << 28) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_LDCA ((uint64_t)1 << 29) +#else +#define BLE_LL_S_LDCA ((uint64_t)0 << 29) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_LDCA_PS ((uint64_t)1 << 30) +#define BLE_LL_S_LDCA_AS ((uint64_t)1 << 31) +#else +#define BLE_LL_S_LDCA_PS ((uint64_t)0 << 30) +#define BLE_LL_S_LDCA_AS ((uint64_t)0 << 31) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_CA_INIT ((uint64_t)1 << 32) +#define BLE_LL_S_HDCA_INIT ((uint64_t)1 << 33) +#define BLE_LL_S_LDCA_INIT ((uint64_t)1 << 34) +#else +#define BLE_LL_S_CA_INIT ((uint64_t)0 << 32) +#define BLE_LL_S_HDCA_INIT ((uint64_t)0 << 33) +#define BLE_LL_S_LDCA_INIT ((uint64_t)0 << 34) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_CA_MASTER ((uint64_t)1 << 35) +#define BLE_LL_S_HDCA_MASTER ((uint64_t)1 << 36) +#define BLE_LL_S_LDCA_MASTER ((uint64_t)1 << 37) +#else +#define BLE_LL_S_CA_MASTER ((uint64_t)0 << 35) +#define BLE_LL_S_HDCA_MASTER ((uint64_t)0 << 36) +#define BLE_LL_S_LDCA_MASTER ((uint64_t)0 << 37) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_CA_SLAVE ((uint64_t)1 << 38) +#define BLE_LL_S_HDCA_SLAVE ((uint64_t)1 << 39) +#define BLE_LL_S_LDCA_SLAVE ((uint64_t)1 << 40) +#else +#define BLE_LL_S_CA_SLAVE ((uint64_t)0 << 38) +#define BLE_LL_S_HDCA_SLAVE ((uint64_t)0 << 39) +#define BLE_LL_S_LDCA_SLAVE ((uint64_t)0 << 40) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_INIT_SLAVE ((uint64_t)1 << 41) +#else +#define BLE_LL_S_INIT_SLAVE ((uint64_t)0 << 41) +#endif #define BLE_LL_SUPPORTED_STATES \ ( \ @@ -223,8 +352,10 @@ STATS_NAME_START(ble_ll_stats) STATS_NAME_END(ble_ll_stats) static void ble_ll_event_rx_pkt(struct ble_npl_event *ev); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_event_tx_pkt(struct ble_npl_event *ev); static void ble_ll_event_dbuf_overflow(struct ble_npl_event *ev); +#endif #if MYNEWT @@ -576,10 +707,23 @@ ble_ll_set_random_addr(const uint8_t *cmdbuf, uint8_t len, bool hci_adv_ext) * Test specification extends this also to initiating. */ - if (g_ble_ll_conn_create_sm || ble_ll_scan_enabled() || - (!hci_adv_ext && ble_ll_adv_enabled())) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (g_ble_ll_conn_create_sm.connsm) { return BLE_ERR_CMD_DISALLOWED; } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_scan_enabled()){ + return BLE_ERR_CMD_DISALLOWED; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + if (!hci_adv_ext && ble_ll_adv_enabled()) { + return BLE_ERR_CMD_DISALLOWED; + } +#endif if (!ble_ll_is_valid_random_addr(cmd->addr)) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -588,12 +732,14 @@ ble_ll_set_random_addr(const uint8_t *cmdbuf, uint8_t len, bool hci_adv_ext) memcpy(g_random_addr, cmd->addr, BLE_DEV_ADDR_LEN); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* For instance 0 we need same address if legacy advertising might be * used. If extended advertising is in use than this command doesn't * affect instance 0. */ if (!hci_adv_ext) ble_ll_adv_set_random_addr(cmd->addr, 0); +#endif #endif return BLE_ERR_SUCCESS; @@ -667,27 +813,35 @@ ble_ll_wfr_timer_exp(void *arg) /* If we have started a reception, there is nothing to do here */ if (!rx_start) { switch (lls) { +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: ble_ll_adv_wfr_timer_exp(); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_STATE_CONNECTION: ble_ll_conn_wfr_timer_exp(); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_LL_STATE_SCANNING: ble_ll_scan_wfr_timer_exp(); break; - case BLE_LL_STATE_INITIATING: - ble_ll_conn_init_wfr_timer_exp(); - break; -#if MYNEWT_VAL(BLE_LL_DTM) - case BLE_LL_STATE_DTM: - ble_ll_dtm_wfr_timer_exp(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + ble_ll_scan_aux_wfr_timer_exp(); break; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) case BLE_LL_STATE_SYNC: ble_ll_sync_wfr_timer_exp(); break; +#endif +#endif +#if MYNEWT_VAL(BLE_LL_DTM) + case BLE_LL_STATE_DTM: + ble_ll_dtm_wfr_timer_exp(); + break; #endif default: break; @@ -703,6 +857,7 @@ ble_ll_wfr_timer_exp(void *arg) * Context: Link layer task * */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_tx_pkt_in(void) { @@ -742,6 +897,7 @@ ble_ll_tx_pkt_in(void) ble_ll_conn_tx_pkt_in(om, handle, length); } } +#endif /** * Count Link Layer statistics for received PDUs @@ -758,7 +914,12 @@ ble_ll_count_rx_stats(struct ble_mbuf_hdr *hdr, uint16_t len, uint8_t pdu_type) bool connection_data; crcok = BLE_MBUF_HDR_CRC_OK(hdr); + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) connection_data = (BLE_MBUF_HDR_RX_STATE(hdr) == BLE_LL_STATE_CONNECTION); +#else + connection_data = false; +#endif #if MYNEWT_VAL(BLE_LL_DTM) /* Reuse connection stats for DTM */ @@ -825,29 +986,37 @@ ble_ll_rx_pkt_in(void) /* Process the data or advertising pdu */ /* Process the PDU */ switch (BLE_MBUF_HDR_RX_STATE(ble_hdr)) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_STATE_CONNECTION: ble_ll_conn_rx_data_pdu(m, ble_hdr); /* m is going to be free by function above */ m = NULL; break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: ble_ll_adv_rx_pkt_in(pdu_type, rxbuf, ble_hdr); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_LL_STATE_SCANNING: ble_ll_scan_rx_pkt_in(pdu_type, m, ble_hdr); break; - case BLE_LL_STATE_INITIATING: - ble_ll_init_rx_pkt_in(pdu_type, rxbuf, ble_hdr); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + case BLE_LL_STATE_SYNC: + ble_ll_sync_rx_pkt_in(m, ble_hdr); + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + ble_ll_scan_aux_rx_pkt_in(m, ble_hdr); break; +#endif +#endif #if MYNEWT_VAL(BLE_LL_DTM) case BLE_LL_STATE_DTM: ble_ll_dtm_rx_pkt_in(m, ble_hdr); break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_STATE_SYNC: - ble_ll_sync_rx_pkt_in(m, ble_hdr); - break; #endif default: /* Any other state should never occur */ @@ -876,6 +1045,7 @@ ble_ll_rx_pdu_in(struct os_mbuf *rxpdu) ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_rx_pkt_ev); } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /** * Called to put a packet on the Link Layer transmit packet queue. * @@ -906,6 +1076,7 @@ ble_ll_data_buffer_overflow(void) { ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_dbuf_overflow_ev); } +#endif /** * Called when a HW error occurs. @@ -963,27 +1134,35 @@ ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *rxhdr) pdu_type); switch (g_ble_ll_data.ll_state) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_STATE_CONNECTION: rc = ble_ll_conn_rx_isr_start(rxhdr, ble_phy_access_addr_get()); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: rc = ble_ll_adv_rx_isr_start(pdu_type); break; - case BLE_LL_STATE_INITIATING: - rc = ble_ll_init_rx_isr_start(pdu_type, rxhdr); - break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_LL_STATE_SCANNING: rc = ble_ll_scan_rx_isr_start(pdu_type, &rxhdr->rxinfo.flags); break; -#if MYNEWT_VAL(BLE_LL_DTM) - case BLE_LL_STATE_DTM: - rc = ble_ll_dtm_rx_isr_start(rxhdr, ble_phy_access_addr_get()); - break; -#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) case BLE_LL_STATE_SYNC: rc = ble_ll_sync_rx_isr_start(pdu_type, rxhdr); break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + rc = ble_ll_scan_aux_rx_isr_start(pdu_type, rxhdr); + break; +#endif +#endif +#if MYNEWT_VAL(BLE_LL_DTM) + case BLE_LL_STATE_DTM: + rc = ble_ll_dtm_rx_isr_start(rxhdr, ble_phy_access_addr_get()); + break; #endif default: /* Should not be in this state! */ @@ -1035,12 +1214,14 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) } #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_CONNECTION) { rc = ble_ll_conn_rx_isr_end(rxbuf, rxhdr); return rc; } +#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_SYNC) { rc = ble_ll_sync_rx_isr_end(rxbuf, rxhdr); return rc; @@ -1088,6 +1269,7 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) /* Hand packet to the appropriate state machine (if crc ok) */ rxpdu = NULL; switch (BLE_MBUF_HDR_RX_STATE(rxhdr)) { +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: if (!badpkt) { rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); @@ -1097,6 +1279,8 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) } rc = ble_ll_adv_rx_isr_end(pdu_type, rxpdu, crcok); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_LL_STATE_SCANNING: if (!badpkt) { rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); @@ -1106,9 +1290,18 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) } rc = ble_ll_scan_rx_isr_end(rxpdu, crcok); break; - case BLE_LL_STATE_INITIATING: - rc = ble_ll_init_rx_isr_end(rxbuf, crcok, rxhdr); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + if (!badpkt) { + rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); + if (rxpdu) { + ble_phy_rxpdu_copy(rxbuf, rxpdu); + } + } + rc = ble_ll_scan_aux_rx_isr_end(rxpdu, crcok); break; +#endif +#endif default: rc = -1; STATS_INC(ble_ll_stats, bad_ll_state); @@ -1164,6 +1357,7 @@ ble_ll_event_rx_pkt(struct ble_npl_event *ev) ble_ll_rx_pkt_in(); } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_event_tx_pkt(struct ble_npl_event *ev) { @@ -1181,6 +1375,7 @@ ble_ll_event_comp_pkts(struct ble_npl_event *ev) { ble_ll_conn_num_comp_pkts_event_send(NULL); } +#endif /** * Link Layer task. @@ -1198,7 +1393,7 @@ ble_ll_task(void *arg) ble_phy_init(); /* Set output power to 1mW (0 dBm) */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); + ble_phy_txpwr_set(g_ble_ll_tx_power); /* Register callback for transport */ ble_hci_trans_cfg_ll(ble_ll_hci_cmd_rx, NULL, ble_ll_hci_acl_rx, NULL); @@ -1226,6 +1421,10 @@ void ble_ll_state_set(uint8_t ll_state) { g_ble_ll_data.ll_state = ll_state; + + if (ll_state == BLE_LL_STATE_STANDBY) { + BLE_LL_DEBUG_GPIO(SCHED_ITEM, 0); + } } /** @@ -1293,9 +1492,11 @@ ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) { return BLE_ERR_CMD_DISALLOWED; } +#endif if ((cmd->bit_num > 0x3F) || (cmd->val > 1)) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -1402,19 +1603,23 @@ ble_ll_reset(void) OS_ENTER_CRITICAL(sr); ble_phy_disable(); ble_ll_sched_stop(); +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) ble_ll_scan_reset(); +#endif ble_ll_rfmgmt_reset(); OS_EXIT_CRITICAL(sr); +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* Stop any advertising */ ble_ll_adv_reset(); +#endif #if MYNEWT_VAL(BLE_LL_DTM) ble_ll_dtm_reset(); #endif /* Stop sync */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) ble_ll_sync_reset(); #endif @@ -1429,8 +1634,10 @@ ble_ll_reset(void) g_ble_ll_data.ll_pref_tx_phys = 0; g_ble_ll_data.ll_pref_rx_phys = 0; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Reset connection module */ ble_ll_conn_module_reset(); +#endif /* All this does is re-initialize the event masks so call the hci init */ ble_ll_hci_init(); @@ -1452,6 +1659,14 @@ ble_ll_reset(void) ble_ll_resolv_list_reset(); #endif + +#if MYNEWT_VAL(BLE_LL_PA) + ble_ll_plna_pa_init(); +#endif +#if MYNEWT_VAL(BLE_LL_LNA) + ble_ll_plna_lna_init(); +#endif + /* Re-initialize the PHY */ rc = ble_phy_init(); @@ -1553,6 +1768,10 @@ ble_ll_init(void) { int rc; uint64_t features; +#if MYNEWT_VAL(BLE_LL_PUBLIC_DEV_ADDR) + uint64_t pub_dev_addr; + int i; +#endif ble_addr_t addr; struct ble_ll_obj *lldata; @@ -1564,10 +1783,17 @@ ble_ll_init(void) /* Set public device address if not already set */ if (ble_ll_is_addr_empty(g_dev_addr)) { - /* Use sycfg address if configured, otherwise try to read from HW */ - if (!ble_ll_is_addr_empty(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR))) { - memcpy(g_dev_addr, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), BLE_DEV_ADDR_LEN); - } else { +#if MYNEWT_VAL(BLE_LL_PUBLIC_DEV_ADDR) + pub_dev_addr = MYNEWT_VAL(BLE_LL_PUBLIC_DEV_ADDR); + + for (i = 0; i < BLE_DEV_ADDR_LEN; i++) { + g_dev_addr[i] = pub_dev_addr & 0xff; + pub_dev_addr >>= 8; + } +#else + memcpy(g_dev_addr, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), BLE_DEV_ADDR_LEN); +#endif + if (ble_ll_is_addr_empty(g_dev_addr)) { rc = ble_hw_get_public_addr(&addr); if (!rc) { memcpy(g_dev_addr, &addr.val[0], BLE_DEV_ADDR_LEN); @@ -1580,9 +1806,11 @@ ble_ll_init(void) /* Get pointer to global data object */ lldata = &g_ble_ll_data; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Set acl pkt size and number */ lldata->ll_num_acl_pkts = MYNEWT_VAL(BLE_ACL_BUF_COUNT); lldata->ll_acl_pkt_size = MYNEWT_VAL(BLE_ACL_BUF_SIZE); +#endif /* Initialize eventq */ ble_npl_eventq_init(&lldata->ll_evq); @@ -1593,11 +1821,15 @@ ble_ll_init(void) /* Initialize transmit (from host) and receive packet (from phy) event */ ble_npl_event_init(&lldata->ll_rx_pkt_ev, ble_ll_event_rx_pkt, NULL); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) ble_npl_event_init(&lldata->ll_tx_pkt_ev, ble_ll_event_tx_pkt, NULL); +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Initialize data buffer overflow event and completed packets */ ble_npl_event_init(&lldata->ll_dbuf_overflow_ev, ble_ll_event_dbuf_overflow, NULL); ble_npl_event_init(&lldata->ll_comp_pkt_ev, ble_ll_event_comp_pkts, NULL); +#endif /* Initialize the HW error timer */ ble_npl_callout_init(&g_ble_ll_data.ll_hw_err_timer, @@ -1611,14 +1843,20 @@ ble_ll_init(void) /* Init the scheduler */ ble_ll_sched_init(); +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* Initialize advertiser */ ble_ll_adv_init(); +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) /* Initialize a scanner */ ble_ll_scan_init(); +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Initialize the connection module */ ble_ll_conn_module_init(); +#endif /* Set the supported features. NOTE: we always support extended reject. */ features = BLE_LL_FEAT_EXTENDED_REJ; @@ -1664,8 +1902,10 @@ ble_ll_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) features |= BLE_LL_FEAT_PERIODIC_ADV; +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) ble_ll_sync_init(); #endif +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) features |= BLE_LL_FEAT_SYNC_TRANS_RECV; @@ -1700,6 +1940,10 @@ ble_ll_init(void) ble_ll_dtm_init(); #endif +#if MYNEWT_VAL(BLE_LL_HCI_VS) + ble_ll_hci_vs_init(); +#endif + #if MYNEWT /* Initialize the LL task */ os_task_init(&g_ble_ll_task, "ble_ll", ble_ll_task, NULL, diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c index 72c4e7d67d..db17dc4c22 100644 --- a/nimble/controller/src/ble_ll_adv.c +++ b/nimble/controller/src/ble_ll_adv.c @@ -41,6 +41,9 @@ #include "controller/ble_ll_utils.h" #include "controller/ble_ll_rfmgmt.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_priv.h" + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* XXX: TODO * 1) Need to look at advertising and scan request PDUs. Do I allocate these @@ -110,7 +113,6 @@ struct ble_ll_adv_sm uint32_t adv_event_start_time; uint32_t adv_pdu_start_time; uint32_t adv_end_time; - uint32_t adv_rpa_timer; uint8_t adva[BLE_DEV_ADDR_LEN]; uint8_t adv_rpa[BLE_DEV_ADDR_LEN]; uint8_t peer_addr[BLE_DEV_ADDR_LEN]; @@ -119,7 +121,9 @@ struct ble_ll_adv_sm struct os_mbuf *new_adv_data; struct os_mbuf *scan_rsp_data; struct os_mbuf *new_scan_rsp_data; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint8_t *conn_comp_ev; +#endif struct ble_npl_event adv_txdone_ev; struct ble_ll_sched_item adv_sch; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) @@ -207,6 +211,8 @@ struct ble_ll_adv_sm struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_ADV_INSTANCES]; struct ble_ll_adv_sm *g_ble_ll_cur_adv_sm; +static void ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm); + static struct ble_ll_adv_sm * ble_ll_adv_sm_find_configured(uint8_t instance) { @@ -551,11 +557,6 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) /* only ADV_EXT_IND goes on primary advertising channels */ pdu_type = BLE_ADV_PDU_TYPE_ADV_EXT_IND; - /* Set TxAdd to random if needed. */ - if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { - pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND; - } - *hdr_byte = pdu_type; adv_mode = 0; @@ -958,6 +959,7 @@ struct aux_conn_rsp_data { * * @param advsm */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static uint8_t ble_ll_adv_aux_conn_rsp_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) @@ -1006,6 +1008,7 @@ ble_ll_adv_aux_conn_rsp_pdu_make(uint8_t *dptr, void *pducb_arg, return pdulen; } #endif +#endif /** * Called to indicate the advertising event is over. @@ -1021,7 +1024,7 @@ ble_ll_adv_tx_done(void *arg) struct ble_ll_adv_sm *advsm; /* reset power to max after advertising */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); + ble_phy_txpwr_set(g_ble_ll_tx_power); advsm = (struct ble_ll_adv_sm *)arg; @@ -1055,12 +1058,7 @@ ble_ll_adv_tx_done(void *arg) void ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm) { - /* - * Need to set advertising channel to final chan so new event gets - * scheduled. - */ - advsm->adv_chan = ble_ll_adv_final_chan(advsm); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_adv_drop_event(advsm); } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) @@ -1536,7 +1534,8 @@ ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm) * scheduled aux will fit inside duration. If not, remove it from scheduler * so advertising will stop after current aux. */ - if (advsm->duration && (aux_next->sch.end_time > advsm->adv_end_time)) { + if (advsm->duration && + CPUTIME_GT(aux_next->sch.end_time, advsm->adv_end_time)) { ble_ll_sched_rmv_elem(&aux_next->sch); } } @@ -1666,7 +1665,7 @@ ble_ll_adv_aux_schedule(struct ble_ll_adv_sm *advsm) * not start extended advertising event which we cannot finish in time. */ if (advsm->duration && - (AUX_CURRENT(advsm)->sch.end_time > advsm->adv_end_time)) { + CPUTIME_GT(AUX_CURRENT(advsm)->sch.end_time, advsm->adv_end_time)) { ble_ll_adv_sm_stop_timeout(advsm); } } @@ -1689,7 +1688,7 @@ ble_ll_adv_halt(void) ble_ll_trace_u32(BLE_LL_TRACE_ID_ADV_HALT, advsm->adv_instance); - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); + ble_phy_txpwr_set(g_ble_ll_tx_power); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) if (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING) { @@ -1758,6 +1757,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) adv_filter_policy = cmd->filter_policy; switch (cmd->type) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: adv_filter_policy = BLE_HCI_ADV_FILT_NONE; memcpy(advsm->peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); @@ -1777,6 +1777,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) case BLE_HCI_ADV_TYPE_ADV_IND: props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND; break; +#endif case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN; break; @@ -1943,11 +1944,13 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm) ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* If there is an event buf we need to free it */ if (advsm->conn_comp_ev) { ble_hci_trans_buf_free(advsm->conn_comp_ev); advsm->conn_comp_ev = NULL; } +#endif ble_ll_adv_active_chanset_clear(advsm); @@ -1970,6 +1973,7 @@ ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm) } #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* * For high duty directed advertising we need to send connection * complete event with proper status @@ -1979,6 +1983,7 @@ ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm) advsm->conn_comp_ev, advsm); advsm->conn_comp_ev = NULL; } +#endif /* Disable advertising */ ble_ll_adv_sm_stop(advsm); @@ -2000,11 +2005,13 @@ ble_ll_adv_sm_stop_limit_reached(struct ble_ll_adv_sm *advsm) * be used if HD directed advertising was terminated before timeout due to * events count limit. For now just use same code as with duration timeout. */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { ble_ll_conn_comp_event_send(NULL, BLE_ERR_DIR_ADV_TMO, advsm->conn_comp_ev, advsm); advsm->conn_comp_ev = NULL; } +#endif /* Disable advertising */ ble_ll_adv_sm_stop(advsm); @@ -2106,8 +2113,8 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) static void ble_ll_adv_sync_tx_done(struct ble_ll_adv_sm *advsm) { - /* reset power to max after advertising */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); + /* reset power to default after advertising */ + ble_phy_txpwr_set(g_ble_ll_tx_power); /* for sync we trace a no pri nor sec set */ ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance, 0); @@ -2289,7 +2296,6 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, { struct ble_ll_adv_sync *sync; struct ble_ll_sched_item *sch; - uint32_t sch_start; uint32_t max_usecs; uint8_t chan; int rc; @@ -2332,7 +2338,7 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, sch->end_time = sch->start_time + ble_ll_usecs_to_ticks_round_up(max_usecs); sch->start_time -= g_ble_ll_sched_offset_ticks; - rc = ble_ll_sched_periodic_adv(sch, &sch_start, first_pdu); + rc = ble_ll_sched_periodic_adv(sch, first_pdu); if (rc) { STATS_INC(ble_ll_stats, periodic_adv_drop_event); ble_npl_eventq_put(&g_ble_ll_data.ll_evq, @@ -2340,7 +2346,7 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, return; } - sync->start_time = sch_start + g_ble_ll_sched_offset_ticks; + sync->start_time = sch->start_time + g_ble_ll_sched_offset_ticks; assert(first_pdu || (sync->start_time == advsm->periodic_adv_event_start_time)); @@ -2424,8 +2430,8 @@ ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm) sync_next); /* if we are pass advertising interval, drop chain */ - if (sch->end_time > advsm->periodic_adv_event_start_time + - advsm->periodic_adv_itvl_ticks) { + if (CPUTIME_GT(sch->end_time, advsm->periodic_adv_event_start_time + + advsm->periodic_adv_itvl_ticks)) { STATS_INC(ble_ll_stats, periodic_chain_drop_event); ble_ll_sched_rmv_elem(&sync->sch); ble_npl_eventq_put(&g_ble_ll_data.ll_evq, @@ -2638,7 +2644,6 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) { uint8_t adv_chan; uint8_t *addr; - uint8_t *evbuf; uint32_t start_delay_us; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) uint32_t access_addr; @@ -2666,16 +2671,17 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) * Get an event with which to send the connection complete event if * this is connectable */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { /* We expect this to be NULL but if not we wont allocate one... */ if (advsm->conn_comp_ev == NULL) { - evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!evbuf) { + advsm->conn_comp_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + if (!advsm->conn_comp_ev) { return BLE_ERR_MEM_CAPACITY; } - advsm->conn_comp_ev = evbuf; } } +#endif /* Set advertising address */ if ((advsm->own_addr_type & 1) == 0) { @@ -3291,9 +3297,11 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, /* if legacy bit is set possible values are limited */ switch (props) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND: case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR: case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR: +#endif case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN: case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN: break; @@ -3302,6 +3310,12 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, goto done; } } else { +#if !MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { + rc = BLE_ERR_INV_HCI_CMD_PARMS; + goto done; + } +#endif /* HD directed advertising allowed only on legacy PDUs */ if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { rc = BLE_ERR_INV_HCI_CMD_PARMS; @@ -4105,6 +4119,7 @@ ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, * @param [in] addr_type Public address (0) or random address (1). * @return Return 1 if already connected, 0 otherwise. */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static int ble_ll_adv_already_connected(const uint8_t* addr, uint8_t addr_type) { @@ -4127,6 +4142,7 @@ ble_ll_adv_already_connected(const uint8_t* addr, uint8_t addr_type) return 0; } +#endif /** * Called when the LL receives a scan request or connection request @@ -4152,9 +4168,11 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) uint8_t *peer; struct ble_mbuf_hdr *ble_hdr; struct ble_ll_adv_sm *advsm; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) struct aux_conn_rsp_data rsp_data; #endif +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) struct ble_ll_resolv_entry *rl; #endif @@ -4261,6 +4279,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) STATS_INC(ble_ll_stats, scan_rsp_txg); } } else if (pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* See if the device is already connected */ if (ble_ll_adv_already_connected(peer, peer_addr_type)) { return -1; @@ -4293,6 +4312,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD); STATS_INC(ble_ll_stats, aux_conn_rsp_tx); } +#endif #endif } @@ -4309,6 +4329,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) * * @return 0: no connection started. 1: connection started */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static int ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, struct ble_ll_adv_sm *advsm) @@ -4399,6 +4420,7 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, return valid; } +#endif /** * Called on phy rx pdu end when in advertising state. @@ -4489,7 +4511,7 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr) #endif /* - * It is possible that advertising was stopped and a packet plcaed on the + * It is possible that advertising was stopped and a packet placed on the * LL receive packet queue. In this case, just ignore the received packet * as the advertising state machine is no longer "valid" */ @@ -4507,9 +4529,11 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr) adv_event_over = 1; if (BLE_MBUF_HDR_CRC_OK(hdr)) { if (ptype == BLE_ADV_PDU_TYPE_CONNECT_IND) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (ble_ll_adv_conn_req_rxd(rxbuf, hdr, advsm)) { adv_event_over = 0; } +#endif } else { if ((ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) && (hdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_TXD)) { @@ -4594,13 +4618,15 @@ ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm) static void ble_ll_adv_reschedule_event(struct ble_ll_adv_sm *advsm) { - int rc; - uint32_t start_time; + struct ble_ll_sched_item *sch; uint32_t max_delay_ticks; + int rc; assert(advsm->adv_enabled); - if (!advsm->adv_sch.enqueued) { + sch = &advsm->adv_sch; + + if (!sch->enqueued) { if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { max_delay_ticks = 0; } else { @@ -4608,16 +4634,15 @@ ble_ll_adv_reschedule_event(struct ble_ll_adv_sm *advsm) os_cputime_usecs_to_ticks(BLE_LL_ADV_DELAY_MS_MAX * 1000); } - rc = ble_ll_sched_adv_reschedule(&advsm->adv_sch, &start_time, - max_delay_ticks); + rc = ble_ll_sched_adv_reschedule(sch, max_delay_ticks); if (rc) { ble_ll_adv_drop_event(advsm); return; } - start_time += g_ble_ll_sched_offset_ticks; - advsm->adv_event_start_time = start_time; - advsm->adv_pdu_start_time = start_time; + advsm->adv_event_start_time = sch->start_time + + g_ble_ll_sched_offset_ticks; + advsm->adv_pdu_start_time = advsm->adv_event_start_time; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) @@ -4739,7 +4764,8 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) /* If we're past aux (unlikely, but can happen), just drop an event */ if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && advsm->aux_active && - advsm->adv_pdu_start_time > AUX_CURRENT(advsm)->start_time) { + CPUTIME_GT(advsm->adv_pdu_start_time, + AUX_CURRENT(advsm)->start_time)) { ble_ll_adv_drop_event(advsm); return; } @@ -4751,7 +4777,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) /* check if advertising timed out */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (advsm->duration && - advsm->adv_pdu_start_time >= advsm->adv_end_time) { + CPUTIME_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) { /* Legacy PDUs need to be stop here. * For ext adv it will be stopped when AUX is done (unless it was * dropped so check if AUX is active here as well). @@ -4765,7 +4791,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) } #else if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) && - (advsm->adv_pdu_start_time >= advsm->adv_end_time)) { + CPUTIME_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) { ble_ll_adv_sm_stop_timeout(advsm); return; } @@ -4869,7 +4895,8 @@ ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm) ble_ll_scan_chk_resume(); /* Check if advertising timed out */ - if (advsm->duration && (advsm->adv_pdu_start_time >= advsm->adv_end_time)) { + if (advsm->duration && + CPUTIME_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) { ble_ll_adv_sm_stop_timeout(advsm); return; } @@ -4943,11 +4970,11 @@ ble_ll_adv_can_chg_whitelist(void) * * @return uint8_t* Pointer to event buffer */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) void ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) { - uint8_t *evbuf; struct ble_ll_adv_sm *advsm; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) @@ -4956,12 +4983,11 @@ ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, advsm = &g_ble_ll_adv_sm[0]; #endif - evbuf = advsm->conn_comp_ev; - assert(evbuf != NULL); + assert(advsm->conn_comp_ev != NULL); + ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, advsm->conn_comp_ev, + advsm); advsm->conn_comp_ev = NULL; - ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, advsm); - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) ble_ll_hci_ev_le_csa(connsm); #endif @@ -4973,6 +4999,7 @@ ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, } #endif } +#endif /** * Returns the local resolvable private address currently being using by @@ -5134,3 +5161,5 @@ ble_ll_adv_init(void) ble_ll_adv_sm_init(&g_ble_ll_adv_sm[i]); } } + +#endif diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c index b8352f4aa2..2fb65869ef 100644 --- a/nimble/controller/src/ble_ll_conn.c +++ b/nimble/controller/src/ble_ll_conn.c @@ -25,10 +25,8 @@ #include "os/os.h" #include "os/os_cputime.h" #include "nimble/ble.h" -#include "nimble/nimble_opt.h" #include "nimble/hci_common.h" #include "nimble/ble_hci_trans.h" -#include "ble/xcvr.h" #include "controller/ble_ll.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_scan.h" @@ -40,9 +38,9 @@ #include "controller/ble_ll_trace.h" #include "controller/ble_ll_rfmgmt.h" #include "controller/ble_phy.h" -#include "controller/ble_hw.h" #include "controller/ble_ll_utils.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_ctrl_priv.h" #if (BLETEST_THROUGHPUT_TEST == 1) extern void bletest_completed_pkt(uint16_t handle); @@ -119,6 +117,11 @@ extern void bletest_completed_pkt(uint16_t handle); * 1) The current connection event has not ended but a schedule item starts */ +/* Global LL connection parameters */ +struct ble_ll_conn_global_params g_ble_ll_conn_params; + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + /* This is a dummy structure we use for the empty PDU */ struct ble_ll_empty_pdu { @@ -132,19 +135,19 @@ struct ble_ll_empty_pdu #error "Maximum # of connections is 254" #endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Global connection complete event. Used when initiating */ uint8_t *g_ble_ll_conn_comp_ev; - -/* Global LL connection parameters */ -struct ble_ll_conn_global_params g_ble_ll_conn_params; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) /* Global default sync transfer params */ struct ble_ll_conn_sync_transfer_params g_ble_ll_conn_sync_transfer_params; #endif -/* Pointer to connection state machine we are trying to create */ -struct ble_ll_conn_sm *g_ble_ll_conn_create_sm; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +struct ble_ll_conn_create_sm g_ble_ll_conn_create_sm; +#endif /* Pointer to current connection */ struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm; @@ -421,25 +424,23 @@ ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *csm) } #endif -static void -ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm) +void +ble_ll_conn_itvl_to_ticks(uint32_t itvl, uint32_t *itvl_ticks, + uint8_t *itvl_usecs) { uint32_t ticks; uint32_t usecs; - /* - * Precalculate the number of ticks and remaining microseconds for - * the connection interval - */ - usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; + usecs = itvl * BLE_LL_CONN_ITVL_USECS; ticks = os_cputime_usecs_to_ticks(usecs); - connsm->conn_itvl_usecs = (uint8_t)(usecs - - os_cputime_ticks_to_usecs(ticks)); - if (connsm->conn_itvl_usecs == 31) { - connsm->conn_itvl_usecs = 0; + usecs = usecs - os_cputime_ticks_to_usecs(ticks); + if (usecs == 31) { + usecs = 0; ++ticks; } - connsm->conn_itvl_ticks = ticks; + + *itvl_ticks = ticks; + *itvl_usecs = usecs; } /** @@ -448,6 +449,7 @@ ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm) * * @return uint8_t* */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) static uint8_t * ble_ll_init_get_conn_comp_ev(void) { @@ -459,6 +461,7 @@ ble_ll_init_get_conn_comp_ev(void) return evbuf; } +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) /** @@ -674,64 +677,6 @@ ble_ll_conn_wfr_timer_exp(void) STATS_INC(ble_ll_conn_stats, wfr_expirations); } -void -ble_ll_conn_reset_pending_aux_conn_rsp(void) -{ -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return; -#endif - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return; - } - - if (CONN_F_AUX_CONN_REQ(connsm)) { - STATS_INC(ble_ll_stats, aux_conn_rsp_err); - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - return; - } - - return; -} - -bool -ble_ll_conn_init_pending_aux_conn_rsp(void) -{ -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return false; -#endif - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return false; - } - - return CONN_F_AUX_CONN_REQ(connsm); -} - -void -ble_ll_conn_init_wfr_timer_exp(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return; - } - - ble_ll_conn_reset_pending_aux_conn_rsp(); - connsm->inita_identity_used = 0; - - ble_ll_scan_interrupted(connsm->scansm); - -#endif -} /** * Callback for slave when it transmits a data pdu and the connection event * ends after the transmission. @@ -764,6 +709,7 @@ ble_ll_conn_start_rx_encrypt(void *arg) !CONN_IS_MASTER(connsm)); } +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_conn_start_rx_unencrypt(void *arg) { @@ -773,6 +719,7 @@ ble_ll_conn_start_rx_unencrypt(void *arg) CONN_F_ENCRYPTED(connsm) = 0; ble_phy_encrypt_disable(); } +#endif static void ble_ll_conn_txend_encrypt(void *arg) @@ -784,6 +731,7 @@ ble_ll_conn_txend_encrypt(void *arg) ble_ll_conn_current_sm_over(connsm); } +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_conn_rxend_unencrypt(void *arg) { @@ -793,6 +741,7 @@ ble_ll_conn_rxend_unencrypt(void *arg) CONN_F_ENCRYPTED(connsm) = 0; ble_ll_conn_current_sm_over(connsm); } +#endif static void ble_ll_conn_continue_rx_encrypt(void *arg) @@ -917,7 +866,7 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) static uint16_t ble_ll_conn_adjust_pyld_len(struct ble_ll_conn_sm *connsm, uint16_t pyld_len) { - uint16_t phy_max_tx_octets; + uint16_t max_pyld_len; uint16_t ret; #if (BLE_LL_BT5_PHY_SUPPORTED == 1) @@ -930,22 +879,28 @@ ble_ll_conn_adjust_pyld_len(struct ble_ll_conn_sm *connsm, uint16_t pyld_len) phy_mode = connsm->phy_data.tx_phy_mode; } - phy_max_tx_octets = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, - phy_mode); + max_pyld_len = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, + phy_mode); #else - phy_max_tx_octets = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, - BLE_PHY_MODE_1M); + max_pyld_len = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, + BLE_PHY_MODE_1M); #endif ret = pyld_len; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + if (CONN_F_ENCRYPTED(connsm)) { + max_pyld_len -= BLE_LL_DATA_MIC_LEN; + } +#endif + if (ret > connsm->eff_max_tx_octets) { ret = connsm->eff_max_tx_octets; } - if (ret > phy_max_tx_octets) { - ret = phy_max_tx_octets; + if (ret > max_pyld_len) { + ret = max_pyld_len; } return ret; @@ -959,8 +914,8 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) uint8_t hdr_byte; uint8_t end_transition; uint8_t cur_txlen; - uint8_t next_txlen; - uint8_t cur_offset; + uint16_t next_txlen; + uint16_t cur_offset; uint16_t pktlen; uint32_t next_event_time; uint32_t ticks; @@ -1035,7 +990,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * packets can be let go. */ if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr) - && ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || + && (CONN_IS_MASTER(connsm) || !ble_ll_ctrl_is_start_enc_rsp(m))) { nextpkthdr = NULL; } @@ -1082,7 +1037,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) /* We will allow a next packet if it itself is allowed */ pkthdr = OS_MBUF_PKTHDR(connsm->cur_tx_pdu); if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr) - && ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || + && (CONN_IS_MASTER(connsm) || !ble_ll_ctrl_is_start_enc_rsp(connsm->cur_tx_pdu))) { nextpkthdr = NULL; } @@ -1129,11 +1084,10 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) if ((cur_offset + cur_txlen) < pktlen) { next_txlen = pktlen - (cur_offset + cur_txlen); } else { - if (nextpkthdr->omp_len > connsm->eff_max_tx_octets) { - next_txlen = connsm->eff_max_tx_octets; - } else { - next_txlen = nextpkthdr->omp_len; - } + next_txlen = connsm->eff_max_tx_octets; + } + if (next_txlen > connsm->eff_max_tx_octets) { + next_txlen = connsm->eff_max_tx_octets; } /* @@ -1152,9 +1106,11 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) ble_ll_pdu_tx_time_get(next_txlen, tx_phy_mode) + ble_ll_pdu_tx_time_get(cur_txlen, tx_phy_mode); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { ticks += (BLE_LL_IFS + connsm->eff_max_rx_time); } +#endif ticks = os_cputime_usecs_to_ticks(ticks); if (CPUTIME_LT(os_cputime_get32() + ticks, next_event_time)) { @@ -1210,7 +1166,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * overrun next scheduled item. */ if ((connsm->csmflags.cfbit.terminate_ind_rxd) || - ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && (md == 0) && + (CONN_IS_SLAVE(connsm) && (md == 0) && (connsm->cons_rxd_bad_crc == 0) && ((connsm->last_rxd_hdr_byte & BLE_LL_DATA_HDR_MD_MASK) == 0) && !ble_ll_ctrl_is_terminate_ind(hdr_byte, m->om_data[0]))) { @@ -1263,7 +1219,17 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * The slave sends the PAUSE_ENC_RSP encrypted. The master sends * it unencrypted (note that link was already set unencrypted). */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: + CONN_F_ENCRYPTED(connsm) = 0; + connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; + connsm->enc_data.tx_encrypted = 0; + ble_phy_encrypt_disable(); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: CONN_F_ENCRYPTED(connsm) = 1; connsm->enc_data.tx_encrypted = 1; ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, @@ -1275,11 +1241,11 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) } else { txend_func = ble_ll_conn_rxend_unencrypt; } - } else { - CONN_F_ENCRYPTED(connsm) = 0; - connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; - connsm->enc_data.tx_encrypted = 0; - ble_phy_encrypt_disable(); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } else { /* If encrypted set packet counter */ @@ -1336,7 +1302,9 @@ static int ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) { int rc; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint32_t usecs; +#endif uint32_t start; struct ble_ll_conn_sm *connsm; @@ -1377,7 +1345,9 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) ble_phy_mode_set(connsm->phy_data.tx_phy_mode, connsm->phy_data.rx_phy_mode); #endif - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: /* Set start time of transmission */ start = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_tx_set_start_time(start, sch->remainder); @@ -1403,7 +1373,10 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) STATS_INC(ble_ll_conn_stats, conn_ev_late); rc = BLE_LL_SCHED_STATE_DONE; } - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (CONN_F_ENCRYPTED(connsm)) { ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr, @@ -1459,6 +1432,11 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) /* Set next wakeup time to connection event end time */ rc = BLE_LL_SCHED_STATE_RUNNING; } + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } if (rc == BLE_LL_SCHED_STATE_DONE) { @@ -1490,8 +1468,9 @@ static int ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime, uint32_t add_usecs) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) int rc; - uint8_t rem_bytes; + uint16_t rem_bytes; uint32_t ticks; uint32_t usecs; uint32_t next_sched_time; @@ -1545,6 +1524,9 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime, } return rc; +#else + return 1; +#endif } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) @@ -1569,22 +1551,6 @@ ble_ll_conn_auth_pyld_timer_cb(struct ble_npl_event *ev) ble_ll_conn_auth_pyld_timer_start(connsm); } -void -ble_ll_conn_rd_features_timer_cb(struct ble_npl_event *ev) -{ - struct ble_ll_conn_sm *connsm; - - connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev); - - if (!connsm->csmflags.cfbit.pending_hci_rd_features || - !connsm->csmflags.cfbit.rxd_features) { - return; - } - - ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; -} - /** * Start (or restart) the authenticated payload timer * @@ -1601,6 +1567,7 @@ ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm) } #endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) static void ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm) { @@ -1644,55 +1611,25 @@ ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm) */ void ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, - struct hci_create_conn *hcc) + struct ble_ll_conn_create_scan *cc_scan, + struct ble_ll_conn_create_params *cc_params) { ble_ll_conn_master_common_init(connsm); - /* Set slave latency and supervision timeout */ - connsm->slave_latency = hcc->conn_latency; - connsm->supervision_tmo = hcc->supervision_timeout; - - /* Set own address type and peer address if needed */ - connsm->own_addr_type = hcc->own_addr_type; - if (hcc->filter_policy == 0) { - memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN); - connsm->peer_addr_type = hcc->peer_addr_type; - } - - /* XXX: for now, just make connection interval equal to max */ - connsm->conn_itvl = hcc->conn_itvl_max; + connsm->own_addr_type = cc_scan->own_addr_type; + memcpy(&connsm->peer_addr, &cc_scan->peer_addr, BLE_DEV_ADDR_LEN); + connsm->peer_addr_type = cc_scan->peer_addr_type; - /* Check the min/max CE lengths are less than connection interval */ - if (hcc->min_ce_len > (connsm->conn_itvl * 2)) { - connsm->min_ce_len = connsm->conn_itvl * 2; - } else { - connsm->min_ce_len = hcc->min_ce_len; - } - - if (hcc->max_ce_len > (connsm->conn_itvl * 2)) { - connsm->max_ce_len = connsm->conn_itvl * 2; - } else { - connsm->max_ce_len = hcc->max_ce_len; - } -} - -static void -ble_ll_update_max_tx_octets_phy_mode(struct ble_ll_conn_sm *connsm) -{ - uint32_t usecs; - - usecs = connsm->eff_max_tx_time; - - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_1M] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_1M); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_2M] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_2M); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_CODED_125KBPS] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_CODED_125KBPS); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_CODED_500KBPS] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_CODED_500KBPS); + connsm->conn_itvl = cc_params->conn_itvl; + connsm->conn_itvl_ticks = cc_params->conn_itvl_ticks; + connsm->conn_itvl_usecs = cc_params->conn_itvl_usecs; + connsm->slave_latency = cc_params->conn_latency; + connsm->supervision_tmo = cc_params->supervision_timeout; + connsm->min_ce_len = cc_params->min_ce_len; + connsm->max_ce_len = cc_params->max_ce_len; } +#endif #if (BLE_LL_BT5_PHY_SUPPORTED == 1) @@ -1743,64 +1680,27 @@ ble_ll_conn_init_phy(struct ble_ll_conn_sm *connsm, int phy) connsm->rem_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - - ble_ll_update_max_tx_octets_phy_mode(connsm); } #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - -void -ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm, - struct hci_ext_create_conn *hcc) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +static void +ble_ll_conn_create_set_params(struct ble_ll_conn_sm *connsm, uint8_t phy) { + struct ble_ll_conn_create_params *cc_params; - ble_ll_conn_master_common_init(connsm); + cc_params = &g_ble_ll_conn_create_sm.params[phy - 1]; - /* Set own address type and peer address if needed */ - connsm->own_addr_type = hcc->own_addr_type; - if (hcc->filter_policy == 0) { - memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN); - connsm->peer_addr_type = hcc->peer_addr_type; - } + connsm->slave_latency = cc_params->conn_latency; + connsm->supervision_tmo = cc_params->supervision_timeout; - connsm->initial_params = *hcc; + connsm->conn_itvl = cc_params->conn_itvl; + connsm->conn_itvl_ticks = cc_params->conn_itvl_ticks; + connsm->conn_itvl_usecs = cc_params->conn_itvl_usecs; } - -void -ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm, - struct hci_ext_conn_params *hcc_params, int phy) -{ - /* Set slave latency and supervision timeout */ - connsm->slave_latency = hcc_params->conn_latency; - connsm->supervision_tmo = hcc_params->supervision_timeout; - - /* XXX: for now, just make connection interval equal to max */ - connsm->conn_itvl = hcc_params->conn_itvl_max; - - - /* Check the min/max CE lengths are less than connection interval */ - if (hcc_params->min_ce_len > (connsm->conn_itvl * 2)) { - connsm->min_ce_len = connsm->conn_itvl * 2; - } else { - connsm->min_ce_len = hcc_params->min_ce_len; - } - - if (hcc_params->max_ce_len > (connsm->conn_itvl * 2)) { - connsm->max_ce_len = connsm->conn_itvl * 2; - } else { - connsm->max_ce_len = hcc_params->max_ce_len; - } - - ble_ll_conn_calc_itvl_ticks(connsm); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_ll_conn_init_phy(connsm, phy); #endif -} - - #endif static void @@ -1851,7 +1751,6 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm->sub_vers_nr = 0; connsm->reject_reason = BLE_ERR_SUCCESS; connsm->conn_rssi = BLE_LL_CONN_UNKNOWN_RSSI; - connsm->rpa_index = -1; connsm->inita_identity_used = 0; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) @@ -1915,8 +1814,6 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm->host_req_max_tx_time = 0; #endif - ble_ll_update_max_tx_octets_phy_mode(connsm); - /* Reset encryption data */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) memset(&connsm->enc_data, 0, sizeof(struct ble_ll_conn_enc_data)); @@ -1932,8 +1829,6 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm); #endif - ble_ll_conn_calc_itvl_ticks(connsm); - /* Add to list of active connections */ SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); } @@ -1968,8 +1863,6 @@ ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm) if (eff_time != connsm->eff_max_tx_time) { connsm->eff_max_tx_time = eff_time; send_event = 1; - - ble_ll_update_max_tx_octets_phy_mode(connsm); } eff_bytes = min(connsm->rem_max_tx_octets, connsm->max_rx_octets); if (eff_bytes != connsm->eff_max_rx_octets) { @@ -2149,8 +2042,10 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) { uint16_t latency; uint32_t itvl; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint32_t cur_ww; uint32_t max_ww; +#endif struct ble_ll_conn_upd_req *upd; uint32_t ticks; uint32_t usecs; @@ -2163,7 +2058,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) ble_ll_ctrl_terminate_start(connsm); } - if (CONN_F_TERMINATE_STARTED(connsm) && (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE)) { + if (CONN_F_TERMINATE_STARTED(connsm) && CONN_IS_SLAVE(connsm)) { /* Some of the devices waits whole connection interval to ACK our * TERMINATE_IND sent as a Slave. Since we are here it means we are still waiting for ACK. * Make sure we catch it in next connection event. @@ -2203,7 +2098,6 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) connsm->anchor_point += connsm->conn_itvl_ticks; connsm->anchor_point_usecs += connsm->conn_itvl_usecs; } else { - uint32_t ticks; ticks = os_cputime_usecs_to_ticks(itvl); connsm->anchor_point += ticks; connsm->anchor_point_usecs += (itvl - os_cputime_ticks_to_usecs(ticks)); @@ -2224,8 +2118,8 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) /* Set flag so we send connection update event */ upd = &connsm->conn_update_req; - if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || - ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && + if (CONN_IS_MASTER(connsm) || + (CONN_IS_SLAVE(connsm) && IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) || (connsm->conn_itvl != upd->interval) || (connsm->slave_latency != upd->latency) || @@ -2240,7 +2134,10 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS; connsm->tx_win_off = upd->winoffset; connsm->conn_itvl = upd->interval; - ble_ll_conn_calc_itvl_ticks(connsm); + + ble_ll_conn_itvl_to_ticks(connsm->conn_itvl, &connsm->conn_itvl_ticks, + &connsm->conn_itvl_usecs); + if (upd->winoffset != 0) { usecs = upd->winoffset * BLE_LL_CONN_ITVL_USECS; ticks = os_cputime_usecs_to_ticks(usecs); @@ -2355,8 +2252,9 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) itvl = g_ble_ll_sched_data.sch_ticks_per_period; #else - itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; + itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_TICKS_PER_SLOT; #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { cur_ww = ble_ll_utils_calc_window_widening(connsm->anchor_point, @@ -2370,6 +2268,7 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) connsm->slave_cur_window_widening = cur_ww; itvl += os_cputime_usecs_to_ticks(cur_ww + connsm->slave_cur_tx_win_usecs); } +#endif itvl -= g_ble_ll_sched_offset_ticks; connsm->ce_end_time = connsm->anchor_point + itvl; @@ -2395,9 +2294,13 @@ static int ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) { int rc; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) uint8_t *evbuf; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint32_t endtime; uint32_t usecs; +#endif /* XXX: TODO this assumes we received in 1M phy */ @@ -2422,6 +2325,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) * the transmit window offset from the end of the connection request. */ rc = 1; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { /* * With a 32.768 kHz crystal we dont care about the remaining usecs @@ -2469,7 +2373,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) #else connsm->ce_end_time = connsm->anchor_point + - (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT) + (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_TICKS_PER_SLOT) + os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1; #endif connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS; @@ -2483,6 +2387,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) } } } +#endif /* Send connection complete event to inform host of connection */ if (rc) { @@ -2499,9 +2404,9 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) CONN_F_CTRLR_PHY_UPDATE(connsm) = 1; } #endif - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - ble_ll_adv_send_conn_comp_ev(connsm, rxhdr); - } else { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: evbuf = ble_ll_init_get_conn_comp_ev(); ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, NULL); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) @@ -2517,6 +2422,16 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) * if it has some additional features to use. */ ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: + ble_ll_adv_send_conn_comp_ev(connsm, rxhdr); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } @@ -2685,8 +2600,8 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) * @param txoffset The tx window offset for this connection */ -static void -ble_ll_conn_connect_ind_prepare(struct ble_ll_conn_sm *connsm, +void +ble_ll_conn_prepare_connect_ind(struct ble_ll_conn_sm *connsm, struct ble_ll_scan_pdu_data *pdu_data, uint8_t adva_type, uint8_t *adva, uint8_t inita_type, uint8_t *inita, @@ -2721,7 +2636,7 @@ ble_ll_conn_connect_ind_prepare(struct ble_ll_conn_sm *connsm, } } else { /* Get pointer to our device address */ - connsm = g_ble_ll_conn_create_sm; + connsm = g_ble_ll_conn_create_sm.connsm; if ((connsm->own_addr_type & 1) == 0) { addr = g_dev_addr; } else { @@ -2771,110 +2686,8 @@ ble_ll_conn_connect_ind_prepare(struct ble_ll_conn_sm *connsm, pdu_data->hdr_byte = hdr; } -/* Returns true if the address matches the connection peer address having in - * mind privacy mode - */ -static int -ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva, int index) -{ - int rc; - uint8_t *peer_addr = NULL; - struct ble_ll_conn_sm *connsm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - struct ble_ll_resolv_entry *rl; -#endif - - /* XXX: Deal with different types of random addresses here! */ - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return 0; - } - - switch (connsm->peer_addr_type) { - /* Fall-through intentional */ - case BLE_HCI_CONN_PEER_ADDR_PUBLIC: - case BLE_HCI_CONN_PEER_ADDR_RANDOM: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (ble_ll_addr_is_id(adva, addr_type)) { - /* Peer uses its identity address. Let's verify privacy mode. - * - * Note: Core Spec 5.0 Vol 6, Part B - * If the Host has added the peer device to the resolving list - * with an all-zero peer IRK, the Controller shall only accept - * the peer's identity address. - */ - if (ble_ll_resolv_enabled()) { - rl = ble_ll_resolv_list_find(adva, addr_type); - if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_peer) { - return 0; - } - } - } - - /* Check if peer uses RPA. If so and it match, use it as controller - * supports privacy mode - */ - if ((index >= 0) && - (g_ble_ll_resolv_list[index].rl_addr_type == connsm->peer_addr_type)) { - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - } -#endif - /* - * If we are here it means we don't know the device, lets - * check if type is what we are looking for and later - * if address matches - */ - if ((connsm->peer_addr_type == addr_type) && !peer_addr) { - peer_addr = adva; - } - - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - case BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT: - if ((index < 0) || - (g_ble_ll_resolv_list[index].rl_addr_type != 0)) { - return 0; - } - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - break; - case BLE_HCI_CONN_PEER_ADDR_RANDOM_IDENT: - if ((index < 0) || - (g_ble_ll_resolv_list[index].rl_addr_type != 1)) { - return 0; - } - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - break; -#endif - default: - peer_addr = NULL; - break; - } - - rc = 0; - if (peer_addr) { - if (!memcmp(peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN)) { - rc = 1; - } - } - - return rc; -} - -static void -ble_ll_conn_connect_ind_txend_to_standby(void *arg) -{ - ble_ll_state_set(BLE_LL_STATE_STANDBY); -} - -static void -ble_ll_conn_connect_ind_txend_to_init(void *arg) -{ - ble_ll_state_set(BLE_LL_STATE_INITIATING); -} - -static uint8_t -ble_ll_conn_connect_ind_tx_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) +uint8_t +ble_ll_conn_tx_connect_ind_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) { struct ble_ll_conn_sm *connsm; struct ble_ll_scan_pdu_data *pdu_data; @@ -2908,30 +2721,6 @@ ble_ll_conn_connect_ind_tx_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_by return 34; } -/** - * Send a connection requestion to an advertiser - * - * Context: Interrupt - * - * @param addr_type Address type of advertiser - * @param adva Address of advertiser - */ -int -ble_ll_conn_connect_ind_send(struct ble_ll_conn_sm *connsm, uint8_t end_trans) -{ - int rc; - - if (end_trans == BLE_PHY_TRANSITION_NONE) { - ble_phy_set_txend_cb(ble_ll_conn_connect_ind_txend_to_standby, NULL); - } else { - ble_phy_set_txend_cb(ble_ll_conn_connect_ind_txend_to_init, NULL); - } - - rc = ble_phy_tx(ble_ll_conn_connect_ind_tx_pducb, connsm, end_trans); - - return rc; -} - /** * Called when a schedule item overlaps the currently running connection * event. This generally should not happen, but if it does we stop the @@ -2951,581 +2740,149 @@ ble_ll_conn_event_halt(void) } } -/** - * Process a received PDU while in the initiating state. - * - * Context: Link Layer task. - * - * @param pdu_type - * @param rxbuf - * @param ble_hdr - */ -void -ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +int +ble_ll_conn_send_connect_req(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t ext) { - uint8_t addr_type; - uint8_t *addr; - uint8_t *adv_addr; - uint8_t *inita; - uint8_t inita_type; struct ble_ll_conn_sm *connsm; - int ext_adv_mode = -1; + struct ble_mbuf_hdr *rxhdr; + int8_t rpa_index; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = NULL; - - if (ble_hdr->rxinfo.user_data) { - /* aux_data just a local helper, no need to ref - * as ble_hdr->rxinfo.user_data is unref in the end of this function - */ - aux_data = ble_hdr->rxinfo.user_data; - } -#endif - - /* Get the connection state machine we are trying to create */ - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - } + uint8_t phy; #endif - return; - } + int rc; - if (!BLE_MBUF_HDR_CRC_OK(ble_hdr)) { - goto scan_continue; - } + connsm = g_ble_ll_conn_create_sm.connsm; + rxhdr = BLE_MBUF_HDR_PTR(rxpdu); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (BLE_MBUF_HDR_AUX_INVALID(ble_hdr)) { - goto scan_continue; - } - - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (BLE_MBUF_HDR_WAIT_AUX(ble_hdr)) { - /* Just continue scanning. We are waiting for AUX */ - if (!ble_ll_sched_aux_scan(ble_hdr, connsm->scansm, aux_data)) { - /* ref for aux ptr in the scheduler */ - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - ble_ll_scan_chk_resume(); - return; - } - goto scan_continue; - } - } - - if (CONN_F_AUX_CONN_REQ(connsm)) { - if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - /* Wait for connection response, in this point of time aux is NULL */ - BLE_LL_ASSERT(ble_hdr->rxinfo.user_data == NULL); - return; - } + if (ext) { +#if BLE_LL_BT5_PHY_SUPPORTED + phy = rxhdr->rxinfo.phy; +#else + phy = BLE_PHY_1M; +#endif + ble_ll_conn_create_set_params(connsm, phy); } #endif - /* If we have sent a connect request, we need to enter CONNECTION state */ - if (connsm && CONN_F_CONN_REQ_TXD(connsm)) { - /* Set address of advertiser to which we are connecting. */ - - if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr, - &adv_addr, &addr_type, - &inita, &inita_type, &ext_adv_mode)) { - /* Something got wrong, keep trying to connect */ - goto scan_continue; - } + if (ble_ll_sched_master_new(connsm, rxhdr, 0)) { + return -1; + } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * Did we resolve this address? If so, set correct peer address - * and peer address type. - */ - if (connsm->rpa_index >= 0) { - addr_type = g_ble_ll_resolv_list[connsm->rpa_index].rl_addr_type + 2; - addr = g_ble_ll_resolv_list[connsm->rpa_index].rl_identity_addr; - } else { - addr = adv_addr; - } + rpa_index = addrd->rpa_index; #else - addr = adv_addr; -#endif - - if (connsm->rpa_index >= 0) { - connsm->peer_addr_type = addr_type; - memcpy(connsm->peer_addr, addr, BLE_DEV_ADDR_LEN); - - ble_ll_scan_set_peer_rpa(adv_addr); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* Update resolving list with current peer RPA */ - ble_ll_resolv_set_peer_rpa(connsm->rpa_index, rxbuf + BLE_LL_PDU_HDR_LEN); - if (ble_ll_is_rpa(inita, inita_type)) { - ble_ll_resolv_set_local_rpa(connsm->rpa_index, inita); - } - + rpa_index = -1; #endif - } else if (ble_ll_scan_whitelist_enabled()) { - /* if WL is used we need to store peer addr also if it was not - * resolved - */ - connsm->peer_addr_type = addr_type; - memcpy(connsm->peer_addr, addr, BLE_DEV_ADDR_LEN); - } + ble_ll_conn_prepare_connect_ind(connsm, ble_ll_scan_get_pdu_data(), + addrd->adva_type, addrd->adva, + addrd->targeta_type, addrd->targeta, + rpa_index, rxhdr->rxinfo.channel); - /* Connection has been created. Stop scanning */ - g_ble_ll_conn_create_sm = NULL; - ble_ll_scan_sm_stop(0); - - /* For AUX Connect CSA2 is mandatory. Otherwise we need to check bit - * mask - */ - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - ble_ll_conn_set_csa(connsm, 1); - } else { - ble_ll_conn_set_csa(connsm, rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK); - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - /* Lets take last used phy */ - ble_ll_conn_init_phy(connsm, ble_hdr->rxinfo.phy); -#endif - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - } -#endif - ble_ll_conn_created(connsm, NULL); - return; + ble_phy_set_txend_cb(NULL, NULL); + rc = ble_phy_tx(ble_ll_conn_tx_connect_ind_pducb, connsm, + ext ? BLE_PHY_TRANSITION_TX_RX : BLE_PHY_TRANSITION_NONE); + if (rc) { + ble_ll_conn_send_connect_req_cancel(); + return -1; } -scan_continue: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Drop last reference and keep continue to connect */ - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && BLE_LL_BT5_PHY_SUPPORTED + if (ext) { + ble_ll_conn_init_phy(connsm, phy); } #endif - ble_ll_scan_chk_resume(); + + return 0; } -/** - * Called when a receive PDU has started and we are in the initiating state. - * - * Context: Interrupt - * - * @param pdu_type - * @param ble_hdr - * - * @return int - * 0: we will not attempt to reply to this frame - * 1: we may send a response to this frame. - */ -int -ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr) +void +ble_ll_conn_send_connect_req_cancel(void) { struct ble_ll_conn_sm *connsm; - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return 0; - } - - if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || - (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND || - pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP)) { - return 1; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && - connsm->scansm->ext_scanning) { - if (connsm->scansm->cur_aux_data) { - STATS_INC(ble_ll_stats, aux_received); - } - - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_EXT_ADV; - return 1; - } -#endif + connsm = g_ble_ll_conn_create_sm.connsm; - return 0; + ble_ll_sched_rmv_elem(&connsm->conn_sch); } -/** - * Called when a receive PDU has ended and we are in the initiating state. - * - * Context: Interrupt - * - * @param rxpdu - * @param crcok - * @param ble_hdr - * - * @return int - * < 0: Disable the phy after reception. - * == 0: Success. Do not disable the PHY. - * > 0: Do not disable PHY as that has already been done. - */ -int -ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, - struct ble_mbuf_hdr *ble_hdr) +static void +ble_ll_conn_master_start(uint8_t phy, uint8_t csa, + struct ble_ll_scan_addr_data *addrd, uint8_t *targeta) { - int rc; - int resolved; - int chk_wl; - int index; - uint8_t pdu_type; - uint8_t adv_addr_type; - uint8_t peer_addr_type; - uint8_t *adv_addr = NULL; - uint8_t *peer; - uint8_t *init_addr = NULL; - uint8_t init_addr_type; - uint8_t pyld_len; - uint8_t inita_is_rpa; - uint8_t conn_req_end_trans; - struct os_mbuf *rxpdu; struct ble_ll_conn_sm *connsm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - struct ble_ll_resolv_entry *rl; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_scan_sm *scansm; - uint8_t phy; -#endif - int ext_adv_mode = -1; - /* Get connection state machine to use if connection to be established */ - connsm = g_ble_ll_conn_create_sm; - /* This could happen if connection init was cancelled while isr end was - * already pending - */ - if (!connsm) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return -1; - } + connsm = g_ble_ll_conn_create_sm.connsm; + g_ble_ll_conn_create_sm.connsm = NULL; - rc = -1; - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - pyld_len = rxbuf[1]; + connsm->peer_addr_type = addrd->adv_addr_type; + memcpy(connsm->peer_addr, addrd->adv_addr, 6); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - scansm = connsm->scansm; - if (scansm->cur_aux_data) { - ble_hdr->rxinfo.user_data = scansm->cur_aux_data; - scansm->cur_aux_data = NULL; - } -#endif - - if (!crcok) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Invalid packet - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); -#endif - - /* Ignore this packet */ - goto init_rx_isr_exit; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->adva_resolved) { + BLE_LL_ASSERT(addrd->rpa_index >= 0); + connsm->peer_addr_resolved = 1; + ble_ll_resolv_set_peer_rpa(addrd->rpa_index, addrd->adva); + ble_ll_scan_set_peer_rpa(addrd->adva); + } else { + connsm->peer_addr_resolved = 0; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* If we sent AUX_CONNECT_REQ, we only expect AUX_CONNECT_RSP here */ - if (CONN_F_AUX_CONN_REQ(connsm)) { - if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - STATS_INC(ble_ll_stats, aux_conn_rsp_err); - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - } - goto init_rx_isr_exit; + if (addrd->targeta_resolved) { + BLE_LL_ASSERT(addrd->rpa_index >= 0); + BLE_LL_ASSERT(targeta); + ble_ll_resolv_set_local_rpa(addrd->rpa_index, targeta); } #endif - inita_is_rpa = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (!scansm->ext_scanning) { - goto init_rx_isr_exit; - } - - rc = ble_ll_scan_update_aux_data(ble_hdr, rxbuf, NULL); - if (rc < 0) { - /* No memory or broken packet */ - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID; - goto init_rx_isr_exit; - } - } -#endif - - /* Lets get addresses from advertising report*/ - if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr, - &adv_addr, &adv_addr_type, - &init_addr, &init_addr_type, - &ext_adv_mode)) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID; -#endif - goto init_rx_isr_exit; - } - - switch (pdu_type) { - case BLE_ADV_PDU_TYPE_ADV_IND: - break; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_ADV_PDU_TYPE_ADV_EXT_IND: - rc = -1; - - /* If this is not connectable adv mode, lets skip it */ - if (!(ext_adv_mode & BLE_LL_EXT_ADV_MODE_CONN)) { - goto init_rx_isr_exit; - } - - if (!adv_addr) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT; - goto init_rx_isr_exit; - } - - if (!init_addr) { - break; - } - /* if there is direct address lets fall down and check it.*/ - // no break -#endif - case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: - inita_is_rpa = (uint8_t)ble_ll_is_rpa(init_addr, init_addr_type); - if (!inita_is_rpa) { - - /* Resolving will be done later. Check if identity InitA matches */ - if (!ble_ll_is_our_devaddr(init_addr, init_addr_type)) { - goto init_rx_isr_exit; - } - } -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - else { - /* If privacy is off - reject RPA InitA*/ - goto init_rx_isr_exit; - } + ble_ll_conn_set_csa(connsm, csa); +#if BLE_LL_BT5_PHY_SUPPORTED + ble_ll_conn_init_phy(connsm, phy); #endif + ble_ll_conn_created(connsm, NULL); +} - break; - default: - goto init_rx_isr_exit; - } - - /* Should we send a connect request? */ - index = -1; - peer = adv_addr; - peer_addr_type = adv_addr_type; - - resolved = 0; - chk_wl = ble_ll_scan_whitelist_enabled(); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (ble_ll_is_rpa(adv_addr, adv_addr_type) && ble_ll_resolv_enabled()) { - index = ble_hw_resolv_list_match(); - if (index >= 0) { - rl = &g_ble_ll_resolv_list[index]; - - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED; - connsm->rpa_index = index; - peer = rl->rl_identity_addr; - peer_addr_type = rl->rl_addr_type; - resolved = 1; - - /* Assure privacy */ - if ((rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && init_addr && - !inita_is_rpa && rl->rl_has_local) { - goto init_rx_isr_exit; - } - - /* - * If the InitA is a RPA, we must see if it resolves based on the - * identity address of the resolved ADVA. - */ - if (init_addr && inita_is_rpa) { - if (!ble_ll_resolv_rpa(init_addr, - g_ble_ll_resolv_list[index].rl_local_irk)) { - goto init_rx_isr_exit; - } - - /* Core Specification Vol 6, Part B, Section 6.4: - * "The Link Layer should not set the InitA field to the same - * value as the TargetA field in the received advertising PDU." - * - * We update the received PDU directly here, so ble_ll_init_rx_pkt_in - * can process it as is. - */ - memcpy(init_addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); - } - - } else { - if (chk_wl) { - goto init_rx_isr_exit; - } - - /* Could not resolved InitA */ - if (init_addr && inita_is_rpa) { - goto init_rx_isr_exit; - } - } - } else if (init_addr) { - - /* If resolving is off and InitA is RPA we reject advertising */ - if (inita_is_rpa && !ble_ll_resolv_enabled()) { - goto init_rx_isr_exit; - } - - /* Let's see if we have IRK with that peer.*/ - rl = ble_ll_resolv_list_find(adv_addr, adv_addr_type); - - /* Lets make sure privacy mode is correct together with InitA in case it - * is identity address - */ - if (rl && !inita_is_rpa && - (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_local) { - goto init_rx_isr_exit; - } +void +ble_ll_conn_created_on_legacy(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t *targeta) +{ + uint8_t *rxbuf; + uint8_t csa; - /* - * If the InitA is a RPA, we must see if it resolves based on the - * identity address of the resolved ADVA. - */ - if (inita_is_rpa) { - if (!rl || !ble_ll_resolv_rpa(init_addr, rl->rl_local_irk)) { - goto init_rx_isr_exit; - } + rxbuf = rxpdu->om_data; + csa = rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK; - /* Core Specification Vol 6, Part B, Section 6.4: - * "The Link Layer should not set the InitA field to the same - * value as the TargetA field in the received advertising PDU." - * - * We update the received PDU directly here, so ble_ll_init_rx_pkt_in - * can process it as is. - */ - memcpy(init_addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); - } - } else if (!ble_ll_is_rpa(adv_addr, adv_addr_type)) { - /* undirected with ID address, assure privacy if on RL */ - rl = ble_ll_resolv_list_find(adv_addr, adv_addr_type); - if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_peer) { - goto init_rx_isr_exit; - } - } + ble_ll_conn_master_start(BLE_PHY_1M, csa, addrd, targeta); +} #endif - /* Check filter policy */ - if (chk_wl) { - if (!ble_ll_whitelist_match(peer, peer_addr_type, resolved)) { - goto init_rx_isr_exit; - } - } else { - /* Must match the connection address */ - if (!ble_ll_conn_is_peer_adv(adv_addr_type, adv_addr, index)) { - goto init_rx_isr_exit; - } - } - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH; - - /* For CONNECT_IND we don't go into RX state */ - conn_req_end_trans = BLE_PHY_TRANSITION_NONE; - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Check if we should send AUX_CONNECT_REQ and wait for AUX_CONNECT_RSP */ - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - conn_req_end_trans = BLE_PHY_TRANSITION_TX_RX; - } - - if (connsm->scansm->ext_scanning) { - phy = ble_hdr->rxinfo.phy; - - /* Update connection state machine with appropriate parameters for - * certain PHY - */ - ble_ll_conn_ext_set_params(connsm, - &connsm->initial_params.params[phy - 1], - phy); - - } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +void +ble_ll_conn_created_on_aux(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t *targeta) +{ +#if BLE_LL_BT5_PHY_SUPPORTED + struct ble_mbuf_hdr *rxhdr; #endif + uint8_t phy; - /* Schedule new connection */ - if (ble_ll_sched_master_new(connsm, ble_hdr, pyld_len)) { - STATS_INC(ble_ll_conn_stats, cant_set_sched); - goto init_rx_isr_exit; - } - - /* Prepare data for connect request */ - ble_ll_conn_connect_ind_prepare(connsm, - ble_ll_scan_get_pdu_data(), - adv_addr_type, adv_addr, - init_addr_type, init_addr, - index, ble_hdr->rxinfo.channel); - - /* Setup to transmit the connect request */ - rc = ble_ll_conn_connect_ind_send(connsm, conn_req_end_trans); - if (rc) { - ble_ll_sched_rmv_elem(&connsm->conn_sch); - goto init_rx_isr_exit; - } - - if (init_addr && !inita_is_rpa) { - connsm->inita_identity_used = 1; - } - - CONN_F_CONN_REQ_TXD(connsm) = 1; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - /* Lets wait for AUX_CONNECT_RSP */ - CONN_F_AUX_CONN_REQ(connsm) = 1; - /* Keep aux data until we get scan response */ - scansm->cur_aux_data = ble_hdr->rxinfo.user_data; - ble_hdr->rxinfo.user_data = NULL; - STATS_INC(ble_ll_stats, aux_conn_req_tx); - } +#if BLE_LL_BT5_PHY_SUPPORTED + rxhdr = BLE_MBUF_HDR_PTR(rxpdu); + phy = rxhdr->rxinfo.phy; +#else + phy = BLE_PHY_1M; #endif - STATS_INC(ble_ll_conn_stats, conn_req_txd); - -init_rx_isr_exit: - - /* - * We have to restart receive if we cant hand up pdu. We return 0 so that - * the phy does not get disabled. - */ - rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN); - if (rxpdu == NULL) { - /* - * XXX: possible allocate the PDU when we start initiating? - * I cannot say I like this solution, but if we cannot allocate a PDU - * to hand up to the LL, we need to remove the connection we just - * scheduled since the connection state machine will not get processed - * by link layer properly. For now, just remove it from the scheduler - */ - if (CONN_F_CONN_REQ_TXD(connsm) == 1) { - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - } - ble_phy_restart_rx(); - rc = 0; - } else { - ble_phy_rxpdu_copy(rxbuf, rxpdu); - ble_ll_rx_pdu_in(rxpdu); - } - - if (rc) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - - return rc; + ble_ll_conn_master_start(phy, 1, addrd, targeta); } +#endif +#endif /* BLE_LL_CFG_FEAT_LL_EXT_ADV */ /** * Function called when a timeout has occurred for a connection. There are @@ -3695,11 +3052,13 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) * If we are a slave, we can only start to use slave latency * once we have received a NESN of 1 from the master */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) { connsm->csmflags.cfbit.allow_slave_latency = 1; } } +#endif /* * Discard the received PDU if the sequence number is the same @@ -3791,7 +3150,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) uint8_t conn_sn; uint8_t conn_nesn; uint8_t reply; - uint8_t rem_bytes; + uint16_t rem_bytes; uint8_t opcode = 0; uint8_t rx_pyld_len; uint32_t begtime; @@ -3872,7 +3231,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) /* * Check the packet CRC. A connection event can continue even if the * received PDU does not pass the CRC check. If we receive two consecutive - * CRC errors we end the conection event. + * CRC errors we end the connection event. */ if (!BLE_MBUF_HDR_CRC_OK(rxhdr)) { /* @@ -3883,11 +3242,21 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) if (connsm->cons_rxd_bad_crc >= 2) { reply = 0; } else { - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: reply = CONN_F_LAST_TXD_MD(connsm); - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: /* A slave always responds with a packet */ reply = 1; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } } else { @@ -4001,7 +3370,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) #if (BLE_LL_BT5_PHY_SUPPORTED == 1) if (BLE_LL_LLID_IS_CTRL(hdr_byte) && - (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && + CONN_IS_SLAVE(connsm) && (opcode == BLE_LL_CTRL_PHY_UPDATE_IND)) { connsm->phy_tx_transition = ble_ll_ctrl_phy_tx_transition_get(rxbuf[3]); @@ -4026,11 +3395,21 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) connsm->rxd_disconnect_reason = rxbuf[3]; } - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: reply = CONN_F_LAST_TXD_MD(connsm) || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK); - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: /* A slave always replies */ reply = 1; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } @@ -4074,7 +3453,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) */ void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, - uint8_t hdr_byte, uint8_t length) + uint8_t hdr_byte, uint16_t length) { os_sr_t sr; struct os_mbuf_pkthdr *pkthdr; @@ -4118,9 +3497,11 @@ ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, lifo = 1; break; case BLE_LL_CTRL_PAUSE_ENC_RSP: +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { lifo = 1; } +#endif break; case BLE_LL_CTRL_ENC_REQ: case BLE_LL_CTRL_ENC_RSP: @@ -4191,7 +3572,7 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length) os_mbuf_free_chain(om); } } - +#endif /** * Called to set the global channel mask that we use for all connections. * @@ -4201,7 +3582,9 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length) void ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) struct ble_ll_conn_sm *connsm; +#endif struct ble_ll_conn_global_params *conn_params; /* Do nothing if same channel map */ @@ -4214,14 +3597,17 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap) conn_params->num_used_chans = num_used_chans; memcpy(conn_params->master_chan_map, chanmap, BLE_LL_CONN_CHMAP_LEN); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Perform channel map update */ SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CHAN_MAP_UPD); } } +#endif } +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /** * Called when a device has received a connect request while advertising and * the connect request has passed the advertising filter policy and is for @@ -4235,6 +3621,7 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap) * * @return 0: connection not started; 1 connecton started */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) int ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, bool force_csa2) @@ -4324,6 +3711,9 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, goto err_slave_start; } + ble_ll_conn_itvl_to_ticks(connsm->conn_itvl, &connsm->conn_itvl_ticks, + &connsm->conn_itvl_usecs); + /* Start the connection state machine */ connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE; ble_ll_conn_sm_new(connsm); @@ -4350,6 +3740,7 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, STATS_INC(ble_ll_conn_stats, slave_rxd_bad_conn_req_params); return 0; } +#endif #define MAX_TIME_UNCODED(_maxbytes) \ ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \ @@ -4380,6 +3771,7 @@ ble_ll_conn_module_reset(void) ble_ll_conn_end(connsm, BLE_ERR_SUCCESS); } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Free the global connection complete event if there is one */ if (g_ble_ll_conn_comp_ev) { ble_hci_trans_buf_free(g_ble_ll_conn_comp_ev); @@ -4387,7 +3779,8 @@ ble_ll_conn_module_reset(void) } /* Reset connection we are attempting to create */ - g_ble_ll_conn_create_sm = NULL; + g_ble_ll_conn_create_sm.connsm = NULL; +#endif /* Now go through and end all the connections */ while (1) { @@ -4459,7 +3852,7 @@ ble_ll_conn_module_init(void) uint16_t i; struct ble_ll_conn_sm *connsm; - /* Initialize list of active conections */ + /* Initialize list of active connections */ SLIST_INIT(&g_ble_ll_conn_active_list); STAILQ_INIT(&g_ble_ll_conn_free_list); @@ -4478,6 +3871,9 @@ ble_ll_conn_module_init(void) /* Initialize fixed schedule elements */ connsm->conn_sch.sched_type = BLE_LL_SCHED_TYPE_CONN; connsm->conn_sch.cb_arg = connsm; + + ble_ll_ctrl_init_conn_sm(connsm); + ++connsm; } @@ -4496,3 +3892,4 @@ ble_ll_conn_module_init(void) /* Call reset to finish reset of initialization */ ble_ll_conn_module_reset(); } +#endif diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c index 9936b9d34e..2e50713e84 100644 --- a/nimble/controller/src/ble_ll_conn_hci.c +++ b/nimble/controller/src/ble_ll_conn_hci.c @@ -23,7 +23,6 @@ #include "syscfg/syscfg.h" #include "os/os.h" #include "nimble/ble.h" -#include "nimble/nimble_opt.h" #include "nimble/hci_common.h" #include "nimble/ble_hci_trans.h" #include "controller/ble_ll.h" @@ -35,6 +34,8 @@ #include "controller/ble_ll_adv.h" #include "ble_ll_conn_priv.h" +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + /* * Used to limit the rate at which we send the number of completed packets * event to the host. This is the os time at which we can send an event. @@ -43,19 +44,22 @@ static ble_npl_time_t g_ble_ll_last_num_comp_pkt_evt; extern uint8_t *g_ble_ll_conn_comp_ev; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static const uint8_t ble_ll_valid_conn_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK +static const uint8_t ble_ll_conn_create_valid_phy_mask = ( + BLE_HCI_LE_PHY_1M_PREF_MASK | #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - | BLE_HCI_LE_PHY_2M_PREF_MASK + BLE_HCI_LE_PHY_2M_PREF_MASK | #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - | BLE_HCI_LE_PHY_CODED_PREF_MASK + BLE_HCI_LE_PHY_CODED_PREF_MASK | #endif - ); -static const uint8_t ble_ll_conn_required_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK + 0); + +static const uint8_t ble_ll_conn_create_required_phy_mask = ( + BLE_HCI_LE_PHY_1M_PREF_MASK | #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - | BLE_HCI_LE_PHY_CODED_PREF_MASK + BLE_HCI_LE_PHY_CODED_PREF_MASK | #endif - ); + 0); #endif /** @@ -156,7 +160,9 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, enh_ev->peer_addr_type = connsm->peer_addr_type; memcpy(enh_ev->peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN); - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: if (connsm->inita_identity_used) { /* We used identity address in CONNECT_IND which can be just * fine if @@ -171,35 +177,57 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, } else { rpa = NULL; } - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: rpa = ble_ll_adv_get_local_rpa(advsm); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } if (rpa) { memcpy(enh_ev->local_rpa, rpa, BLE_DEV_ADDR_LEN); } - /* We need to adjust peer type if device connected using RPA - * and was resolved since RPA needs to be added to HCI event. - */ - if (connsm->peer_addr_type < BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT - && (connsm->rpa_index > -1)) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + /* Adjust address type if peer address was resolved */ + if (connsm->peer_addr_resolved) { enh_ev->peer_addr_type += 2; } +#endif if (enh_ev->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: rpa = ble_ll_scan_get_peer_rpa(); - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: rpa = ble_ll_adv_get_peer_rpa(advsm); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } + memcpy(enh_ev->peer_rpa, rpa, BLE_DEV_ADDR_LEN); } enh_ev->conn_itvl = htole16(connsm->conn_itvl); enh_ev->conn_latency = htole16(connsm->slave_latency); enh_ev->supervision_timeout = htole16(connsm->supervision_tmo); - enh_ev->mca = connsm->master_sca; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + enh_ev->mca = connsm->master_sca; + } +#endif } ble_ll_hci_event_send(hci_ev); @@ -220,15 +248,15 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, ev->conn_handle = htole16(connsm->conn_handle); ev->role = connsm->conn_role - 1; ev->peer_addr_type = connsm->peer_addr_type; - - if (ev->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) { - ev->peer_addr_type -= 2; - } memcpy(ev->peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN); ev->conn_itvl = htole16(connsm->conn_itvl); ev->conn_latency = htole16(connsm->slave_latency); ev->supervision_timeout = htole16(connsm->supervision_tmo); - ev->mca = connsm->master_sca; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + ev->mca = connsm->master_sca; + } +#endif } ble_ll_hci_event_send(hci_ev); @@ -406,18 +434,64 @@ ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason) } } +int +ble_ll_conn_hci_create_check_scan(struct ble_ll_conn_create_scan *p) +{ + if (p->filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if ((p->filter_policy == 0) && + (p->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (p->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (p->init_phy_mask & ~ble_ll_conn_create_valid_phy_mask) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!(p->init_phy_mask & ble_ll_conn_create_required_phy_mask)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } +#endif + + return 0; +} + static int -ble_ll_conn_hci_chk_scan_params(uint16_t itvl, uint16_t window) +ble_ll_conn_hci_create_check_params(struct ble_ll_conn_create_params *cc_params) { - /* Check interval and window */ - if ((itvl < BLE_HCI_SCAN_ITVL_MIN) || - (itvl > BLE_HCI_SCAN_ITVL_MAX) || - (window < BLE_HCI_SCAN_WINDOW_MIN) || - (window > BLE_HCI_SCAN_WINDOW_MAX) || - (itvl < window)) { + int rc; + + rc = ble_ll_conn_hci_chk_conn_params(cc_params->conn_itvl, + cc_params->conn_itvl, + cc_params->conn_latency, + cc_params->supervision_timeout); + if (rc) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (cc_params->min_ce_len > cc_params->max_ce_len) { return BLE_ERR_INV_HCI_CMD_PARMS; } + /* Adjust min/max ce length to be less than interval */ + if (cc_params->min_ce_len > cc_params->conn_itvl) { + cc_params->min_ce_len = cc_params->conn_itvl; + } + if (cc_params->max_ce_len > cc_params->conn_itvl) { + cc_params->max_ce_len = cc_params->conn_itvl; + } + + /* Precalculate conn interval */ + ble_ll_conn_itvl_to_ticks(cc_params->conn_itvl, &cc_params->conn_itvl_ticks, + &cc_params->conn_itvl_usecs); + return 0; } @@ -431,11 +505,14 @@ ble_ll_conn_hci_chk_scan_params(uint16_t itvl, uint16_t window) * @return int */ int -ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) +ble_ll_conn_hci_create(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_create_conn_cp *cmd = (const void *) cmdbuf; + struct ble_ll_conn_create_scan cc_scan; + struct ble_ll_conn_create_params cc_params; struct ble_ll_conn_sm *connsm; - struct hci_create_conn hcc = { 0 }; + uint16_t conn_itvl_min; + uint16_t conn_itvl_max; int rc; if (len < sizeof(*cmd)) { @@ -443,7 +520,7 @@ ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) } /* If we are already creating a connection we should leave */ - if (g_ble_ll_conn_create_sm) { + if (g_ble_ll_conn_create_sm.connsm) { return BLE_ERR_CMD_DISALLOWED; } @@ -452,57 +529,48 @@ ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_CMD_DISALLOWED; } - /* Retrieve command data */ - hcc.scan_itvl = le16toh(cmd->scan_itvl); - hcc.scan_window = le16toh(cmd->scan_window); - - rc = ble_ll_conn_hci_chk_scan_params(hcc.scan_itvl, hcc.scan_window); - if (rc) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Check filter policy */ - hcc.filter_policy = cmd->filter_policy; - if (hcc.filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; + cc_scan.own_addr_type = cmd->own_addr_type; + cc_scan.filter_policy = cmd->filter_policy; + if (cc_scan.filter_policy == 0) { + cc_scan.peer_addr_type = cmd->peer_addr_type; + memcpy(&cc_scan.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); + } else { + cc_scan.peer_addr_type = 0; + memset(&cc_scan.peer_addr, 0, BLE_DEV_ADDR_LEN); } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + cc_scan.init_phy_mask = BLE_HCI_LE_PHY_1M_PREF_MASK; +#endif - /* Get peer address type and address only if no whitelist used */ - if (hcc.filter_policy == 0) { - hcc.peer_addr_type = cmd->peer_addr_type; - if (hcc.peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } + cc_scan.scan_params[PHY_UNCODED].itvl = le16toh(cmd->scan_itvl); + cc_scan.scan_params[PHY_UNCODED].window = le16toh(cmd->scan_window); - memcpy(&hcc.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); + rc = ble_ll_conn_hci_create_check_scan(&cc_scan); + if (rc) { + return rc; } - /* Get own address type (used in connection request) */ - hcc.own_addr_type = cmd->own_addr_type; - if (hcc.own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { + conn_itvl_min = le16toh(cmd->min_conn_itvl); + conn_itvl_max = le16toh(cmd->max_conn_itvl); + + /* Check min/max interval here since generic check does not have min/max + * parameters to check. + */ + if (conn_itvl_min > conn_itvl_max) { return BLE_ERR_INV_HCI_CMD_PARMS; } - /* Check connection interval, latency and supervision timeoout */ - hcc.conn_itvl_min = le16toh(cmd->min_conn_itvl); - hcc.conn_itvl_max = le16toh(cmd->max_conn_itvl); - hcc.conn_latency = le16toh(cmd->conn_latency); - hcc.supervision_timeout = le16toh(cmd->tmo); - rc = ble_ll_conn_hci_chk_conn_params(hcc.conn_itvl_min, - hcc.conn_itvl_max, - hcc.conn_latency, - hcc.supervision_timeout); + cc_params.conn_itvl = conn_itvl_max; + cc_params.conn_latency = le16toh(cmd->conn_latency); + cc_params.supervision_timeout = le16toh(cmd->tmo); + cc_params.min_ce_len = le16toh(cmd->min_ce); + cc_params.max_ce_len = le16toh(cmd->max_ce); + + rc = ble_ll_conn_hci_create_check_params(&cc_params); if (rc) { return rc; } - /* Min/max connection event lengths */ - hcc.min_ce_len = le16toh(cmd->min_ce); - hcc.max_ce_len = le16toh(cmd->max_ce); - if (hcc.min_ce_len > hcc.max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - /* Make sure we can allocate an event to send the connection complete */ if (ble_ll_init_alloc_conn_comp_ev()) { return BLE_ERR_MEM_CAPACITY; @@ -515,18 +583,14 @@ ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) } /* Initialize state machine in master role and start state machine */ - ble_ll_conn_master_init(connsm, &hcc); + ble_ll_conn_master_init(connsm, &cc_scan, &cc_params); ble_ll_conn_sm_new(connsm); - /* CSA will be selected when advertising is received */ /* Start scanning */ - rc = ble_ll_scan_initiator_start(&hcc, &connsm->scansm); + rc = ble_ll_scan_initiator_start(connsm, 0, &cc_scan); if (rc) { SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - } else { - /* Set the connection state machine we are trying to create. */ - g_ble_ll_conn_create_sm = connsm; } return rc; @@ -534,198 +598,166 @@ ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static void -ble_ll_conn_hcc_params_set_fallback(struct hci_ext_create_conn *hcc, - const struct hci_ext_conn_params *fallback) +ble_ll_conn_hci_ext_create_set_fb_params(uint8_t init_phy_mask, + struct ble_ll_conn_create_params *cc_params_fb) { - BLE_LL_ASSERT(fallback); - - if (!(hcc->init_phy_mask & BLE_PHY_MASK_1M)) { - hcc->params[0] = *fallback; + if ((init_phy_mask & BLE_PHY_MASK_1M) == 0) { + g_ble_ll_conn_create_sm.params[BLE_PHY_IDX_1M] = *cc_params_fb; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - if (!(hcc->init_phy_mask & BLE_PHY_MASK_2M)) { - hcc->params[1] = *fallback; + if ((init_phy_mask & BLE_PHY_MASK_2M) == 0) { + g_ble_ll_conn_create_sm.params[BLE_PHY_IDX_2M] = *cc_params_fb; } #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (!(hcc->init_phy_mask & BLE_PHY_MASK_CODED)) { - hcc->params[2] = *fallback; + if ((init_phy_mask & BLE_PHY_MASK_CODED) == 0) { + g_ble_ll_conn_create_sm.params[BLE_PHY_IDX_CODED] = *cc_params_fb; } #endif } -int -ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t len) +static int +ble_ll_conn_hci_ext_create_parse_params(const struct conn_params *params, + uint8_t phy, + struct ble_ll_conn_create_scan *cc_scan, + struct ble_ll_conn_create_params *cc_params) { - const struct ble_hci_le_ext_create_conn_cp *cmd = (const void *) cmdbuf; - const struct conn_params *params = cmd->conn_params; - const struct hci_ext_conn_params *fallback_params = NULL; - struct hci_ext_create_conn hcc = { 0 }; - struct ble_ll_conn_sm *connsm; + uint16_t conn_itvl_min; + uint16_t conn_itvl_max; + uint16_t scan_itvl; + uint16_t scan_window; int rc; - /* validate length */ - if (len < sizeof(*cmd)) { + conn_itvl_min = le16toh(params->conn_min_itvl); + conn_itvl_max = le16toh(params->conn_max_itvl); + + /* Check min/max interval here since generic check does not have min/max + * parameters to check. + */ + if (conn_itvl_min > conn_itvl_max) { return BLE_ERR_INV_HCI_CMD_PARMS; } - len -= sizeof(*cmd); + cc_params->conn_itvl = conn_itvl_max; + cc_params->conn_latency = le16toh(params->conn_latency); + cc_params->supervision_timeout = le16toh(params->supervision_timeout); + cc_params->min_ce_len = le16toh(params->min_ce); + cc_params->max_ce_len = le16toh(params->max_ce); - /* If we are already creating a connection we should leave */ - if (g_ble_ll_conn_create_sm) { - return BLE_ERR_CMD_DISALLOWED; + rc = ble_ll_conn_hci_create_check_params(cc_params); + if (rc) { + return rc; } - /* If already enabled, we return an error */ - if (ble_ll_scan_enabled()) { - return BLE_ERR_CMD_DISALLOWED; - } + if (phy != BLE_PHY_2M) { + scan_itvl = le16toh(params->scan_itvl); + scan_window = le16toh(params->scan_window); - hcc.filter_policy = cmd->filter_policy; - if (hcc.filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } + if ((scan_itvl < BLE_HCI_SCAN_ITVL_MIN) || + (scan_itvl > BLE_HCI_SCAN_ITVL_MAX) || + (scan_window < BLE_HCI_SCAN_WINDOW_MIN) || + (scan_window > BLE_HCI_SCAN_WINDOW_MAX) || + (scan_itvl < scan_window)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } - hcc.own_addr_type = cmd->own_addr_type; - if (hcc.own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; + if (phy == BLE_PHY_1M) { + cc_scan->scan_params[PHY_UNCODED].itvl = scan_itvl; + cc_scan->scan_params[PHY_UNCODED].window = scan_window; + } else { + cc_scan->scan_params[PHY_CODED].itvl = scan_itvl; + cc_scan->scan_params[PHY_CODED].window = scan_window; + } } - /* Validate peer address type only if no whitelist used */ - if (hcc.filter_policy == 0) { - hcc.peer_addr_type = cmd->peer_addr_type; + return 0; +} - if (hcc.peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } +int +ble_ll_conn_hci_ext_create(const uint8_t *cmdbuf, uint8_t len) +{ + static const struct init_phy { + uint8_t idx; + uint8_t mask; + uint8_t phy; + } init_phys[] = { + {BLE_PHY_IDX_1M, BLE_PHY_MASK_1M, BLE_PHY_1M}, +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) + {BLE_PHY_IDX_2M, BLE_PHY_MASK_2M, BLE_PHY_2M}, +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + {BLE_PHY_IDX_CODED, BLE_PHY_MASK_CODED, BLE_PHY_CODED}, +#endif + }; - memcpy(hcc.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); - } + const struct ble_hci_le_ext_create_conn_cp *cmd = (const void *)cmdbuf; + const struct conn_params *params = cmd->conn_params; + struct ble_ll_conn_create_scan cc_scan; + struct ble_ll_conn_create_params *cc_params; + struct ble_ll_conn_create_params *cc_params_fb; + struct ble_ll_conn_sm *connsm; + const struct init_phy *init_phy; + int rc; - hcc.init_phy_mask = cmd->init_phy_mask; - if (hcc.init_phy_mask & ~ble_ll_valid_conn_phy_mask) { + /* validate length */ + if (len < sizeof(*cmd) + + __builtin_popcount(cmd->init_phy_mask) * sizeof(*params)) { return BLE_ERR_INV_HCI_CMD_PARMS; } - if (!(hcc.init_phy_mask & ble_ll_conn_required_phy_mask)) { - /* At least one of those need to be set */ - return BLE_ERR_INV_HCI_CMD_PARMS; + /* If we are already creating a connection we should leave */ + if (g_ble_ll_conn_create_sm.connsm) { + return BLE_ERR_CMD_DISALLOWED; } - if (hcc.init_phy_mask & BLE_PHY_MASK_1M) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - len -= sizeof(*params); - - hcc.params[0].scan_itvl = le16toh(params->scan_itvl); - hcc.params[0].scan_window = le16toh(params->scan_window); - - rc = ble_ll_conn_hci_chk_scan_params(hcc.params[0].scan_itvl, - hcc.params[0].scan_window); - if (rc) { - return rc; - } - - hcc.params[0].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[0].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[0].conn_latency = le16toh(params->conn_latency); - hcc.params[0].supervision_timeout = le16toh(params->supervision_timeout); - - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[0].conn_itvl_min, - hcc.params[0].conn_itvl_max, - hcc.params[0].conn_latency, - hcc.params[0].supervision_timeout); - if (rc) { - return rc; - } - - /* Min/max connection event lengths */ - hcc.params[0].min_ce_len = le16toh(params->min_ce); - hcc.params[0].max_ce_len = le16toh(params->max_ce); - if (hcc.params[0].min_ce_len > hcc.params[0].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - fallback_params = &hcc.params[0]; - params++; + /* If already enabled, we return an error */ + if (ble_ll_scan_enabled()) { + return BLE_ERR_CMD_DISALLOWED; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - if (hcc.init_phy_mask & BLE_PHY_MASK_2M) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - len -= sizeof(*params); - - hcc.params[1].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[1].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[1].conn_latency = le16toh(params->conn_latency); - hcc.params[1].supervision_timeout = le16toh(params->supervision_timeout); - - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[1].conn_itvl_min, - hcc.params[1].conn_itvl_max, - hcc.params[1].conn_latency, - hcc.params[1].supervision_timeout); - if (rc) { - return rc; - } - - /* Min/max connection event lengths */ - hcc.params[1].min_ce_len = le16toh(params->min_ce); - hcc.params[1].max_ce_len = le16toh(params->max_ce); - if (hcc.params[1].min_ce_len > hcc.params[1].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } + cc_scan.own_addr_type = cmd->own_addr_type; + cc_scan.filter_policy = cmd->filter_policy; + if (cc_scan.filter_policy == 0) { + cc_scan.peer_addr_type = cmd->peer_addr_type; + memcpy(cc_scan.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); + } else { + cc_scan.peer_addr_type = 0; + memset(cc_scan.peer_addr, 0, BLE_DEV_ADDR_LEN); + } + cc_scan.init_phy_mask = cmd->init_phy_mask; - params++; + rc = ble_ll_conn_hci_create_check_scan(&cc_scan); + if (rc) { + return rc; } -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (hcc.init_phy_mask & BLE_PHY_MASK_CODED) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - len -= sizeof(*params); + cc_params_fb = NULL; - hcc.params[2].scan_itvl = le16toh(params->scan_itvl); - hcc.params[2].scan_window = le16toh(params->scan_window); + for (int i = 0; i < ARRAY_SIZE(init_phys); i++) { + init_phy = &init_phys[i]; - rc = ble_ll_conn_hci_chk_scan_params(hcc.params[2].scan_itvl, - hcc.params[2].scan_window); - if (rc) { - return rc; + if ((cc_scan.init_phy_mask & init_phy->mask) == 0) { + continue; } - hcc.params[2].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[2].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[2].conn_latency = le16toh(params->conn_latency); - hcc.params[2].supervision_timeout = le16toh(params->supervision_timeout); + cc_params = &g_ble_ll_conn_create_sm.params[init_phy->idx]; - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[2].conn_itvl_min, - hcc.params[2].conn_itvl_max, - hcc.params[2].conn_latency, - hcc.params[2].supervision_timeout); + rc = ble_ll_conn_hci_ext_create_parse_params(params, init_phy->phy, + &cc_scan, cc_params); if (rc) { return rc; } - /* Min/max connection event lengths */ - hcc.params[2].min_ce_len = le16toh(params->min_ce); - hcc.params[2].max_ce_len = le16toh(params->max_ce); - if (hcc.params[2].min_ce_len > hcc.params[2].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!fallback_params) { - fallback_params = &hcc.params[2]; + if (!cc_params_fb) { + cc_params_fb = cc_params; } params++; } -#endif + + ble_ll_conn_hci_ext_create_set_fb_params(cc_scan.init_phy_mask, + cc_params_fb); /* Make sure we can allocate an event to send the connection complete */ if (ble_ll_init_alloc_conn_comp_ev()) { @@ -738,22 +770,16 @@ ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_CONN_LIMIT; } - ble_ll_conn_hcc_params_set_fallback(&hcc, fallback_params); - /* Initialize state machine in master role and start state machine */ - ble_ll_conn_ext_master_init(connsm, &hcc); + ble_ll_conn_master_init(connsm, &cc_scan, + &g_ble_ll_conn_create_sm.params[0]); ble_ll_conn_sm_new(connsm); - /* CSA will be selected when advertising is received */ - /* Start scanning */ - rc = ble_ll_scan_ext_initiator_start(&hcc, &connsm->scansm); + rc = ble_ll_scan_initiator_start(connsm, 1, &cc_scan); if (rc) { SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - } else { - /* Set the connection state machine we are trying to create. */ - g_ble_ll_conn_create_sm = connsm; } return rc; @@ -827,10 +853,12 @@ ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len) */ if (!connsm->csmflags.cfbit.rxd_features && !IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && !(ble_ll_read_supp_features() & BLE_LL_FEAT_SLAVE_INIT)) { return BLE_ERR_CMD_DISALLOWED; } +#endif ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG); } @@ -881,9 +909,11 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) /* See if this feature is supported on both sides */ if ((connsm->conn_features & BLE_LL_FEAT_CONN_PARM_REQ) == 0) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { return BLE_ERR_UNSUPP_REM_FEATURE; } +#endif ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE; } else { ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ; @@ -896,14 +926,24 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) * slave. */ if (connsm->csmflags.cfbit.awaiting_host_reply) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - return BLE_ERR_LMP_COLLISION; - } else { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: connsm->csmflags.cfbit.awaiting_host_reply = 0; /* XXX: If this fails no reject ind will be sent! */ ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, BLE_ERR_LMP_COLLISION); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: + return BLE_ERR_LMP_COLLISION; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } @@ -911,11 +951,13 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) * If we are a slave and the master has initiated the channel map * update procedure we should deny the slave request for now. */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (connsm->csmflags.cfbit.chanmap_update_scheduled) { if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { return BLE_ERR_DIFF_TRANS_COLL; } } +#endif /* Retrieve command data */ hcu = &connsm->conn_param_req; @@ -1099,10 +1141,10 @@ ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) * return disallowed as well */ OS_ENTER_CRITICAL(sr); - connsm = g_ble_ll_conn_create_sm; + connsm = g_ble_ll_conn_create_sm.connsm; if (connsm && (connsm->conn_state == BLE_LL_CONN_STATE_IDLE)) { /* stop scanning and end the connection event */ - g_ble_ll_conn_create_sm = NULL; + g_ble_ll_conn_create_sm.connsm = NULL; ble_ll_scan_sm_stop(1); ble_ll_conn_end(connsm, BLE_ERR_UNK_CONN_ID); @@ -1302,6 +1344,7 @@ ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len, *rsplen = sizeof(*rsp); return rc; } +#endif /** * Called when the host issues the LE command "set host channel classification" @@ -1335,6 +1378,8 @@ ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_SUCCESS; } +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) int ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len, @@ -1422,8 +1467,10 @@ ble_ll_conn_hci_le_start_encrypt(const uint8_t *cmdbuf, uint8_t len) connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) } else if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { rc = BLE_ERR_UNSPECIFIED; +#endif } else if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { /* * The specification does not say what to do here but the host should @@ -1476,11 +1523,13 @@ ble_ll_conn_hci_le_ltk_reply(const uint8_t *cmdbuf, uint8_t len, goto ltk_key_cmd_complete; } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Should never get this if we are a master! */ if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { rc = BLE_ERR_UNSPECIFIED; goto ltk_key_cmd_complete; } +#endif /* The connection should be awaiting a reply. If not, just discard */ if (connsm->enc_data.enc_state != CONN_ENC_S_LTK_REQ_WAIT) { @@ -1533,11 +1582,13 @@ ble_ll_conn_hci_le_ltk_neg_reply(const uint8_t *cmdbuf, uint8_t len, goto ltk_key_cmd_complete; } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Should never get this if we are a master! */ if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { rc = BLE_ERR_UNSPECIFIED; goto ltk_key_cmd_complete; } +#endif /* The connection should be awaiting a reply. If not, just discard */ if (connsm->enc_data.enc_state != CONN_ENC_S_LTK_REQ_WAIT) { @@ -1917,3 +1968,4 @@ ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_SUCCESS; } #endif +#endif diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h index 53358c4a0d..73e4106074 100644 --- a/nimble/controller/src/ble_ll_conn_priv.h +++ b/nimble/controller/src/ble_ll_conn_priv.h @@ -64,6 +64,7 @@ struct ble_ll_conn_global_params { uint8_t master_chan_map[BLE_LL_CONN_CHMAP_LEN]; uint8_t num_used_chans; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint8_t supp_max_tx_octets; uint8_t supp_max_rx_octets; uint8_t conn_init_max_tx_octets; @@ -74,6 +75,7 @@ struct ble_ll_conn_global_params uint16_t conn_init_max_tx_time_coded; uint16_t supp_max_tx_time; uint16_t supp_max_rx_time; +#endif }; extern struct ble_ll_conn_global_params g_ble_ll_conn_params; @@ -93,8 +95,38 @@ STAILQ_HEAD(ble_ll_conn_free_list, ble_ll_conn_sm); extern struct ble_ll_conn_active_list g_ble_ll_conn_active_list; extern struct ble_ll_conn_free_list g_ble_ll_conn_free_list; -/* Pointer to connection state machine we are trying to create */ -extern struct ble_ll_conn_sm *g_ble_ll_conn_create_sm; +struct ble_ll_conn_create_scan { + uint8_t filter_policy; + uint8_t own_addr_type; + uint8_t peer_addr_type; + uint8_t peer_addr[BLE_DEV_ADDR_LEN]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + uint8_t init_phy_mask; +#endif + struct { + uint16_t itvl; + uint16_t window; + } scan_params[2]; +}; + +struct ble_ll_conn_create_params { + uint32_t conn_itvl; + uint32_t conn_itvl_ticks; + uint8_t conn_itvl_usecs; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +}; + +struct ble_ll_conn_create_sm { + struct ble_ll_conn_sm *connsm; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + struct ble_ll_conn_create_params params[3]; +#endif +}; + +extern struct ble_ll_conn_create_sm g_ble_ll_conn_create_sm; /* Generic interface */ struct ble_ll_len_req; @@ -120,18 +152,11 @@ struct hci_create_conn void ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm); void ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err); void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, - uint8_t hdr_byte, uint8_t length); + uint8_t hdr_byte, uint16_t length); struct ble_ll_conn_sm *ble_ll_conn_sm_get(void); void ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, - struct hci_create_conn *hcc); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -void ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm, - struct hci_ext_create_conn *hcc); - -void ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm, - struct hci_ext_conn_params *hcc_params, - int phy); -#endif + struct ble_ll_conn_create_scan *cc_scan, + struct ble_ll_conn_create_params *cc_params); struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle); void ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm); @@ -148,25 +173,17 @@ void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len); int ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa); int ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr); -void ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr); -int ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr); -int ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, - struct ble_mbuf_hdr *ble_hdr); void ble_ll_conn_wfr_timer_exp(void); -void ble_ll_conn_init_wfr_timer_exp(void); int ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2); uint32_t ble_ll_conn_get_ce_end_time(void); void ble_ll_conn_event_halt(void); -void ble_ll_conn_reset_pending_aux_conn_rsp(void); -bool ble_ll_conn_init_pending_aux_conn_rsp(void); /* HCI */ void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason); void ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm); int ble_ll_conn_hci_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd); int ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_conn_hci_create(const uint8_t *cmdbuf, uint8_t len); int ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len); int ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len); int ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, @@ -213,6 +230,9 @@ bool ble_ll_conn_cth_flow_enable(bool enabled); void ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf); #endif +void ble_ll_conn_itvl_to_ticks(uint32_t itvl, + uint32_t *itvl_ticks, uint8_t *itvl_usecs); + int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg); int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg); @@ -221,7 +241,7 @@ int ble_ll_conn_hci_le_rd_phy(const uint8_t *cmdbuf, uint8_t len, int ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len); int ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *connsm); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_conn_hci_ext_create(const uint8_t *cmdbuf, uint8_t len); #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c index c4ac6504c9..432045e675 100644 --- a/nimble/controller/src/ble_ll_ctrl.c +++ b/nimble/controller/src/ble_ll_ctrl.c @@ -31,6 +31,8 @@ #include "controller/ble_ll_sync.h" #include "ble_ll_conn_priv.h" +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + /* To use spec sample data for testing */ #undef BLE_LL_ENCRYPT_USE_TEST_DATA @@ -314,8 +316,7 @@ ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * update the connection parameters. This means that the previous * check is all we need for a master (when receiving a request). */ - if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) || - (opcode == BLE_LL_CTRL_CONN_PARM_RSP)) { + if (CONN_IS_SLAVE(connsm) || (opcode == BLE_LL_CTRL_CONN_PARM_RSP)) { /* * Not sure what to do about the slave. It is possible that the * current connection parameters are not the same ones as the local host @@ -488,11 +489,13 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t * break; case BLE_LL_CTRL_CONN_PARM_REQ: BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_CONN_PARM_REQ); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL); connsm->reject_reason = BLE_ERR_SUCCESS; return BLE_LL_CTRL_CONN_UPDATE_IND; } +#endif /* note: fall-through intentional */ case BLE_LL_CTRL_CONN_PARM_RSP: ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ; @@ -559,11 +562,6 @@ ble_ll_ctrl_proc_rsp_timer_cb(struct ble_npl_event *ev) static void ble_ll_ctrl_start_rsp_timer(struct ble_ll_conn_sm *connsm) { - ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer, - &g_ble_ll_data.ll_evq, - ble_ll_ctrl_proc_rsp_timer_cb, - connsm); - /* Re-start timer. Control procedure timeout is 40 seconds */ ble_npl_callout_reset(&connsm->ctrl_proc_rsp_timer, ble_npl_time_ms_to_ticks32(BLE_LL_CTRL_PROC_TIMEOUT_MS)); @@ -679,6 +677,7 @@ ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm) } } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /** * * There is probably a better way for the controller to choose which PHY use. @@ -718,6 +717,7 @@ ble_ll_ctrl_find_new_phy(uint8_t phy_mask_prefs) * @param ctrdata: Pointer to where CtrData of UPDATE_IND pdu starts * @param slave_req flag denoting if slave requested this. 0: no 1:yes */ + static void ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t *ctrdata, int slave_req) @@ -734,10 +734,12 @@ ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, rx_phys = dptr[1]; /* If we are master, check if slave requested symmetric PHY */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { is_slave_sym = tx_phys == rx_phys; is_slave_sym &= __builtin_popcount(tx_phys) == 1; } +#endif /* Get m_to_s and s_to_m masks */ if (slave_req) { @@ -823,6 +825,7 @@ ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, ctrdata[1] = s_to_m; put_le16(ctrdata + 2, instant); } +#endif /** * Create a LL_PHY_REQ or LL_PHY_RSP pdu @@ -877,7 +880,9 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, err = ble_ll_ctrl_proc_with_instant_initiated(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: if (err) { ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_PHY_REQ, err, rsp); rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; @@ -890,7 +895,10 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, ble_ll_ctrl_phy_update_ind_make(connsm, req, rsp, 1); rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND; } - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: /* XXX: deal with other control procedures that we need to stop */ if (err) { if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) { @@ -918,7 +926,13 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, /* Start response timer */ connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE; ble_ll_ctrl_start_rsp_timer(connsm); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } + return rsp_opcode; } @@ -938,7 +952,10 @@ ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t rsp_opcode; rsp_opcode = BLE_ERR_MAX; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) { ble_ll_ctrl_phy_update_ind_make(connsm, dptr, rsp, 0); ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer); @@ -951,8 +968,16 @@ ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * * XXX: TODO count some stat? */ - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } /* NOTE: slave should never receive one of these */ @@ -981,9 +1006,11 @@ ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) uint16_t instant; uint16_t delta; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif /* * Reception stops the procedure response timer but does not @@ -1439,9 +1466,11 @@ static uint8_t ble_ll_ctrl_rx_enc_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t *rspdata) { - if (connsm->conn_role != BLE_LL_CONN_ROLE_SLAVE) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_TO_BE_SENT; @@ -1484,15 +1513,27 @@ ble_ll_ctrl_rx_start_enc_req(struct ble_ll_conn_sm *connsm) /* Only master should receive start enc request */ rc = BLE_ERR_MAX; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: /* We only want to send a START_ENC_RSP if we havent yet */ if (connsm->enc_data.enc_state == CONN_ENC_S_START_ENC_REQ_WAIT) { connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT; rc = BLE_LL_CTRL_START_ENC_RSP; } - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: rc = BLE_LL_CTRL_UNKNOWN_RSP; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } + return rc; } @@ -1507,7 +1548,7 @@ ble_ll_ctrl_rx_pause_enc_req(struct ble_ll_conn_sm *connsm) * ignore it... */ rc = BLE_ERR_MAX; - if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && + if (CONN_IS_SLAVE(connsm) && (connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED)) { rc = BLE_LL_CTRL_PAUSE_ENC_RSP; } else { @@ -1530,16 +1571,28 @@ ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm *connsm) { int rc; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: rc = BLE_LL_CTRL_PAUSE_ENC_RSP; - } else if (connsm->enc_data.enc_state == CONN_ENC_S_PAUSE_ENC_RSP_WAIT) { - /* Master sends back unencrypted LL_PAUSE_ENC_RSP. - * From this moment encryption is paused. - */ - rc = BLE_ERR_MAX; - connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; - } else { - rc = BLE_LL_CTRL_UNKNOWN_RSP; + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: + if (connsm->enc_data.enc_state == CONN_ENC_S_PAUSE_ENC_RSP_WAIT) { + /* Master sends back unencrypted LL_PAUSE_ENC_RSP. + * From this moment encryption is paused. + */ + rc = BLE_ERR_MAX; + connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; + } else { + rc = BLE_LL_CTRL_UNKNOWN_RSP; + } + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } return rc; @@ -1564,9 +1617,9 @@ ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm *connsm) return BLE_ERR_MAX; } - /* If master, we are done. Stop control procedure and sent event to host */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT); /* We are encrypted */ @@ -1575,7 +1628,10 @@ ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm *connsm) ble_ll_conn_auth_pyld_timer_start(connsm); #endif rc = BLE_ERR_MAX; - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: /* Procedure has completed but slave needs to send START_ENC_RSP */ rc = BLE_LL_CTRL_START_ENC_RSP; @@ -1583,6 +1639,11 @@ ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm *connsm) if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT); } + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } /* @@ -1697,14 +1758,24 @@ ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp, { uint8_t rsp_opcode; - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - /* Create a connection parameter response */ - ble_ll_ctrl_conn_param_pdu_make(connsm, rsp + 1, req); - rsp_opcode = BLE_LL_CTRL_CONN_PARM_RSP; - } else { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: /* Create a connection update pdu */ ble_ll_ctrl_conn_upd_make(connsm, rsp + 1, req); rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: + /* Create a connection parameter response */ + ble_ll_ctrl_conn_param_pdu_make(connsm, rsp + 1, req); + rsp_opcode = BLE_LL_CTRL_CONN_PARM_RSP; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } return rsp_opcode; @@ -1737,14 +1808,24 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, switch (connsm->cur_ctrl_proc) { case BLE_LL_CTRL_PROC_CONN_PARAM_REQ: if (opcode == BLE_LL_CTRL_REJECT_IND_EXT) { - /* As a master we should send connection update indication in this point */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { + #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: + /* As a master we should send connection update indication in this point */ rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL); connsm->reject_reason = BLE_ERR_SUCCESS; - } else { + break; + #endif + #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); ble_ll_hci_ev_conn_update(connsm, ble_error); + break; + #endif + default: + BLE_LL_ASSERT(0); + break; } } break; @@ -1797,9 +1878,11 @@ ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr) struct ble_ll_conn_upd_req *reqdata; /* Only a slave should receive this */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif /* Retrieve parameters */ reqdata = &connsm->conn_update_req; @@ -1918,12 +2001,12 @@ ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * requests if we are a slave. */ if (opcode == BLE_LL_CTRL_SLAVE_FEATURE_REQ) { - if (connsm->conn_role != BLE_LL_CONN_ROLE_MASTER) { + if (!CONN_IS_MASTER(connsm)) { return BLE_LL_CTRL_UNKNOWN_RSP; } } else { /* XXX: not sure this is correct but do it anyway */ - if (connsm->conn_role != BLE_LL_CONN_ROLE_SLAVE) { + if (!CONN_IS_SLAVE(connsm)) { return BLE_LL_CTRL_UNKNOWN_RSP; } } @@ -2023,15 +2106,24 @@ ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * transaction collision error code. */ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); - ble_ll_hci_ev_conn_update(connsm, BLE_ERR_LMP_COLLISION); - } else { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: /* The master sends reject ind ext w/error code 0x23 */ rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ; rspbuf[2] = BLE_ERR_LMP_COLLISION; return rsp_opcode; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); + ble_ll_hci_ev_conn_update(connsm, BLE_ERR_LMP_COLLISION); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } @@ -2039,6 +2131,7 @@ ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * If we are a master and we currently performing a channel map * update procedure we need to return an error */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) && (connsm->csmflags.cfbit.chanmap_update_scheduled)) { rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; @@ -2046,6 +2139,7 @@ ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, rspbuf[2] = BLE_ERR_DIFF_TRANS_COLL; return rsp_opcode; } +#endif /* Process the received connection parameter request */ rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf, @@ -2060,9 +2154,11 @@ ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t rsp_opcode; /* A slave should never receive this response */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif /* * This case should never happen! It means that the slave initiated a @@ -2136,9 +2232,11 @@ ble_ll_ctrl_rx_chanmap_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr) uint16_t instant; uint16_t conn_events; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif /* If instant is in the past, we have to end the connection */ instant = get_le16(dptr + BLE_LL_CONN_CHMAP_LEN); @@ -2193,10 +2291,20 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc) ble_ll_ctrl_chanmap_req_make(connsm, ctrdata); break; case BLE_LL_CTRL_PROC_FEATURE_XCHG: - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: opcode = BLE_LL_CTRL_FEATURE_REQ; - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: opcode = BLE_LL_CTRL_SLAVE_FEATURE_REQ; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } put_le64(ctrdata, ble_ll_read_supp_features()); break; @@ -2473,6 +2581,12 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) len = dptr[1]; opcode = dptr[2]; +#if MYNEWT_VAL(BLE_LL_HCI_LLCP_TRACE) + ble_ll_hci_ev_send_vs_llcp_trace(0x03, connsm->conn_handle, + connsm->event_cntr, + &dptr[2], len); +#endif + /* * rspbuf points to first byte of response. The response buffer does not * contain the Data Channel PDU. Thus, the first byte of rspbuf is the @@ -2802,6 +2916,12 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) int rc; uint8_t opcode; +#if MYNEWT_VAL(BLE_LL_HCI_LLCP_TRACE) + ble_ll_hci_ev_send_vs_llcp_trace(0x04, connsm->conn_handle, + connsm->event_cntr, + txpdu->om_data, txpdu->om_len); +#endif + rc = 0; opcode = txpdu->om_data[0]; switch (opcode) { @@ -2842,6 +2962,7 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) connsm->enc_data.enc_state = CONN_ENC_S_LTK_REQ_WAIT; connsm->csmflags.cfbit.send_ltk_req = 1; break; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_CTRL_START_ENC_RSP: if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED; @@ -2856,11 +2977,17 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) } break; #endif +#endif #if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_CTRL_PHY_REQ: - connsm->phy_tx_transition = - ble_ll_ctrl_phy_tx_transition_get(connsm->phy_data.req_pref_tx_phys_mask); + if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + connsm->phy_tx_transition = + ble_ll_ctrl_phy_tx_transition_get( + connsm->phy_data.req_pref_tx_phys_mask); + } break; +#endif case BLE_LL_CTRL_PHY_UPDATE_IND: connsm->phy_tx_transition = ble_ll_ctrl_phy_tx_transition_get(txpdu->om_data[2]); @@ -2873,3 +3000,11 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) os_mbuf_free_chain(txpdu); return rc; } + +void +ble_ll_ctrl_init_conn_sm(struct ble_ll_conn_sm *connsm) +{ + ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer, &g_ble_ll_data.ll_evq, + ble_ll_ctrl_proc_rsp_timer_cb, connsm); +} +#endif diff --git a/porting/targets/dummy_bsp/include/bsp/bsp.h b/nimble/controller/src/ble_ll_ctrl_priv.h similarity index 82% rename from porting/targets/dummy_bsp/include/bsp/bsp.h rename to nimble/controller/src/ble_ll_ctrl_priv.h index 69e8b1cfbb..ca1c83d390 100644 --- a/porting/targets/dummy_bsp/include/bsp/bsp.h +++ b/nimble/controller/src/ble_ll_ctrl_priv.h @@ -17,15 +17,19 @@ * under the License. */ -#ifndef H_BSP_H -#define H_BSP_H +#ifndef H_BLE_LL_CTRL_PRIV_ +#define H_BLE_LL_CTRL_PRIV_ + +#include "controller/ble_ll_conn.h" #ifdef __cplusplus extern "C" { #endif +void ble_ll_ctrl_init_conn_sm(struct ble_ll_conn_sm *connsm); + #ifdef __cplusplus } #endif -#endif /* H_BSP_H */ +#endif /* H_BLE_LL_CTRL_PRIV_ */ diff --git a/nimble/controller/src/ble_ll_dtm.c b/nimble/controller/src/ble_ll_dtm.c index de3b168b22..8c9167799a 100644 --- a/nimble/controller/src/ble_ll_dtm.c +++ b/nimble/controller/src/ble_ll_dtm.c @@ -261,7 +261,7 @@ ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch) ble_ll_state_set(BLE_LL_STATE_DTM); - return BLE_LL_SCHED_STATE_DONE; + return BLE_LL_SCHED_STATE_RUNNING; resched: /* Reschedule from LL task if late for this PDU */ @@ -427,9 +427,10 @@ ble_ll_dtm_rx_sched_cb(struct ble_ll_sched_item *sch) if (ble_ll_dtm_rx_start() != 0) { ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); STATS_INC(ble_ll_dtm_stats, rx_failed); + return BLE_LL_SCHED_STATE_DONE; } - return BLE_LL_SCHED_STATE_DONE; + return BLE_LL_SCHED_STATE_RUNNING; } static int diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c index 7cd3621c6d..d368672914 100644 --- a/nimble/controller/src/ble_ll_hci.c +++ b/nimble/controller/src/ble_ll_hci.c @@ -36,6 +36,7 @@ #include "controller/ble_ll_iso.h" #include "ble_ll_priv.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_hci_priv.h" #if MYNEWT_VAL(BLE_LL_DTM) #include "ble_ll_dtm_priv.h" @@ -321,8 +322,14 @@ ble_ll_hci_le_read_bufsize(uint8_t *rspbuf, uint8_t *rsplen) { struct ble_hci_le_rd_buf_size_rp *rp = (void *) rspbuf; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) rp->data_len = htole16(g_ble_ll_data.ll_acl_pkt_size); rp->data_packets = g_ble_ll_data.ll_num_acl_pkts; +#else + /* TODO check if can just not support this command */ + rp->data_len = 0; + rp->data_packets = 0; +#endif *rsplen = sizeof(*rp); return BLE_ERR_SUCCESS; @@ -409,6 +416,7 @@ ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys, * * @return int */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) static int ble_ll_hci_le_set_def_phy(const uint8_t *cmdbuf, uint8_t len) { @@ -425,6 +433,7 @@ ble_ll_hci_le_set_def_phy(const uint8_t *cmdbuf, uint8_t len) return rc; } #endif +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) /** @@ -657,6 +666,7 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /** HCI LE read maximum advertising data length command. Returns the controllers * max supported advertising data length; * @@ -694,6 +704,7 @@ ble_ll_adv_rd_sup_adv_sets(uint8_t *rspbuf, uint8_t *rsplen) *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; } +#endif static bool ble_ll_is_valid_adv_mode(uint8_t ocf) @@ -785,7 +796,7 @@ ble_ll_read_rf_path_compensation(uint8_t *rspbuf, uint8_t *rsplen) rsp->rx_path_compensation = htole16(rx_path_pwr_compensation); rsp->tx_path_compensation = htole16(tx_path_pwr_compensation); - *rsplen = sizeof(*rsp);; + *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; } @@ -886,6 +897,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_set_random_addr(cmdbuf, len, false); #endif break; +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_HCI_OCF_LE_SET_ADV_PARAMS: rc = ble_ll_adv_set_adv_params(cmdbuf, len); break; @@ -903,20 +915,25 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, case BLE_HCI_OCF_LE_SET_ADV_ENABLE: rc = ble_ll_hci_adv_set_enable(cmdbuf, len); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_HCI_OCF_LE_SET_SCAN_PARAMS: - rc = ble_ll_scan_set_scan_params(cmdbuf, len); + rc = ble_ll_scan_hci_set_params(cmdbuf, len); break; case BLE_HCI_OCF_LE_SET_SCAN_ENABLE: - rc = ble_ll_hci_scan_set_enable(cmdbuf, len); + rc = ble_ll_scan_hci_set_enable(cmdbuf, len); break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_CREATE_CONN: - rc = ble_ll_conn_create(cmdbuf, len); + rc = ble_ll_conn_hci_create(cmdbuf, len); break; case BLE_HCI_OCF_LE_CREATE_CONN_CANCEL: if (len == 0) { rc = ble_ll_conn_create_cancel(cb); } break; +#endif +#endif case BLE_HCI_OCF_LE_RD_WHITE_LIST_SIZE: if (len == 0) { rc = ble_ll_whitelist_read_size(rspbuf, rsplen); @@ -933,18 +950,22 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, case BLE_HCI_OCF_LE_RMV_WHITE_LIST: rc = ble_ll_whitelist_rmv(cmdbuf, len); break; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_CONN_UPDATE: rc = ble_ll_conn_hci_update(cmdbuf, len); break; +#endif case BLE_HCI_OCF_LE_SET_HOST_CHAN_CLASS: rc = ble_ll_conn_hci_set_chan_class(cmdbuf, len); break; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_RD_CHAN_MAP: rc = ble_ll_conn_hci_rd_chan_map(cmdbuf, len, rspbuf, rsplen); break; case BLE_HCI_OCF_LE_RD_REM_FEAT: rc = ble_ll_conn_hci_read_rem_features(cmdbuf, len); break; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) case BLE_HCI_OCF_LE_ENCRYPT: rc = ble_ll_hci_le_encrypt(cmdbuf, len, rspbuf, rsplen); @@ -956,15 +977,19 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, } break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_START_ENCRYPT: rc = ble_ll_conn_hci_le_start_encrypt(cmdbuf, len); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY: rc = ble_ll_conn_hci_le_ltk_reply(cmdbuf, len, rspbuf, rsplen); break; case BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY: rc = ble_ll_conn_hci_le_ltk_neg_reply(cmdbuf, len, rspbuf, rsplen); break; +#endif #endif case BLE_HCI_OCF_LE_RD_SUPP_STATES : if (len == 0) { @@ -984,12 +1009,14 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, } break; #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_REM_CONN_PARAM_RR: rc = ble_ll_conn_hci_param_rr(cmdbuf, len, rspbuf, rsplen); break; case BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR: rc = ble_ll_conn_hci_param_nrr(cmdbuf, len, rspbuf, rsplen); break; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) case BLE_HCI_OCF_LE_SET_DATA_LEN: rc = ble_ll_conn_hci_set_data_len(cmdbuf, len, rspbuf, rsplen); @@ -1041,6 +1068,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; #endif #if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_RD_PHY: rc = ble_ll_conn_hci_le_rd_phy(cmdbuf, len, rspbuf, rsplen); break; @@ -1051,6 +1079,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_conn_hci_le_set_phy(cmdbuf, len); break; #endif +#endif #if MYNEWT_VAL(BLE_LL_DTM) case BLE_HCI_OCF_LE_RX_TEST_V2: rc = ble_ll_hci_dtm_rx_test_v2(cmdbuf, len); @@ -1059,6 +1088,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_hci_dtm_tx_test_v2(cmdbuf, len); break; #endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) case BLE_HCI_OCF_LE_SET_ADV_SET_RND_ADDR: rc = ble_ll_adv_hci_set_random_addr(cmdbuf, len); @@ -1105,17 +1135,21 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; #endif #endif +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) case BLE_HCI_OCF_LE_SET_EXT_SCAN_PARAM: - rc = ble_ll_set_ext_scan_params(cmdbuf, len); + rc = ble_ll_scan_hci_set_ext_params(cmdbuf, len); break; case BLE_HCI_OCF_LE_SET_EXT_SCAN_ENABLE: - rc = ble_ll_hci_ext_scan_set_enable(cmdbuf, len); + rc = ble_ll_scan_hci_set_ext_enable(cmdbuf, len); break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_EXT_CREATE_CONN: - rc = ble_ll_ext_conn_create(cmdbuf, len); + rc = ble_ll_conn_hci_ext_create(cmdbuf, len); break; #endif +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC: rc = ble_ll_sync_create(cmdbuf, len); @@ -1149,12 +1183,17 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_sync_receive_enable(cmdbuf, len); break; #endif +#endif #endif case BLE_HCI_OCF_LE_RD_TRANSMIT_POWER: - rc = ble_ll_read_tx_power(rspbuf, rsplen); + if (len == 0) { + rc = ble_ll_read_tx_power(rspbuf, rsplen); + } break; case BLE_HCI_OCF_LE_RD_RF_PATH_COMPENSATION: - rc = ble_ll_read_rf_path_compensation(rspbuf, rsplen); + if (len == 0) { + rc = ble_ll_read_rf_path_compensation(rspbuf, rsplen); + } break; case BLE_HCI_OCF_LE_WR_RF_PATH_COMPENSATION: rc = ble_ll_write_rf_path_compensation(cmdbuf, len); @@ -1165,12 +1204,16 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER: rc = ble_ll_sync_transfer(cmdbuf, len, rspbuf, rsplen); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER: rc = ble_ll_adv_periodic_set_info_transfer(cmdbuf, len, rspbuf, rsplen); break; +#endif case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS: rc = ble_ll_set_sync_transfer_params(cmdbuf, len, rspbuf, rsplen); break; @@ -1216,7 +1259,9 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_iso_remove_iso_data_path(cmdbuf, len); break; case BLE_HCI_OCF_LE_RD_BUF_SIZE_V2: - rc = ble_ll_hci_le_read_bufsize_v2(rspbuf, rsplen); + if (len == 0) { + rc = ble_ll_hci_le_read_bufsize_v2(rspbuf, rsplen); + } break; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST) @@ -1259,17 +1304,15 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, * This code is here because we add 256 to the return code to denote * that the reply to this command should be command status (as opposed to * command complete). - * - * For unknown HCI command let us return always command status as per - * specification Bluetooth 5, Vol. 2, Chapter 4.4 */ - if (ble_ll_hci_le_cmd_send_cmd_status(ocf) || rc == BLE_ERR_UNKNOWN_HCI_CMD) { + if (ble_ll_hci_le_cmd_send_cmd_status(ocf)) { rc += (BLE_ERR_MAX + 1); } return rc; } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static int ble_ll_hci_disconnect(const uint8_t *cmdbuf, uint8_t len) { @@ -1289,6 +1332,7 @@ ble_ll_hci_disconnect(const uint8_t *cmdbuf, uint8_t len) return ble_ll_conn_hci_disconnect_cmd(cmd); } +#endif /** * Process a link control command sent from the host to the controller. The HCI @@ -1309,18 +1353,18 @@ ble_ll_hci_link_ctrl_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf) int rc; switch (ocf) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_HCI_OCF_DISCONNECT_CMD: rc = ble_ll_hci_disconnect(cmdbuf, len); /* Send command status instead of command complete */ rc += (BLE_ERR_MAX + 1); break; - case BLE_HCI_OCF_RD_REM_VER_INFO: rc = ble_ll_conn_hci_rd_rem_ver_cmd(cmdbuf, len); /* Send command status instead of command complete */ rc += (BLE_ERR_MAX + 1); break; - +#endif default: rc = BLE_ERR_UNKNOWN_HCI_CMD; break; @@ -1514,9 +1558,11 @@ ble_ll_hci_status_params_cmd_proc(const uint8_t *cmdbuf, uint8_t len, int rc; switch (ocf) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_RD_RSSI: rc = ble_ll_conn_hci_rd_rssi(cmdbuf, len, rspbuf, rsplen); break; +#endif default: rc = BLE_ERR_UNKNOWN_HCI_CMD; break; @@ -1525,47 +1571,6 @@ ble_ll_hci_status_params_cmd_proc(const uint8_t *cmdbuf, uint8_t len, return rc; } -#if MYNEWT_VAL(BLE_HCI_VS) -static int -ble_ll_hci_vs_rd_static_addr(uint8_t *rspbuf, uint8_t *rsplen) -{ - struct ble_hci_vs_rd_static_addr_rp *rsp = (void *) rspbuf; - ble_addr_t addr; - - if (ble_hw_get_static_addr(&addr) < 0) { - return BLE_ERR_UNSPECIFIED; - } - - memcpy(rsp->addr, addr.val, sizeof(rsp->addr)); - - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; -} - -static int -ble_ll_hci_vs_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, - uint8_t *rspbuf, uint8_t *rsplen) -{ - int rc; - - /* Assume error; if all pass rc gets set to 0 */ - rc = BLE_ERR_INV_HCI_CMD_PARMS; - - switch (ocf) { - case BLE_HCI_OCF_VS_RD_STATIC_ADDR: - if (len == 0) { - rc = ble_ll_hci_vs_rd_static_addr(rspbuf, rsplen); - } - break; - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; - break; - } - - return rc; -} -#endif - /** * Called to process an HCI command from the host. * @@ -1625,7 +1630,7 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) case BLE_HCI_OGF_LE: rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen, &post_cb); break; -#if MYNEWT_VAL(BLE_HCI_VS) +#if MYNEWT_VAL(BLE_LL_HCI_VS) case BLE_HCI_OGF_VENDOR: rc = ble_ll_hci_vs_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); break; @@ -1636,6 +1641,13 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) break; } + /* We always send command status for unknown command + * ref: Core 5.3, Vol 4, Part E, 4.5 + */ + if (rc == BLE_ERR_UNKNOWN_HCI_CMD) { + rc += (BLE_ERR_MAX + 1); + } + /* If no response is generated, we free the buffers */ BLE_LL_ASSERT(rc >= 0); if (rc <= BLE_ERR_MAX) { @@ -1735,7 +1747,12 @@ ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg) int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) ble_ll_acl_data_in(om); +#else + /* host should never send ACL in that case but if it does just ignore it */ + os_mbuf_free_chain(om); +#endif return 0; } diff --git a/nimble/controller/src/ble_ll_hci_ev.c b/nimble/controller/src/ble_ll_hci_ev.c index 0d6da9a01e..9d6c39ecc0 100644 --- a/nimble/controller/src/ble_ll_hci_ev.c +++ b/nimble/controller/src/ble_ll_hci_ev.c @@ -493,9 +493,9 @@ ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, uint8_t status, #endif void -ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) +ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line) { - struct ble_hci_ev_vendor_debug *ev; + struct ble_hci_ev_vs_debug *ev; struct ble_hci_ev *hci_ev; unsigned int str_len; bool skip = true; @@ -510,7 +510,7 @@ ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_VENDOR_DEBUG; + hci_ev->opcode = BLE_HCI_EVCODE_VS_DEBUG; hci_ev->length = sizeof(*ev); ev = (void *) hci_ev->data; @@ -551,3 +551,31 @@ ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) ble_ll_hci_event_send(hci_ev); } } + +#if MYNEWT_VAL(BLE_LL_HCI_LLCP_TRACE) +void +ble_ll_hci_ev_send_vs_llcp_trace(uint8_t type, uint16_t handle, uint16_t count, + void *pdu, size_t length) +{ + struct ble_hci_ev_vs_debug *ev; + struct ble_hci_ev *hci_ev; + + hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + if (hci_ev) { + hci_ev->opcode = BLE_HCI_EVCODE_VS_DEBUG; + hci_ev->length = sizeof(*ev) + 8 + length; + ev = (void *) hci_ev->data; + + ev->id = 0x17; + ev->data[0] = type; + put_le16(&ev->data[1], handle); + put_le16(&ev->data[3], count); + ev->data[5] = 0; + ev->data[6] = 0; + ev->data[7] = 0; + memcpy(&ev->data[8], pdu, length); + + ble_ll_hci_event_send(hci_ev); + } +} +#endif diff --git a/nimble/controller/src/ble_ll_hci_priv.h b/nimble/controller/src/ble_ll_hci_priv.h new file mode 100644 index 0000000000..af67e0a1a3 --- /dev/null +++ b/nimble/controller/src/ble_ll_hci_priv.h @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_HCI_PRIV_ +#define H_BLE_LL_HCI_PRIV_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MYNEWT_VAL(BLE_LL_HCI_VS) +void ble_ll_hci_vs_init(void); +int ble_ll_hci_vs_cmd_proc(const uint8_t *cmdbuf, uint8_t cmdlen, uint16_t ocf, + uint8_t *rspbuf, uint8_t *rsplen); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_HCI_ */ diff --git a/nimble/controller/src/ble_ll_hci_vs.c b/nimble/controller/src/ble_ll_hci_vs.c new file mode 100644 index 0000000000..f2057ea428 --- /dev/null +++ b/nimble/controller/src/ble_ll_hci_vs.c @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "syscfg/syscfg.h" +#include "controller/ble_ll.h" +#include "controller/ble_ll_hci.h" +#include "controller/ble_ll_sync.h" +#include "controller/ble_ll_adv.h" +#include "controller/ble_ll_scan.h" +#include "controller/ble_hw.h" +#include "ble_ll_conn_priv.h" +#include "ble_ll_priv.h" + +#if MYNEWT_VAL(BLE_LL_HCI_VS) + +SLIST_HEAD(ble_ll_hci_vs_list, ble_ll_hci_vs_cmd); +static struct ble_ll_hci_vs_list g_ble_ll_hci_vs_list; + +static int +ble_ll_hci_vs_rd_static_addr(uint16_t ocf, + const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + struct ble_hci_vs_rd_static_addr_rp *rsp = (void *) rspbuf; + ble_addr_t addr; + + if (cmdlen != 0) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_hw_get_static_addr(&addr) < 0) { + return BLE_ERR_UNSPECIFIED; + } + + memcpy(rsp->addr, addr.val, sizeof(rsp->addr)); + + *rsplen = sizeof(*rsp); + + return BLE_ERR_SUCCESS; +} + +/* disallow changing TX power if there is any radio activity + * note: we could allow to change it if there is no TX activity (eg only + * passive scan or sync) but lets just keep this simple for now + */ +static int +ble_ll_hci_vs_is_controller_busy(void) +{ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + struct ble_ll_conn_sm *cur; + int i = 0; +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_sync_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + if (ble_ll_adv_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_scan_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (g_ble_ll_conn_create_sm.connsm) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + STAILQ_FOREACH(cur, &g_ble_ll_conn_free_list, free_stqe) { + i++; + } + + /* check if all connection objects are free */ + if (i < MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { + return 1; + } +#endif + + return 0; +} + +static int +ble_ll_hci_vs_set_tx_power(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_set_tx_pwr_cp *cmd = (const void *) cmdbuf; + struct ble_hci_vs_set_tx_pwr_rp *rsp = (void *) rspbuf; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_ll_hci_vs_is_controller_busy()) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (cmd->tx_power == 127) { + /* restore reset default */ + g_ble_ll_tx_power = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); + } else { + g_ble_ll_tx_power = ble_phy_txpower_round(cmd->tx_power); + } + + rsp->tx_power = g_ble_ll_tx_power; + *rsplen = sizeof(*rsp); + + return BLE_ERR_SUCCESS; +} + +static struct ble_ll_hci_vs_cmd g_ble_ll_hci_vs_cmds[] = { + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_RD_STATIC_ADDR, + ble_ll_hci_vs_rd_static_addr), + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_TX_PWR, + ble_ll_hci_vs_set_tx_power), +}; + +static struct ble_ll_hci_vs_cmd * +ble_ll_hci_vs_find_by_ocf(uint16_t ocf) +{ + struct ble_ll_hci_vs_cmd *entry; + + entry = SLIST_FIRST(&g_ble_ll_hci_vs_list); + while (entry) { + if (entry->ocf == ocf) { + return entry; + } + + entry = SLIST_NEXT(entry, link); + } + + return NULL; +} + +int +ble_ll_hci_vs_cmd_proc(const uint8_t *cmdbuf, uint8_t cmdlen, uint16_t ocf, + uint8_t *rspbuf, uint8_t *rsplen) +{ + struct ble_ll_hci_vs_cmd *cmd; + int rc; + + cmd = ble_ll_hci_vs_find_by_ocf(ocf); + if (!cmd) { + rc = BLE_ERR_UNKNOWN_HCI_CMD; + } else { + rc = cmd->cb(ocf, cmdbuf, cmdlen, rspbuf, rsplen); + } + + return rc; +} + +void +ble_ll_hci_vs_register(struct ble_ll_hci_vs_cmd *cmds, uint32_t num_cmds) +{ + uint32_t i; + + /* Assume all cmds are registered early on init, so just assert in case of + * invalid request since it means something is wrong with the code itself. + */ + + for (i = 0; i < num_cmds; i++, cmds++) { + BLE_LL_ASSERT(cmds->cb != NULL); + BLE_LL_ASSERT(ble_ll_hci_vs_find_by_ocf(cmds->ocf) == NULL); + + SLIST_INSERT_HEAD(&g_ble_ll_hci_vs_list, cmds, link); + } +} + +void +ble_ll_hci_vs_init(void) +{ + SLIST_INIT(&g_ble_ll_hci_vs_list); + + ble_ll_hci_vs_register(g_ble_ll_hci_vs_cmds, + ARRAY_SIZE(g_ble_ll_hci_vs_cmds)); +} + +#endif diff --git a/nimble/controller/src/ble_ll_priv.h b/nimble/controller/src/ble_ll_priv.h index 900950ef64..ca8e082958 100644 --- a/nimble/controller/src/ble_ll_priv.h +++ b/nimble/controller/src/ble_ll_priv.h @@ -24,6 +24,8 @@ extern "C" { #endif +extern int8_t g_ble_ll_tx_power; + #ifdef MYNEWT #include "syscfg/syscfg.h" diff --git a/nimble/controller/src/ble_ll_resolv.c b/nimble/controller/src/ble_ll_resolv.c index 02af93040a..86f8ea7830 100644 --- a/nimble/controller/src/ble_ll_resolv.c +++ b/nimble/controller/src/ble_ll_resolv.c @@ -50,14 +50,31 @@ struct ble_ll_resolv_entry g_ble_ll_resolv_list[MYNEWT_VAL(BLE_LL_RESOLV_LIST_SI static int ble_ll_is_controller_busy(void) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) if (ble_ll_sync_enabled()) { return 1; } #endif - return ble_ll_adv_enabled() || ble_ll_scan_enabled() || - g_ble_ll_conn_create_sm; +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + if (ble_ll_adv_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_scan_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (g_ble_ll_conn_create_sm.connsm) { + return 1; + } +#endif + + return 0; } /** * Called to determine if a change is allowed to the resolving list at this @@ -155,7 +172,9 @@ ble_ll_resolv_rpa_timer_cb(struct ble_npl_event *ev) ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer, g_ble_ll_resolv_data.rpa_tmo); +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) ble_ll_adv_rpa_timeout(); +#endif } /** diff --git a/nimble/controller/src/ble_ll_rfmgmt.c b/nimble/controller/src/ble_ll_rfmgmt.c index 3bf5d5fae6..986645f4a1 100644 --- a/nimble/controller/src/ble_ll_rfmgmt.c +++ b/nimble/controller/src/ble_ll_rfmgmt.c @@ -27,6 +27,7 @@ #include "controller/ble_ll.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_rfmgmt.h" +#include "ble_ll_priv.h" #if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0 @@ -65,6 +66,7 @@ ble_ll_rfmgmt_enable(void) g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_ENABLING; g_ble_ll_rfmgmt_data.enabled_at = os_cputime_get32(); ble_phy_rfclk_enable(); + BLE_LL_DEBUG_GPIO(RFMGMT, 1); } } @@ -74,6 +76,7 @@ ble_ll_rfmgmt_disable(void) OS_ASSERT_CRITICAL(); if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) { + BLE_LL_DEBUG_GPIO(RFMGMT, 0); ble_phy_rfclk_disable(); g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_OFF; } @@ -212,6 +215,8 @@ ble_ll_rfmgmt_init(void) { struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; + BLE_LL_DEBUG_GPIO_INIT(RFMGMT); + rfmgmt->state = RFMGMT_STATE_OFF; rfmgmt->ticks_to_enabled = diff --git a/nimble/controller/src/ble_ll_scan.c b/nimble/controller/src/ble_ll_scan.c index 197ec91072..987ab463ff 100644 --- a/nimble/controller/src/ble_ll_scan.c +++ b/nimble/controller/src/ble_ll_scan.c @@ -25,15 +25,16 @@ #include "os/os.h" #include "os/os_cputime.h" #include "nimble/ble.h" -#include "nimble/nimble_opt.h" #include "nimble/hci_common.h" #include "nimble/ble_hci_trans.h" #include "controller/ble_phy.h" #include "controller/ble_hw.h" #include "controller/ble_ll.h" #include "controller/ble_ll_sched.h" -#include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#include "controller/ble_ll_scan_aux.h" +#endif #include "controller/ble_ll_hci.h" #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" @@ -42,6 +43,8 @@ #include "controller/ble_ll_sync.h" #include "ble_ll_conn_priv.h" +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + /* * XXX: * 1) I think I can guarantee that we dont process things out of order if @@ -64,30 +67,17 @@ #define SCAN_VALID_PHY_MASK (BLE_HCI_LE_PHY_1M_PREF_MASK) #endif -/* The scanning parameters set by host */ -static struct ble_ll_scan_params g_ble_ll_scan_params[BLE_LL_SCAN_PHY_NUMBER]; +struct ble_ll_scan_params { + uint8_t own_addr_type; + uint8_t scan_filt_policy; + struct ble_ll_scan_phy scan_phys[BLE_LL_SCAN_PHY_NUMBER]; +}; + +static struct ble_ll_scan_params g_ble_ll_scan_params; /* The scanning state machine global object */ static struct ble_ll_scan_sm g_ble_ll_scan_sm; -struct ble_ll_ext_adv_hdr -{ - uint8_t mode; - uint8_t hdr_len; - uint8_t hdr[0]; -}; - -struct ble_ll_scan_addr_data { - bool adva_present; - uint8_t adva_type; - uint8_t *adva; - uint8_t targeta_type; - uint8_t *targeta; - uint8_t adv_addr_type; - uint8_t *adv_addr; - struct ble_ll_resolv_entry *rl; -}; - /* * Structure used to store advertisers. This is used to limit sending scan * requests to the same advertiser and also to filter duplicate events sent @@ -140,122 +130,9 @@ static struct os_mempool g_scan_dup_pool; static TAILQ_HEAD(ble_ll_scan_dup_list, ble_ll_scan_dup_entry) g_scan_dup_list; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#if MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT) != 0 -static os_membuf_t ext_scan_aux_mem[ OS_MEMPOOL_SIZE( - MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT), - sizeof (struct ble_ll_aux_data)) -]; -#else -#define ext_scan_aux_mem NULL -#endif - -static struct os_mempool ext_scan_aux_pool; - -static int ble_ll_scan_start(struct ble_ll_scan_sm *scansm, - struct ble_ll_sched_item *sch); - -static void -ble_ll_aux_scan_drop_event_cb(struct ble_npl_event *ev) -{ - struct ble_ll_aux_data *aux_data = ble_npl_event_get_arg(ev); - - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); -} - -static void -ble_ll_aux_scan_drop(struct ble_ll_aux_data *aux_data) -{ - BLE_LL_ASSERT(aux_data); - - STATS_INC(ble_ll_stats, aux_scan_drop); - - ble_npl_event_init(&aux_data->ev, ble_ll_aux_scan_drop_event_cb, aux_data); - ble_ll_event_send(&aux_data->ev); -} - -static int -ble_ll_aux_scan_cb(struct ble_ll_sched_item *sch) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - uint8_t lls = ble_ll_state_get(); - uint32_t wfr_usec; - - STATS_INC(ble_ll_stats, aux_sched_cb); - - /* Drop the scheduled item if scan was disable or there is aux or scan - * response pending - */ - if (!scansm->scan_enabled || scansm->cur_aux_data || - scansm->scan_rsp_pending) { - ble_ll_aux_scan_drop(sch->cb_arg); - sch->cb_arg = NULL; - goto done; - } - - /* Check if there is no aux connect sent. If so drop the sched item */ - if (lls == BLE_LL_STATE_INITIATING && ble_ll_conn_init_pending_aux_conn_rsp()) { - ble_ll_aux_scan_drop(sch->cb_arg); - sch->cb_arg = NULL; - goto done; - } - - /* This function is called only when scanner is running. This can happen - * in 3 states: - * BLE_LL_STATE_SCANNING - * BLE_LL_STATE_INITIATING - * BLE_LL_STATE_STANDBY - */ - if (lls != BLE_LL_STATE_STANDBY) { - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - - /* When doing RX for AUX pkt, cur_aux_data keeps valid aux data */ - scansm->cur_aux_data = sch->cb_arg; - sch->cb_arg = NULL; - BLE_LL_ASSERT(scansm->cur_aux_data != NULL); - scansm->cur_aux_data->scanning = 1; - - if (ble_ll_scan_start(scansm, sch)) { - ble_ll_scan_interrupted(scansm); - goto done; - } - - STATS_INC(ble_ll_stats, aux_fired_for_read); - - wfr_usec = scansm->cur_aux_data->offset_units ? 300 : 30; - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usec); - -done: - - return BLE_LL_SCHED_STATE_DONE; -} - static int -ble_ll_scan_ext_adv_init(struct ble_ll_aux_data **aux_data) -{ - struct ble_ll_aux_data *e; - - e = os_memblock_get(&ext_scan_aux_pool); - if (!e) { - return -1; - } - - memset(e, 0, sizeof(*e)); - e->sch.sched_cb = ble_ll_aux_scan_cb; - e->sch.sched_type = BLE_LL_SCHED_TYPE_AUX_SCAN; - e->ref_cnt = 1; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - e->rpa_index = -1; -#endif - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t)e, e->ref_cnt); - - *aux_data = e; - STATS_INC(ble_ll_stats, aux_allocated); +ble_ll_scan_start(struct ble_ll_scan_sm *scansm); - return 0; -} #endif static inline uint32_t @@ -314,17 +191,66 @@ ble_ll_scan_refresh_nrpa(struct ble_ll_scan_sm *scansm) scansm->scan_nrpa_timer = now + ble_ll_resolv_get_rpa_tmo(); } } + +uint8_t * +ble_ll_get_scan_nrpa(void) +{ + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; + + ble_ll_scan_refresh_nrpa(scansm); + + return scansm->scan_nrpa; +} #endif +uint8_t +ble_ll_scan_get_own_addr_type(void) +{ + return g_ble_ll_scan_sm.own_addr_type; +} + +uint8_t +ble_ll_scan_get_filt_policy(void) +{ + return g_ble_ll_scan_sm.scan_filt_policy; +} + +uint8_t +ble_ll_scan_get_filt_dups(void) +{ + return g_ble_ll_scan_sm.scan_filt_dups; +} + +uint8_t +ble_ll_scan_backoff_kick(void) +{ + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; + + if (scansm->backoff_count > 0) { + scansm->backoff_count--; + } + + return scansm->backoff_count; +} + +void +ble_ll_scan_backoff_update(int success) +{ + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; + + ble_ll_scan_req_backoff(scansm, success); +} + static void ble_ll_scan_req_pdu_prepare(struct ble_ll_scan_sm *scansm, const uint8_t *adv_addr, uint8_t adv_addr_type, - struct ble_ll_resolv_entry *rl) + int8_t rpa_index) { uint8_t hdr_byte; struct ble_ll_scan_pdu_data *pdu_data; uint8_t *scana; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl; uint8_t rpa[BLE_DEV_ADDR_LEN]; #endif @@ -346,6 +272,12 @@ ble_ll_scan_req_pdu_prepare(struct ble_ll_scan_sm *scansm, #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (scansm->own_addr_type & 0x02) { + if (rpa_index >= 0) { + rl = &g_ble_ll_resolv_list[rpa_index]; + } else { + rl = NULL; + } + /* * If device is on RL and we have local IRK, we use RPA generated using * that IRK as ScanA. Otherwise we use NRPA as ScanA to prevent our @@ -431,99 +363,17 @@ ble_ll_scan_get_ext_adv_report(struct ext_adv_report *copy_from) return hci_ev; } -static void -ble_ll_scan_send_truncated(struct ble_ll_aux_data *aux_data) -{ - struct ble_hci_ev_le_subev_ext_adv_rpt *ev; - struct ext_adv_report *report; - struct ble_hci_ev *hci_ev; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - return; - } - - BLE_LL_ASSERT(aux_data); - - /* No need to send if we did not send any report or sent truncated already */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)) { - return; - } - - BLE_LL_ASSERT(aux_data->evt); - hci_ev = aux_data->evt; - aux_data->evt = NULL; - - hci_ev->length = sizeof(*ev) + sizeof(*report); - - ev = (void *) hci_ev->data; - report = ev->reports; - - report->data_len = 0; - - report->evt_type = aux_data->evt_type; - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - memcpy(report->addr, aux_data->adva, 6); - report->addr_type = aux_data->adva_type; - } - - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - memcpy(report->dir_addr, aux_data->targeta, 6); - report->dir_addr_type = aux_data->targeta_type; - } - - report->sid = aux_data->adi >> 12; - ble_ll_hci_event_send(hci_ev); - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_ANY; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; -} - -static int -ble_ll_scan_get_adi(struct ble_ll_aux_data *aux_data, uint16_t *adi) -{ - if (!aux_data || !(aux_data->flags & BLE_LL_AUX_HAS_ADI)) { - return -1; - } - - *adi = aux_data->adi; - - return 0; -} - void ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data) { - /* Make sure we send report with 'truncated' data state if needed */ - ble_ll_scan_send_truncated(aux_data); } #endif -static void -ble_ll_scan_clean_cur_aux_data(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - - /* If scanner was reading aux ptr, we need to clean it up */ - if (scansm->cur_aux_data) { - ble_ll_scan_end_adv_evt(scansm->cur_aux_data); - ble_ll_scan_aux_data_unref(scansm->cur_aux_data); - scansm->cur_aux_data = NULL; - } -#endif -} - void ble_ll_scan_halt(void) { struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - ble_ll_scan_clean_cur_aux_data(); - /* Update backoff if we failed to receive scan response */ if (scansm->scan_rsp_pending) { scansm->scan_rsp_pending = 0; @@ -539,7 +389,7 @@ ble_ll_scan_halt(void) * * @return int 0: have not received a scan response; 1 otherwise. */ -static int +int ble_ll_scan_have_rxd_scan_rsp(uint8_t *addr, uint8_t txadd, uint8_t ext_adv, uint16_t adi) { @@ -583,7 +433,7 @@ ble_ll_scan_have_rxd_scan_rsp(uint8_t *addr, uint8_t txadd, } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void +void ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd, uint8_t ext_adv, uint16_t adi) { @@ -862,8 +712,8 @@ ble_ll_scan_send_adv_report(uint8_t pdu_type, hdr->rxinfo.rssi, adv_data_len, om, inita, inita_type); - goto done; - } +goto done; +} #endif if (subev == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) { @@ -880,27 +730,6 @@ ble_ll_scan_send_adv_report(uint8_t pdu_type, } } -static void -ble_ll_get_chan_to_scan(struct ble_ll_scan_sm *scansm, uint8_t *chan, - int *phy) -{ - struct ble_ll_scan_params *scanp = scansm->scanp; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = scansm->cur_aux_data; - - if (!scansm->ext_scanning || !aux_data || !aux_data->scanning) { - *chan = scanp->scan_chan; - *phy = scanp->phy; - return; - } - - *chan = aux_data->chan; - *phy = aux_data->aux_phy; -#else - *chan = scanp->scan_chan; - *phy = scanp->phy; -#endif -} /** * Called to enable the receiver for scanning. * @@ -911,29 +740,21 @@ ble_ll_get_chan_to_scan(struct ble_ll_scan_sm *scansm, uint8_t *chan, * @return int */ static int -ble_ll_scan_start(struct ble_ll_scan_sm *scansm, struct ble_ll_sched_item *sch) +ble_ll_scan_start(struct ble_ll_scan_sm *scansm) { int rc; - struct ble_ll_scan_params *scanp = scansm->scanp; - uint8_t scan_chan; + struct ble_ll_scan_phy *scanp = scansm->scanp; + uint8_t chan; #if (BLE_LL_BT5_PHY_SUPPORTED == 1) uint8_t phy_mode; -#endif int phy; +#endif BLE_LL_ASSERT(scansm->scan_rsp_pending == 0); - ble_ll_get_chan_to_scan(scansm, &scan_chan, &phy); - - /* XXX: right now scheduled item is only present if we schedule for aux - * scan just make sanity check that we have proper combination of - * sch and resulting scan_chan - */ - BLE_LL_ASSERT(!sch || scan_chan < BLE_PHY_ADV_CHAN_START); - BLE_LL_ASSERT(sch || scan_chan >= BLE_PHY_ADV_CHAN_START); - /* Set channel */ - rc = ble_phy_setchan(scan_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); + chan = scanp->scan_chan; + rc = ble_phy_setchan(chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); BLE_LL_ASSERT(rc == 0); /* @@ -955,20 +776,13 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, struct ble_ll_sched_item *sch) #endif #if (BLE_LL_BT5_PHY_SUPPORTED == 1) + phy = scanp->phy; phy_mode = ble_ll_phy_to_phy_mode(phy, BLE_HCI_LE_PHY_CODED_ANY); ble_phy_mode_set(phy_mode, phy_mode); #endif - /* XXX: probably need to make sure hfxo is running too */ - /* XXX: can make this better; want to just start asap. */ - if (sch) { - rc = ble_phy_rx_set_start_time(sch->start_time + - g_ble_ll_sched_offset_ticks, - sch->remainder); - } else { - rc = ble_phy_rx_set_start_time(os_cputime_get32() + - g_ble_ll_sched_offset_ticks, 0); - } + rc = ble_phy_rx_set_start_time(os_cputime_get32() + + g_ble_ll_sched_offset_ticks, 0); if (!rc || rc == BLE_PHY_ERR_RX_LATE) { /* If we are late here, it is still OK because we keep scanning. * Clear error @@ -976,18 +790,13 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, struct ble_ll_sched_item *sch) rc = 0; /* Enable/disable whitelisting */ - if (scanp->scan_filt_policy & 1) { + if (scansm->scan_filt_policy & 1) { ble_ll_whitelist_enable(); } else { ble_ll_whitelist_disable(); } - /* Set link layer state to scanning */ - if (scanp->scan_type == BLE_SCAN_TYPE_INITIATE) { - ble_ll_state_set(BLE_LL_STATE_INITIATING); - } else { - ble_ll_state_set(BLE_LL_STATE_SCANNING); - } + ble_ll_state_set(BLE_LL_STATE_SCANNING); } return rc; @@ -1005,7 +814,7 @@ ble_ll_scan_get_next_adv_prim_chan(uint8_t chan) } static uint32_t -ble_ll_scan_move_window_to(struct ble_ll_scan_params *scanp, uint32_t time) +ble_ll_scan_move_window_to(struct ble_ll_scan_phy *scanp, uint32_t time) { uint32_t end_time; @@ -1025,7 +834,7 @@ ble_ll_scan_move_window_to(struct ble_ll_scan_params *scanp, uint32_t time) } static bool -ble_ll_scan_is_inside_window(struct ble_ll_scan_params *scanp, uint32_t time) +ble_ll_scan_is_inside_window(struct ble_ll_scan_phy *scanp, uint32_t time) { uint32_t start_time; @@ -1041,76 +850,6 @@ ble_ll_scan_is_inside_window(struct ble_ll_scan_params *scanp, uint32_t time) CPUTIME_LT(time, start_time + scanp->timing.window); } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_data) -{ - if (aux_data) { - if (aux_data->evt) { - ble_hci_trans_buf_free((uint8_t *)aux_data->evt); - aux_data->evt = NULL; - } - os_memblock_put(&ext_scan_aux_pool, aux_data); - STATS_INC(ble_ll_stats, aux_freed); - } -} - -struct ble_ll_aux_data * -ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_data) -{ - os_sr_t sr; - - BLE_LL_ASSERT(aux_data); - - OS_ENTER_CRITICAL(sr); - aux_data->ref_cnt++; - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t) aux_data, aux_data->ref_cnt); - - OS_EXIT_CRITICAL(sr); - - return aux_data; -} - -void -ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_data) -{ - os_sr_t sr; - - BLE_LL_ASSERT(aux_data); - - OS_ENTER_CRITICAL(sr); - aux_data->ref_cnt--; - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_UNREF, (uint32_t) aux_data, aux_data->ref_cnt); - - if (aux_data->ref_cnt == 0) { - /* - * Some validation to make sure that we completed scan properly: - * - we either did not send any report or sent completed/truncated - * - we only sent one of completed/truncated - * - in case of error, we wither did not send anything or sent truncated - */ - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - ((aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) && - (aux_data->flags_ll & (BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED | BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)))); - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED) || !(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)); - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR) || - !(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)); - - ble_ll_scan_aux_data_free(aux_data); - } - - OS_EXIT_CRITICAL(sr); -} - -static void -ble_ll_scan_sched_remove(struct ble_ll_sched_item *sch) -{ - ble_ll_scan_end_adv_evt(sch->cb_arg); - ble_ll_scan_aux_data_unref(sch->cb_arg); - sch->cb_arg = NULL; -} -#endif /** * Stop the scanning state machine */ @@ -1130,8 +869,7 @@ ble_ll_scan_sm_stop(int chk_disable) OS_ENTER_CRITICAL(sr); lls = ble_ll_state_get(); - if ((lls == BLE_LL_STATE_SCANNING) || - (lls == BLE_LL_STATE_INITIATING && chk_disable == 1)) { + if (lls == BLE_LL_STATE_SCANNING) { /* Disable phy */ ble_phy_disable(); @@ -1143,14 +881,17 @@ ble_ll_scan_sm_stop(int chk_disable) OS_ENTER_CRITICAL(sr); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + scansm->connsm = NULL; +#endif + /* Disable scanning state machine */ scansm->scan_enabled = 0; scansm->restart_timer_needed = 0; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (scansm->ext_scanning) { - ble_ll_scan_clean_cur_aux_data(); - ble_ll_sched_rmv_elem_type(BLE_LL_SCHED_TYPE_AUX_SCAN, ble_ll_scan_sched_remove); + ble_ll_sched_rmv_elem_type(BLE_LL_SCHED_TYPE_SCAN_AUX, ble_ll_scan_aux_sched_remove); scansm->ext_scanning = 0; } #endif @@ -1175,8 +916,8 @@ ble_ll_scan_sm_stop(int chk_disable) static int ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm) { - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_next; + struct ble_ll_scan_phy *scanp; + struct ble_ll_scan_phy *scanp_next; if (!ble_ll_is_valid_own_addr_type(scansm->own_addr_type, g_random_addr)) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -1229,45 +970,15 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm) return BLE_ERR_SUCCESS; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_aux_scan_rsp_failed(struct ble_ll_scan_sm *scansm) -{ - if (!scansm->cur_aux_data) { - return; - } - - STATS_INC(ble_ll_stats, aux_scan_rsp_err); - ble_ll_scan_interrupted(scansm); -} -#endif - static void ble_ll_scan_interrupted_event_cb(struct ble_npl_event *ev) { struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data; -#endif if (!scansm->scan_enabled) { return; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - aux_data = ble_npl_event_get_arg(ev); - - if (aux_data) { - if (scansm->scan_rsp_pending) { - STATS_INC(ble_ll_stats, aux_scan_rsp_err); - } - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); - ble_npl_event_set_arg(ev, NULL); - STATS_INC(ble_ll_stats, aux_missed_adv); - } -#endif - /* * If we timed out waiting for a response, the scan response pending * flag should be set. Deal with scan backoff. Put device back into rx. @@ -1295,10 +1006,10 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) os_sr_t sr; bool start_scan; bool inside_window; - struct ble_ll_scan_params *scanp; + struct ble_ll_scan_phy *scanp; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) bool inside_window_next; - struct ble_ll_scan_params *scanp_next; + struct ble_ll_scan_phy *scanp_next; #endif uint32_t next_proc_time; uint32_t now; @@ -1321,7 +1032,7 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) return; } - if (scansm->cur_aux_data || scansm->scan_rsp_pending) { + if (scansm->scan_rsp_pending) { /* Aux scan in progress. Wait */ STATS_INC(ble_ll_stats, scan_timer_stopped); scansm->restart_timer_needed = 1; @@ -1380,20 +1091,20 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) */ start_scan = inside_window; switch (ble_ll_state_get()) { +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_STATE_CONNECTION: +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) case BLE_LL_STATE_SYNC: +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: start_scan = false; break; - case BLE_LL_STATE_INITIATING: - /* Must disable PHY since we will move to a new channel */ - ble_phy_disable(); - if (!inside_window) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - /* PHY is disabled - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); - break; +#endif case BLE_LL_STATE_SCANNING: /* Must disable PHY since we will move to a new channel */ ble_phy_disable(); @@ -1409,7 +1120,7 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) } if (start_scan) { - ble_ll_scan_start(scansm, NULL); + ble_ll_scan_start(scansm); } else { ble_ll_rfmgmt_release(); } @@ -1438,7 +1149,7 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) { int rc; struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; + struct ble_ll_scan_phy *scanp; rc = 0; scansm = &g_ble_ll_scan_sm; @@ -1459,10 +1170,6 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) } #endif - if (scansm->cur_aux_data && !scansm->scan_rsp_pending ) { - STATS_INC(ble_ll_stats, aux_received); - } - /* * If this is the first PDU after we sent the scan response (as * denoted by the scan rsp pending flag), we set a bit in the ble @@ -1479,9 +1186,6 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) *rxflags |= BLE_MBUF_HDR_F_SCAN_RSP_RXD; } else { ble_ll_scan_req_backoff(scansm, 0); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_ll_aux_scan_rsp_failed(scansm); -#endif } } break; @@ -1492,469 +1196,26 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) } break; #endif - default: - break; - } - - return rc; -} +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_SCAN_TYPE_INITIATE: + if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || + (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND)) { + rc = 1; + } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static uint8_t -ble_ll_ext_adv_phy_mode_to_local_phy(uint8_t adv_phy_mode) -{ - switch (adv_phy_mode) { - case 0x00: - return BLE_PHY_1M; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case 0x01: - return BLE_PHY_2M; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case 0x02: - return BLE_PHY_CODED; -#endif - } - - return 0; -} - -static int -ble_ll_ext_scan_parse_aux_ptr(struct ble_ll_aux_data *aux_data, uint8_t *buf) -{ - uint32_t aux_ptr_field = get_le32(buf) & 0x00FFFFFF; - - aux_data->chan = (aux_ptr_field) & 0x3F; - if (aux_data->chan >= BLE_PHY_NUM_DATA_CHANS) { - return -1; - } - - /* TODO use CA aux_ptr_field >> 6 */ - - aux_data->offset = 30 * ((aux_ptr_field >> 8) & 0x1FFF); - - if ((aux_ptr_field >> 7) & 0x01) { - aux_data->offset *= 10; - aux_data->offset_units = 1; - } - - if (aux_data->offset < BLE_LL_MAFS) { - return -1; - } - - aux_data->aux_phy = - ble_ll_ext_adv_phy_mode_to_local_phy((aux_ptr_field >> 21) & 0x07); - if (aux_data->aux_phy == 0) { - return -1; - } - - return 0; -} - -static void -ble_ll_ext_scan_parse_adv_info(struct ext_adv_report *report, const uint8_t *buf) -{ - uint16_t adv_info = get_le16(buf); - - /* TODO Use DID */ - - report->sid = (adv_info >> 12); -} - -/** - * ble_ll_scan_update_aux_data - * - * Update aux_data stored in ble_hdr.rxinfo.user_data. If no aux_data is present - * (i.e. processing ADV_EXT_IND) this will try to allocate new aux_data. - * - * Context: Interrupt - * - * @param ble_hdr - * @param rxbuf - * - * @return int - * 1: do not scan for next AUX (no AuxPtr or malformed data) - * 0: scan for next AUX (valid AuxPtr found) - * -1: error - */ -int -ble_ll_scan_update_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf, - bool *adva_present) -{ - uint8_t pdu_hdr; - uint8_t pdu_len; - uint8_t adv_mode; - uint8_t eh_len; - uint8_t eh_flags; - uint8_t *eh; - struct ble_ll_aux_data *aux_data; - bool is_aux; - - aux_data = ble_hdr->rxinfo.user_data; - /* aux_data is initially not set only for ADV_EXT_IND */ - is_aux = aux_data; - - pdu_hdr = rxbuf[0]; - pdu_len = rxbuf[1]; - - /* PDU without at least Extended Header Length is invalid */ - if (pdu_len == 0) { - return -1; - } - - adv_mode = rxbuf[2] >> 6; - eh_len = rxbuf[2] & 0x3f; - eh_flags = rxbuf[3]; - eh = &rxbuf[4]; - - /* - * PDU without Extended Header is valid in case of last AUX_CHAIN_IND in - * chain so aux_data has to be set and advertising mode has to be 00b, - * otherwise it's an invalid PDU. - */ - if (eh_len == 0) { - if (!aux_data || adv_mode) { - return -1; - } - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_COMPLETE; - return 1; - } - - /* - * If aux_data is not set, this is ADV_EXT_IND which starts new extended - * advertising event. - */ - if (!aux_data) { - if (ble_ll_scan_ext_adv_init(&aux_data)) { - return -1; - } - - aux_data->aux_primary_phy = ble_hdr->rxinfo.phy; - } else { - if (aux_data->flags_isr & BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED; - } else { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED; - } - } - - /* Now parse extended header... */ - - if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_ADVA; - memcpy(aux_data->adva, eh, 6); - aux_data->adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); - eh += BLE_LL_EXT_ADV_ADVA_SIZE; - - if (adva_present) { - *adva_present = true; - } - } else if (adva_present) { - *adva_present = false; - } - - if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_TARGETA; - memcpy(aux_data->targeta, eh, 6); - aux_data->targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); - eh += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - - if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - eh += 1; - } - - if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_ADI; - if (is_aux) { - if (get_le16(eh) != aux_data->adi) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_ERROR; - STATS_INC(ble_ll_stats, aux_chain_err); - } - } else { - aux_data->adi = get_le16(eh); - } - eh += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } - - if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - if (ble_ll_ext_scan_parse_aux_ptr(aux_data, eh)) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_ERROR; - } - } else if (!(adv_mode & BLE_LL_EXT_ADV_MODE_SCAN)) { - /* No AuxPtr for scannable PDU is ignored since we can still scan it */ - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_COMPLETE; - } - - ble_hdr->rxinfo.user_data = aux_data; - - /* Do not scan for next AUX if either no AuxPtr or malformed data found */ - return !(eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) || - (aux_data->flags_isr & BLE_LL_AUX_FLAG_SCAN_ERROR); -} - -/** - * Called when a receive ADV_EXT PDU has ended. - * - * Context: Interrupt - * - * @return int - * < 0 Error - * >= 0: Success (number of bytes left in PDU) - * - */ -static int -ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, - const uint8_t *adva, uint8_t adva_type, - const uint8_t *inita, uint8_t inita_type, - struct ble_mbuf_hdr *ble_hdr, - struct ext_adv_report *report) -{ - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - uint8_t *rxbuf = om->om_data; - int i = 1; - struct ble_ll_scan_sm *scansm; - struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data; - - BLE_LL_ASSERT(report); - - scansm = &g_ble_ll_scan_sm; - - if (!scansm->ext_scanning) { - /* Ignore ext adv if host does not want it*/ - return -1; - } - - pdu_len = rxbuf[1]; - if (pdu_len == 0) { - return -1; - } - - report->evt_type = rxbuf[2] >> 6; - if ( report->evt_type > BLE_LL_EXT_ADV_MODE_SCAN) { - return -1; - } - - if (BLE_MBUF_HDR_SCAN_RSP_RXD(ble_hdr)) { - report->evt_type |= BLE_HCI_ADV_SCAN_RSP_MASK; - } - - ext_hdr_len = rxbuf[2] & 0x3F; - os_mbuf_adj(om, 3); - - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - - if (ext_hdr_len) { - i = 0; - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - i += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - if (adva) { - memcpy(report->addr, adva, 6); - report->addr_type = adva_type; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - if (inita) { - memcpy(report->dir_addr, inita, 6); - report->dir_addr_type = inita_type; - report->evt_type |= BLE_HCI_ADV_DIRECT_MASK; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - /* Just skip it for now*/ - i += 1; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - ble_ll_ext_scan_parse_adv_info(report, (ext_hdr + i)); - i += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } else if (report->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK) { - report->sid = (aux_data->adi >> 12); - } - - /* In this point of time we don't want to care about aux ptr */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - i += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { - report->periodic_itvl = get_le16(ext_hdr + i + 2); - i += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - report->tx_power = *(ext_hdr + i); - i += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } - - /* TODO Handle ACAD if needed */ - } - - /* In the event we need information on primary and secondary PHY used during - * advertising. - */ - if (!aux_data) { - report->pri_phy = ble_hdr->rxinfo.phy; - goto done; - } - - report->sec_phy = aux_data->aux_phy; - report->pri_phy = aux_data->aux_primary_phy; - - if (ext_hdr_len) { - /* Adjust mbuf to contain advertising data only */ - os_mbuf_adj(om, ext_hdr_len); - } - - /* Let us first keep update event type in aux data. - * Note that in aux chain and aux scan response packets - * we do miss original event type, which we need for advertising report. - */ - aux_data->evt_type |= report->evt_type; - report->evt_type = aux_data->evt_type; - -done: - return pdu_len - ext_hdr_len - 1; -} - -static int -ble_ll_scan_get_addr_from_ext_adv(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *inita_type, - int *ext_mode) -{ - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - bool has_adva = false; - bool has_inita = false; - int i; - struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data; - - *addr = NULL; - *inita = NULL; - - pdu_len = rxbuf[1]; - if (pdu_len == 0) { - return -1; - } - - *ext_mode = rxbuf[2] >> 6; - if (*ext_mode > BLE_LL_EXT_ADV_MODE_SCAN) { - return -1; - } - - ext_hdr_len = rxbuf[2] & 0x3F; - if (ext_hdr_len == 0) { - goto done; - } - - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - - i = 0; - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - if (ext_hdr_len < BLE_LL_EXT_ADV_ADVA_SIZE) { - return -1; - } - - *addr = ext_hdr + i; - *addr_type = - ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - i += BLE_LL_EXT_ADV_ADVA_SIZE; - - has_adva = true; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - *inita = ext_hdr + i; - *inita_type = - ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - - has_inita = true; - } - -done: - /* Check if we had address already. If yes, replace it with new one */ - - if (aux_data) { - /* If address has been provided, we do have it already in aux_data.*/ - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - if (!has_adva) { - *addr = aux_data->adva; - *addr_type = aux_data->adva_type; - } else { - memcpy(aux_data->adva, *addr, 6); - aux_data->adva_type = *addr_type; - } - } - - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - if (!has_inita) { - *inita = aux_data->targeta; - *inita_type = aux_data->targeta_type; - } else { - memcpy(aux_data->targeta, *inita, 6); - aux_data->targeta_type = *inita_type; - } + if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && scansm->ext_scanning)) { + *rxflags |= BLE_MBUF_HDR_F_EXT_ADV; + rc = 1; } - } - - return 0; -} #endif - -int -ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *inita_type, - int *ext_mode) -{ - /* - * XXX this should be only used for legacy advertising, but need to refactor - * code in ble_ll_init first so it does not call this for ext - */ - - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND && - pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - /* Legacy advertising */ - *addr_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - *addr = rxbuf + BLE_LL_PDU_HDR_LEN; - - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) { - *inita = NULL; - *inita_type = 0; - return 0; - } - - *inita = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN; - *inita_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); - - return 0; - } - - /* Extended advertising */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return ble_ll_scan_get_addr_from_ext_adv(rxbuf, ble_hdr, addr, addr_type, - inita, inita_type, ext_mode); -#else - return -1; + break; #endif + default: + break; + } - return 0; + return rc; } static void @@ -1963,8 +1224,6 @@ ble_ll_scan_get_addr_data_from_legacy(uint8_t pdu_type, uint8_t *rxbuf, { BLE_LL_ASSERT(pdu_type < BLE_ADV_PDU_TYPE_ADV_EXT_IND); - addrd->adva_present = true; - addrd->adva = rxbuf + BLE_LL_PDU_HDR_LEN; addrd->adva_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); @@ -1977,80 +1236,45 @@ ble_ll_scan_get_addr_data_from_legacy(uint8_t pdu_type, uint8_t *rxbuf, } } -/* - * Matches incoming PDU using scan filter policy and whitelist, if applicable. - * This will also resolve addresses and update flags/fields in header and - * addr_data as needed. - * - * @return 0 = no match - * 1 = match - * 2 = match, but do not scan - */ -static int -ble_ll_scan_rx_filter(struct ble_mbuf_hdr *hdr, struct ble_ll_scan_addr_data *addrd) +int +ble_ll_scan_rx_filter(uint8_t own_addr_type, uint8_t scan_filt_policy, + struct ble_ll_scan_addr_data *addrd, uint8_t *scan_ok) { - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data; -#endif - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; struct ble_ll_resolv_entry *rl = NULL; #endif bool scan_req_allowed = true; - int resolved = 0; + bool resolved; + + /* Note: caller is expected to fill adva, targeta and rpa_index in addrd */ - /* Use AdvA as initial advertiser address, we may try to resolve it later */ + /* Use AdvA as initial advertiser address, we may change it if resolved */ addrd->adv_addr = addrd->adva; addrd->adv_addr_type = addrd->adva_type; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* By default, assume AdvA is not resolved */ - rxinfo->rpa_index = -1; + addrd->adva_resolved = 0; + addrd->targeta_resolved = 0; + + BLE_LL_ASSERT((addrd->rpa_index < 0) || + (ble_ll_addr_subtype(addrd->adva, addrd->adva_type) == + BLE_LL_ADDR_SUBTYPE_RPA)); switch (ble_ll_addr_subtype(addrd->adva, addrd->adva_type)) { case BLE_LL_ADDR_SUBTYPE_RPA: - /* - * Only resolve if packet actually contained AdvA. - * In extended advertising PDUs we may use RL index from a PDU that - * already had AdvA (e.g. ADV_EXT_IND in case of AUX_ADV_IND without - * AdvA). In legacy advertising PDUs we always need to resolve AdvA. - */ - if (addrd->adva_present) { - rxinfo->rpa_index = ble_hw_resolv_list_match(); - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - BLE_LL_ASSERT(aux_data); - rxinfo->rpa_index = aux_data->rpa_index; -#else - BLE_LL_ASSERT(false); - rxinfo->rpa_index = -1; -#endif - } - - if (rxinfo->rpa_index < 0) { + if (addrd->rpa_index < 0) { break; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data) { - aux_data->rpa_index = rxinfo->rpa_index; - } -#endif + addrd->adva_resolved = 1; /* Use resolved identity address as advertiser address */ - rl = &g_ble_ll_resolv_list[rxinfo->rpa_index]; + rl = &g_ble_ll_resolv_list[addrd->rpa_index]; addrd->adv_addr = rl->rl_identity_addr; addrd->adv_addr_type = rl->rl_addr_type; - addrd->rl = rl; - - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - resolved = 1; break; case BLE_LL_ADDR_SUBTYPE_IDENTITY: - /* - * If AdvA is an identity address, we need to check if that device was + /* If AdvA is an identity address, we need to check if that device was * added to RL in order to use proper privacy mode. */ rl = ble_ll_resolv_list_find(addrd->adva, addrd->adva_type); @@ -2058,12 +1282,12 @@ ble_ll_scan_rx_filter(struct ble_mbuf_hdr *hdr, struct ble_ll_scan_addr_data *ad break; } - addrd->rl = rl; - /* Ignore device if using network privacy mode and it has IRK */ if ((rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && rl->rl_has_peer) { - return 0; + return -1; } + + addrd->rpa_index = ble_ll_resolv_get_idx(rl); break; default: /* NRPA goes through filtering policy directly */ @@ -2075,30 +1299,29 @@ ble_ll_scan_rx_filter(struct ble_mbuf_hdr *hdr, struct ble_ll_scan_addr_data *ad case BLE_LL_ADDR_SUBTYPE_RPA: /* Check if TargetA can be resolved using the same RL entry as AdvA */ if (rl && ble_ll_resolv_rpa(addrd->targeta, rl->rl_local_irk)) { - rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; + addrd->targeta_resolved = 1; break; } /* Check if scan filter policy allows unresolved RPAs to be processed */ - if (!(scanp->scan_filt_policy & 0x02)) { - return 0; + if (!(scan_filt_policy & 0x02)) { + return -2; } - /* - * We will notify host as requited by scan policy, but make sure we - * do not send scan request since we do not know if this is directed - * to us. + /* Do not send scan request even if scan policy allows unresolved + * RPAs - we do not know if this one if directed to us. */ scan_req_allowed = false; break; case BLE_LL_ADDR_SUBTYPE_IDENTITY: /* We shall ignore identity in TargetA if we are using RPA */ - if ((scanp->own_addr_type & 0x02) && rl && rl->rl_has_local) { - return 0; + if ((own_addr_type & 0x02) && rl && rl->rl_has_local) { + return -1; } + /* Ignore if not directed to us */ if (!ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { - return 0; + return -1; } break; default: @@ -2106,182 +1329,174 @@ ble_ll_scan_rx_filter(struct ble_mbuf_hdr *hdr, struct ble_ll_scan_addr_data *ad break; } } + + resolved = addrd->adva_resolved; #else /* Ignore if not directed to us */ if (addrd->targeta && !ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { - return 0; + return -1; } + + resolved = false; #endif - /* Check on WL if required by scan filter policy */ - if (scanp->scan_filt_policy & 0x01) { - if (!ble_ll_whitelist_match(addrd->adv_addr, addrd->adv_addr_type, resolved)) { - return 0; + if (scan_filt_policy & 0x01) { + /* Check on WL if required by scan filter policy */ + if (!ble_ll_whitelist_match(addrd->adv_addr, addrd->adv_addr_type, + resolved)) { + return -2; } } - return scan_req_allowed ? 1 : 2; + if (scan_ok) { + *scan_ok = scan_req_allowed; + } + + return 0; +} + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +int +ble_ll_scan_rx_check_init(struct ble_ll_scan_addr_data *addrd) +{ + struct ble_ll_scan_sm *scansm; + struct ble_ll_conn_sm *connsm; + + scansm = &g_ble_ll_scan_sm; + connsm = scansm->connsm; + BLE_LL_ASSERT(connsm); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if ((connsm->peer_addr_type > BLE_ADDR_RANDOM) && !addrd->adva_resolved) { + return -1; + } +#endif + if ((addrd->adv_addr_type != (connsm->peer_addr_type & 0x01)) || + memcmp(addrd->adv_addr, connsm->peer_addr, 6) != 0) { + return -1; + } + + return 0; } +#endif static int -ble_ll_scan_rx_isr_on_legacy(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) +ble_ll_scan_rx_isr_end_on_adv(uint8_t pdu_type, uint8_t *rxbuf, + struct ble_mbuf_hdr *hdr, + struct ble_ll_scan_addr_data *addrd) { struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; + struct ble_ll_scan_phy *scanp = scansm->scanp; struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - uint8_t sreq_adva_type; - uint8_t *sreq_adva; + uint8_t scan_ok; int rc; ble_ll_scan_get_addr_data_from_legacy(pdu_type, rxbuf, addrd); - if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_RSP) { - if (!BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { - /* - * We were not expecting scan response so just ignore and do not - * update backoff. - */ - return -1; - } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd->rpa_index = ble_hw_resolv_list_match(); +#endif - sreq_adva_type = !!(scansm->pdu_data.hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK); - sreq_adva = scansm->pdu_data.adva; + rc = ble_ll_scan_rx_filter(scansm->own_addr_type, + scansm->scan_filt_policy, addrd, &scan_ok); + if (rc < 0) { + return 0; + } - /* - * Ignore scan response if AdvA does not match AdvA in request and also - * update backoff as if there was no scan response. - */ - if ((addrd->adva_type != sreq_adva_type) || - memcmp(addrd->adva, sreq_adva, BLE_DEV_ADDR_LEN)) { - ble_ll_scan_req_backoff(scansm, 0); - return -1; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if ((scanp->scan_type == BLE_SCAN_TYPE_INITIATE) && + !(scansm->scan_filt_policy & 0x01)) { + rc = ble_ll_scan_rx_check_init(addrd); + if (rc < 0) { + return 0; } + } +#endif + rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * We are not pushing this one through filters so need to update - * rpa_index here as otherwise pkt_in won't be able to determine - * advertiser address properly. - */ - rxinfo->rpa_index = ble_hw_resolv_list_match(); - if (rxinfo->rpa_index >= 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - } + rxinfo->rpa_index = addrd->rpa_index; + if (addrd->adva_resolved) { + rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; + } + if (addrd->targeta_resolved) { + rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; + } #endif - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - + if (!scan_ok) { + /* Scan request forbidden by filter policy */ return 0; } - rc = ble_ll_scan_rx_filter(hdr, addrd); - if (!rc) { - return 0; + /* Allow responding to all PDUs when initiating since unwanted PDUs were + * already filtered out in isr_start. + */ + if ((scanp->scan_type == BLE_SCAN_TYPE_ACTIVE) && + ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || + (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND))) { + return 1; } - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - - if (rc == 2) { - /* Scan request forbidden by filter policy */ - return 0; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (scanp->scan_type == BLE_SCAN_TYPE_INITIATE) { + return 1; } +#endif - return (scanp->scan_type == BLE_SCAN_TYPE_ACTIVE) && - ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || - (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND)); + return 0; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static int -ble_ll_scan_rx_isr_on_aux(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) +ble_ll_scan_rx_isr_end_on_scan_rsp(uint8_t pdu_type, uint8_t *rxbuf, + struct ble_mbuf_hdr *hdr, + struct ble_ll_scan_addr_data *addrd) { struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data; - int rc; + uint8_t sreq_adva_type; + uint8_t *sreq_adva; - if (!scansm->ext_scanning) { - return -1; - } + ble_ll_scan_get_addr_data_from_legacy(pdu_type, rxbuf, addrd); - rc = ble_ll_scan_update_aux_data(hdr, rxbuf, &addrd->adva_present); - if (rc < 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_AUX_INVALID; + if (!BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { + /* + * We were not expecting scan response so just ignore and do not + * update backoff. + */ return -1; - } else if (rc == 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT; } - /* Now we can update aux_data from header since it may have just been created */ - aux_data = rxinfo->user_data; + sreq_adva_type = !!(scansm->pdu_data.hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK); + sreq_adva = scansm->pdu_data.adva; /* - * Restore proper header flags if filtering was already done successfully on - * some previous PDU in an event. + * Ignore scan response if AdvA does not match AdvA in request and also + * update backoff as if there was no scan response. */ - if (aux_data->flags & BLE_LL_AUX_IS_MATCHED) { - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - rxinfo->rpa_index = aux_data->rpa_index; - if (rxinfo->rpa_index >= 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - } - if (aux_data->flags & BLE_LL_AUX_IS_TARGETA_RESOLVED) { - rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; - } -#endif - goto done; - } - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - addrd->adva = aux_data->adva; - addrd->adva_type = aux_data->adva_type; - } else { - /* Accept this PDU and wait for AdvA in aux */ - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - return 0; - } - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - addrd->targeta = aux_data->targeta; - addrd->targeta_type = aux_data->targeta_type; - } else { - addrd->targeta = NULL; - } - - rc = ble_ll_scan_rx_filter(hdr, addrd); - if (!rc) { - return 0; + if ((addrd->adva_type != sreq_adva_type) || + memcmp(addrd->adva, sreq_adva, BLE_DEV_ADDR_LEN)) { + ble_ll_scan_req_backoff(scansm, 0); + return -1; } - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) /* - * Once we matched device, there's no need to go through filtering on every - * other PDU in an event so just store info required to restore state for - * subsequent PDUs in aux_data. + * We are not pushing this one through filters so need to update + * rpa_index here as otherwise pkt_in won't be able to determine + * advertiser address properly. */ - aux_data->flags |= BLE_LL_AUX_IS_MATCHED; - if (rxinfo->flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED) { - aux_data->flags |= BLE_LL_AUX_IS_TARGETA_RESOLVED; - /* AdvA state is already stored in rpa_index */ + rxinfo->rpa_index = ble_hw_resolv_list_match(); + if (rxinfo->rpa_index >= 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; } +#endif - if (rc == 2) { - /* Scan request forbidden by filter policy */ - return 0; - } + rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; -done: - return (scanp->scan_type == BLE_SCAN_TYPE_ACTIVE) && - ((rxbuf[2] >> 6) == BLE_LL_EXT_ADV_MODE_SCAN); + return 0; } -#endif static bool ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, @@ -2290,23 +1505,11 @@ ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, { struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = rxinfo->user_data; - uint8_t phy_mode; -#endif bool is_ext_adv = false; + int8_t rpa_index; uint16_t adi = 0; int rc; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (ble_ll_scan_get_adi(aux_data, &adi) < 0) { - return false; - } - is_ext_adv = true; - } -#endif - /* Check if we already scanned this device successfully */ if (ble_ll_scan_have_rxd_scan_rsp(addrd->adv_addr, addrd->adv_addr_type, is_ext_adv, adi)) { @@ -2323,15 +1526,15 @@ ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, } } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - phy_mode = ble_ll_phy_to_phy_mode(rxinfo->phy, BLE_HCI_LE_PHY_CODED_ANY); - if (ble_ll_sched_scan_req_over_aux_ptr(rxinfo->channel, phy_mode)) { - return false; - } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + rpa_index = addrd->rpa_index; +#else + rpa_index = -1; #endif /* Use original AdvA in scan request (Core 5.1, Vol 6, Part B, section 6.3) */ - ble_ll_scan_req_pdu_prepare(scansm, addrd->adva, addrd->adva_type, addrd->rl); + ble_ll_scan_req_pdu_prepare(scansm, addrd->adva, addrd->adva_type, + rpa_index); rc = ble_phy_tx(ble_ll_scan_req_tx_pdu_cb, scansm, BLE_PHY_TRANSITION_TX_RX); if (rc) { @@ -2341,14 +1544,6 @@ ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, scansm->scan_rsp_pending = 1; rxinfo->flags |= BLE_MBUF_HDR_F_SCAN_REQ_TXD; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (rxinfo->channel < BLE_PHY_NUM_DATA_CHANS) { - /* Keep aux_data for expected scan response */ - scansm->cur_aux_data = ble_ll_scan_aux_data_ref(aux_data); - STATS_INC(ble_ll_stats, aux_scan_req_tx); - } -#endif - return true; } @@ -2384,48 +1579,34 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) return 0; } - rxbuf = rxpdu->om_data; - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* - * In case aux was expected, copy aux_data for LL to use. Make sure this was - * indeed an aux as otherwise there's no need to process it and just pass to - * LL immediately. - */ - if (scansm->cur_aux_data) { - rxinfo->user_data = scansm->cur_aux_data; - scansm->cur_aux_data = NULL; - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return -1; - } - } -#endif - if (!crcok) { goto scan_rx_isr_ignore; } - /* - * Addresses will be always set in handlers, no need to initialize them. We - * only need to initialize rl which may not be always set, depending on how - * filtering goes. - */ - addrd.rl = NULL; + rxbuf = rxpdu->om_data; + pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; switch (pdu_type) { case BLE_ADV_PDU_TYPE_ADV_IND: case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: case BLE_ADV_PDU_TYPE_ADV_NONCONN_IND: - case BLE_ADV_PDU_TYPE_SCAN_RSP: case BLE_ADV_PDU_TYPE_ADV_SCAN_IND: - rc = ble_ll_scan_rx_isr_on_legacy(pdu_type, rxbuf, hdr, &addrd); + rc = ble_ll_scan_rx_isr_end_on_adv(pdu_type, rxbuf, hdr, &addrd); + break; + case BLE_ADV_PDU_TYPE_SCAN_RSP: + rc = ble_ll_scan_rx_isr_end_on_scan_rsp(pdu_type, rxbuf, hdr, &addrd); break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) case BLE_ADV_PDU_TYPE_ADV_EXT_IND: - rc = ble_ll_scan_rx_isr_on_aux(pdu_type, rxbuf, hdr, &addrd); - break; + rc = ble_ll_scan_aux_rx_isr_end_on_ext(&g_ble_ll_scan_sm, rxpdu); + if (rc < 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + } + ble_ll_state_set(BLE_LL_STATE_STANDBY); + /* Return here, we do not want any further processing since it's all + * handled in scan_aux. + */ + return -1; #endif default: /* This is not something we would like to process here */ @@ -2435,10 +1616,24 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) if (rc == -1) { goto scan_rx_isr_ignore; - } else if (rc == 1) { - if (ble_ll_scan_send_scan_req(pdu_type, rxbuf, hdr, &addrd)) { - /* Keep PHY active and LL in scanning state */ - return 0; + } + + if (rc == 1) { + switch (scansm->scanp->scan_type) { + case BLE_SCAN_TYPE_ACTIVE: + if (ble_ll_scan_send_scan_req(pdu_type, rxbuf, hdr, &addrd)) { + /* Keep PHY active and LL in scanning state */ + return 0; + } + break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_SCAN_TYPE_INITIATE: + if (ble_ll_conn_send_connect_req(rxpdu, &addrd, 0) == 0) { + hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONNECT_IND_TXD; + return 0; + } + break; +#endif } } @@ -2474,372 +1669,64 @@ ble_ll_scan_chk_resume(void) OS_ENTER_CRITICAL(sr); if (scansm->restart_timer_needed) { scansm->restart_timer_needed = 0; - ble_ll_event_send(&scansm->scan_sched_ev); - STATS_INC(ble_ll_stats, scan_timer_restarted); - OS_EXIT_CRITICAL(sr); - return; - } - - now = os_cputime_get32(); - if (ble_ll_state_get() == BLE_LL_STATE_STANDBY && - ble_ll_scan_is_inside_window(scansm->scanp, now)) { - /* Turn on the receiver and set state */ - ble_ll_scan_start(scansm, NULL); - } - OS_EXIT_CRITICAL(sr); - } -} - -/** - * Scan timer callback; means that the scan window timeout has been reached - * and we should perform the appropriate actions. - * - * Context: Interrupt (cputimer) - * - * @param arg Pointer to scan state machine. - */ -void -ble_ll_scan_timer_cb(void *arg) -{ - struct ble_ll_scan_sm *scansm; - - scansm = (struct ble_ll_scan_sm *)arg; - ble_ll_event_send(&scansm->scan_sched_ev); -} - -void -ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_npl_event_set_arg(&scansm->scan_interrupted_ev, scansm->cur_aux_data); - scansm->cur_aux_data = NULL; -#endif - - ble_ll_event_send(&scansm->scan_interrupted_ev); -} - -/** - * Called when the wait for response timer expires while in the scanning - * state. - * - * Context: Interrupt. - */ -void -ble_ll_scan_wfr_timer_exp(void) -{ - struct ble_ll_scan_sm *scansm; - uint8_t chan; - int phy; - int rc; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - uint8_t phy_mode; -#endif - uint32_t now; - - scansm = &g_ble_ll_scan_sm; - - /* Update backoff if we failed to receive scan response */ - if (scansm->scan_rsp_pending) { - scansm->scan_rsp_pending = 0; - ble_ll_scan_req_backoff(scansm, 0); - } - - if (scansm->cur_aux_data) { - /* We actually care about interrupted scan only for EXT ADV because only - * then we might consider to send truncated event to the host. - */ - ble_ll_scan_interrupted(scansm); - - /* Need to disable phy since we are going to move to BLE_LL_STATE_STANDBY - * or we will need to change channel to primary one - */ - ble_phy_disable(); - - now = os_cputime_get32(); - if (!ble_ll_scan_is_inside_window(scansm->scanp, now)) { - /* Outside the window scan */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return; - } - - ble_ll_get_chan_to_scan(scansm, &chan, &phy); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - phy_mode = ble_ll_phy_to_phy_mode(phy, BLE_HCI_LE_PHY_CODED_ANY); - ble_phy_mode_set(phy_mode, phy_mode); -#endif - rc = ble_phy_setchan(chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); - BLE_LL_ASSERT(rc == 0); - } - - - ble_phy_restart_rx(); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/* - * Send extended advertising report - * - * @return -1 on error (data truncated or other error) - * 0 on success (data status is "completed") - * 1 on success (data status is not "completed") - */ -static int -ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type, - uint8_t *inita, uint8_t inita_type, - struct os_mbuf *om, - struct ble_mbuf_hdr *hdr) -{ - struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data; - struct ble_hci_ev_le_subev_ext_adv_rpt *ev; - struct ext_adv_report *report; - struct ble_hci_ev *hci_ev; - struct ble_hci_ev *hci_ev_next; - int offset; - int datalen; - int rc; - bool need_event; - bool is_scannable_aux; - uint8_t max_data_len; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - rc = -1; - goto done; - } - - /* - * We keep one allocated event in aux_data to be able to truncate chain - * properly in case of error. If there is no event in aux_data it means this - * is the first event for this chain. - */ - if (aux_data && aux_data->evt) { - hci_ev = aux_data->evt; - aux_data->evt = NULL; - - hci_ev->length = sizeof(*ev) + sizeof(*report); - } else { - hci_ev = ble_ll_scan_get_ext_adv_report(NULL); - if (!hci_ev) { - rc = -1; - goto done; - } - } - - ev = (void *) hci_ev->data; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* If RPA has been used, make sure we use correct address types - * in the advertising report. - */ - if (BLE_MBUF_HDR_RESOLVED(hdr)) { - adva_type += 2; - } - if (BLE_MBUF_HDR_TARGETA_RESOLVED(hdr)) { - inita_type += 2; - } -#endif - - datalen = ble_ll_scan_parse_ext_hdr(om, adva, adva_type, inita, inita_type, - hdr, ev->reports); - if (datalen < 0) { - rc = -1; - - /* Need to send truncated event if we already sent some reports */ - if (aux_data && (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED)); - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)); - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; - - report = ev->reports; - report->data_len = 0; - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - - ble_ll_hci_event_send(hci_ev); - goto done; - } - - ble_hci_trans_buf_free((uint8_t *)hci_ev); - goto done; - } - - is_scannable_aux = aux_data && - (aux_data->evt_type & BLE_HCI_ADV_SCAN_MASK) && - !(aux_data->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK); - - max_data_len = BLE_LL_MAX_EVT_LEN - sizeof(*hci_ev) - sizeof(*ev) - sizeof(*report); - offset = 0; - - do { - hci_ev_next = NULL; - - ev = (void *) hci_ev->data; - report = ev->reports; - - report->data_len = min(max_data_len, datalen - offset); - - /* adjust event length */ - hci_ev->length += report->data_len; - report->rssi = hdr->rxinfo.rssi; - - os_mbuf_copydata(om, offset, report->data_len, report->data); - offset += report->data_len; - - /* - * We need another event if either there are still some data left to - * send in current PDU or scan is not completed. There are two exceptions - * though: - * - we sent all data from this PDU and there is scan error set already; - * it may be set before entering current function due to failed aux - * scan scheduling - * - this is a scannable event which is not a scan response - */ - need_event = ((offset < datalen) || (aux_data && !(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_COMPLETE))) && - !((offset == datalen) && (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR)) && - !is_scannable_aux; - - if (need_event) { - /* - * We will need another event so let's try to allocate one now. If - * we cannot do this, need to mark event as truncated. - */ - hci_ev_next = ble_ll_scan_get_ext_adv_report(report); - - if (hci_ev_next) { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_INCOMPLETE; - rc = 1; - } else { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - rc = -1; - } - } else if (aux_data && (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR)) { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - rc = -1; - } else { - rc = 0; + ble_ll_event_send(&scansm->scan_sched_ev); + STATS_INC(ble_ll_stats, scan_timer_restarted); + OS_EXIT_CRITICAL(sr); + return; } - if ((rc == -1) && aux_data) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - ble_hci_trans_buf_free((uint8_t *)hci_ev); - goto done; - } - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; - } else if (!is_scannable_aux) { - /* - * We do not set 'sent' flags for scannable AUX since we only care - * about scan response that will come next. - */ - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_ANY; - if (rc == 0) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED; - } + now = os_cputime_get32(); + if (ble_ll_state_get() == BLE_LL_STATE_STANDBY && + ble_ll_scan_is_inside_window(scansm->scanp, now)) { + /* Turn on the receiver and set state */ + ble_ll_scan_start(scansm); } - - ble_ll_hci_event_send(hci_ev); - - hci_ev = hci_ev_next; - } while ((offset < datalen) && hci_ev); - - BLE_LL_ASSERT(offset <= datalen); - - if (aux_data) { - /* Store any event left for later use */ - aux_data->evt = hci_ev; - } else { - /* If it is empty beacon, evt shall be NULL */ - BLE_LL_ASSERT(!hci_ev); + OS_EXIT_CRITICAL(sr); } +} -done: - if (!aux_data) { - return rc; - } +/** + * Scan timer callback; means that the scan window timeout has been reached + * and we should perform the appropriate actions. + * + * Context: Interrupt (cputimer) + * + * @param arg Pointer to scan state machine. + */ +void +ble_ll_scan_timer_cb(void *arg) +{ + struct ble_ll_scan_sm *scansm; - if (rc == 0) { - if (aux_data->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK) { - /* Complete scan response can be added to duplicates list */ - ble_ll_scan_add_scan_rsp_adv(aux_data->adva, aux_data->adva_type, - 1, aux_data->adi); - } else if (is_scannable_aux) { - /* - * Scannable AUX is marked as incomplete because we do not want to - * add this to duplicates list now, this should happen only after - * we receive complete scan response. The drawback here is that we - * will keep receiving reports for scannable PDUs until complete - * scan response is received. - * - * XXX ^^ extend duplicates list to fix - */ - rc = 1; - } - } else if (rc < 0) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - } + scansm = (struct ble_ll_scan_sm *)arg; + ble_ll_event_send(&scansm->scan_sched_ev); +} - return rc; +void +ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm) +{ + ble_ll_event_send(&scansm->scan_interrupted_ev); } -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -static void -ble_ll_scan_check_periodic_sync(const struct os_mbuf *om, struct ble_mbuf_hdr *rxhdr, - uint8_t *adva, uint8_t adva_type, int rpa_index) +/** + * Called when the wait for response timer expires while in the scanning + * state. + * + * Context: Interrupt. + */ +void +ble_ll_scan_wfr_timer_exp(void) { - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - uint8_t *rxbuf = om->om_data; - uint8_t sid; - int i; + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - pdu_len = rxbuf[1]; - if (pdu_len == 0) { - return; + /* Update backoff if we failed to receive scan response */ + if (scansm->scan_rsp_pending) { + scansm->scan_rsp_pending = 0; + ble_ll_scan_req_backoff(scansm, 0); } - ext_hdr_len = rxbuf[2] & 0x3F; - - if (ext_hdr_len) { - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - i = 0; - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - i += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - i += 1; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - sid = (get_le16(ext_hdr + i) >> 12); - i += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } else { - /* ADI is mandatory */ - return; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - i += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { - ble_ll_sync_info_event(adva, adva_type, rpa_index, sid, rxhdr, - ext_hdr + i); - } - } + ble_phy_restart_rx(); } -#endif static inline void ble_ll_scan_dup_move_to_head(struct ble_ll_scan_dup_entry *e) @@ -2906,20 +1793,17 @@ ble_ll_scan_dup_check_legacy(uint8_t addr_type, uint8_t *addr, uint8_t pdu_type) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static int -ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, - struct ble_ll_aux_data *aux_data) +int +ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, bool has_aux, + uint16_t adi) { struct ble_ll_scan_dup_entry *e; - bool has_aux; bool is_anon; - uint16_t adi; uint8_t type; int rc; - has_aux = aux_data != NULL; is_anon = addr == NULL; - adi = has_aux ? aux_data->adi : 0; + adi = has_aux ? adi : 0; type = BLE_LL_SCAN_ENTRY_TYPE_EXT(addr_type, has_aux, is_anon, adi); @@ -2958,19 +1842,16 @@ ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, return rc; } -static int -ble_ll_scan_dup_update_ext(uint8_t addr_type, uint8_t *addr, - struct ble_ll_aux_data *aux_data) +int +ble_ll_scan_dup_update_ext(uint8_t addr_type, uint8_t *addr, bool has_aux, + uint16_t adi) { struct ble_ll_scan_dup_entry *e; - bool has_aux; bool is_anon; - uint16_t adi; uint8_t type; - has_aux = aux_data != NULL; is_anon = addr == NULL; - adi = has_aux ? aux_data->adi : 0; + adi = has_aux ? adi : 0; type = BLE_LL_SCAN_ENTRY_TYPE_EXT(addr_type, has_aux, is_anon, adi); @@ -3002,15 +1883,24 @@ ble_ll_scan_rx_pkt_in_restore_addr_data(struct ble_mbuf_hdr *hdr, addrd->adv_addr_type = addrd->adva_type; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (rxinfo->rpa_index >= 0) { + addrd->rpa_index = rxinfo->rpa_index; + + if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_RESOLVED) { + BLE_LL_ASSERT(rxinfo->rpa_index >= 0); rl = &g_ble_ll_resolv_list[rxinfo->rpa_index]; addrd->adv_addr = rl->rl_identity_addr; addrd->adv_addr_type = rl->rl_addr_type; - addrd->rl = rl; + addrd->adva_resolved = 1; + } else { + addrd->adva_resolved = 0; } + if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED) { addrd->targeta = ble_ll_get_our_devaddr(scansm->own_addr_type & 1); addrd->targeta_type = scansm->own_addr_type & 1; + addrd->targeta_resolved = 1; + } else { + addrd->targeta_resolved = 0; } #endif } @@ -3052,143 +1942,6 @@ ble_ll_scan_rx_pkt_in_on_legacy(uint8_t pdu_type, struct os_mbuf *om, } } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_scan_rx_pkt_in_on_aux(uint8_t pdu_type, struct os_mbuf *om, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - uint8_t *rxbuf = om->om_data; -#endif - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data = rxinfo->user_data; - bool send_hci_report; - int rc; - - if (aux_data) { - aux_data->flags_ll |= aux_data->flags_isr; - } - - /* - * For every new extended advertising event scanned, rx_isr_end will either - * allocate new aux_data or set 'invalid' flag. This means if no 'invalid' - * flag is set, aux_data is always valid. - */ - - /* Drop on scan error or if we received not what we expected to receive */ - if (!BLE_MBUF_HDR_CRC_OK(hdr) || - BLE_MBUF_HDR_IGNORED(hdr) || - BLE_MBUF_HDR_AUX_INVALID(hdr) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR) || - (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) || - !scansm->scan_enabled) { - if (aux_data) { - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); - rxinfo->user_data = NULL; - } - return; - } - - BLE_LL_ASSERT(aux_data); - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - addrd->adva = aux_data->adva; - addrd->adva_type = aux_data->adva_type; - } else { - addrd->adva = NULL; - addrd->adva_type = 0; - } - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - addrd->targeta = aux_data->targeta; - addrd->targeta_type = aux_data->targeta_type; - } else { - addrd->targeta = NULL; - addrd->targeta_type = 0; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* - * Periodic scan uses own filter list so we need to let it do own filtering - * regardless of scanner filtering. Just make sure we already have AdvA. - */ - if (ble_ll_sync_enabled() && - ((rxbuf[2] >> 6) == BLE_LL_EXT_ADV_MODE_NON_CONN) && addrd->adva && - !(aux_data->flags_ll & BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED)) { - ble_ll_scan_check_periodic_sync(om, hdr, addrd->adva, addrd->adva_type, - rxinfo->rpa_index); - } -#endif - - /* Ignore if device was not matched by either whitelist or scan policy */ - if (!BLE_MBUF_HDR_DEVMATCH(hdr)) { - goto scan_continue; - } - - ble_ll_scan_rx_pkt_in_restore_addr_data(hdr, addrd); - - /* - * If there is AuxPtr in this PDU, we should first try to schedule scan for - * subsequent aux. - */ - if (BLE_MBUF_HDR_WAIT_AUX(hdr)) { - if (ble_ll_sched_aux_scan(hdr, scansm, aux_data)) { - rxinfo->flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - /* Silently ignore if no HCI event was sent to host */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - goto scan_continue; - } - } - - /* Ignore if this was just ADV_EXT_IND with AuxPtr, will process aux */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED)) { - goto scan_continue; - } - - STATS_INC(ble_ll_stats, aux_chain_cnt); - } - - send_hci_report = !scansm->scan_filt_dups || - !ble_ll_scan_dup_check_ext(addrd->adv_addr_type, - addrd->adv_addr, aux_data); - if (send_hci_report) { - rc = ble_ll_hci_send_ext_adv_report(pdu_type, - addrd->adv_addr, addrd->adv_addr_type, - addrd->targeta, addrd->targeta_type, - om, hdr); - if ((rc < 0) && BLE_MBUF_HDR_WAIT_AUX(hdr)) { - /* Data were truncated so stop scanning for subsequent auxes */ - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - if (ble_ll_sched_rmv_elem(&aux_data->sch) == 0) { - ble_ll_scan_aux_data_unref(aux_data->sch.cb_arg); - aux_data->sch.cb_arg = NULL; - } - } else if ((rc == 0) && scansm->scan_filt_dups) { - /* Complete data were send so we can update scan_dup list */ - ble_ll_scan_dup_update_ext(addrd->adv_addr_type, addrd->adv_addr, - aux_data); - } - } - - if (BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { - /* - * For now assume success if we just received direct scan response, - * don't care about complete aux chain. - */ - ble_ll_scan_req_backoff(scansm, 1); - } - -scan_continue: - ble_ll_scan_aux_data_unref(rxinfo->user_data); - rxinfo->user_data = NULL; -} -#endif - /** * Process a received PDU while in the scanning state. * @@ -3200,32 +1953,71 @@ ble_ll_scan_rx_pkt_in_on_aux(uint8_t pdu_type, struct os_mbuf *om, void ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hdr) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data = rxinfo->user_data; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + struct ble_mbuf_hdr_rxinfo *rxinfo; + uint8_t *targeta; #endif + struct ble_ll_scan_sm *scansm; struct ble_ll_scan_addr_data addrd; + uint8_t max_pdu_type; + + scansm = &g_ble_ll_scan_sm; + + /* Ignore PDUs we do not expect here */ + max_pdu_type = BLE_ADV_PDU_TYPE_ADV_SCAN_IND; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (scansm->ext_scanning) { + /* Note: We do not expect AUX_CONNECT_RSP here */ + max_pdu_type = BLE_ADV_PDU_TYPE_ADV_EXT_IND; + } +#endif + if (ptype > max_pdu_type) { + ble_ll_scan_chk_resume(); + return; + } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data || (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND)) { - ble_ll_scan_rx_pkt_in_on_aux(ptype, om, hdr, &addrd); + if (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { + ble_ll_scan_aux_pkt_in_on_ext(om, hdr); ble_ll_scan_chk_resume(); return; } #endif - ble_ll_scan_rx_pkt_in_on_legacy(ptype, om, hdr, &addrd); + switch (scansm->scanp->scan_type) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_SCAN_TYPE_INITIATE: + rxinfo = &hdr->rxinfo; + if (rxinfo->flags & BLE_MBUF_HDR_F_CONNECT_IND_TXD) { + /* We need to keep original TargetA in case it was resolved, so rl + * can be updated properly. + */ + ble_ll_scan_get_addr_data_from_legacy(ptype, om->om_data, &addrd); + targeta = addrd.targeta; + ble_ll_scan_rx_pkt_in_restore_addr_data(hdr, &addrd); + + ble_ll_scan_sm_stop(0); + ble_ll_conn_created_on_legacy(om, &addrd, targeta); + return; + } + break; +#endif + default: + ble_ll_scan_rx_pkt_in_on_legacy(ptype, om, hdr, &addrd); + break; + } + ble_ll_scan_chk_resume(); } int -ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len) +ble_ll_scan_hci_set_params(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_set_scan_params_cp *cmd = (const void *)cmdbuf; uint16_t scan_itvl; uint16_t scan_window; struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; + struct ble_ll_scan_phy *scanp; if (len != sizeof(*cmd)) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -3267,16 +2059,18 @@ ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len) } /* Store scan parameters */ - scanp = &g_ble_ll_scan_params[PHY_UNCODED]; + g_ble_ll_scan_params.own_addr_type = cmd->own_addr_type; + g_ble_ll_scan_params.scan_filt_policy = cmd->filter_policy; + + scanp = &g_ble_ll_scan_params.scan_phys[PHY_UNCODED]; scanp->configured = 1; scanp->scan_type = cmd->scan_type; scanp->timing.interval = ble_ll_scan_time_hci_to_ticks(scan_itvl); scanp->timing.window = ble_ll_scan_time_hci_to_ticks(scan_window); - scanp->scan_filt_policy = cmd->filter_policy; - scanp->own_addr_type = cmd->own_addr_type; #if (BLE_LL_SCAN_PHY_NUMBER == 2) - g_ble_ll_scan_params[PHY_CODED].configured = 0; + scanp = &g_ble_ll_scan_params.scan_phys[PHY_CODED]; + scanp->configured = 0; #endif return 0; @@ -3284,7 +2078,7 @@ ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static int -ble_ll_check_scan_params(uint8_t type, uint16_t itvl, uint16_t window) +ble_ll_scan_check_phy_params(uint8_t type, uint16_t itvl, uint16_t window) { /* Check scan type */ if ((type != BLE_HCI_SCAN_TYPE_PASSIVE) && @@ -3294,9 +2088,9 @@ ble_ll_check_scan_params(uint8_t type, uint16_t itvl, uint16_t window) /* Check interval and window */ if ((itvl < BLE_HCI_SCAN_ITVL_MIN) || - (itvl > BLE_HCI_SCAN_ITVL_MAX) || + (itvl > BLE_HCI_SCAN_ITVL_MAX_EXT) || (window < BLE_HCI_SCAN_WINDOW_MIN) || - (window > BLE_HCI_SCAN_WINDOW_MAX) || + (window > BLE_HCI_SCAN_WINDOW_MAX_EXT) || (itvl < window)) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -3305,14 +2099,16 @@ ble_ll_check_scan_params(uint8_t type, uint16_t itvl, uint16_t window) } int -ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) +ble_ll_scan_hci_set_ext_params(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_set_ext_scan_params_cp *cmd = (const void *) cmdbuf; const struct scan_params *params = cmd->scans; - struct ble_ll_scan_params new_params[BLE_LL_SCAN_PHY_NUMBER] = { }; - struct ble_ll_scan_params *uncoded = &new_params[PHY_UNCODED]; - struct ble_ll_scan_params *coded = &new_params[PHY_CODED]; + struct ble_ll_scan_phy new_params[BLE_LL_SCAN_PHY_NUMBER] = { }; + struct ble_ll_scan_phy *uncoded = &new_params[PHY_UNCODED]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + struct ble_ll_scan_phy *coded = &new_params[PHY_CODED]; +#endif uint16_t interval; uint16_t window; int rc; @@ -3333,17 +2129,11 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - coded->own_addr_type = cmd->own_addr_type; - uncoded->own_addr_type = cmd->own_addr_type; - /* Check scanner filter policy */ if (cmd->filter_policy > BLE_HCI_SCAN_FILT_MAX) { return BLE_ERR_INV_HCI_CMD_PARMS; } - coded->scan_filt_policy = cmd->filter_policy; - uncoded->scan_filt_policy = cmd->filter_policy; - /* Check if no reserved bits in PHYS are set and that at least one valid PHY * is set. */ @@ -3360,7 +2150,7 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) interval = le16toh(params->itvl); window = le16toh(params->window); - rc = ble_ll_check_scan_params(params->type, interval, window); + rc = ble_ll_scan_check_phy_params(params->type, interval, window); if (rc) { return rc; } @@ -3384,7 +2174,7 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) interval = le16toh(params->itvl); window = le16toh(params->window); - rc = ble_ll_check_scan_params(params->type, interval, window); + rc = ble_ll_scan_check_phy_params(params->type, interval, window); if (rc) { return rc; } @@ -3396,7 +2186,6 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) /* That means user wants to use this PHY for scanning */ coded->configured = 1; } -#endif /* if any of PHYs is configured for continuous scan we alter interval to * fit other PHY @@ -3407,11 +2196,15 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) } if (uncoded->timing.interval == uncoded->timing.window) { - uncoded->timing.window += coded->timing.window; + uncoded->timing.interval += coded->timing.window; } } +#endif - memcpy(g_ble_ll_scan_params, new_params, sizeof(new_params)); + g_ble_ll_scan_params.own_addr_type = cmd->own_addr_type; + g_ble_ll_scan_params.scan_filt_policy = cmd->filter_policy; + + memcpy(g_ble_ll_scan_params.scan_phys, new_params, sizeof(new_params)); return 0; } @@ -3422,30 +2215,24 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) static void ble_ll_scan_duration_period_timers_restart(struct ble_ll_scan_sm *scansm) { - uint32_t now; - - now = os_cputime_get32(); - - os_cputime_timer_stop(&scansm->duration_timer); - os_cputime_timer_stop(&scansm->period_timer); + ble_npl_callout_stop(&scansm->duration_timer); + ble_npl_callout_stop(&scansm->period_timer); if (scansm->duration_ticks) { - os_cputime_timer_start(&scansm->duration_timer, - now + scansm->duration_ticks); + ble_npl_callout_reset(&scansm->duration_timer, + scansm->duration_ticks); if (scansm->period_ticks) { - os_cputime_timer_start(&scansm->period_timer, - now + scansm->period_ticks); + ble_npl_callout_reset(&scansm->period_timer, + scansm->period_ticks); } } } static void -ble_ll_scan_duration_timer_cb(void *arg) +ble_ll_scan_duration_timer_cb(struct ble_npl_event *ev) { - struct ble_ll_scan_sm *scansm; - - scansm = (struct ble_ll_scan_sm *)arg; + struct ble_ll_scan_sm *scansm = ble_npl_event_get_arg(ev); ble_ll_scan_sm_stop(2); @@ -3456,9 +2243,9 @@ ble_ll_scan_duration_timer_cb(void *arg) } static void -ble_ll_scan_period_timer_cb(void *arg) +ble_ll_scan_period_timer_cb(struct ble_npl_event *ev) { - struct ble_ll_scan_sm *scansm = arg; + struct ble_ll_scan_sm *scansm = ble_npl_event_get_arg(ev); ble_ll_scan_sm_start(scansm); @@ -3484,12 +2271,12 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, { int rc; struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_phy; + struct ble_ll_scan_phy *scanp; + struct ble_ll_scan_phy *scanp_phy; int i; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - uint32_t period_ticks = 0; - uint32_t dur_ticks = 0; + ble_npl_time_t period_ticks = 0; + ble_npl_time_t dur_ticks = 0; #endif /* Check for valid parameters */ @@ -3509,16 +2296,13 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, period = 0; } - /* period is in 1.28 sec units - * TODO support full range, would require os_cputime milliseconds API - */ - if (period > 3355) { + /* period is in 1.28 sec units */ + if (ble_npl_time_ms_to_ticks(period * 1280, &period_ticks)) { return BLE_ERR_INV_HCI_CMD_PARMS; } - period_ticks = os_cputime_usecs_to_ticks(period * 1280000); /* duration is in 10ms units */ - dur_ticks = os_cputime_usecs_to_ticks(dur * 10000); + dur_ticks = ble_npl_time_ms_to_ticks32(dur * 10); if (dur_ticks && period_ticks && (dur_ticks >= period_ticks)) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -3532,8 +2316,8 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, ble_ll_scan_sm_stop(1); } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - os_cputime_timer_stop(&scansm->duration_timer); - os_cputime_timer_stop(&scansm->period_timer); + ble_npl_callout_stop(&scansm->duration_timer); + ble_npl_callout_stop(&scansm->period_timer); #endif return BLE_ERR_SUCCESS; @@ -3542,13 +2326,15 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, /* if already enable we just need to update parameters */ if (scansm->scan_enabled) { /* Controller does not allow initiating and scanning.*/ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { - scanp_phy = &scansm->scanp_phys[i]; + scanp_phy = &scansm->scan_phys[i]; if (scanp_phy->configured && scanp_phy->scan_type == BLE_SCAN_TYPE_INITIATE) { return BLE_ERR_CMD_DISALLOWED; } } +#endif #if MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS) /* update filter policy */ @@ -3575,9 +2361,12 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, scansm->scanp = NULL; scansm->scanp_next = NULL; + scansm->own_addr_type = g_ble_ll_scan_params.own_addr_type; + scansm->scan_filt_policy = g_ble_ll_scan_params.scan_filt_policy; + for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { - scanp_phy = &scansm->scanp_phys[i]; - scanp = &g_ble_ll_scan_params[i]; + scanp_phy = &scansm->scan_phys[i]; + scanp = &g_ble_ll_scan_params.scan_phys[i]; if (!scanp->configured) { continue; @@ -3586,15 +2375,9 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, scanp_phy->configured = scanp->configured; scanp_phy->scan_type = scanp->scan_type; scanp_phy->timing = scanp->timing; - scanp_phy->scan_filt_policy = scanp->scan_filt_policy; - scanp_phy->own_addr_type = scanp->own_addr_type; if (!scansm->scanp) { scansm->scanp = scanp_phy; - /* Take own_addr_type from the first configured PHY. - * Note: All configured PHYs shall have the same own_addr_type - */ - scansm->own_addr_type = scanp_phy->own_addr_type; } else { scansm->scanp_next = scanp_phy; } @@ -3606,8 +2389,9 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, * Parameters defaults. */ if (!scansm->scanp) { - scansm->scanp = &scansm->scanp_phys[PHY_UNCODED]; + scansm->scanp = &scansm->scan_phys[PHY_UNCODED]; scansm->own_addr_type = BLE_ADDR_PUBLIC; + scansm->scan_filt_policy = BLE_HCI_SCAN_FILT_NO_WL; scanp_phy = scansm->scanp; scanp_phy->configured = 1; @@ -3616,8 +2400,6 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_ITVL_DEF); scanp_phy->timing.window = ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_WINDOW_DEF); - scanp_phy->scan_filt_policy = BLE_HCI_SCAN_FILT_NO_WL; - scanp_phy->own_addr_type = BLE_ADDR_PUBLIC; } rc = ble_ll_scan_sm_start(scansm); @@ -3633,7 +2415,7 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, return rc; } -int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len) +int ble_ll_scan_hci_set_enable(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_set_scan_enable_cp *cmd = (const void *) cmdbuf; @@ -3646,7 +2428,7 @@ int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_hci_ext_scan_set_enable(const uint8_t *cmdbuf, uint8_t len) +int ble_ll_scan_hci_set_ext_enable(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_set_ext_scan_enable_cp *cmd = (const void *) cmdbuf; @@ -3671,11 +2453,9 @@ ble_ll_scan_can_chg_whitelist(void) { int rc; struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; scansm = &g_ble_ll_scan_sm; - scanp = scansm->scanp; - if (scansm->scan_enabled && (scanp->scan_filt_policy & 1)) { + if (scansm->scan_enabled && (scansm->scan_filt_policy & 1)) { rc = 0; } else { rc = 1; @@ -3684,83 +2464,61 @@ ble_ll_scan_can_chg_whitelist(void) return rc; } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) int -ble_ll_scan_initiator_start(struct hci_create_conn *hcc, - struct ble_ll_scan_sm **sm) +ble_ll_scan_initiator_start(struct ble_ll_conn_sm *connsm, uint8_t ext, + struct ble_ll_conn_create_scan *cc_scan) { struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - int rc; - - scansm = &g_ble_ll_scan_sm; - scansm->own_addr_type = hcc->own_addr_type; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - scansm->ext_scanning = 0; + struct ble_ll_scan_phy *scanp_uncoded; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + struct ble_ll_scan_phy *scanp_coded; #endif - scansm->scanp = &scansm->scanp_phys[PHY_UNCODED]; - scansm->scanp_next = NULL; - - scanp = scansm->scanp; - scanp->scan_filt_policy = hcc->filter_policy; - scanp->timing.interval = ble_ll_scan_time_hci_to_ticks(hcc->scan_itvl); - scanp->timing.window = ble_ll_scan_time_hci_to_ticks(hcc->scan_window); - scanp->scan_type = BLE_SCAN_TYPE_INITIATE; - - rc = ble_ll_scan_sm_start(scansm); - if (sm == NULL) { - return rc; - } - - if (rc == BLE_ERR_SUCCESS) { - *sm = scansm; - } else { - *sm = NULL; - } - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int -ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, - struct ble_ll_scan_sm **sm) -{ - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp_uncoded; - struct ble_ll_scan_params *scanp_coded; - struct hci_ext_conn_params *params; + uint8_t init_phy_mask; int rc; scansm = &g_ble_ll_scan_sm; - scansm->own_addr_type = hcc->own_addr_type; + scansm->own_addr_type = cc_scan->own_addr_type; + scansm->scan_filt_policy = cc_scan->filter_policy; scansm->scanp = NULL; scansm->scanp_next = NULL; - scansm->ext_scanning = 1; - - if (hcc->init_phy_mask & BLE_PHY_MASK_1M) { - params = &hcc->params[0]; - scanp_uncoded = &scansm->scanp_phys[PHY_UNCODED]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + scansm->ext_scanning = ext; + init_phy_mask = cc_scan->init_phy_mask; +#else + init_phy_mask = BLE_PHY_MASK_1M; +#endif + scansm->connsm = connsm; - scanp_uncoded->timing.interval = ble_ll_scan_time_hci_to_ticks(params->scan_itvl); - scanp_uncoded->timing.window = ble_ll_scan_time_hci_to_ticks(params->scan_window); + scanp_uncoded = &scansm->scan_phys[PHY_UNCODED]; + if (init_phy_mask & BLE_PHY_MASK_1M) { + scanp_uncoded->configured = 1; + scanp_uncoded->timing.interval = ble_ll_scan_time_hci_to_ticks( + cc_scan->scan_params[PHY_UNCODED].itvl); + scanp_uncoded->timing.window = ble_ll_scan_time_hci_to_ticks( + cc_scan->scan_params[PHY_UNCODED].window); scanp_uncoded->scan_type = BLE_SCAN_TYPE_INITIATE; - scanp_uncoded->scan_filt_policy = hcc->filter_policy; scansm->scanp = scanp_uncoded; + } else { + scanp_uncoded->configured = 0; } - if (hcc->init_phy_mask & BLE_PHY_MASK_CODED) { - params = &hcc->params[2]; - scanp_coded = &scansm->scanp_phys[PHY_CODED]; - - scanp_coded->timing.interval = ble_ll_scan_time_hci_to_ticks(params->scan_itvl); - scanp_coded->timing.window = ble_ll_scan_time_hci_to_ticks(params->scan_window); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + scanp_coded = &scansm->scan_phys[PHY_CODED]; + if (init_phy_mask & BLE_PHY_MASK_CODED) { + scanp_coded->configured = 1; + scanp_coded->timing.interval = ble_ll_scan_time_hci_to_ticks( + cc_scan->scan_params[PHY_CODED].itvl); + scanp_coded->timing.window = ble_ll_scan_time_hci_to_ticks( + cc_scan->scan_params[PHY_CODED].window); scanp_coded->scan_type = BLE_SCAN_TYPE_INITIATE; - scanp_coded->scan_filt_policy = hcc->filter_policy; if (scansm->scanp) { scansm->scanp_next = scanp_coded; } else { scansm->scanp = scanp_coded; } + } else { + scanp_coded->configured = 0; } /* if any of PHYs is configured for continuous scan we alter interval to @@ -3776,16 +2534,11 @@ ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, scanp_uncoded->timing.interval += scanp_coded->timing.window; } } +#endif rc = ble_ll_scan_sm_start(scansm); - if (sm == NULL) { - return rc; - } - - if (rc == BLE_ERR_SUCCESS) { - *sm = scansm; - } else { - *sm = NULL; + if (rc == 0) { + g_ble_ll_conn_create_sm.connsm = connsm; } return rc; @@ -3853,18 +2606,11 @@ ble_ll_scan_get_pdu_data(void) return &g_ble_ll_scan_sm.pdu_data; } -/* Returns true if whitelist is enabled for scanning */ -int -ble_ll_scan_whitelist_enabled(void) -{ - return g_ble_ll_scan_sm.scanp->scan_filt_policy & 1; -} - static void ble_ll_scan_common_init(void) { struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; + struct ble_ll_scan_phy *scanp; int i; /* Clear state machine in case re-initialized */ @@ -3872,23 +2618,23 @@ ble_ll_scan_common_init(void) memset(scansm, 0, sizeof(struct ble_ll_scan_sm)); /* Clear scan parameters in case re-initialized */ - memset(g_ble_ll_scan_params, 0, sizeof(g_ble_ll_scan_params)); + memset(&g_ble_ll_scan_params, 0, sizeof(g_ble_ll_scan_params)); /* Initialize scanning window end event */ ble_npl_event_init(&scansm->scan_sched_ev, ble_ll_scan_event_proc, scansm); for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { /* Set all non-zero default parameters */ - scanp = &g_ble_ll_scan_params[i]; + scanp = &g_ble_ll_scan_params.scan_phys[i]; scanp->timing.interval = ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_ITVL_DEF); scanp->timing.window = ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_WINDOW_DEF); } - scansm->scanp_phys[PHY_UNCODED].phy = BLE_PHY_1M; + scansm->scan_phys[PHY_UNCODED].phy = BLE_PHY_1M; #if (BLE_LL_SCAN_PHY_NUMBER == 2) - scansm->scanp_phys[PHY_CODED].phy = BLE_PHY_CODED; + scansm->scan_phys[PHY_CODED].phy = BLE_PHY_CODED; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) @@ -3901,10 +2647,10 @@ ble_ll_scan_common_init(void) /* Initialize extended scan timers */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - os_cputime_timer_init(&scansm->duration_timer, + ble_npl_callout_init(&scansm->duration_timer, &g_ble_ll_data.ll_evq, ble_ll_scan_duration_timer_cb, scansm); - os_cputime_timer_init(&scansm->period_timer, ble_ll_scan_period_timer_cb, - scansm); + ble_npl_callout_init(&scansm->period_timer, &g_ble_ll_data.ll_evq, + ble_ll_scan_period_timer_cb, scansm); #endif ble_npl_event_init(&scansm->scan_interrupted_ev, ble_ll_scan_interrupted_event_cb, NULL); @@ -3930,8 +2676,8 @@ ble_ll_scan_reset(void) /* stop extended scan timers */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - os_cputime_timer_stop(&scansm->duration_timer); - os_cputime_timer_stop(&scansm->period_timer); + ble_npl_callout_stop(&scansm->duration_timer); + ble_npl_callout_stop(&scansm->period_timer); #endif /* Reset duplicate advertisers and those from which we rxd a response */ @@ -3941,13 +2687,11 @@ ble_ll_scan_reset(void) os_mempool_clear(&g_scan_dup_pool); TAILQ_INIT(&g_scan_dup_list); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* clear memory pool for AUX scan results */ - os_mempool_clear(&ext_scan_aux_pool); -#endif - /* Call the common init function again */ ble_ll_scan_common_init(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + ble_ll_scan_aux_init(); +#endif } /** @@ -3961,15 +2705,6 @@ ble_ll_scan_init(void) { os_error_t err; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - err = os_mempool_init(&ext_scan_aux_pool, - MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT), - sizeof (struct ble_ll_aux_data), - ext_scan_aux_mem, - "ble_ll_aux_scan_pool"); - BLE_LL_ASSERT(err == 0); -#endif - err = os_mempool_init(&g_scan_dup_pool, MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS), sizeof(struct ble_ll_scan_dup_entry), @@ -3980,4 +2715,9 @@ ble_ll_scan_init(void) TAILQ_INIT(&g_scan_dup_list); ble_ll_scan_common_init(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + ble_ll_scan_aux_init(); +#endif } + +#endif diff --git a/nimble/controller/src/ble_ll_scan_aux.c b/nimble/controller/src/ble_ll_scan_aux.c new file mode 100644 index 0000000000..69ab10cde9 --- /dev/null +++ b/nimble/controller/src/ble_ll_scan_aux.c @@ -0,0 +1,1761 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + +#include +#include +#include +#include +#include "os/os.h" +#include "nimble/ble.h" +#include "nimble/hci_common.h" +#include "nimble/ble_hci_trans.h" +#include "controller/ble_phy.h" +#include "controller/ble_hw.h" +#include "controller/ble_ll.h" +#include "controller/ble_ll_sched.h" +#include "controller/ble_ll_scan.h" +#include "controller/ble_ll_scan_aux.h" +#include "controller/ble_ll_hci.h" +#include "controller/ble_ll_whitelist.h" +#include "controller/ble_ll_resolv.h" +#include "controller/ble_ll_sync.h" + +#define BLE_LL_SCAN_AUX_F_AUX_ADV 0x0001 +#define BLE_LL_SCAN_AUX_F_AUX_CHAIN 0x0002 +#define BLE_LL_SCAN_AUX_F_MATCHED 0x0004 +#define BLE_LL_SCAN_AUX_F_W4_SCAN_RSP 0x0008 +#define BLE_LL_SCAN_AUX_F_SCANNED 0x0010 +#define BLE_LL_SCAN_AUX_F_HAS_ADVA 0x0020 +#define BLE_LL_SCAN_AUX_F_HAS_TARGETA 0x0040 +#define BLE_LL_SCAN_AUX_F_HAS_ADI 0x0080 +#define BLE_LL_SCAN_AUX_F_RESOLVED_ADVA 0x0100 +#define BLE_LL_SCAN_AUX_F_RESOLVED_TARGETA 0x0200 +#define BLE_LL_SCAN_AUX_F_CONNECTABLE 0x0400 +#define BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP 0x0800 + +#define BLE_LL_SCAN_AUX_H_SENT_ANY 0x01 +#define BLE_LL_SCAN_AUX_H_DONE 0x02 +#define BLE_LL_SCAN_AUX_H_TRUNCATED 0x04 + +struct ble_ll_scan_aux_data { + uint16_t flags; + uint8_t hci_state; + + uint8_t scan_type; + + uint8_t pri_phy; + uint8_t sec_phy; + uint8_t chan; + uint8_t offset_unit : 1; + uint32_t aux_ptr; + struct ble_ll_sched_item sch; + struct ble_npl_event break_ev; + struct ble_hci_ev *hci_ev; + + uint16_t adi; + + uint8_t adva[6]; + uint8_t targeta[6]; + uint8_t adva_type : 1; + uint8_t targeta_type : 1; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + int8_t rpa_index; +#endif +}; + +#define AUX_MEMPOOL_SIZE (OS_MEMPOOL_SIZE( \ + MYNEWT_VAL(BLE_LL_SCAN_AUX_SEGMENT_CNT), \ + sizeof(struct ble_ll_scan_aux_data))) + +static os_membuf_t aux_data_mem[AUX_MEMPOOL_SIZE]; +static struct os_mempool aux_data_pool; + +static struct ble_ll_scan_aux_data *aux_data_current; + +static void ble_ll_hci_ev_send_ext_adv_truncated_report(struct ble_ll_scan_aux_data *aux); + +static inline uint8_t * +ble_ll_scan_aux_get_own_addr(void) +{ + uint8_t own_addr_type; + + own_addr_type = ble_ll_scan_get_own_addr_type() & 1; + + return ble_ll_get_our_devaddr(own_addr_type); +} + +static int +ble_ll_scan_aux_sched_cb(struct ble_ll_sched_item *sch) +{ + struct ble_ll_scan_aux_data *aux = sch->cb_arg; + uint32_t wfr_us; +#if BLE_LL_BT5_PHY_SUPPORTED + uint8_t phy_mode; +#endif + uint8_t lls; + int rc; + + BLE_LL_ASSERT(aux); + + lls = ble_ll_state_get(); + BLE_LL_ASSERT(lls == BLE_LL_STATE_STANDBY); + + rc = ble_phy_setchan(aux->chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); + BLE_LL_ASSERT(rc == 0); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + ble_phy_encrypt_disable(); +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (ble_ll_resolv_enabled()) { + ble_phy_resolv_list_enable(); + } else { + ble_phy_resolv_list_disable(); + } +#endif + +#if BLE_LL_BT5_PHY_SUPPORTED + phy_mode = ble_ll_phy_to_phy_mode(aux->sec_phy, BLE_HCI_LE_PHY_CODED_ANY); + ble_phy_mode_set(phy_mode, phy_mode); +#endif + + rc = ble_phy_rx_set_start_time(sch->start_time + g_ble_ll_sched_offset_ticks, + sch->remainder); + if (rc != 0 && rc != BLE_PHY_ERR_RX_LATE) { + ble_ll_scan_aux_break(aux); + return BLE_LL_SCHED_STATE_DONE; + } + + /* Keep listening even if we are late, we may still receive something */ + + if (ble_ll_scan_get_filt_policy() & 1) { + ble_ll_whitelist_enable(); + } else { + ble_ll_whitelist_disable(); + } + + wfr_us = aux->offset_unit ? 300 : 30; + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_us); + + aux_data_current = aux; + + ble_ll_state_set(BLE_LL_STATE_SCAN_AUX); + + return BLE_LL_SCHED_STATE_RUNNING; +} + +static struct ble_ll_scan_aux_data * +ble_ll_scan_aux_alloc(void) +{ + struct ble_ll_scan_aux_data *aux; + + aux = os_memblock_get(&aux_data_pool); + if (!aux) { + return NULL; + } + + memset(aux, 0, sizeof(*aux)); + + aux->sch.sched_cb = ble_ll_scan_aux_sched_cb; + aux->sch.sched_type = BLE_LL_SCHED_TYPE_SCAN_AUX; + aux->sch.cb_arg = aux; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + aux->rpa_index = -1; +#endif + + return aux; +} + +static void +ble_ll_scan_aux_free(struct ble_ll_scan_aux_data *aux) +{ + BLE_LL_ASSERT(!aux->sch.enqueued); + BLE_LL_ASSERT(aux->hci_ev == NULL); + BLE_LL_ASSERT((aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) || + !(aux->hci_state & BLE_LL_SCAN_AUX_H_SENT_ANY)); + + os_memblock_put(&aux_data_pool, aux); +} + +static void +ble_ll_scan_aux_update_scan_backoff(struct ble_ll_scan_aux_data *aux) +{ + if (!(aux->flags & BLE_LL_SCAN_AUX_F_W4_SCAN_RSP) && + !(aux->flags & BLE_LL_SCAN_AUX_F_SCANNED)) { + return; + } + + if ((aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) && + !(aux->hci_state & BLE_LL_SCAN_AUX_H_TRUNCATED)) { + ble_ll_scan_backoff_update(1); + } else { + ble_ll_scan_backoff_update(0); + } +} + +static inline bool +ble_ll_scan_aux_need_truncation(struct ble_ll_scan_aux_data *aux) +{ + return (aux->hci_state & BLE_LL_SCAN_AUX_H_SENT_ANY) && + !(aux->hci_state & BLE_LL_SCAN_AUX_H_DONE); +} + +static struct ble_hci_ev * +ble_ll_hci_ev_alloc_ext_adv_report_for_aux(struct ble_ll_scan_addr_data *addrd, + struct ble_ll_scan_aux_data *aux) +{ + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; + struct ble_hci_ev *hci_ev; + + hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + if (!hci_ev) { + return NULL; + } + + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*hci_subev) + sizeof(*report); + + hci_subev = (void *)hci_ev->data; + hci_subev->subev_code = BLE_HCI_LE_SUBEV_EXT_ADV_RPT; + hci_subev->num_reports = 1; + + report = hci_subev->reports; + + memset(report, 0, sizeof(*report)); + + report->evt_type = 0; + if (addrd->adva) { + report->addr_type = addrd->adv_addr_type; + memcpy(report->addr, addrd->adv_addr, 6); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->adva_resolved) { + report->addr_type += 2; + } +#endif + } else { + report->addr_type = 0xff; + } + report->pri_phy = aux->pri_phy; + report->sec_phy = aux->sec_phy; + report->sid = aux->adi >> 12; + report->tx_power = 0x7f; + report->rssi = 0x7f; + report->periodic_itvl = 0; + if (addrd->targeta) { + report->evt_type |= BLE_HCI_ADV_DIRECT_MASK; + report->dir_addr_type = addrd->targeta_type; + memcpy(report->dir_addr, addrd->targeta, 6); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->targeta_resolved) { + report->dir_addr_type += 2; + } +#endif + } + report->data_len = 0; + + return hci_ev; +} + +static struct ble_hci_ev * +ble_ll_hci_ev_dup_ext_adv_report(struct ble_hci_ev *hci_ev_src) +{ + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; + struct ble_hci_ev *hci_ev; + + hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + if (!hci_ev) { + return NULL; + } + + memcpy(hci_ev, hci_ev_src, sizeof(*hci_ev) + sizeof(*hci_subev) + + sizeof(*report)); + hci_ev->length = sizeof(*hci_subev) + sizeof(*report); + + hci_subev = (void *)hci_ev->data; + + report = hci_subev->reports; + report->data_len = 0; + + return hci_ev; +} + +static void +ble_ll_hci_ev_update_ext_adv_report_from_aux(struct ble_hci_ev *hci_ev, + struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + uint8_t *rxbuf; + + hci_subev = (void *)hci_ev->data; + report = hci_subev->reports; + rxbuf = rxpdu->om_data; + + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + report->evt_type |= adv_mode; + if (rxhdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD) { + report->evt_type |= BLE_HCI_ADV_SCAN_MASK | BLE_HCI_ADV_SCAN_RSP_MASK; + } + report->sec_phy = rxhdr->rxinfo.phy; + + /* Strip PDU header and ext header, leave only AD */ + os_mbuf_adj(rxpdu, 3 + eh_len); + + /* + * We only care about SyncInfo and TxPower so don't bother parsing if they + * are not present, just set to 'unknown' values. + */ + if ((eh_len == 0) || !(eh_flags & ((1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT) | + (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)))) { + report->periodic_itvl = 0; + report->tx_power = 0x7f; + return; + } + /* Now parse extended header... */ + + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_CTE_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + eh_data += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { + report->periodic_itvl = get_le16(eh_data + 2); + eh_data += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; + } else { + report->periodic_itvl = 0; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { + report->tx_power = *eh_data; + } else { + report->tx_power = 0x7f; + } +} + +static void +ble_ll_hci_ev_update_ext_adv_report_from_ext(struct ble_hci_ev *hci_ev, + struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_mbuf_hdr_rxinfo *rxinfo = &rxhdr->rxinfo; + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl; +#endif + uint8_t pdu_hdr; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + uint8_t *rxbuf; + + rxbuf = rxpdu->om_data; + + pdu_hdr = rxbuf[0]; + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*hci_subev) + sizeof(*report); + + hci_subev = (void *)hci_ev->data; + hci_subev->subev_code = BLE_HCI_LE_SUBEV_EXT_ADV_RPT; + hci_subev->num_reports = 1; + + report = hci_subev->reports; + + memset(report, 0, sizeof(*report)); + + report->evt_type = adv_mode; + + report->pri_phy = rxinfo->phy; + report->sec_phy = 0; + report->sid = 0xff; + report->rssi = rxhdr->rxinfo.rssi; + report->periodic_itvl = 0; + report->data_len = 0; + + /* Now parse extended header... */ + + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (rxinfo->rpa_index >= 0) { + rl = &g_ble_ll_resolv_list[rxinfo->rpa_index]; + report->addr_type = rl->rl_addr_type + 2; + memcpy(report->addr, rl->rl_identity_addr, 6); + } else { + report->addr_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); + memcpy(report->addr, eh_data, 6); + } +#else + report->addr_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); + memcpy(report->addr, eh_data, 6); +#endif + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + report->evt_type |= BLE_HCI_ADV_DIRECT_MASK; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (rxinfo->flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED) { + report->dir_addr_type = (ble_ll_scan_get_own_addr_type() & 1) + 2; + memcpy(report->dir_addr, ble_ll_scan_aux_get_own_addr(), 6); + } else { + report->dir_addr_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); + memcpy(report->dir_addr, eh_data, 6); + } +#else + report->dir_addr_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); + memcpy(report->dir_addr, eh_data, 6); +#endif + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_CTE_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + eh_data += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { + report->tx_power = *eh_data; + } else { + report->tx_power = 0x7f; + } + + /* Strip PDU header and ext header, leave only AD */ + os_mbuf_adj(rxpdu, 3 + eh_len); + +} + +static void +ble_ll_hci_ev_send_ext_adv_truncated_report(struct ble_ll_scan_aux_data *aux) +{ + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; + struct ble_hci_ev *hci_ev; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + return; + } + + hci_ev = aux->hci_ev; + aux->hci_ev = NULL; + + BLE_LL_ASSERT(hci_ev); + + hci_subev = (void *)hci_ev->data; + report = hci_subev->reports; + report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; + + ble_ll_hci_event_send(hci_ev); + + aux->hci_state |= BLE_LL_SCAN_AUX_H_DONE | BLE_LL_SCAN_AUX_H_TRUNCATED; +} + +static int +ble_ll_hci_ev_send_ext_adv_report(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr, + struct ble_hci_ev **hci_ev) +{ + struct ble_mbuf_hdr_rxinfo *rxinfo = &rxhdr->rxinfo; + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ble_hci_ev *hci_ev_next; + struct ext_adv_report *report; + bool truncated = false; + int max_data_len; + int data_len; + int offset; + + data_len = OS_MBUF_PKTLEN(rxpdu); + max_data_len = BLE_LL_MAX_EVT_LEN - + sizeof(**hci_ev) - sizeof(*hci_subev) - sizeof(*report); + offset = 0; + hci_ev_next = NULL; + + do { + hci_subev = (void *)(*hci_ev)->data; + report = hci_subev->reports; + + report->rssi = rxinfo->rssi; + + report->data_len = min(max_data_len, data_len - offset); + os_mbuf_copydata(rxpdu, offset, report->data_len, report->data); + (*hci_ev)->length += report->data_len; + + offset += report->data_len; + + /* + * We need another event if either there are still some data left in + * this PDU or scan for next aux is scheduled. + */ + if ((offset < data_len) || + (rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT)) { + hci_ev_next = ble_ll_hci_ev_dup_ext_adv_report(*hci_ev); + if (hci_ev_next) { + report->evt_type |= BLE_HCI_ADV_DATA_STATUS_INCOMPLETE; + } else { + report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; + } + } + + switch (report->evt_type & BLE_HCI_ADV_DATA_STATUS_MASK) { + case BLE_HCI_ADV_DATA_STATUS_TRUNCATED: + truncated = true; + /* no break */ + case BLE_HCI_ADV_DATA_STATUS_COMPLETE: + BLE_LL_ASSERT(!hci_ev_next); + break; + case BLE_HCI_ADV_DATA_STATUS_INCOMPLETE: + BLE_LL_ASSERT(hci_ev_next); + break; + default: + BLE_LL_ASSERT(0); + } + + ble_ll_hci_event_send(*hci_ev); + + *hci_ev = hci_ev_next; + } while ((offset < data_len) && *hci_ev); + + return truncated ? -1 : 0; +} + + +static int +ble_ll_hci_ev_send_ext_adv_report_for_aux(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr, + struct ble_ll_scan_aux_data *aux, + struct ble_ll_scan_addr_data *addrd) +{ + struct ble_hci_ev *hci_ev; + int rc; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + return -1; + } + + /* + * We need to always keep one event allocated in aux to be able to truncate + * data properly in case of an error. If there is no event in aux it means + * this is first event and we can silently ignore in case of an error. + */ + if (aux->hci_ev) { + hci_ev = aux->hci_ev; + aux->hci_ev = NULL; + } else { + hci_ev = ble_ll_hci_ev_alloc_ext_adv_report_for_aux(addrd, aux); + if (!hci_ev) { + return -1; + } + } + + ble_ll_hci_ev_update_ext_adv_report_from_aux(hci_ev, rxpdu, rxhdr); + + rc = ble_ll_hci_ev_send_ext_adv_report(rxpdu, rxhdr, &hci_ev); + if (rc < 0) { + BLE_LL_ASSERT(!hci_ev); + aux->hci_state = BLE_LL_SCAN_AUX_H_DONE | BLE_LL_SCAN_AUX_H_TRUNCATED; + } else if (hci_ev) { + aux->hci_state = BLE_LL_SCAN_AUX_H_SENT_ANY; + } else { + aux->hci_state = BLE_LL_SCAN_AUX_H_DONE; + } + + aux->hci_ev = hci_ev; + + return rc; +} + +static void +ble_ll_hci_ev_send_ext_adv_report_for_ext(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_hci_ev *hci_ev; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + return; + } + + hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + if (!hci_ev) { + return; + } + + ble_ll_hci_ev_update_ext_adv_report_from_ext(hci_ev, rxpdu, rxhdr); + + ble_ll_hci_ev_send_ext_adv_report(rxpdu, rxhdr, &hci_ev); + + BLE_LL_ASSERT(!hci_ev); +} + +static void +ble_ll_scan_aux_break_ev(struct ble_npl_event *ev) +{ + struct ble_ll_scan_aux_data *aux = ble_npl_event_get_arg(ev); + + BLE_LL_ASSERT(aux); + + if (ble_ll_scan_aux_need_truncation(aux)) { + ble_ll_hci_ev_send_ext_adv_truncated_report(aux); + } + + ble_ll_scan_aux_update_scan_backoff(aux); + + ble_ll_scan_aux_free(aux); + ble_ll_scan_chk_resume(); +} + +void +ble_ll_scan_aux_break(struct ble_ll_scan_aux_data *aux) +{ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + ble_ll_conn_send_connect_req_cancel(); + } +#endif + + ble_npl_event_init(&aux->break_ev, ble_ll_scan_aux_break_ev, aux); + ble_ll_event_send(&aux->break_ev); +} + +static int +ble_ll_scan_aux_parse_aux_ptr(struct ble_ll_scan_aux_data *aux, + uint32_t aux_ptr, uint32_t *offset_us) +{ + uint8_t offset_unit; + uint32_t offset; + uint8_t chan; + uint8_t phy; + + phy = (aux_ptr >> 21) & 0x07; + switch (phy) { + case 0: + phy = BLE_PHY_1M; + break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) + case 1: + phy = BLE_PHY_2M; + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + case 2: + phy = BLE_PHY_CODED; + break; +#endif + default: + return -1; + } + + chan = aux_ptr & 0x3f; + if (chan >= BLE_PHY_NUM_DATA_CHANS) { + return -1; + } + + offset = 30 * ((aux_ptr >> 8) & 0x1fff); + if ((aux_ptr >> 7) & 0x01) { + offset *= 10; + offset_unit = 1; + } else { + offset_unit = 0; + } + + if (offset < BLE_LL_MAFS) { + return -1; + } + + aux->sec_phy = phy; + aux->chan = chan; + aux->offset_unit = offset_unit; + + *offset_us = offset; + + return 0; +} + +int +ble_ll_scan_aux_sched(struct ble_ll_scan_aux_data *aux, uint32_t pdu_time, + uint8_t pdu_time_rem, uint32_t aux_ptr) +{ + uint32_t offset_us; + int rc; + + rc = ble_ll_scan_aux_parse_aux_ptr(aux, aux_ptr, &offset_us); + if (rc < 0) { + return -1; + } + + rc = ble_ll_sched_scan_aux(&aux->sch, pdu_time, pdu_time_rem, offset_us); + if (rc < 0) { + return -1; + } + + return 0; +} + +int +ble_ll_scan_aux_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr) +{ + struct ble_ll_scan_aux_data *aux; + + BLE_LL_ASSERT(aux_data_current); + aux = aux_data_current; + + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { + aux_data_current = NULL; + ble_ll_scan_aux_break(aux); + ble_ll_state_set(BLE_LL_STATE_STANDBY); + return -1; + } + return 0; + } + + if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) { + aux_data_current = NULL; + ble_ll_scan_aux_break(aux); + ble_ll_state_set(BLE_LL_STATE_STANDBY); + return -1; + } + + /* + * Prepare TX transition when doing active scanning and receiving 1st PDU + * since we may want to send AUX_SCAN_REQ. + */ + if ((aux->scan_type != BLE_SCAN_TYPE_PASSIVE) && + !(aux->flags & BLE_LL_SCAN_AUX_F_AUX_ADV)) { + return 1; + } + + return 0; +} + +static int +ble_ll_scan_aux_parse_to_aux_data(struct ble_ll_scan_aux_data *aux, + uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) +{ + uint8_t pdu_hdr; + uint8_t pdu_len; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + + pdu_hdr = rxbuf[0]; + pdu_len = rxbuf[1]; + + /* PDU without at least Extended Header Length is invalid */ + if (pdu_len == 0) { + return -1; + } + + /* Mark as AUX received on 1st PDU, then as CHAIN received on subsequent */ + if (aux->flags & BLE_LL_SCAN_AUX_F_AUX_ADV) { + aux->flags |= BLE_LL_SCAN_AUX_F_AUX_CHAIN; + } else { + aux->flags |= BLE_LL_SCAN_AUX_F_AUX_ADV; + } + + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + + /* Only AUX_CHAIN_IND is valid without Extended Header */ + if (eh_len == 0) { + if (!(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN) || adv_mode) { + return -1; + } + return 0; + } + + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + /* Now parse extended header... */ + + /* AdvA is only valid in 1st PDU, ignore in AUX_CHAIN_IND */ + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + if (!(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN)) { + memcpy(aux->adva, eh_data, 6); + aux->adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_ADVA; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + aux->rpa_index = ble_hw_resolv_list_match(); +#endif + } + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + /* TargetA is only valid in 1st PDU, ignore in AUX_CHAIN_IND */ + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + if (!(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN)) { + memcpy(aux->targeta, eh_data, 6); + aux->targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_TARGETA; + } + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_CTE_INFO_SIZE; + } + + /* + * ADI handling is a bit convoluted.... + * ADI is mandatory in ADV_EXT_IND with AuxPtr and is also mandatory in PDU + * if included in superior PDU. This implies that each AUX_CHAIN shall have + * ADI. However... AUX_SCAN_RSP does not need to have ADI, so if there's no + * ADI in AUX_SCAN_RSP we allow it and clear corresponding flag to skip ADI + * checks on subsequent PDUs. + */ + if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADI) { + if (get_le16(eh_data) != aux->adi) { + return -1; + } + } + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } else if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADI) { + if (rxhdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD) { + aux->flags &= ~BLE_LL_SCAN_AUX_F_HAS_ADI; + } else { + return -1; + } + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + aux->aux_ptr = get_le24(eh_data); + rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT; + } + + return 0; +} + +static int +ble_ll_scan_aux_ext_parse(uint8_t *rxbuf, struct ble_ll_scan_addr_data *addrd, + uint16_t *adi, uint32_t *aux_ptr) +{ + uint8_t pdu_hdr; + uint8_t pdu_len; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + + pdu_hdr = rxbuf[0]; + pdu_len = rxbuf[1]; + + if (pdu_len == 0) { + return -1; + } + + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + + if ((adv_mode == 3) || (eh_len == 0)) { + return -1; + } + + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + /* ADV_EXT_IND with AuxPtr but without ADI is invalid */ + if ((eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) && + !(eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT))) { + return -1; + } + + /* ADV_EXT_IND without either AdvA or AuxPtr is not valid */ + if (!(eh_flags & ((1 << BLE_LL_EXT_ADV_ADVA_BIT) | + (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)))) { + return -1; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + addrd->adva = eh_data; + addrd->adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_RAND); + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } else { + addrd->adva = NULL; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + addrd->targeta = eh_data; + addrd->targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_RAND); + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } else { + addrd->targeta = NULL; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_CTE_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + *adi = get_le16(eh_data); + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } else { + *adi = 0; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + *aux_ptr = get_le24(eh_data); + } else { + *aux_ptr = 0; + } + + return 0; +} + +static void +ble_ll_scan_aux_update_rxinfo_from_addrd(struct ble_ll_scan_addr_data *addrd, + struct ble_mbuf_hdr_rxinfo *rxinfo) +{ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + rxinfo->rpa_index = addrd->rpa_index; + if (addrd->adva_resolved) { + rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; + } + if (addrd->targeta_resolved) { + rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; + } +#endif +} + +static void +ble_ll_scan_aux_update_aux_data_from_addrd(struct ble_ll_scan_addr_data *addrd, + struct ble_ll_scan_aux_data *aux) +{ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + aux->rpa_index = addrd->rpa_index; + if (addrd->adva_resolved) { + aux->flags |= BLE_LL_SCAN_AUX_F_RESOLVED_ADVA; + } + if (addrd->targeta_resolved) { + aux->flags |= BLE_LL_SCAN_AUX_F_RESOLVED_TARGETA; + } +#endif +} + +int +ble_ll_scan_aux_rx_isr_end_on_ext(struct ble_ll_scan_sm *scansm, + struct os_mbuf *rxpdu) +{ + struct ble_mbuf_hdr *rxhdr = BLE_MBUF_HDR_PTR(rxpdu); + struct ble_mbuf_hdr_rxinfo *rxinfo = &rxhdr->rxinfo; + struct ble_ll_scan_addr_data addrd; + struct ble_ll_scan_aux_data *aux; + uint8_t *rxbuf; + uint32_t aux_ptr; + uint16_t adi; + bool do_match; + int rc; + + rxbuf = rxpdu->om_data; + + rc = ble_ll_scan_aux_ext_parse(rxbuf, &addrd, &adi, &aux_ptr); + if (rc < 0) { + return -1; + } + + /* We can filter based on ext PDU alone if both AdvA and TargetA are present + * or there's no AuxPtr. Otherwise, we need to wait for aux PDU to filter. + */ + do_match = !aux_ptr || (addrd.adva && addrd.targeta); + if (do_match) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd.rpa_index = ble_hw_resolv_list_match(); +#endif + rc = ble_ll_scan_rx_filter(ble_ll_scan_get_own_addr_type(), + ble_ll_scan_get_filt_policy(), + &addrd, NULL); + if (rc < 0) { + return -1; + } + + /* Don't care about initiator here, there are no AdvA and TargetA + * in connectable ADV_EXT_IND so no filtering to do. + */ + + if (!aux_ptr) { + /* We do not allocate aux_data for ADV_EXT_IND without AuxPtr so + * need to pass match data in rxinfo. + */ + ble_ll_scan_aux_update_rxinfo_from_addrd(&addrd, rxinfo); + } + } + + if (aux_ptr) { + aux = ble_ll_scan_aux_alloc(); + if (!aux) { + return -1; + } + + aux->scan_type = scansm->scanp->scan_type; + + aux->pri_phy = rxinfo->phy; + aux->aux_ptr = aux_ptr; + + if (addrd.adva) { + memcpy(aux->adva, addrd.adva, 6); + aux->adva_type = addrd.adva_type; + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_ADVA; + } + + if (addrd.targeta) { + memcpy(aux->targeta, addrd.targeta, 6); + aux->targeta_type = addrd.targeta_type; + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_TARGETA; + } + + aux->adi = adi; + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_ADI; + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (aux->scan_type == BLE_SCAN_TYPE_INITIATE) { + aux->flags |= BLE_LL_SCAN_AUX_F_CONNECTABLE; + } +#endif + + if (do_match) { + aux->flags |= BLE_LL_SCAN_AUX_F_MATCHED; + ble_ll_scan_aux_update_aux_data_from_addrd(&addrd, aux); + } else if (addrd.adva) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + /* If ext PDU has AdvA, we need to store rpa_index to be able to + * reuse it for filtering when done on aux PDU. + */ + aux->rpa_index = ble_hw_resolv_list_match(); +#endif + } + + rxinfo->user_data = aux; + } + + return 0; +} + +void +ble_ll_scan_aux_pkt_in_on_ext(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_mbuf_hdr_rxinfo *rxinfo = &rxhdr->rxinfo; + struct ble_ll_scan_aux_data *aux = rxinfo->user_data; + int rc; + + if (rxinfo->flags & BLE_MBUF_HDR_F_IGNORED) { + BLE_LL_ASSERT(!aux); + return; + } + + if (!aux) { + ble_ll_hci_ev_send_ext_adv_report_for_ext(rxpdu, rxhdr); + return; + } + + BLE_LL_ASSERT(aux->aux_ptr); + + rc = ble_ll_scan_aux_sched(aux, rxhdr->beg_cputime, rxhdr->rem_usecs, + aux->aux_ptr); + if (rc < 0) { + ble_ll_scan_aux_free(aux); + } +} + +static uint8_t +ble_ll_scan_aux_scan_req_tx_pdu_cb(uint8_t *dptr, void *arg, uint8_t *hdr_byte) +{ + struct ble_ll_scan_aux_data *aux = arg; + uint8_t *scana; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl; + uint8_t rpa[BLE_DEV_ADDR_LEN]; +#endif + uint8_t hb; + + hb = BLE_ADV_PDU_TYPE_SCAN_REQ; + + /* ScanA */ + if (ble_ll_scan_get_own_addr_type() & 0x01) { + hb |= BLE_ADV_PDU_HDR_TXADD_RAND; + scana = g_random_addr; + } else { + scana = g_dev_addr; + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (ble_ll_scan_get_own_addr_type() & 0x02) { + if (aux->rpa_index >=0) { + rl = &g_ble_ll_resolv_list[aux->rpa_index]; + } else { + rl = NULL; + } + + /* + * If device is on RL and we have local IRK, we use RPA generated using + * that IRK as ScanA. Otherwise we use NRPA as ScanA to prevent our + * device from being tracked when doing an active scan + * ref: Core 5.2, Vol 6, Part B, section 6.3) + */ + if (rl && rl->rl_has_local) { + ble_ll_resolv_get_priv_addr(rl, 1, rpa); + scana = rpa; + } else { + scana = ble_ll_get_scan_nrpa(); + } + + hb |= BLE_ADV_PDU_HDR_TXADD_RAND; + } +#endif + memcpy(dptr, scana, BLE_DEV_ADDR_LEN); + + /* AdvA */ + if (aux->adva_type) { + hb |= BLE_ADV_PDU_HDR_RXADD_RAND; + } + memcpy(dptr + BLE_DEV_ADDR_LEN, aux->adva, BLE_DEV_ADDR_LEN); + + *hdr_byte = hb; + + return BLE_DEV_ADDR_LEN * 2; +} + +static bool +ble_ll_scan_aux_send_scan_req(struct ble_ll_scan_aux_data *aux, + struct ble_ll_scan_addr_data *addrd) +{ + int rc; + + /* Check if we already scanned this device successfully */ + if (ble_ll_scan_have_rxd_scan_rsp(addrd->adv_addr, addrd->adv_addr_type, + true, aux->adi)) { + return false; + } + + /* We want to send a request, see if backoff allows us */ + if (ble_ll_scan_backoff_kick() != 0) { + return false; + } + + /* TODO perhaps we should check if scan req+rsp won't overlap with scheduler + * item (old code did it), but for now let's just scan and we will be + * interrupted if scheduler kicks in. + */ + + rc = ble_phy_tx(ble_ll_scan_aux_scan_req_tx_pdu_cb, aux, + BLE_PHY_TRANSITION_TX_RX); + if (rc) { + return false; + } + + return true; +} + +int +ble_ll_scan_aux_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) +{ + struct ble_ll_scan_addr_data addrd; + struct ble_mbuf_hdr_rxinfo *rxinfo; + struct ble_ll_scan_aux_data *aux; + struct ble_mbuf_hdr *rxhdr; + uint8_t scan_filt_policy; + uint8_t scan_ok; + uint8_t adv_mode; + uint8_t *rxbuf; + int rc; + + BLE_LL_ASSERT(aux_data_current); + aux = aux_data_current; + aux_data_current = NULL; + + if (rxpdu == NULL) { + ble_ll_scan_aux_break(aux); + goto done; + } + + rxhdr = BLE_MBUF_HDR_PTR(rxpdu); + rxinfo = &rxhdr->rxinfo; + rxinfo->user_data = aux; + + if (!crcok) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + goto done; + } + + rxbuf = rxpdu->om_data; + + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + aux->flags &= ~BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP; + rxinfo->flags |= BLE_MBUF_HDR_F_CONNECT_RSP_RXD; + goto done; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_SCAN_RSP) { + aux->flags &= ~BLE_LL_SCAN_AUX_F_W4_SCAN_RSP; + aux->flags |= BLE_LL_SCAN_AUX_F_SCANNED; + rxinfo->flags |= BLE_MBUF_HDR_F_SCAN_RSP_RXD; + } + + rc = ble_ll_scan_aux_parse_to_aux_data(aux, rxbuf, rxhdr); + if (rc < 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + goto done; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_MATCHED) { + goto done; + } + + /* We do filtering on either ADV_EXT_IND or AUX_ADV_IND so we should not be + * here when processing AUX_CHAIN_IND. + */ + BLE_LL_ASSERT(!(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN)); + + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADVA) { + addrd.adva = aux->adva; + addrd.adva_type = aux->adva_type; + } else { + addrd.adva = NULL; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_TARGETA) { + addrd.targeta = aux->targeta; + addrd.targeta_type = aux->targeta_type; + } else { + addrd.targeta = NULL; + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd.rpa_index = aux->rpa_index; +#endif + + scan_filt_policy = ble_ll_scan_get_filt_policy(); + + rc = ble_ll_scan_rx_filter(ble_ll_scan_get_own_addr_type(), + scan_filt_policy, &addrd, &scan_ok); + if (rc < 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + /* + * XXX hack warning + * Even if PDU was not allowed by current scan filter policy, we should + * still allow it to sync if SyncInfo is present. Since we do not use + * F_DEVMATCH in aux code for its intended purpose, let's use it here to + * indicate no match due to scan filter policy. + */ + if (rc == -2) { + rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; + } + goto done; + } + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if ((aux->scan_type == BLE_SCAN_TYPE_INITIATE) && + !(scan_filt_policy & 0x01)) { + rc = ble_ll_scan_rx_check_init(&addrd); + if (rc < 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + goto done; + } + } +#endif + + aux->flags |= BLE_LL_SCAN_AUX_F_MATCHED; + + ble_ll_scan_aux_update_aux_data_from_addrd(&addrd, aux); + + adv_mode = rxbuf[2] >> 6; + + switch (aux->scan_type) { + case BLE_SCAN_TYPE_ACTIVE: + if ((adv_mode == BLE_LL_EXT_ADV_MODE_SCAN) && scan_ok && + ble_ll_scan_aux_send_scan_req(aux, &addrd)) { + /* AUX_SCAN_REQ sent, keep PHY enabled to continue */ + aux->flags |= BLE_LL_SCAN_AUX_F_W4_SCAN_RSP; + rxinfo->flags |= BLE_MBUF_HDR_F_SCAN_REQ_TXD; + aux_data_current = aux; + return 0; + } + break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_SCAN_TYPE_INITIATE: + if (ble_ll_conn_send_connect_req(rxpdu, &addrd, 1) == 0) { + /* AUX_CONNECT_REQ sent, keep PHY enabled to continue */ + aux->flags |= BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP; + rxinfo->flags |= BLE_MBUF_HDR_F_CONNECT_REQ_TXD; + aux_data_current = aux; + return 0; + } else { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + } + break; +#endif + default: + break; + } + +done: + /* We are done with this PDU so go to standby and let LL resume if needed */ + ble_ll_state_set(BLE_LL_STATE_STANDBY); + return -1; +} + +static void +ble_ll_scan_aux_init_addrd_from_aux_data(struct ble_ll_scan_aux_data *aux, + struct ble_ll_scan_addr_data *addrd) +{ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl; +#endif + + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADVA) { + addrd->adva = aux->adva; + addrd->adva_type = aux->adva_type; + } else { + addrd->adva = NULL; + addrd->adva_type = 0; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_TARGETA) { + addrd->targeta = aux->targeta; + addrd->targeta_type = aux->targeta_type; + } else { + addrd->targeta = NULL; + addrd->targeta_type = 0; + } + + addrd->adv_addr = addrd->adva; + addrd->adv_addr_type = addrd->adva_type; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd->rpa_index = aux->rpa_index; + + if (aux->flags & BLE_LL_SCAN_AUX_F_RESOLVED_ADVA) { + BLE_LL_ASSERT(aux->rpa_index >= 0); + rl = &g_ble_ll_resolv_list[aux->rpa_index]; + addrd->adv_addr = rl->rl_identity_addr; + addrd->adv_addr_type = rl->rl_addr_type; + addrd->adva_resolved = 1; + } else { + addrd->adva_resolved = 0; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_RESOLVED_TARGETA) { + addrd->targeta = ble_ll_scan_aux_get_own_addr(); + addrd->targeta_type = ble_ll_scan_get_own_addr_type() & 1; + addrd->targeta_resolved = 1; + } else { + addrd->targeta_resolved = 0; + } +#endif +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +static void +ble_ll_scan_aux_sync_check(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd) +{ + struct ble_mbuf_hdr *rxhdr = BLE_MBUF_HDR_PTR(rxpdu); + uint8_t *rxbuf = rxpdu->om_data; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + uint8_t sid; + + adv_mode = rxbuf[2] >> 6; + + if (adv_mode != BLE_LL_EXT_ADV_MODE_NON_CONN) { + return; + } + + eh_len = rxbuf[2] & 0x3f; + + if (eh_len == 0) { + return; + } + + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + /* Need ADI and SyncInfo */ + if (!(eh_flags & ((1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT) | + (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)))) { + return; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += 1; + } + + sid = get_le16(eh_data) >> 12; + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + eh_data += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + } + + ble_ll_sync_info_event(addrd, sid, rxhdr, eh_data); +} +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +static int +ble_ll_scan_aux_check_connect_rsp(uint8_t *rxbuf, + struct ble_ll_scan_pdu_data *pdu_data, + struct ble_ll_scan_addr_data *addrd) +{ + uint8_t pdu_hdr; + uint8_t pdu_len; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + uint8_t adva_type; + uint8_t *adva; + uint8_t targeta_type; + uint8_t *targeta; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl = NULL; +#endif + + pdu_hdr = rxbuf[0]; + pdu_len = rxbuf[1]; + + if (pdu_len == 0) { + return -1; + } + + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + + if ((adv_mode != 0) || (eh_len == 0)) { + return -1; + } + + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + /* AUX_CONNECT_RSP without AdvA or TargetA is not valid */ + if (!(eh_flags & ((1 << BLE_LL_EXT_ADV_ADVA_BIT) | + (1 << BLE_LL_EXT_ADV_TARGETA_BIT)))) { + return -1; + } + + adva = eh_data; + adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_RAND); + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + + targeta = eh_data; + targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_RAND); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + /* If AdvA was initially resolved, we need to check if current AdvA also + * resolved with the same IRK since it may have changes due to RPA timeout. + * Otherwise it shall be the same as in AUX_CONNECT_REQ. + */ + if (addrd->adva_resolved) { + if (!adva_type) { + return -1; + } + + BLE_LL_ASSERT(addrd->rpa_index >= 0); + rl = &g_ble_ll_resolv_list[addrd->rpa_index]; + + if (!ble_ll_resolv_rpa(adva, rl->rl_peer_irk)) { + return -1; + } + + addrd->adva = adva; + } else if ((adva_type != + !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK)) || + (memcmp(adva, pdu_data->adva, 6) != 0)) { + return -1; + } +#else + if ((adva_type != !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK)) || + (memcmp(adva, pdu_data->adva, 6) != 0)) { + return -1; + } +#endif /* BLE_LL_CFG_FEAT_LL_PRIVACY */ + + if ((targeta_type != !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK)) || + (memcmp(targeta, pdu_data->inita, 6) != 0)) { + return -1; + } + + return 0; +} + +static void +ble_ll_scan_aux_rx_pkt_in_for_initiator(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_ll_scan_addr_data addrd; + struct ble_mbuf_hdr_rxinfo *rxinfo; + struct ble_ll_scan_aux_data *aux; + + rxinfo = &rxhdr->rxinfo; + aux = rxinfo->user_data; + + if (rxinfo->flags & BLE_MBUF_HDR_F_IGNORED) { + ble_ll_scan_chk_resume(); + goto done; + } + + if (!(rxinfo->flags & BLE_MBUF_HDR_F_CONNECT_RSP_RXD)) { + BLE_LL_ASSERT(rxinfo->flags & BLE_MBUF_HDR_F_CONNECT_REQ_TXD); + /* Waiting for AUX_CONNECT_RSP, do nothing */ + return; + } + + ble_ll_scan_aux_init_addrd_from_aux_data(aux, &addrd); + + if (ble_ll_scan_aux_check_connect_rsp(rxpdu->om_data, + ble_ll_scan_get_pdu_data(), + &addrd) < 0) { + ble_ll_scan_chk_resume(); + goto done; + } + + aux->flags &= ~BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP; + + ble_ll_scan_sm_stop(0); + ble_ll_conn_created_on_aux(rxpdu, &addrd, aux->targeta); + +done: + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + ble_ll_conn_send_connect_req_cancel(); + } + ble_ll_scan_aux_free(aux); +} +#endif + +void +ble_ll_scan_aux_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr) +{ + struct ble_ll_scan_addr_data addrd; + struct ble_mbuf_hdr_rxinfo *rxinfo; + struct ble_ll_scan_aux_data *aux; + bool scan_duplicate = false; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + bool sync_check = false; +#endif + int rc; + + rxinfo = &rxhdr->rxinfo; + aux = rxinfo->user_data; + + BLE_LL_ASSERT(aux); + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (aux->scan_type == BLE_SCAN_TYPE_INITIATE) { + ble_ll_scan_aux_rx_pkt_in_for_initiator(rxpdu, rxhdr); + return; + } +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + sync_check = ble_ll_sync_enabled() && + !(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN); + + /* PDU was not allowed due to scan filter policy, but we can still try to + * sync since separate filter policy is used for this purpose. + */ + if ((rxinfo->flags & BLE_MBUF_HDR_F_DEVMATCH) && sync_check) { + ble_ll_scan_aux_init_addrd_from_aux_data(aux, &addrd); + ble_ll_scan_aux_sync_check(rxpdu, &addrd); + } +#endif + + if (rxinfo->flags & BLE_MBUF_HDR_F_IGNORED) { + if (ble_ll_scan_aux_need_truncation(aux)) { + ble_ll_hci_ev_send_ext_adv_truncated_report(aux); + } else { + aux->hci_state |= BLE_LL_SCAN_AUX_H_DONE; + } + + ble_ll_scan_aux_update_scan_backoff(aux); + } + + if (aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) { + ble_ll_scan_aux_free(aux); + ble_ll_scan_chk_resume(); + return; + } + + /* Try to schedule scan for subsequent aux asap, if needed */ + if (rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT) { + rc = ble_ll_scan_aux_sched(aux, rxhdr->beg_cputime, rxhdr->rem_usecs, + aux->aux_ptr); + if (rc < 0) { + rxinfo->flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT; + } + } + + ble_ll_scan_aux_init_addrd_from_aux_data(aux, &addrd); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + if (sync_check) { + ble_ll_scan_aux_sync_check(rxpdu, &addrd); + } +#endif + + scan_duplicate = ble_ll_scan_get_filt_dups() && + ble_ll_scan_dup_check_ext(addrd.adv_addr_type, + addrd.adv_addr, true, aux->adi); + if (!scan_duplicate) { + rc = ble_ll_hci_ev_send_ext_adv_report_for_aux(rxpdu, rxhdr, aux, + &addrd); + + /* + * Update duplicates list if report was sent successfully and we are + * done with this chain. On error, status is already set to 'done' so + * we will cancel aux scan (if any) and stop further processing. + * However, if we send AUX_SCAN_REQ for this PDU then need to remove + * 'done' as we should continue with scanning after AUX_SCAN_RSP. + */ + + if (rc == 0) { + if (rxinfo->flags & BLE_MBUF_HDR_F_SCAN_REQ_TXD) { + aux->hci_state &= ~BLE_LL_SCAN_AUX_H_DONE; + } else if (aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) { + BLE_LL_ASSERT(!(rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT)); + if (ble_ll_scan_get_filt_dups()) { + ble_ll_scan_dup_update_ext(addrd.adv_addr_type, + addrd.adv_addr, true, aux->adi); + } + if (aux->flags & BLE_LL_SCAN_AUX_F_SCANNED) { + ble_ll_scan_add_scan_rsp_adv(addrd.adv_addr, + addrd.adv_addr_type, + 1, aux->adi); + } + } + } + } else { + /* This is a duplicate, we don't want to scan it anymore */ + aux->hci_state |= BLE_LL_SCAN_AUX_H_DONE; + } + + /* + * If we are done processing this chain and aux scan was not scheduled or + * we removed it from scheduler, we can remove aux_data now. Otherwise we + * will remove on next pkt_in. + */ + if ((aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) && + (!(rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT) || + (ble_ll_sched_rmv_elem(&aux->sch) == 0))) { + ble_ll_scan_aux_update_scan_backoff(aux); + ble_ll_scan_aux_free(aux); + } + + ble_ll_scan_chk_resume(); +} + +void +ble_ll_scan_aux_wfr_timer_exp(void) +{ + ble_phy_disable(); + ble_ll_scan_aux_halt(); +} + +void +ble_ll_scan_aux_halt(void) +{ + struct ble_ll_scan_aux_data *aux = aux_data_current; + + BLE_LL_ASSERT(aux); + + aux_data_current = NULL; + + ble_ll_state_set(BLE_LL_STATE_STANDBY); + + ble_ll_scan_aux_break(aux); +} + +void +ble_ll_scan_aux_sched_remove(struct ble_ll_sched_item *sch) +{ + ble_ll_scan_aux_break(sch->cb_arg); +} + +void +ble_ll_scan_aux_init(void) +{ + os_error_t err; + + err = os_mempool_init(&aux_data_pool, + MYNEWT_VAL(BLE_LL_SCAN_AUX_SEGMENT_CNT), + sizeof(struct ble_ll_scan_aux_data), + aux_data_mem, "ble_ll_scan_aux_data_pool"); + BLE_LL_ASSERT(err == 0); +} + +#endif /* BLE_LL_CFG_FEAT_LL_EXT_ADV */ diff --git a/nimble/controller/src/ble_ll_sched.c b/nimble/controller/src/ble_ll_sched.c index d01f10edab..cd60014d67 100644 --- a/nimble/controller/src/ble_ll_sched.c +++ b/nimble/controller/src/ble_ll_sched.c @@ -20,7 +20,6 @@ #include #include #include -#include "os/os.h" #include "os/os_cputime.h" #include "ble/xcvr.h" #include "controller/ble_phy.h" @@ -28,26 +27,27 @@ #include "controller/ble_ll_sched.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" +#include "controller/ble_ll_scan_aux.h" #include "controller/ble_ll_rfmgmt.h" #include "controller/ble_ll_trace.h" #include "controller/ble_ll_sync.h" #include "ble_ll_priv.h" #include "ble_ll_conn_priv.h" -/* XXX: this is temporary. Not sure what I want to do here */ -struct hal_timer g_ble_ll_sched_timer; +#define BLE_LL_SCHED_MAX_DELAY_ANY (0x7fffffff) -uint8_t g_ble_ll_sched_offset_ticks; +static struct hal_timer g_ble_ll_sched_timer; -#define BLE_LL_SCHED_ADV_WORST_CASE_USECS \ - (BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS + BLE_LL_SCHED_ADV_MAX_USECS \ - + XCVR_TX_SCHED_DELAY_USECS) +uint8_t g_ble_ll_sched_offset_ticks; #if (BLE_LL_SCHED_DEBUG == 1) int32_t g_ble_ll_sched_max_late; int32_t g_ble_ll_sched_max_early; #endif +typedef int (* ble_ll_sched_preempt_cb_t)(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item); + /* XXX: TODO: * 1) Add some accounting to the schedule code to see how late we are * (min/max?) @@ -61,12 +61,230 @@ int32_t g_ble_ll_sched_max_early; */ /* Queue for timers */ -TAILQ_HEAD(ll_sched_qhead, ble_ll_sched_item) g_ble_ll_sched_q; +static TAILQ_HEAD(ll_sched_qhead, ble_ll_sched_item) g_ble_ll_sched_q; +static uint8_t g_ble_ll_sched_q_head_changed; #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) struct ble_ll_sched_obj g_ble_ll_sched_data; #endif +static int +preempt_any(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item) +{ + return 1; +} + +static int +preempt_none(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item) +{ + return 0; +} + +static int +preempt_any_except_conn(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item) +{ + BLE_LL_ASSERT(sch->sched_type == BLE_LL_SCHED_TYPE_CONN); + + if (item->sched_type != BLE_LL_SCHED_TYPE_CONN) { + return 1; + } + + return ble_ll_conn_is_lru(sch->cb_arg, item->cb_arg); +} + +static inline int +ble_ll_sched_check_overlap(struct ble_ll_sched_item *sch1, + struct ble_ll_sched_item *sch2) +{ + /* Note: item ranges are defined as [start, end) so items do not overlap + * if one item starts at the same time as another ends. + */ + return CPUTIME_GT(sch1->end_time, sch2->start_time) && + CPUTIME_GT(sch2->end_time, sch1->start_time); +} + +static void +ble_ll_sched_preempt(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *first) +{ + struct ble_ll_sched_item *entry; + struct ble_ll_sched_item *next; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + struct ble_ll_conn_sm *connsm; +#endif + + entry = first; + + do { + next = TAILQ_NEXT(entry, link); + + TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); + entry->enqueued = 0; + + switch (entry->sched_type) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_SCHED_TYPE_CONN: + connsm = (struct ble_ll_conn_sm *)entry->cb_arg; + ble_ll_event_send(&connsm->conn_ev_end); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + case BLE_LL_SCHED_TYPE_ADV: + ble_ll_adv_event_rmvd_from_sched(entry->cb_arg); + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + case BLE_LL_SCHED_TYPE_SCAN_AUX: + ble_ll_scan_aux_break(entry->cb_arg); + break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + case BLE_LL_SCHED_TYPE_PERIODIC: + ble_ll_adv_periodic_rmvd_from_sched(entry->cb_arg); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + case BLE_LL_SCHED_TYPE_SYNC: + ble_ll_sync_rmvd_from_sched(entry->cb_arg); + break; +#endif +#endif +#endif + default: + BLE_LL_ASSERT(0); + break; + } + + entry = next; + } while (entry != sch); +} + +static inline void +ble_ll_sched_q_head_changed(void) +{ + if (g_ble_ll_sched_q_head_changed) { + return; + } + + g_ble_ll_sched_q_head_changed = 1; + + os_cputime_timer_stop(&g_ble_ll_sched_timer); +} + +static inline void +ble_ll_sched_restart(void) +{ + struct ble_ll_sched_item *first; + + if (!g_ble_ll_sched_q_head_changed) { + return; + } + + g_ble_ll_sched_q_head_changed = 0; + + first = TAILQ_FIRST(&g_ble_ll_sched_q); + + ble_ll_rfmgmt_sched_changed(first); + + if (first) { + os_cputime_timer_start(&g_ble_ll_sched_timer, first->start_time); + } +} + +static int +ble_ll_sched_insert(struct ble_ll_sched_item *sch, uint32_t max_delay, + ble_ll_sched_preempt_cb_t preempt_cb) +{ + struct ble_ll_sched_item *preempt_first; + struct ble_ll_sched_item *first; + struct ble_ll_sched_item *entry; + uint32_t max_start_time; + uint32_t duration; + + OS_ASSERT_CRITICAL(); + + preempt_first = NULL; + + max_start_time = sch->start_time + max_delay; + duration = sch->end_time - sch->start_time; + + first = TAILQ_FIRST(&g_ble_ll_sched_q); + if (!first) { + TAILQ_INSERT_HEAD(&g_ble_ll_sched_q, sch, link); + sch->enqueued = 1; + goto done; + } + + TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { + if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { + TAILQ_INSERT_BEFORE(entry, sch, link); + sch->enqueued = 1; + goto done; + } + + /* If current item overlaps our item check if we can preempt. If we + * cannot preempt, move our item past current item and see if it's + * still within allowed range. + */ + + if (ble_ll_sched_check_overlap(sch, entry)) { + if (preempt_cb(sch, entry)) { + if (!preempt_first) { + preempt_first = entry; + } + } else { + preempt_first = NULL; + /* + * For the 32768 Hz crystal in nrf chip, 1 tick is 30.517us. + * The connection state machine use anchor point to store the + * cpu ticks and anchor_point_usec to store the remainder. + * Therefore, to compensate the inaccuracy of the crystal, the + * ticks of anchor_point will be add with 1 once the value of + * anchor_point_usec exceed 31. If two connections have same + * connection interval, the time difference between the two + * start of schedule item will decreased 1, which lead to + * an overlap. To prevent this from happenning, we set the + * start_time of sch to 1 cpu tick after the end_time of entry. + */ + sch->start_time = entry->end_time + 1; + + if ((max_delay == 0) || CPUTIME_GEQ(sch->start_time, + max_start_time)) { + sch->enqueued = 0; + goto done; + } + + sch->end_time = sch->start_time + duration; + } + } + } + + if (!entry) { + TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); + sch->enqueued = 1; + } + +done: + if (preempt_first) { + BLE_LL_ASSERT(sch->enqueued); + ble_ll_sched_preempt(sch, preempt_first); + } + + /* Pause scheduler if inserted as 1st item, we do not want to miss this + * one. Caller should restart outside critical section. + */ + if (TAILQ_FIRST(&g_ble_ll_sched_q) == sch) { + BLE_LL_ASSERT(sch->enqueued); + ble_ll_sched_q_head_changed(); + } + + return sch->enqueued ? 0 : -1; +} + +#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) /** * Checks if two events in the schedule will overlap in time. NOTE: consecutive * schedule items can end and start at the same time. @@ -97,6 +315,7 @@ ble_ll_sched_is_overlap(struct ble_ll_sched_item *s1, return rc; } +#endif /* * Determines if the schedule item overlaps the currently running schedule @@ -105,39 +324,21 @@ ble_ll_sched_is_overlap(struct ble_ll_sched_item *s1, static int ble_ll_sched_overlaps_current(struct ble_ll_sched_item *sch) { - int rc; + int rc = 0; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) uint32_t ce_end_time; - rc = 0; if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) { ce_end_time = ble_ll_conn_get_ce_end_time(); if (CPUTIME_GT(ce_end_time, sch->start_time)) { rc = 1; } } +#endif return rc; } -static int -ble_ll_sched_conn_overlap(struct ble_ll_sched_item *entry) -{ - int rc; - struct ble_ll_conn_sm *connsm; - - /* Should only be advertising or a connection here */ - if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN) { - connsm = (struct ble_ll_conn_sm *)entry->cb_arg; - entry->enqueued = 0; - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - ble_ll_event_send(&connsm->conn_ev_end); - rc = 0; - } else { - rc = -1; - } - - return rc; -} - +#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) static struct ble_ll_sched_item * ble_ll_sched_insert_if_empty(struct ble_ll_sched_item *sch) { @@ -150,31 +351,41 @@ ble_ll_sched_insert_if_empty(struct ble_ll_sched_item *sch) } return entry; } +#endif int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm) { - int rc; - os_sr_t sr; - uint32_t usecs; struct ble_ll_sched_item *sch; - struct ble_ll_sched_item *start_overlap; - struct ble_ll_sched_item *end_overlap; - struct ble_ll_sched_item *entry; - struct ble_ll_conn_sm *tmp; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + uint32_t usecs; +#endif + os_sr_t sr; + int rc; /* Get schedule element from connection */ sch = &connsm->conn_sch; /* Set schedule start and end times */ sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks; - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_MASTER: + sch->remainder = connsm->anchor_point_usecs; + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_SLAVE: usecs = connsm->slave_cur_window_widening; sch->start_time -= (os_cputime_usecs_to_ticks(usecs) + 1); sch->remainder = 0; - } else { - sch->remainder = connsm->anchor_point_usecs; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } + sch->end_time = connsm->ce_end_time; /* Better be past current time or we just leave */ @@ -182,7 +393,6 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm) return -1; } - /* We have to find a place for this schedule */ OS_ENTER_CRITICAL(sr); if (ble_ll_sched_overlaps_current(sch)) { @@ -190,98 +400,11 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm) return -1; } - /* Stop timer since we will add an element */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - - start_overlap = NULL; - end_overlap = NULL; - rc = 0; - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - if (ble_ll_sched_is_overlap(sch, entry)) { - if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN && - !ble_ll_conn_is_lru((struct ble_ll_conn_sm *)sch->cb_arg, - (struct ble_ll_conn_sm *)entry->cb_arg)) { - /* Only insert if this element is older than all that we - * overlap - */ - start_overlap = NULL; - rc = -1; - break; - } - - if (start_overlap == NULL) { - start_overlap = entry; - end_overlap = entry; - } else { - end_overlap = entry; - } - } else { - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - } - } - - if (!rc) { - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - sch->enqueued = 1; - } - - /* Remove first to last scheduled elements */ - entry = start_overlap; - while (entry) { - start_overlap = TAILQ_NEXT(entry,link); - switch (entry->sched_type) { - case BLE_LL_SCHED_TYPE_CONN: - tmp = (struct ble_ll_conn_sm *)entry->cb_arg; - ble_ll_event_send(&tmp->conn_ev_end); - break; - case BLE_LL_SCHED_TYPE_ADV: - ble_ll_adv_event_rmvd_from_sched((struct ble_ll_adv_sm *)entry->cb_arg); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_LL_SCHED_TYPE_AUX_SCAN: - ble_ll_scan_end_adv_evt((struct ble_ll_aux_data *)entry->cb_arg); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_SCHED_TYPE_PERIODIC: - ble_ll_adv_periodic_rmvd_from_sched((struct ble_ll_adv_sm *)entry->cb_arg); - break; - case BLE_LL_SCHED_TYPE_SYNC: - ble_ll_sync_rmvd_from_sched((struct ble_ll_sync_sm *)entry->cb_arg); - break; -#endif -#endif - default: - BLE_LL_ASSERT(0); - break; - } - - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - entry->enqueued = 0; - - if (entry == end_overlap) { - break; - } - entry = start_overlap; - } - - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } + rc = ble_ll_sched_insert(sch, 0, preempt_any_except_conn); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } @@ -401,7 +524,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, } } earliest_start += MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * - BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; + BLE_LL_SCHED_TICKS_PER_SLOT; itvl_t = connsm->conn_itvl_ticks; /* We have to find a place for this schedule */ @@ -536,27 +659,17 @@ int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len) { - int rc; - os_sr_t sr; - uint8_t req_slots; - uint32_t initial_start; + struct ble_ll_sched_item *sch; + uint32_t orig_start_time; uint32_t earliest_start; - uint32_t earliest_end; - uint32_t dur; - uint32_t itvl_t; + uint32_t min_win_offset; + uint32_t max_delay; uint32_t adv_rxend; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *sch; - - /* - * XXX: TODO this code assumes the advertisement and connect request were - * sent at 1Mbps. - */ + os_sr_t sr; + int rc; /* Get schedule element from connection */ - rc = -1; sch = &connsm->conn_sch; - req_slots = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS); /* XXX: * The calculations for the 32kHz crystal bear alot of explanation. The @@ -599,7 +712,6 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, * wont be listening. We could do better calculation if we wanted to use * a transmit window of 1 as opposed to 2, but for now we dont care. */ - dur = req_slots * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; adv_rxend = os_cputime_get32(); if (ble_hdr->rxinfo.channel >= BLE_PHY_NUM_DATA_CHANS) { /* @@ -631,86 +743,38 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, BLE_LL_ASSERT(0); } } - earliest_start += MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * - BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; - earliest_end = earliest_start + dur; - itvl_t = connsm->conn_itvl_ticks; - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); + sch->start_time = earliest_start - g_ble_ll_sched_offset_ticks; + sch->end_time = earliest_start + MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * + BLE_LL_SCHED_TICKS_PER_SLOT; - /* The schedule item must occur after current running item (if any) */ - sch->start_time = earliest_start; - initial_start = earliest_start; + orig_start_time = sch->start_time; - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible */ - rc = 0; - connsm->tx_win_off = MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET); - } else { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* Set these because overlap function needs them to be set */ - sch->start_time = earliest_start; - sch->end_time = earliest_end; + min_win_offset = MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * + BLE_LL_SCHED_TICKS_PER_SLOT; + sch->start_time += min_win_offset; + sch->end_time += min_win_offset; - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - } - break; - } + max_delay = connsm->conn_itvl_ticks - min_win_offset; - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - /* Earliest start is end of this event since we overlap */ - earliest_start = entry->end_time; - earliest_end = earliest_start + dur; - } - } + OS_ENTER_CRITICAL(sr); - /* Must be able to schedule within one connection interval */ - if (!entry) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - } + rc = ble_ll_sched_insert(sch, max_delay, preempt_none); - if (!rc) { - /* calculate number of window offsets. Each offset is 1.25 ms */ - sch->enqueued = 1; - /* - * NOTE: we dont add sched offset ticks as we want to under-estimate - * the transmit window slightly since the window size is currently - * 2 when using a 32768 crystal. - */ - dur = os_cputime_ticks_to_usecs(earliest_start - initial_start); - connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS; - } - } + if (rc == 0) { + connsm->tx_win_off = os_cputime_ticks_to_usecs(sch->start_time - + orig_start_time) / + BLE_LL_CONN_TX_OFF_USECS; - if (!rc) { - sch->start_time = earliest_start; - sch->end_time = earliest_end; - /* - * Since we have the transmit window to transmit in, we dont need - * to set the anchor point usecs; just transmit to the nearest tick. - */ - connsm->anchor_point = earliest_start + g_ble_ll_sched_offset_ticks; + connsm->anchor_point = sch->start_time + g_ble_ll_sched_offset_ticks; connsm->anchor_point_usecs = 0; - connsm->ce_end_time = earliest_end; - } + connsm->ce_end_time = sch->end_time; - /* Get head of list to restart timer */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - ble_ll_rfmgmt_sched_changed(sch); + } OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } @@ -728,15 +792,11 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) { - int rc; - os_sr_t sr; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *next_sch; struct ble_ll_sched_item *sch; - int first = 0; + os_sr_t sr; + int rc; /* Get schedule element from connection */ - rc = -1; sch = &connsm->conn_sch; /* Set schedule start and end times */ @@ -751,73 +811,34 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) sch->end_time = connsm->ce_end_time; sch->remainder = 0; - /* We have to find a place for this schedule */ OS_ENTER_CRITICAL(sr); - /* The schedule item must occur after current running item (if any) */ - if (ble_ll_sched_overlaps_current(sch)) { - OS_EXIT_CRITICAL(sr); - return rc; - } - - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - /* Nothing in schedule. Schedule as soon as possible */ - rc = 0; - first = 1; - } else { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - while (1) { - next_sch = entry->link.tqe_next; - /* Insert if event ends before next starts */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - if (ble_ll_sched_is_overlap(sch, entry)) { - /* If we overlap with a connection, we re-schedule */ - if (ble_ll_sched_conn_overlap(entry)) { - break; - } - } + rc = ble_ll_sched_insert(sch, 0, preempt_any); - /* Move to next entry */ - entry = next_sch; + OS_EXIT_CRITICAL(sr); - /* Insert at tail if none left to check */ - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - break; - } - } + ble_ll_sched_restart(); - if (!rc) { - sch->enqueued = 1; - } + return rc; +} - next_sch = TAILQ_FIRST(&g_ble_ll_sched_q); - if (next_sch == sch) { - first = 1; - } else { - sch = next_sch; - } - } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +static inline uint32_t +usecs_to_ticks_fast(uint32_t usecs) +{ + uint32_t ticks; - if (first) { - ble_ll_rfmgmt_sched_changed(sch); + if (usecs <= 31249) { + ticks = (usecs * 137439) / 4194304; + } else { + ticks = os_cputime_usecs_to_ticks(usecs); } - OS_EXIT_CRITICAL(sr); - - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - - return rc; + return ticks; } +#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) /* * Determines if the schedule item overlaps the currently running schedule * item. This function cares about connection and sync. @@ -830,9 +851,11 @@ ble_ll_sched_sync_overlaps_current(struct ble_ll_sched_item *sch) state = ble_ll_state_get(); switch (state) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_STATE_CONNECTION: end_time = ble_ll_conn_get_ce_end_time(); break; +#endif case BLE_LL_STATE_SYNC: end_time = ble_ll_sync_get_event_end_time(); break; @@ -849,7 +872,6 @@ ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, uint32_t window_widening, int8_t phy_mode) { - struct ble_ll_sched_item *entry; uint8_t start_time_rem_usecs; uint8_t window_rem_usecs; uint32_t window_ticks; @@ -889,7 +911,6 @@ ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, return -1; } - /* We have to find a place for this schedule */ OS_ENTER_CRITICAL(sr); if (ble_ll_sched_sync_overlaps_current(sch)) { @@ -897,43 +918,11 @@ ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, return -1; } - /* Try to find slot for sync scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - rc = -1; - break; - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } + rc = ble_ll_sched_insert(sch, 0, preempt_none); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } @@ -943,7 +932,6 @@ ble_ll_sched_sync(struct ble_ll_sched_item *sch, uint32_t beg_cputime, uint32_t rem_usecs, uint32_t offset, int8_t phy_mode) { - struct ble_ll_sched_item *entry; uint32_t start_time_rem_usecs; uint32_t off_rem_usecs; uint32_t start_time; @@ -953,7 +941,7 @@ ble_ll_sched_sync(struct ble_ll_sched_item *sch, os_sr_t sr; int rc = 0; - off_ticks = os_cputime_usecs_to_ticks(offset); + off_ticks = usecs_to_ticks_fast(offset); off_rem_usecs = offset - os_cputime_ticks_to_usecs(off_ticks); start_time = beg_cputime + off_ticks; @@ -965,7 +953,7 @@ ble_ll_sched_sync(struct ble_ll_sched_item *sch, dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), phy_mode); - end_time = start_time + os_cputime_usecs_to_ticks(dur); + end_time = start_time + usecs_to_ticks_fast(dur); start_time -= g_ble_ll_sched_offset_ticks; @@ -975,51 +963,14 @@ ble_ll_sched_sync(struct ble_ll_sched_item *sch, OS_ENTER_CRITICAL(sr); - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - goto done; - } - - /* Try to find slot for scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - rc = -1; - break; - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } + rc = ble_ll_sched_insert(sch, 0, preempt_none); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); STATS_INC(ble_ll_stats, sync_scheduled); + return rc; } #endif @@ -1029,257 +980,87 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, ble_ll_sched_adv_new_cb cb, void *arg) { os_sr_t sr; - uint32_t adv_start; - uint32_t duration; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *orig; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; - orig = sch; + int rc; OS_ENTER_CRITICAL(sr); - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - adv_start = sch->start_time; - } else { - /* XXX: no need to stop timer if not first on list. Modify code? */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - /* Earliest start is end of this event since we overlap */ - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } - } - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - adv_start = sch->start_time; - - sch->enqueued = 1; - - /* Restart with head of list */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - - if (cb) { - cb((struct ble_ll_adv_sm *)orig->cb_arg, adv_start, arg); - } + rc = ble_ll_sched_insert(sch, BLE_LL_SCHED_MAX_DELAY_ANY, + preempt_none); + BLE_LL_ASSERT(rc == 0); - if (orig == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } + cb(sch->cb_arg, sch->start_time, arg); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); - return 0; + return rc; } int -ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start, - bool after_overlap) +ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, bool first_event) { - int rc = 0; os_sr_t sr; - uint32_t adv_start; - uint32_t duration; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *orig = sch; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; + int rc; OS_ENTER_CRITICAL(sr); - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - adv_start = sch->start_time; - } else { - /* XXX: no need to stop timer if not first on list. Modify code? */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - if (after_overlap) { - /* Earliest start is end of this event since we overlap */ - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } else { - rc = -1; - break; - } - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - adv_start = sch->start_time; - - if (!rc) { - sch->enqueued = 1; - } - - /* Restart with head of list */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - - if (!rc) { - *start = adv_start; - } - if (orig == sch) { - ble_ll_rfmgmt_sched_changed(sch); + if (first_event) { + rc = ble_ll_sched_insert(sch, BLE_LL_SCHED_MAX_DELAY_ANY, + preempt_none); + } else { + rc = ble_ll_sched_insert(sch, 0, preempt_any); } OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } int -ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start, +ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t max_delay_ticks) { - int rc; - os_sr_t sr; - uint32_t orig_start; - uint32_t duration; + struct ble_ll_sched_item *next; + uint32_t max_end_time; uint32_t rand_ticks; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *next_sch; - struct ble_ll_sched_item *before; - struct ble_ll_sched_item *start_overlap; - struct ble_ll_sched_item *end_overlap; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; + os_sr_t sr; + int rc; - /* Add maximum randomization delay to end */ - rand_ticks = max_delay_ticks; - sch->end_time += max_delay_ticks; + max_end_time = sch->end_time + max_delay_ticks; - start_overlap = NULL; - end_overlap = NULL; - before = NULL; - rc = 0; OS_ENTER_CRITICAL(sr); - entry = ble_ll_sched_insert_if_empty(sch); - if (entry) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - while (1) { - next_sch = entry->link.tqe_next; - if (ble_ll_sched_is_overlap(sch, entry)) { - if (start_overlap == NULL) { - start_overlap = entry; - end_overlap = entry; - } else { - end_overlap = entry; - } - } else { - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - before = entry; - break; - } - } - - entry = next_sch; - if (entry == NULL) { - break; - } - } + /* Try to schedule as early as possible but no later than max allowed delay. + * If succeeded, randomize start time to be within max allowed delay from + * the original start time but make sure it ends before next scheduled item. + */ - /* - * If there is no overlap, we either insert before the 'before' entry - * or we insert at the end if there is no before entry. - */ - if (start_overlap == NULL) { - if (before) { - TAILQ_INSERT_BEFORE(before, sch, link); - } else { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); + rc = ble_ll_sched_insert(sch, max_delay_ticks, preempt_none); + if (rc == 0) { + next = TAILQ_NEXT(sch, link); + if (next) { + if (CPUTIME_LT(next->start_time, max_end_time)) { + max_end_time = next->start_time; } + rand_ticks = max_end_time - sch->end_time; } else { - /* - * This item will overlap with others. See if we can fit it in - * with original duration. - */ - before = NULL; - orig_start = sch->start_time; - entry = start_overlap; - sch->end_time = sch->start_time + duration; - while (1) { - next_sch = entry->link.tqe_next; - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rand_ticks = entry->start_time - sch->end_time; - before = entry; - TAILQ_INSERT_BEFORE(before, sch, link); - break; - } else { - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } - - if (entry == end_overlap) { - rand_ticks = (orig_start + max_delay_ticks) - sch->start_time; - if (rand_ticks > max_delay_ticks) { - /* No place for advertisement. */ - rc = -1; - } else { - if (next_sch == NULL) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } else { - TAILQ_INSERT_BEFORE(next_sch, sch, link); - } - } - break; - } - entry = next_sch; - BLE_LL_ASSERT(entry != NULL); - } + rand_ticks = max_delay_ticks; } - } - if (!rc) { - sch->enqueued = 1; if (rand_ticks) { - sch->start_time += ble_ll_rand() % rand_ticks; + rand_ticks = ble_ll_rand() % rand_ticks; } - sch->end_time = sch->start_time + duration; - *start = sch->start_time; - if (sch == TAILQ_FIRST(&g_ble_ll_sched_q)) { - ble_ll_rfmgmt_sched_changed(sch); - } + sch->start_time += rand_ticks; + sch->end_time += rand_ticks; } OS_EXIT_CRITICAL(sr); - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } @@ -1289,36 +1070,38 @@ ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch) { uint8_t lls; os_sr_t sr; - struct ble_ll_sched_item *entry; + int rc; OS_ENTER_CRITICAL(sr); lls = ble_ll_state_get(); - if ((lls == BLE_LL_STATE_ADV) || (lls == BLE_LL_STATE_CONNECTION) || - (lls == BLE_LL_STATE_SYNC)) { - goto adv_resched_pdu_fail; - } - - entry = ble_ll_sched_insert_if_empty(sch); - if (entry) { - /* If we overlap with the first item, simply re-schedule */ - if (ble_ll_sched_is_overlap(sch, entry)) { - goto adv_resched_pdu_fail; - } - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; + switch(lls) { +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + case BLE_LL_STATE_ADV: + OS_EXIT_CRITICAL(sr); + return -1; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_STATE_CONNECTION: + OS_EXIT_CRITICAL(sr); + return -1; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + case BLE_LL_STATE_SYNC: + OS_EXIT_CRITICAL(sr); + return -1; +#endif + default: + break; } - ble_ll_rfmgmt_sched_changed(TAILQ_FIRST(&g_ble_ll_sched_q)); + rc = ble_ll_sched_insert(sch, 0, preempt_none); OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - return 0; -adv_resched_pdu_fail: - OS_EXIT_CRITICAL(sr); - return -1; + ble_ll_sched_restart(); + + return rc; } /** @@ -1331,75 +1114,71 @@ ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch) int ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch) { + uint8_t first_removed; os_sr_t sr; - struct ble_ll_sched_item *first; - int rc = 1; + int rc; - if (!sch) { - return rc; - } + BLE_LL_ASSERT(sch); OS_ENTER_CRITICAL(sr); + + first_removed = 0; + if (sch->enqueued) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first == sch) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); + if (sch == TAILQ_FIRST(&g_ble_ll_sched_q)) { + first_removed = 1; } TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); sch->enqueued = 0; + rc = 0; + } else { + rc = 1; + } - if (first == sch) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first) { - os_cputime_timer_start(&g_ble_ll_sched_timer, first->start_time); - } - ble_ll_rfmgmt_sched_changed(first); - } + if (first_removed) { + ble_ll_sched_q_head_changed(); } + OS_EXIT_CRITICAL(sr); + ble_ll_sched_restart(); + return rc; } void ble_ll_sched_rmv_elem_type(uint8_t type, sched_remove_cb_func remove_cb) { - os_sr_t sr; - struct ble_ll_sched_item *entry; struct ble_ll_sched_item *first; + struct ble_ll_sched_item *entry; + uint8_t first_removed; + os_sr_t sr; OS_ENTER_CRITICAL(sr); - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (!first) { - OS_EXIT_CRITICAL(sr); - return; + first = TAILQ_FIRST(&g_ble_ll_sched_q); + if (first->sched_type == type) { + first_removed = 1; } TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - if (entry->sched_type == type) { - if (first == entry) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - first = NULL; - } - - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - remove_cb(entry); - entry->enqueued = 0; + if (entry->sched_type != type) { + continue; } + TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); + remove_cb(entry); + entry->enqueued = 0; } - if (!first) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first) { - os_cputime_timer_start(&g_ble_ll_sched_timer, first->start_time); - } - ble_ll_rfmgmt_sched_changed(first); + if (first_removed) { + ble_ll_sched_q_head_changed(); } OS_EXIT_CRITICAL(sr); + + ble_ll_sched_restart(); } /** @@ -1426,20 +1205,6 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch) goto sched; } - /* If aux scan scheduled and LL is in state when scanner is running - * in 3 states: - * BLE_LL_STATE_SCANNING - * BLE_LL_STATE_INITIATING - * BLE_LL_STATE_STANDBY - * - * Let scanner to decide to disable phy or not. - */ - if (sch->sched_type == BLE_LL_SCHED_TYPE_AUX_SCAN) { - if (lls == BLE_LL_STATE_INITIATING || lls == BLE_LL_STATE_SCANNING) { - goto sched; - } - } - /* * This is either an advertising event or connection event start. If * we are scanning or initiating just stop it. @@ -1448,32 +1213,51 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch) /* We have to disable the PHY no matter what */ ble_phy_disable(); - if (lls == BLE_LL_STATE_SCANNING) { + switch (lls) { +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + case BLE_LL_STATE_SCANNING: ble_ll_state_set(BLE_LL_STATE_STANDBY); ble_ll_scan_halt(); - } else if (lls == BLE_LL_STATE_INITIATING) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_scan_halt(); - /* PHY is disabled - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); - } else if (lls == BLE_LL_STATE_ADV) { - STATS_INC(ble_ll_stats, sched_state_adv_errs); - ble_ll_adv_halt(); + break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - } else if (lls == BLE_LL_STATE_SYNC) { + case BLE_LL_STATE_SYNC: STATS_INC(ble_ll_stats, sched_state_sync_errs); ble_ll_sync_halt(); + break; #endif - } else { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + ble_ll_state_set(BLE_LL_STATE_STANDBY); + ble_ll_scan_aux_halt(); + break; +#endif +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + case BLE_LL_STATE_ADV: + STATS_INC(ble_ll_stats, sched_state_adv_errs); + ble_ll_adv_halt(); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_STATE_CONNECTION: STATS_INC(ble_ll_stats, sched_state_conn_errs); ble_ll_conn_event_halt(); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } sched: - BLE_LL_DEBUG_GPIO(SCHED_ITEM_CB, 1); BLE_LL_ASSERT(sch->sched_cb); + + BLE_LL_DEBUG_GPIO(SCHED_ITEM, 1); rc = sch->sched_cb(sch); - BLE_LL_DEBUG_GPIO(SCHED_ITEM_CB, 0); + if (rc != BLE_LL_SCHED_STATE_RUNNING) { + BLE_LL_DEBUG_GPIO(SCHED_ITEM, 0); + } + return rc; } @@ -1510,14 +1294,11 @@ ble_ll_sched_run(void *arg) /* Remove schedule item and execute the callback */ TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); sch->enqueued = 0; + g_ble_ll_sched_q_head_changed = 1; + ble_ll_sched_execute_item(sch); - /* Restart if there is an item on the schedule */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - if (sch) { - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - } - ble_ll_rfmgmt_sched_changed(sch); + ble_ll_sched_restart(); } BLE_LL_DEBUG_GPIO(SCHED_RUN, 0); @@ -1553,164 +1334,29 @@ ble_ll_sched_next_time(uint32_t *next_event_time) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/** - * Called to check if there is place for a planned scan req. - * - * @param chan - * @param phy_mode - * - * @return int 0: Clear for scan req 1: there is an upcoming event - */ int -ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode) +ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch, uint32_t pdu_time, + uint8_t pdu_time_rem, uint32_t offset_us) { - struct ble_ll_sched_item *sch; - uint32_t usec_dur; - uint32_t now = os_cputime_get32(); - - /* Lets calculate roughly how much time we need for scan req and scan rsp */ - usec_dur = ble_ll_pdu_tx_time_get(BLE_SCAN_REQ_LEN, phy_mode); - if (chan >= BLE_PHY_NUM_DATA_CHANS) { - usec_dur += ble_ll_pdu_tx_time_get(BLE_SCAN_RSP_MAX_LEN, phy_mode); - } else { - usec_dur += ble_ll_pdu_tx_time_get(BLE_SCAN_RSP_MAX_EXT_LEN, phy_mode); - } - - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - while (sch) { - /* Let's check if there is no scheduled item which want to start within - * given usecs.*/ - if (CPUTIME_GT(sch->start_time, now + os_cputime_usecs_to_ticks(usec_dur))) { - /* We are fine. Have time for scan req */ - return 0; - } - - /* There is something in the scheduler. If it is not aux ptr we assume - * it is more important that scan req - */ - if (sch->sched_type != BLE_LL_SCHED_TYPE_AUX_SCAN) { - return 1; - } - - ble_ll_scan_end_adv_evt((struct ble_ll_aux_data *)sch->cb_arg); - TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 0; - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - return 0; -} - -/** - * Called to schedule a aux scan. - * - * Context: Interrupt - * - * @param ble_hdr - * @param scansm - * @param aux_scan - * - * @return 0 on success, 1 otherwise - */ -int -ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, - struct ble_ll_scan_sm *scansm, - struct ble_ll_aux_data *aux_scan) -{ - int rc = 1; + uint32_t offset_ticks; os_sr_t sr; - uint32_t off_ticks; - uint32_t off_rem_usecs; - uint32_t start_time; - uint32_t start_time_rem_usecs; - uint32_t end_time; - uint32_t dur; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *sch; - int phy_mode; - - sch = &aux_scan->sch; - BLE_LL_ASSERT(sch->cb_arg == NULL); - - off_ticks = os_cputime_usecs_to_ticks(aux_scan->offset); - off_rem_usecs = aux_scan->offset - os_cputime_ticks_to_usecs(off_ticks); - - start_time = ble_hdr->beg_cputime + off_ticks; - start_time_rem_usecs = ble_hdr->rem_usecs + off_rem_usecs; - if (start_time_rem_usecs >= 31) { - start_time++; - start_time_rem_usecs -= 31; - } - start_time -= g_ble_ll_sched_offset_ticks; + int rc; - /* Let's calculate time we reserve for aux packet. For now we assume to wait - * for fixed number of bytes and handle possible interrupting it in - * ble_ll_sched_execute_item(). This is because aux packet can be up to - * 256bytes and we don't want to block sched that long - */ - phy_mode = ble_ll_phy_to_phy_mode(aux_scan->aux_phy, - BLE_HCI_LE_PHY_CODED_ANY); - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_AUX_PDU_LEN), - phy_mode); - end_time = start_time + os_cputime_usecs_to_ticks(dur); + offset_us += pdu_time_rem; + offset_ticks = usecs_to_ticks_fast(offset_us); - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; + sch->start_time = pdu_time + offset_ticks - g_ble_ll_sched_offset_ticks; + sch->remainder = offset_us - os_cputime_ticks_to_usecs(offset_ticks); + /* TODO: make some sane slot reservation */ + sch->end_time = sch->start_time + usecs_to_ticks_fast(5000); OS_ENTER_CRITICAL(sr); - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - rc = 0; - goto done; - } - - /* Try to find slot for aux scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - break; - } - } - - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - - if (rc == 0) { - sch->cb_arg = ble_ll_scan_aux_data_ref(aux_scan); - STATS_INC(ble_ll_stats, aux_scheduled); - } - - /* Get head of list to restart timer */ - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } + rc = ble_ll_sched_insert(sch, 0, preempt_none); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } @@ -1719,57 +1365,18 @@ ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, #if MYNEWT_VAL(BLE_LL_DTM) int ble_ll_sched_dtm(struct ble_ll_sched_item *sch) { - int rc; os_sr_t sr; - struct ble_ll_sched_item *entry; + int rc; OS_ENTER_CRITICAL(sr); - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - rc = 0; - goto done; - } - - /* Try to find slot for test. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (sch->end_time <= entry->start_time) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - OS_EXIT_CRITICAL(sr); - return -1; - } - } - - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - - /* Get head of list to restart timer */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - - ble_ll_rfmgmt_sched_changed(sch); + rc = ble_ll_sched_insert(sch, 0, preempt_any); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + if (rc == 0) { + ble_ll_sched_restart(); + } return rc; } @@ -1794,7 +1401,7 @@ ble_ll_sched_stop(void) int ble_ll_sched_init(void) { - BLE_LL_DEBUG_GPIO_INIT(SCHED_ITEM_CB); + BLE_LL_DEBUG_GPIO_INIT(SCHED_ITEM); BLE_LL_DEBUG_GPIO_INIT(SCHED_RUN); /* @@ -1824,5 +1431,7 @@ ble_ll_sched_init(void) g_ble_ll_sched_data.sch_ticks_per_period; #endif + g_ble_ll_sched_q_head_changed = 0; + return 0; } diff --git a/nimble/controller/src/ble_ll_supp_cmd.c b/nimble/controller/src/ble_ll_supp_cmd.c index cae9eb7dd1..2fc0d7d3af 100644 --- a/nimble/controller/src/ble_ll_supp_cmd.c +++ b/nimble/controller/src/ble_ll_supp_cmd.c @@ -27,7 +27,11 @@ #include "controller/ble_ll_hci.h" /* Octet 0 */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_DISCONNECT (1 << 5) +#else +#define BLE_SUPP_CMD_DISCONNECT (0 << 5) +#endif #define BLE_LL_SUPP_CMD_OCTET_0 (BLE_SUPP_CMD_DISCONNECT) /* Octet 5 */ @@ -64,7 +68,12 @@ /* Octet 15 */ #define BLE_SUPP_CMD_RD_BD_ADDR (1 << 1) + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_RD_RSSI (1 << 5) +#else +#define BLE_SUPP_CMD_RD_RSSI (0 << 5) +#endif #define BLE_LL_SUPP_CMD_OCTET_15 \ ( \ @@ -77,9 +86,15 @@ #define BLE_SUPP_CMD_LE_RD_BUF_SIZE (1 << 1) #define BLE_SUPP_CMD_LE_RD_LOC_FEAT (1 << 2) #define BLE_SUPP_CMD_LE_SET_RAND_ADDR (1 << 4) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #define BLE_SUPP_CMD_LE_SET_ADV_PARAMS (1 << 5) #define BLE_SUPP_CMD_LE_SET_ADV_TX_PWR (1 << 6) #define BLE_SUPP_CMD_LE_SET_ADV_DATA (1 << 7) +#else +#define BLE_SUPP_CMD_LE_SET_ADV_PARAMS (0 << 5) +#define BLE_SUPP_CMD_LE_SET_ADV_TX_PWR (0 << 6) +#define BLE_SUPP_CMD_LE_SET_ADV_DATA (0 << 7) +#endif #define BLE_LL_SUPP_CMD_OCTET_25 \ ( \ @@ -93,12 +108,28 @@ ) /* Octet 26 */ +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #define BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA (1 << 0) #define BLE_SUPP_CMD_LE_SET_ADV_ENABLE (1 << 1) +#else +#define BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA (0 << 0) +#define BLE_SUPP_CMD_LE_SET_ADV_ENABLE (0 << 1) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) #define BLE_SUPP_CMD_LE_SET_SCAN_PARAMS (1 << 2) #define BLE_SUPP_CMD_LE_SET_SCAN_ENABLE (1 << 3) +#else +#define BLE_SUPP_CMD_LE_SET_SCAN_PARAMS (0 << 2) +#define BLE_SUPP_CMD_LE_SET_SCAN_ENABLE (0 << 3) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_LE_CREATE_CONN (1 << 4) #define BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL (1 << 5) +#else +#define BLE_SUPP_CMD_LE_CREATE_CONN (0 << 4) +#define BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL (0 << 5) + +#endif #define BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE (1 << 6) #define BLE_SUPP_CMD_LE_CLR_WHITELIST (1 << 7) @@ -117,10 +148,19 @@ /* Octet 27 */ #define BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST (1 << 0) #define BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST (1 << 1) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_LE_CONN_UPDATE (1 << 2) +#else +#define BLE_SUPP_CMD_LE_CONN_UPDATE (0 << 2) +#endif #define BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS (1 << 3) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_LE_RD_CHAN_MAP (1 << 4) #define BLE_SUPP_CMD_LE_RD_REM_USED_FEAT (1 << 5) +#else +#define BLE_SUPP_CMD_LE_RD_CHAN_MAP (0 << 4) +#define BLE_SUPP_CMD_LE_RD_REM_USED_FEAT (0 << 5) +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) #define BLE_SUPP_CMD_LE_ENCRYPT (1 << 6) #else @@ -142,10 +182,19 @@ /* Octet 28 */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_LE_START_ENCRYPT (1 << 0) +#else +#define BLE_SUPP_CMD_LE_START_ENCRYPT (0 << 0) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) #define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (1 << 1) #define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (1 << 2) #else +#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (0 << 1) +#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (0 << 2) +#endif +#else #define BLE_SUPP_CMD_LE_START_ENCRYPT (0 << 0) #define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (0 << 1) #define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (0 << 2) @@ -175,6 +224,7 @@ ) /* Octet 33 */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_LE_REM_CONN_PRR (1 << 4) #define BLE_SUPP_CMD_LE_REM_CONN_PRNR (1 << 5) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) @@ -184,6 +234,13 @@ #define BLE_SUPP_CMD_LE_SET_DATALEN (0 << 6) #define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (0 << 7) #endif +#else +#define BLE_SUPP_CMD_LE_REM_CONN_PRR (0 << 4) +#define BLE_SUPP_CMD_LE_REM_CONN_PRNR (0 << 5) +#define BLE_SUPP_CMD_LE_SET_DATALEN (0 << 6) +#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (0 << 7) +#endif + #define BLE_LL_SUPP_CMD_OCTET_33 \ ( \ @@ -194,11 +251,15 @@ ) /* Octet 34 */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) #define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (1 << 0) #else #define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (0 << 0) #endif +#else +#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (0 << 0) +#endif #define BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK (0 << 1) #define BLE_SUPP_CMD_LE_GENERATE_DH_KEY (0 << 2) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) @@ -239,6 +300,7 @@ #endif #define BLE_SUPP_CMD_LE_RD_MAX_DATALEN (1 << 3) #if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_LE_READ_PHY (1 << 4) #define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (1 << 5) #define BLE_SUPP_CMD_LE_SET_PHY (1 << 6) @@ -247,6 +309,11 @@ #define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (0 << 5) #define BLE_SUPP_CMD_LE_SET_PHY (0 << 6) #endif +#else +#define BLE_SUPP_CMD_LE_READ_PHY (0 << 4) +#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (0 << 5) +#define BLE_SUPP_CMD_LE_SET_PHY (0 << 6) +#endif #if MYNEWT_VAL(BLE_LL_DTM) #define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (1 << 7) @@ -273,7 +340,7 @@ #define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (0 << 0) #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (1 << 1) #define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (1 << 2) #define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (1 << 3) @@ -304,14 +371,14 @@ ) /* Octet 37 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #define BLE_SUPP_CMD_LE_REMOVE_ADVS (1 << 0) #define BLE_SUPP_CMD_LE_CLEAR_ADVS (1 << 1) #else #define BLE_SUPP_CMD_LE_REMOVE_ADVS (0 << 0) #define BLE_SUPP_CMD_LE_CLEAR_ADVS (0 << 1) #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #define BLE_SUPP_CMD_LE_SET_PADV_PARAM (1 << 2) #define BLE_SUPP_CMD_LE_SET_PADV_DATA (1 << 3) #define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (1 << 4) @@ -321,10 +388,19 @@ #define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (0 << 4) #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) #define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (1 << 5) #define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (1 << 6) +#else +#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (0 << 5) +#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (0 << 6) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (1 << 7) #else +#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (0 << 7) +#endif +#else #define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (0 << 5) #define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (0 << 6) #define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (0 << 7) @@ -343,7 +419,7 @@ ) /* Octet 38 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) #define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (1 << 0) #define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (1 << 1) #define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (1 << 2) @@ -391,7 +467,8 @@ ) /* Octet 40 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_VERSION) >= 51 +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_VERSION) >= 51 && \ + MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) #define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (1 << 5) #else #define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (0 << 5) @@ -483,9 +560,9 @@ /* Octet 44 */ #if MYNEWT_VAL(BLE_VERSION) >= 52 -#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (1 << 0) +#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (1 << 1) #else -#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (0 << 0) +#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (0 << 1) #endif #define BLE_LL_SUPP_CMD_OCTET_44 \ ( \ diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c index 7c46d10a29..7b6208ce11 100644 --- a/nimble/controller/src/ble_ll_sync.c +++ b/nimble/controller/src/ble_ll_sync.c @@ -41,7 +41,7 @@ #include "stats/stats.h" -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) /* defines number of events that can be lost during sync establishment * before failed to be established error is reported @@ -61,6 +61,7 @@ #define BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED 0x0080 #define BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED 0x0100 #define BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP 0x0200 +#define BLE_LL_SYNC_SM_FLAG_CHAIN 0x0400 #define BLE_LL_SYNC_CHMAP_LEN 5 #define BLE_LL_SYNC_ITVL_USECS 1250 @@ -137,6 +138,8 @@ static uint8_t *g_ble_ll_sync_create_comp_ev; static struct ble_ll_sync_sm *g_ble_ll_sync_sm_current; +static int ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch); + static int ble_ll_sync_on_list(const uint8_t *addr, uint8_t addr_type, uint8_t sid) { @@ -211,7 +214,12 @@ ble_ll_sync_sm_clear(struct ble_ll_sync_sm *sm) BLE_LL_ASSERT(sm->sync_ev_end.ev.ev_queued == 0); BLE_LL_ASSERT(sm->sch.enqueued == 0); + memset(sm, 0, sizeof(*sm)); + + sm->sch.sched_cb = ble_ll_sync_event_start_cb; + sm->sch.cb_arg = sm; + sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; } static uint8_t @@ -436,6 +444,7 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) struct ble_ll_sync_sm *sm; uint32_t wfr_usecs; uint32_t start; + uint8_t chan; int rc; /* Set current connection state machine */ @@ -451,7 +460,9 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) ble_ll_state_set(BLE_LL_STATE_SYNC); /* Set channel */ - ble_phy_setchan(sm->chan_index, sm->access_addr, sm->crcinit); + chan = sm->flags & BLE_LL_SYNC_SM_FLAG_CHAIN ? sm->chan_chain : + sm->chan_index; + ble_phy_setchan(chan, sm->access_addr, sm->crcinit); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) ble_phy_resolv_list_disable(); @@ -469,31 +480,35 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) rc = ble_phy_rx_set_start_time(start, sch->remainder); if (rc && rc != BLE_PHY_ERR_RX_LATE) { STATS_INC(ble_ll_stats, sync_event_failed); - rc = BLE_LL_SCHED_STATE_DONE; ble_ll_event_send(&sm->sync_ev_end); ble_ll_sync_current_sm_over(); + rc = BLE_LL_SCHED_STATE_DONE; } else { - /* - * Set flag that tells to set last anchor point if a packet - * has been received. - */ - sm->flags |= BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; - - /* Set WFR timer. - * If establishing we always adjust with offset unit. - * If this is first packet of sync (one that was pointed by from - * SyncInfo we don't adjust WFT with window widening. - */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { + if (sm->flags & BLE_LL_SYNC_SM_FLAG_CHAIN) { wfr_usecs = (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) ? 300 : 30; - if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_SYNC_INFO)) { - wfr_usecs += 2 * sm->window_widening; - } } else { - wfr_usecs = 2 * sm->window_widening; + /* Set flag that tells to set last anchor point if a packet + * has been received. + */ + sm->flags |= BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; + + /* Set WFR timer. + * If establishing we always adjust with offset unit. + * If this is first packet of sync (one that was pointed by from + * SyncInfo we don't adjust WFR with window widening. + */ + if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { + wfr_usecs = (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) ? 300 + : 30; + if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_SYNC_INFO)) { + wfr_usecs += 2 * sm->window_widening; + } + } else { + wfr_usecs = 2 * sm->window_widening; + } } - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usecs); + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usecs); rc = BLE_LL_SCHED_STATE_RUNNING; } @@ -566,7 +581,7 @@ ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power, /* Ignore CTE for now */ if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - i += 1; + i += BLE_LL_EXT_ADV_CTE_INFO_SIZE; } /* there should be no ADI in Sync or chain, skip it */ @@ -848,7 +863,7 @@ static void ble_ll_sync_parse_aux_ptr(const uint8_t *buf, uint8_t *chan, uint32_t *offset, uint8_t *offset_units, uint8_t *phy) { - uint32_t aux_ptr_field = get_le32(buf) & 0x00FFFFFF; + uint32_t aux_ptr_field = get_le24(buf); *chan = aux_ptr_field & 0x3F; @@ -865,63 +880,6 @@ ble_ll_sync_parse_aux_ptr(const uint8_t *buf, uint8_t *chan, uint32_t *offset, *phy = (aux_ptr_field >> 21) & 0x07; } -static int -ble_ll_sync_chain_start_cb(struct ble_ll_sched_item *sch) -{ - struct ble_ll_sync_sm *sm; - uint32_t wfr_usecs; - uint32_t start; - int rc; - - /* Set current connection state machine */ - sm = sch->cb_arg; - g_ble_ll_sync_sm_current = sm; - BLE_LL_ASSERT(sm); - - /* Disable whitelisting */ - ble_ll_whitelist_disable(); - - /* Set LL state */ - ble_ll_state_set(BLE_LL_STATE_SYNC); - - /* Set channel */ - ble_phy_setchan(sm->chan_chain, sm->access_addr, sm->crcinit); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_phy_resolv_list_disable(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - ble_phy_encrypt_disable(); -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_set(sm->phy_mode, sm->phy_mode); -#endif - - start = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_rx_set_start_time(start, sch->remainder); - if (rc && rc != BLE_PHY_ERR_RX_LATE) { - STATS_INC(ble_ll_stats, sync_chain_failed); - rc = BLE_LL_SCHED_STATE_DONE; - ble_ll_event_send(&sm->sync_ev_end); - ble_ll_sync_current_sm_over(); - } else { - /* - * Clear flag that tells to set last anchor point if a packet - * has been received, this is chain and we don't need it. - */ - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; - - wfr_usecs = (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) ? 300 : 30; - - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usecs); - rc = BLE_LL_SCHED_STATE_RUNNING; - } - - return rc; -} - static int ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr, const uint8_t *aux) @@ -954,9 +912,7 @@ ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr, sm->chan_chain = chan; - sm->sch.sched_cb = ble_ll_sync_chain_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; + sm->flags |= BLE_LL_SYNC_SM_FLAG_CHAIN; return ble_ll_sched_sync(&sm->sch, hdr->beg_cputime, hdr->rem_usecs, offset, sm->phy_mode); @@ -1308,10 +1264,7 @@ ble_ll_sync_event_end(struct ble_npl_event *ev) /* Event ended so we are no longer chaining */ sm->flags &= ~BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED; - - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; + sm->flags &= ~BLE_LL_SYNC_SM_FLAG_CHAIN; do { if (ble_ll_sync_next_event(sm, 0) < 0) { @@ -1333,14 +1286,11 @@ ble_ll_sync_event_end(struct ble_npl_event *ev) } void -ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, +ble_ll_sync_info_event(struct ble_ll_scan_addr_data *addrd, uint8_t sid, struct ble_mbuf_hdr *rxhdr, const uint8_t *syncinfo) { struct ble_ll_sync_sm *sm = NULL; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - const uint8_t *rpa = NULL; -#endif uint16_t max_skip; uint32_t offset; uint32_t usecs; @@ -1365,28 +1315,21 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, return; } - /* check if resolved */ - if (rpa_index >= 0) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - rpa = addr; -#endif - addr = g_ble_ll_resolv_list[rpa_index].rl_identity_addr; - addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type; - } - /* check peer */ if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) { - if (ble_ll_sync_on_list(addr, addr_type, sid) < 0) { + if (ble_ll_sync_on_list(addrd->adv_addr, + addrd->adv_addr_type, sid) < 0) { return; } /* set addr and sid in sm */ sm->adv_sid = sid; - sm->adv_addr_type = addr_type; - memcpy(sm->adv_addr, addr, BLE_DEV_ADDR_LEN); + sm->adv_addr_type = addrd->adv_addr_type; + memcpy(sm->adv_addr, addrd->adv_addr, BLE_DEV_ADDR_LEN); } else { - if ((sm->adv_sid != sid) || (sm->adv_addr_type != addr_type) || - memcmp(sm->adv_addr, addr, BLE_DEV_ADDR_LEN)) { + if ((sm->adv_sid != sid) || + (sm->adv_addr_type != addrd->adv_addr_type) || + memcmp(sm->adv_addr, addrd->adv_addr, BLE_DEV_ADDR_LEN)) { return; } } @@ -1406,12 +1349,14 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, return; } - if (rpa_index >= 0) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->adva_resolved) { sm->flags |= BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - memcpy(sm->adv_addr_rpa, rpa, BLE_DEV_ADDR_LEN); + memcpy(sm->adv_addr_rpa, addrd->adva, BLE_DEV_ADDR_LEN); #endif } +#endif /* set params from HCI LE Create Periodic Sync */ sm->timeout = g_ble_ll_sync_create_params.timeout; @@ -1481,10 +1426,6 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id, sm->num_used_chans, sm->chanmap); - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; - if (ble_ll_sched_sync(&sm->sch, rxhdr->beg_cputime, rxhdr->rem_usecs, offset, sm->phy_mode)) { return; @@ -1930,6 +1871,7 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, rpa_index = -1; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) /* check if need to resolve */ if (ble_ll_is_rpa(addr, addr_type)) { rpa_index = ble_ll_resolv_peer_rpa_any(addr); @@ -1939,6 +1881,7 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type; } } +#endif OS_ENTER_CRITICAL(sr); /* check if already synchronized with this peer */ @@ -2037,10 +1980,6 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id, sm->num_used_chans, sm->chanmap); - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; - /* get anchor for specified conn event */ conn_event_count = get_le16(sync_ind + 20); ble_ll_conn_get_anchor(connsm, conn_event_count, &sm->anchor_point, diff --git a/nimble/controller/src/ble_ll_whitelist.c b/nimble/controller/src/ble_ll_whitelist.c index 04ec6428b5..12d841a7f8 100644 --- a/nimble/controller/src/ble_ll_whitelist.c +++ b/nimble/controller/src/ble_ll_whitelist.c @@ -48,8 +48,6 @@ struct ble_ll_whitelist_entry g_ble_ll_whitelist[BLE_LL_WHITELIST_SIZE]; static int ble_ll_whitelist_chg_allowed(void) { - int rc; - /* * This command is not allowed if: * -> advertising uses the whitelist and we are currently advertising. @@ -57,11 +55,19 @@ ble_ll_whitelist_chg_allowed(void) * -> initiating uses whitelist and a LE create connection command is in * progress */ - rc = 1; - if (!ble_ll_adv_can_chg_whitelist() || !ble_ll_scan_can_chg_whitelist()) { - rc = 0; +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + if (ble_ll_adv_can_chg_whitelist()) { + return 1; } - return rc; +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_scan_can_chg_whitelist()) { + return 1; + } +#endif + + return 0; } /** diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml index b900ba9106..afb3859708 100644 --- a/nimble/controller/syscfg.yml +++ b/nimble/controller/syscfg.yml @@ -23,6 +23,30 @@ syscfg.defs: this setting shall not be overriden. value: 1 + BLE_LL_ROLE_CENTRAL: + description: 'Enables controller support for the Central role.' + value: MYNEWT_VAL(BLE_ROLE_CENTRAL) + restrictions: + - 'BLE_LL_ROLE_OBSERVER if 1' + + BLE_LL_ROLE_PERIPHERAL: + description: 'Enables controller support for the Peripheral role.' + value: MYNEWT_VAL(BLE_ROLE_PERIPHERAL) + restrictions: + - 'BLE_LL_ROLE_BROADCASTER if 1' + + BLE_LL_ROLE_BROADCASTER: + description: 'Enables controller support for the Broadcaster role.' + value: MYNEWT_VAL(BLE_ROLE_BROADCASTER) + restrictions: + - 'BLE_LL_ROLE_OBSERVER if 0' + + BLE_LL_ROLE_OBSERVER: + description: 'Enables controller support for the Observer role.' + value: MYNEWT_VAL(BLE_ROLE_OBSERVER) + restrictions: + - 'BLE_LL_ROLE_BROADCASTER if 0' + BLE_HW_WHITELIST_ENABLE: description: > Used to enable hardware white list @@ -44,7 +68,9 @@ syscfg.defs: range: 0..500 BLE_LL_TX_PWR_DBM: - description: 'Transmit power level.' + description: > + Default Transmit power level (in dBm). Actual transmit power + may be rounded up or down depending on used radio. value: '0' BLE_LL_NUM_COMP_PKT_ITVL_MS: @@ -163,6 +189,11 @@ syscfg.defs: PHY enabled all the time. value: MYNEWT_VAL(BLE_XTAL_SETTLE_TIME) + BLE_LL_HCI_LLCP_TRACE: + description: > + Enables LLCP tracing using HCI vendor-specific events. + value: '0' + # Configuration for LL supported features. # # There are a total 8 features that the LL can support. These can be found @@ -179,21 +210,21 @@ syscfg.defs: description: > This option enables/disables encryption support in the controller. This option saves both both code and RAM. - value: '1' + value: 'MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL' BLE_LL_CFG_FEAT_CONN_PARAM_REQ: description: > This option enables/disables the connection parameter request procedure. This is implemented in the controller but is disabled by default. - value: '1' + value: 'MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL' BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG: description: > This option allows a slave to initiate the feature exchange procedure. This feature is implemented but currently has no impact on code or ram size - value: '1' + value: 'MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL' BLE_LL_CFG_FEAT_LE_PING: description: > @@ -208,7 +239,7 @@ syscfg.defs: the controller. If enabled, the controller is allowed to change the size of tx/rx pdu's used in a connection. This option has only minor impact on code size and non on RAM. - value: '1' + value: 'MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL' BLE_LL_CFG_FEAT_LL_PRIVACY: description: > @@ -243,8 +274,6 @@ syscfg.defs: This option is used to enable/disable support for Periodic Advertising Feature. value: MYNEWT_VAL(BLE_PERIODIC_ADV) - restrictions: - - 'BLE_LL_CFG_FEAT_LL_EXT_ADV if 1' BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT: description: > @@ -268,6 +297,8 @@ syscfg.defs: limit number of ACL packets sent at once from controller to avoid congestion on HCI transport if feature is also supported by host. value: 0 + restrictions: + - '(BLE_ROLE_CENTRAL || BLE_ROLE_PERIPHERAL) if 1' BLE_LL_CFG_FEAT_LL_SCA_UPDATE: description: > @@ -291,20 +322,25 @@ syscfg.defs: restrictions: - 'BLE_LL_CFG_FEAT_LL_ISO if 1' + BLE_LL_SCAN_AUX_SEGMENT_CNT: + description: > + Number of auxiliary advertising segments that can be scanned + concurrently (Core 5.2, Vol 6, Part B, 4.4.2.2.2). + value: 8 + BLE_LL_EXT_ADV_AUX_PTR_CNT: description: > This option configure a max number of scheduled outstanding auxiliary packets for receive on secondary advertising channel. value: 0 - BLE_PUBLIC_DEV_ADDR: + BLE_LL_PUBLIC_DEV_ADDR: description: > - Allows the target or app to override the public device address - used by the controller. If all zero, the controller will - attempt to retrieve the public device address from its - chip specific location. If non-zero, this address will - be used. - value: "(uint8_t[6]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + Set public device address. Address is specified as 48-bit number. + If non-zero, this setting has priority over BLE_PUBLIC_DEV_ADDR. + Note: this setting should only be used for testing purposes, it is + not intended for production builds. + value: 0x000000000000 BLE_LL_DTM: description: > @@ -329,13 +365,35 @@ syscfg.defs: depending on specified HCI command length. value: 0 - BLE_LL_VND_EVENT_ON_ASSERT: + BLE_LL_HCI_VS: + description: > + Enables support for vendor-specific HCI commands. + value: MYNEWT_VAL(BLE_HCI_VS) + + BLE_LL_HCI_VS_EVENT_ON_ASSERT: description: > This options enables controller to send a vendor-specific event on an assertion in controller code. The event contains file name and line number where assertion occured. value: 0 + BLE_LL_PA: + description: Enable PA support + value: 0 + BLE_LL_PA_GPIO: + description: > + GPIO pin number to control PA. Pin is set to high state when PA + should be enabled. + value: -1 + BLE_LL_LNA: + description: Enable LNA support + value: 0 + BLE_LL_LNA_GPIO: + description: > + GPIO pin number to control LNA. Pin is set to high state when LNA + should be enabled. + value: -1 + BLE_LL_SYSINIT_STAGE: description: > Sysinit stage for the NimBLE controller. @@ -356,10 +414,15 @@ syscfg.defs: GPIO pin number to debug scheduler running (on timer). Pin is set to high state while scheduler is running. value: -1 - BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB: + BLE_LL_DEBUG_GPIO_SCHED_ITEM: description: > GPIO pin number to debug scheduler item execution times. Pin is set - to high state while item is executed. + to high state while item is active. + value: -1 + BLE_LL_DEBUG_GPIO_RFMGMT: + description: > + GPIO pin number to debug rfmgmt activity. Pin is set to high state + while rfmgmt is active. value: -1 # Below settings allow to change scheduler timings. These should be left at @@ -414,6 +477,14 @@ syscfg.defs: description: use BLE_LL_SCA instead value: 60 deprecated: 1 + BLE_LL_VND_EVENT_ON_ASSERT: + description: use BLE_LL_HCI_VS_EVENT_ON_ASSERT + value: 0 + deprecated: 1 + BLE_PUBLIC_DEV_ADDR: + description: use BLE_LL_PUBLIC_DEV_ADDR + value: "(uint8_t[6]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + deprecated: 1 # defunct settings (to be removed eventually) BLE_DEVICE: @@ -442,7 +513,10 @@ syscfg.vals.BLE_LL_CFG_FEAT_LL_EXT_ADV: # Enable vendor event on assert in standalone build to make failed assertions in # controller code visible when connected to external host syscfg.vals.!BLE_HOST: - BLE_LL_VND_EVENT_ON_ASSERT: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 syscfg.restrictions: - OS_CPUTIME_FREQ == 32768 + - BLE_LL_PUBLIC_DEV_ADDR <= 0xffffffffffff + - BLE_LL_PA == 0 || BLE_LL_PA_GPIO >= 0 + - BLE_LL_LNA == 0 || BLE_LL_LNA_GPIO >= 0 diff --git a/nimble/controller/test/pkg.yml b/nimble/controller/test/pkg.yml index ea72881149..1b06a5b576 100644 --- a/nimble/controller/test/pkg.yml +++ b/nimble/controller/test/pkg.yml @@ -31,4 +31,4 @@ pkg.deps.SELFTEST: - "@apache-mynewt-core/sys/log/full" - "@apache-mynewt-core/sys/stats/stub" - nimble/drivers/native - - nimble/transport/ram + - nimble/transport diff --git a/nimble/controller/test/syscfg.yml b/nimble/controller/test/syscfg.yml index 6edad438bb..4448a0e66f 100644 --- a/nimble/controller/test/syscfg.yml +++ b/nimble/controller/test/syscfg.yml @@ -23,3 +23,4 @@ syscfg.vals: MCU_TIMER_POLLER_PRIO: 1 MCU_UART_POLLER_PRIO: 2 NATIVE_SOCKETS_PRIO: 3 + BLE_HCI_TRANSPORT: ram diff --git a/nimble/drivers/dialog_cmac/src/ble_phy.c b/nimble/drivers/dialog_cmac/src/ble_phy.c index ab0f88505f..212d19b671 100644 --- a/nimble/drivers/dialog_cmac/src/ble_phy.c +++ b/nimble/drivers/dialog_cmac/src/ble_phy.c @@ -935,6 +935,12 @@ ble_phy_irq_frame_rx_exc_phy_to_idle_4this(void) rf_chan = g_ble_phy_chan_to_rf[g_ble_phy_data.channel]; ble_rf_setup_tx(rf_chan, g_ble_phy_data.phy_mode_tx); g_ble_phy_data.phy_state = BLE_PHY_STATE_TX; + + /* We do not want FIELD/FRAME interrupts until ble_phy_tx() has pushed all + * fields. + */ + NVIC_DisableIRQ(FRAME_IRQn); + NVIC_DisableIRQ(FIELD_IRQn); } static void @@ -1305,6 +1311,9 @@ ble_phy_disable(void) __enable_irq(); + NVIC_EnableIRQ(FRAME_IRQn); + NVIC_EnableIRQ(FIELD_IRQn); + g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; } @@ -1369,6 +1378,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) { uint32_t ll_val32; int32_t time_till_start; + int rc = 0; MCU_DIAG_SER('r'); @@ -1404,11 +1414,12 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) /* We missed start. Start now */ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_ASAP_Msk; + rc = BLE_PHY_ERR_RX_LATE; } } __enable_irq(); - return 0; + return rc; } int @@ -1550,8 +1561,6 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) tx_late: STATS_INC(ble_phy_stats, tx_late); ble_phy_disable(); - NVIC_EnableIRQ(FRAME_IRQn); - NVIC_EnableIRQ(FIELD_IRQn); rc = BLE_PHY_ERR_TX_LATE; done: diff --git a/nimble/drivers/nrf51/src/ble_hw.c b/nimble/drivers/nrf51/src/ble_hw.c index 3c7296b845..437efd4f7c 100644 --- a/nimble/drivers/nrf51/src/ble_hw.c +++ b/nimble/drivers/nrf51/src/ble_hw.c @@ -474,13 +474,8 @@ ble_hw_resolv_list_size(void) int ble_hw_resolv_list_match(void) { - uint32_t index; - - if (NRF_AAR->EVENTS_END) { - if (NRF_AAR->EVENTS_RESOLVED) { - index = NRF_AAR->STATUS; - return (int)index; - } + if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) { + return (int)NRF_AAR->STATUS; } return -1; diff --git a/nimble/drivers/nrf51/src/ble_phy.c b/nimble/drivers/nrf51/src/ble_phy.c index b7e6329721..d3bc3c2ecc 100644 --- a/nimble/drivers/nrf51/src/ble_phy.c +++ b/nimble/drivers/nrf51/src/ble_phy.c @@ -408,7 +408,7 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs) /** * Function is used to set PPI so that we can time out waiting for a reception * to occur. This happens for two reasons: we have sent a packet and we are - * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are + * waiting for a response (txrx should be set to ENABLE_TXRX) or we are * starting a connection event and we are a slave and we are waiting for the * master to send us a packet (txrx should be set to ENABLE_RX). * @@ -1357,7 +1357,7 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) NRF_RADIO->RXADDRESSES = (1 << 1); NRF_RADIO->CRCINIT = crcinit; } else { - /* Logical adddress 0 preconfigured */ + /* Logical address 0 preconfigured */ NRF_RADIO->TXADDRESS = 0; NRF_RADIO->RXADDRESSES = (1 << 0); NRF_RADIO->CRCINIT = BLE_LL_CRCINIT_ADV; diff --git a/nimble/drivers/nrf52/src/ble_hw.c b/nimble/drivers/nrf52/src/ble_hw.c index 82e6d17ed7..79a7772852 100644 --- a/nimble/drivers/nrf52/src/ble_hw.c +++ b/nimble/drivers/nrf52/src/ble_hw.c @@ -69,6 +69,22 @@ ble_hw_get_public_addr(ble_addr_t *addr) uint32_t addr_high; uint32_t addr_low; +#if MYNEWT_VAL(BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR) + /* + * The BMD-345 modules are preprogrammed from the factory with a unique public + * The Bluetooth device address stored in the CUSTOMER[0] and CUSTOMER[1] + * registers of the User Information Configuration Registers (UICR). + * The Bluetooth device address consists of the IEEE Organizationally Unique + * Identifier (OUI) combined with the hexadecimal digits that are printed on + * a 2D barcode and in human-readable text on the module label.The Bluetooth + * device address is stored in little endian format. The most significant + * bytes of the CUSTOMER[1] register are 0xFF to complete the 32-bit register. + */ + + /* Copy into device address. We can do this because we know platform */ + addr_low = NRF_UICR->CUSTOMER[0]; + addr_high = NRF_UICR->CUSTOMER[1]; +#else /* Does FICR have a public address */ if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) { return -1; @@ -77,6 +93,8 @@ ble_hw_get_public_addr(ble_addr_t *addr) /* Copy into device address. We can do this because we know platform */ addr_low = NRF_FICR->DEVICEADDR[0]; addr_high = NRF_FICR->DEVICEADDR[1]; +#endif + memcpy(addr->val, &addr_low, 4); memcpy(&addr->val[4], &addr_high, 2); addr->type = BLE_ADDR_PUBLIC; @@ -474,13 +492,8 @@ ble_hw_resolv_list_size(void) int ble_hw_resolv_list_match(void) { - uint32_t index; - - if (NRF_AAR->EVENTS_END) { - if (NRF_AAR->EVENTS_RESOLVED) { - index = NRF_AAR->STATUS; - return (int)index; - } + if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) { + return (int)NRF_AAR->STATUS; } return -1; diff --git a/nimble/drivers/nrf52/src/ble_phy.c b/nimble/drivers/nrf52/src/ble_phy.c index 2f6ce08e72..3c7b62690b 100644 --- a/nimble/drivers/nrf52/src/ble_phy.c +++ b/nimble/drivers/nrf52/src/ble_phy.c @@ -29,6 +29,7 @@ #include "controller/ble_phy.h" #include "controller/ble_phy_trace.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_plna.h" #include "nrfx.h" #if MYNEWT #include "mcu/nrf52_clock.h" @@ -49,9 +50,11 @@ * using PPI somewhere else. * * Pre-programmed channels: CH20, CH21, CH23, CH25, CH31 - * Regular channels: CH4, CH5 and optionally CH17, CH18, CH19 + * Regular channels: CH4, CH5 and optionally CH6, CH7, CH17, CH18, CH19 * - CH4 = cancel wfr timer on address match * - CH5 = disable radio on wfr timer expiry + * - CH6 = PA/LNA control (enable) + * - CH7 = PA/LNA control (disable) * - CH17 = (optional) gpio debug for radio ramp-up * - CH18 = (optional) gpio debug for wfr timer RX enabled * - CH19 = (optional) gpio debug for wfr timer radio disabled @@ -277,6 +280,27 @@ struct nrf_ccm_data struct nrf_ccm_data g_nrf_ccm_data; #endif +static int g_ble_phy_gpiote_idx; + +#if MYNEWT_VAL(BLE_LL_PA) || MYNEWT_VAL(BLE_LL_LNA) + +#define PLNA_SINGLE_GPIO \ + (!MYNEWT_VAL(BLE_LL_PA) || !MYNEWT_VAL(BLE_LL_LNA) || \ + (MYNEWT_VAL(BLE_LL_PA_GPIO) == MYNEWT_VAL(BLE_LL_LNA_GPIO))) + +#if PLNA_SINGLE_GPIO +static uint8_t plna_idx; +#else +#if MYNEWT_VAL(BLE_LL_PA) +static uint8_t plna_pa_idx; +#endif +#if MYNEWT_VAL(BLE_LL_LNA) +static uint8_t plna_lna_idx; +#endif +#endif + +#endif + static void ble_phy_apply_errata_102_106_107(void) { @@ -400,6 +424,36 @@ ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) } #endif +static void +ble_phy_plna_enable_pa(void) +{ +#if MYNEWT_VAL(BLE_LL_PA) + ble_ll_plna_pa_enable(); + +#if !PLNA_SINGLE_GPIO + NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[plna_pa_idx]); + NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[plna_pa_idx]); +#endif + + NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; +#endif +} + +static void +ble_phy_plna_enable_lna(void) +{ +#if MYNEWT_VAL(BLE_LL_LNA) + ble_ll_plna_lna_enable(); + +#if !PLNA_SINGLE_GPIO + NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[plna_lna_idx]); + NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[plna_lna_idx]); +#endif + + NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; +#endif +} + int ble_phy_get_cur_phy(void) { @@ -669,7 +723,7 @@ ble_phy_set_start_now(void) /** * Function is used to set PPI so that we can time out waiting for a reception * to occur. This happens for two reasons: we have sent a packet and we are - * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are + * waiting for a response (txrx should be set to ENABLE_TXRX) or we are * starting a connection event and we are a slave and we are waiting for the * master to send us a packet (txrx should be set to ENABLE_RX). * @@ -703,17 +757,6 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) * by waiting 1 usec more. */ end_time += 1; -#if MYNEWT_VAL(BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN) > 0 - if ((phy == BLE_PHY_MODE_CODED_125KBPS) || - (phy == BLE_PHY_MODE_CODED_500KBPS)) { - /* - * Some controllers exceed T_IFS when transmitting on coded phy - * so let's wait a bit longer to be able to talk to them if this - * workaround is enabled. - */ - end_time += MYNEWT_VAL(BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN); - } -#endif } else { /* * RX shall start no later than wfr_usecs after RX enabled. @@ -741,9 +784,6 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) /* Enable wait for response PPI */ NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); - /* Enable the disabled interrupt so we time out on events compare */ - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; - /* * It may happen that if CPU is halted for a brief moment (e.g. during flash * erase or write), TIMER0 already counted past CC[3] and thus wfr will not @@ -871,7 +911,8 @@ ble_phy_rx_xcvr_setup(void) RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk; - NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk; + NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk | + RADIO_INTENSET_DISABLED_Msk; } /** @@ -885,7 +926,6 @@ ble_phy_tx_end_isr(void) uint8_t was_encrypted; uint8_t transition; uint32_t rx_time; - uint32_t wfr_time; /* Store PHY on which we've just transmitted smth */ tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode; @@ -897,13 +937,6 @@ ble_phy_tx_end_isr(void) /* Better be in TX state! */ assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); - /* Clear events and clear interrupt on disabled event */ - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; - NRF_RADIO->EVENTS_END = 0; - wfr_time = NRF_RADIO->SHORTS; - (void)wfr_time; - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) /* * XXX: not sure what to do. We had a HW error during transmission. @@ -946,6 +979,8 @@ ble_phy_tx_end_isr(void) NRF_TIMER0->CC[0] = rx_time; NRF_TIMER0->EVENTS_COMPARE[0] = 0; NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; + + ble_phy_plna_enable_lna(); } else { /* * XXX: not sure we need to stop the timer here all the time. Or that @@ -993,10 +1028,6 @@ ble_phy_rx_end_isr(void) uint32_t tx_time; struct ble_mbuf_hdr *ble_hdr; - /* Clear events and clear interrupt */ - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk; - /* Disable automatic RXEN */ NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; @@ -1078,6 +1109,8 @@ ble_phy_rx_end_isr(void) NRF_TIMER0->EVENTS_COMPARE[0] = 0; NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; + ble_phy_plna_enable_pa(); + /* * XXX: Hack warning! * @@ -1127,9 +1160,9 @@ ble_phy_rx_start_isr(void) /* Clear events and clear interrupt */ NRF_RADIO->EVENTS_ADDRESS = 0; + NRF_RADIO->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk; - /* Clear wfr timer channels and DISABLED interrupt */ - NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk; + /* Clear wfr timer channels */ NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk; /* Initialize the ble mbuf header */ @@ -1221,7 +1254,6 @@ ble_phy_rx_start_isr(void) if (rc >= 0) { /* Set rx started flag and enable rx end ISR */ g_ble_phy_data.phy_rx_started = 1; - NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; } else { /* Disable PHY */ ble_phy_disable(); @@ -1267,28 +1299,44 @@ ble_phy_isr(void) } } - /* Check for disabled event. This only happens for transmits now */ + /* Handle disabled event. This is enabled for both TX and RX. On RX, we + * need to check phy_rx_started flag to make sure we actually were receiving + * a PDU, otherwise this is due to wfr. + */ if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) { - if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) { - NRF_RADIO->EVENTS_DISABLED = 0; - ble_ll_wfr_timer_exp(NULL); - } else if (g_ble_phy_data.phy_state == BLE_PHY_STATE_IDLE) { - assert(0); - } else { + BLE_LL_ASSERT(NRF_RADIO->EVENTS_END || + ((g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) && + !g_ble_phy_data.phy_rx_started)); + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; + + switch (g_ble_phy_data.phy_state) { + case BLE_PHY_STATE_RX: +#if MYNEWT_VAL(BLE_LL_LNA) + NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; + ble_ll_plna_lna_disable(); +#endif + if (g_ble_phy_data.phy_rx_started) { + ble_phy_rx_end_isr(); + } else { + ble_ll_wfr_timer_exp(NULL); + } + break; + case BLE_PHY_STATE_TX: +#if MYNEWT_VAL(BLE_LL_PA) + NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; + ble_ll_plna_pa_disable(); +#endif ble_phy_tx_end_isr(); + break; + default: + BLE_LL_ASSERT(0); } } - /* Receive packet end (we dont enable this for transmit) */ - if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) { - ble_phy_rx_end_isr(); - } - g_ble_phy_data.phy_transition_late = 0; - /* Ensures IRQ is cleared */ - irq_en = NRF_RADIO->SHORTS; - /* Count # of interrupts */ STATS_INC(ble_phy_stats, phy_isrs); @@ -1296,13 +1344,17 @@ ble_phy_isr(void) } #if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 -static inline void -ble_phy_dbg_time_setup_gpiote(int index, int pin) + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \ + MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 || \ + MYNEWT_VAL(BLE_LL_PA) || \ + MYNEWT_VAL(BLE_LL_LNA) +static int +ble_phy_gpiote_configure(int pin) { NRF_GPIO_Type *port; + g_ble_phy_gpiote_idx--; + #if NRF52840_XXAA port = pin > 31 ? NRF_P1 : NRF_P0; pin &= 0x1f; @@ -1314,7 +1366,7 @@ ble_phy_dbg_time_setup_gpiote(int index, int pin) port->DIRSET = (1 << pin); port->OUTCLR = (1 << pin); - NRF_GPIOTE->CONFIG[index] = + NRF_GPIOTE->CONFIG[g_ble_phy_gpiote_idx] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) | #if NRF52840_XXAA @@ -1322,13 +1374,17 @@ ble_phy_dbg_time_setup_gpiote(int index, int pin) #else 0; #endif + + BLE_LL_ASSERT(g_ble_phy_gpiote_idx >= 0); + + return g_ble_phy_gpiote_idx; } #endif static void ble_phy_dbg_time_setup(void) { - int gpiote_idx __attribute__((unused)) = 8; + int idx __attribute__((unused)); /* * We setup GPIOTE starting from last configuration index to minimize risk @@ -1337,44 +1393,41 @@ ble_phy_dbg_time_setup(void) */ #if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); NRF_PPI->CH[17].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY); - NRF_PPI->CH[17].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); + NRF_PPI->CH[17].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]); NRF_PPI->CHENSET = PPI_CHEN_CH17_Msk; /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */ - NRF_PPI->FORK[20].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); - NRF_PPI->FORK[21].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); + NRF_PPI->FORK[20].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]); + NRF_PPI->FORK[21].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]); #endif #if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */ - NRF_PPI->FORK[26].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); - NRF_PPI->FORK[27].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); + NRF_PPI->FORK[26].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]); + NRF_PPI->FORK[27].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]); #endif #if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); #if NRF52840_XXAA NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_RXREADY); #else NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY); #endif - NRF_PPI->CH[18].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); + NRF_PPI->CH[18].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]); NRF_PPI->CH[19].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED); - NRF_PPI->CH[19].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); + NRF_PPI->CH[19].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]); NRF_PPI->CHENSET = PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk; /* CH[4] and CH[5] are always on for wfr */ - NRF_PPI->FORK[4].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); - NRF_PPI->FORK[5].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); + NRF_PPI->FORK[4].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]); + NRF_PPI->FORK[5].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]); #endif } @@ -1390,6 +1443,8 @@ ble_phy_init(void) { int rc; + g_ble_phy_gpiote_idx = 8; + /* Default phy to use is 1M */ g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M; g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M; @@ -1473,6 +1528,27 @@ ble_phy_init(void) NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]); NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE); +#if MYNEWT_VAL(BLE_LL_PA) || MYNEWT_VAL(BLE_LL_LNA) +#if PLNA_SINGLE_GPIO + plna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_PA_GPIO)); + NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[plna_idx]); + NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[plna_idx]); +#else +#if MYNEWT_VAL(BLE_LL_PA) + plna_pa_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_PA_GPIO)); + NRF_GPIOTE->TASKS_CLR[plna_pa_idx] = 1; +#endif +#if MYNEWT_VAL(BLE_LL_LNA) + plna_lna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_LNA_GPIO)); + NRF_GPIOTE->TASKS_CLR[plna_lna_idx] = 1; +#endif +#endif + + NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY); + NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED); + NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; +#endif + /* Set isr in vector table and enable interrupt */ #ifndef RIOT_VERSION NVIC_SetPriority(RADIO_IRQn, 0); @@ -1635,7 +1711,10 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) /* Enable PPI to automatically start TXEN */ NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; rc = 0; + + ble_phy_plna_enable_pa(); } + return rc; } @@ -1680,6 +1759,8 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) /* Enable PPI to automatically start RXEN */ NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; + ble_phy_plna_enable_lna(); + /* Start rx */ rc = ble_phy_rx(); @@ -1977,6 +2058,7 @@ ble_phy_disable_irq_and_ppi(void) NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk; + NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; NVIC_ClearPendingIRQ(RADIO_IRQn); g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; } diff --git a/nimble/drivers/nrf52/syscfg.yml b/nimble/drivers/nrf52/syscfg.yml index ce5123721a..3bd49708ca 100644 --- a/nimble/drivers/nrf52/syscfg.yml +++ b/nimble/drivers/nrf52/syscfg.yml @@ -22,16 +22,6 @@ syscfg.defs: Enable SystemView tracing module for radio driver. value: 0 - BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN: - description: > - This defines additional margin for T_IFS tolerance while in - RX on coded phy to allow maintaining connections with some - controllers that exceed proper T_IFS (150 usecs) by more - than allowed 2 usecs. - This value shall be only used for debugging purposes. It is - strongly recommended to keep this settings at default value - to ensure compliance with specification. - value: 0 BLE_PHY_DBG_TIME_TXRXEN_READY_PIN: description: > When set to proper GPIO pin number, this pin will be set @@ -73,3 +63,10 @@ syscfg.defs: - nRF52840 Engineering C - nRF52840 Rev 1 (final silicon) value: 1 + + BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR: + description: > + Ublox BMD-345 modules come with public address preprogrammed + in UICR register. If enabled public address will be read from + custom UICR instead of FICR register. + value: 0 diff --git a/nimble/drivers/nrf5340/src/ble_hw.c b/nimble/drivers/nrf5340/src/ble_hw.c index bbe6169779..92bf024979 100644 --- a/nimble/drivers/nrf5340/src/ble_hw.c +++ b/nimble/drivers/nrf5340/src/ble_hw.c @@ -461,13 +461,9 @@ ble_hw_resolv_list_size(void) int ble_hw_resolv_list_match(void) { - uint32_t index; - - if (NRF_AAR_NS->EVENTS_END) { - if (NRF_AAR_NS->EVENTS_RESOLVED) { - index = NRF_AAR_NS->STATUS; - return (int)index; - } + if (NRF_AAR_NS->ENABLE && NRF_AAR_NS->EVENTS_END && + NRF_AAR_NS->EVENTS_RESOLVED) { + return (int)NRF_AAR_NS->STATUS; } return -1; diff --git a/nimble/drivers/nrf5340/src/ble_phy.c b/nimble/drivers/nrf5340/src/ble_phy.c index e07bbaa11f..12be202db5 100644 --- a/nimble/drivers/nrf5340/src/ble_phy.c +++ b/nimble/drivers/nrf5340/src/ble_phy.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ * DPPI somewhere else. * TODO maybe we could reduce number of used channels if we reuse same channel * for mutually exclusive events but for now make it simpler to debug. + * + * Optionally channels 6,7,8 are used for GPIO DBG. */ #define DPPI_CH_TIMER0_EVENTS_COMPARE_0 0 @@ -82,6 +85,39 @@ #define DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(_enable) ((DPPI_CH_RADIO_EVENTS_ADDRESS << CCM_SUBSCRIBE_CRYPT_CHIDX_Pos) | \ ((_enable) << CCM_SUBSCRIBE_CRYPT_EN_Pos)) +/* used for GPIO DBG */ +#define DPPI_CH_RADIO_EVENTS_READY 6 +#define DPPI_CH_RADIO_EVENTS_RXREADY 7 +#define DPPI_CH_RADIO_EVENTS_DISABLED 8 + +#define DPPI_CH_ENABLE_RADIO_EVENTS_READY DPPIC_CHEN_CH6_Msk +#define DPPI_CH_ENABLE_RADIO_EVENTS_RXREADY DPPIC_CHEN_CH7_Msk +#define DPPI_CH_ENABLE_RADIO_EVENTS_DISABLED DPPIC_CHEN_CH8_Msk + +#define DPPI_PUBLISH_RADIO_EVENTS_READY ((DPPI_CH_RADIO_EVENTS_READY << RADIO_PUBLISH_READY_CHIDX_Pos) | \ + (RADIO_PUBLISH_READY_EN_Enabled << RADIO_PUBLISH_READY_EN_Pos)) +#define DPPI_PUBLISH_RADIO_EVENTS_RXREADY ((DPPI_CH_RADIO_EVENTS_RXREADY << RADIO_PUBLISH_RXREADY_CHIDX_Pos) | \ + (RADIO_PUBLISH_RXREADY_EN_Enabled << RADIO_PUBLISH_RXREADY_EN_Pos)) +#define DPPI_PUBLISH_RADIO_EVENTS_DISABLED ((DPPI_CH_RADIO_EVENTS_DISABLED << RADIO_PUBLISH_DISABLED_CHIDX_Pos) | \ + (RADIO_PUBLISH_DISABLED_EN_Enabled << RADIO_PUBLISH_DISABLED_EN_Pos)) + +#define DPPI_SUBSCRIBE_GPIOTE_TASKS_SET_TXRXEN ((DPPI_CH_TIMER0_EVENTS_COMPARE_0 << GPIOTE_SUBSCRIBE_SET_CHIDX_Pos) | \ + (1 << GPIOTE_SUBSCRIBE_SET_EN_Pos)) +#define DPPI_SUBSCRIBE_GPIOTE_TASKS_SET_ADDRESS ((DPPI_CH_RADIO_EVENTS_ADDRESS << GPIOTE_SUBSCRIBE_SET_CHIDX_Pos) | \ + (1 << GPIOTE_SUBSCRIBE_SET_EN_Pos)) +#define DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_END ((DPPI_CH_RADIO_EVENTS_END << GPIOTE_SUBSCRIBE_CLR_CHIDX_Pos) | \ + (1 << GPIOTE_SUBSCRIBE_CLR_EN_Pos)) +#define DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_READY ((DPPI_CH_RADIO_EVENTS_READY << GPIOTE_SUBSCRIBE_CLR_CHIDX_Pos) | \ + (1 << GPIOTE_SUBSCRIBE_CLR_EN_Pos)) +#define DPPI_SUBSCRIBE_GPIOTE_TASKS_SET_RXREADY ((DPPI_CH_RADIO_EVENTS_RXREADY << GPIOTE_SUBSCRIBE_SET_CHIDX_Pos) | \ + (1 << GPIOTE_SUBSCRIBE_SET_EN_Pos)) +#define DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_DISABLED ((DPPI_CH_RADIO_EVENTS_DISABLED << GPIOTE_SUBSCRIBE_CLR_CHIDX_Pos) | \ + (1 << GPIOTE_SUBSCRIBE_CLR_EN_Pos)) +#define DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_CAPTURE3 ((DPPI_CH_TIMER0_EVENTS_COMPARE_3 << GPIOTE_SUBSCRIBE_CLR_CHIDX_Pos) | \ + (1 << GPIOTE_SUBSCRIBE_CLR_EN_Pos)) +#define DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_ADDRESS ((DPPI_CH_RADIO_EVENTS_ADDRESS << GPIOTE_SUBSCRIBE_CLR_CHIDX_Pos) | \ + (1 << GPIOTE_SUBSCRIBE_CLR_EN_Pos)) + extern uint8_t g_nrf_num_irks; extern uint32_t g_nrf_irk_list[]; @@ -1179,6 +1215,84 @@ ble_phy_isr(void) os_trace_isr_exit(); } +#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \ + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \ + MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 +static inline void +ble_phy_dbg_time_setup_gpiote(int index, int pin) +{ + NRF_GPIO_Type *port; + + port = pin > 31 ? NRF_P1_NS : NRF_P0_NS; + pin &= 0x1f; + + /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */ + port->DIRSET = (1 << pin); + port->OUTCLR = (1 << pin); + + NRF_GPIOTE_NS->CONFIG[index] = + (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | + ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) | + ((port == NRF_P1_NS) << GPIOTE_CONFIG_PORT_Pos); +} +#endif + +static void +ble_phy_dbg_time_setup(void) +{ + int gpiote_idx __attribute__((unused)) = 8; + + /* + * We setup GPIOTE starting from last configuration index to minimize risk + * of conflict with GPIO setup via hal. It's not great solution, but since + * this is just debugging code we can live with this. + */ + +#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 + ble_phy_dbg_time_setup_gpiote(--gpiote_idx, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + + NRF_GPIOTE_NS->SUBSCRIBE_SET[gpiote_idx] = DPPI_SUBSCRIBE_GPIOTE_TASKS_SET_TXRXEN; + NRF_GPIOTE_NS->SUBSCRIBE_CLR[gpiote_idx] = DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_READY; + + /* Publish RADIO->EVENTS_READY */ + NRF_RADIO_NS->PUBLISH_READY = DPPI_PUBLISH_RADIO_EVENTS_READY; + NRF_DPPIC_NS->CHENSET = DPPI_CH_ENABLE_RADIO_EVENTS_READY; + +#endif + +#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 + ble_phy_dbg_time_setup_gpiote(--gpiote_idx, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + + NRF_GPIOTE_NS->SUBSCRIBE_SET[gpiote_idx] = DPPI_SUBSCRIBE_GPIOTE_TASKS_SET_ADDRESS; + NRF_GPIOTE_NS->SUBSCRIBE_CLR[gpiote_idx] = DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_END; +#endif + +#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 + ble_phy_dbg_time_setup_gpiote(--gpiote_idx, + MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + + NRF_GPIOTE_NS->SUBSCRIBE_SET[gpiote_idx] = DPPI_SUBSCRIBE_GPIOTE_TASKS_SET_RXREADY; + + /* TODO figure out how (if?) to subscribe task to multiple DPPI channels + * Currently only last one is working. Also using multiple GPIOTE for same + * PIN doesn't work... + */ + NRF_GPIOTE_NS->SUBSCRIBE_CLR[gpiote_idx] = DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_DISABLED; + NRF_GPIOTE_NS->SUBSCRIBE_CLR[gpiote_idx] = DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_ADDRESS; + NRF_GPIOTE_NS->SUBSCRIBE_CLR[gpiote_idx] = DPPI_SUBSCRIBE_GPIOTE_TASKS_CLR_CAPTURE3; + + /* Publish RADIO->EVENTS_RXREADY */ + NRF_RADIO_NS->PUBLISH_RXREADY = DPPI_PUBLISH_RADIO_EVENTS_RXREADY; + NRF_DPPIC_NS->CHENSET = DPPI_CH_ENABLE_RADIO_EVENTS_RXREADY; + + /* Publish RADIO->EVENTS_DISABLED */ + NRF_RADIO_NS->PUBLISH_DISABLED = DPPI_CH_ENABLE_RADIO_EVENTS_DISABLED; + NRF_DPPIC_NS->CHENSET = DPPI_CH_ENABLE_RADIO_EVENTS_DISABLED; +#endif +} + int ble_phy_init(void) { @@ -1296,6 +1410,8 @@ ble_phy_init(void) g_ble_phy_data.phy_stats_initialized = 1; } + ble_phy_dbg_time_setup(); + return 0; } @@ -1725,6 +1841,41 @@ ble_phy_restart_rx(void) ble_phy_rx(); } +static void +ble_phy_dbg_clear_pins(void) +{ +#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \ + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \ + MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 + NRF_GPIO_Type *port; + int pin; + +#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 + pin = MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN); + port = pin > 31 ? NRF_P1_NS : NRF_P0_NS; + pin &= 0x1f; + + port->OUTCLR = (1 << pin); +#endif + +#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 + pin = MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN); + port = pin > 31 ? NRF_P1_NS : NRF_P0_NS; + pin &= 0x1f; + + port->OUTCLR = (1 << pin); +#endif + +#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 + pin = MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN); + port = pin > 31 ? NRF_P1_NS : NRF_P0_NS; + pin &= 0x1f; + + port->OUTCLR = (1 << pin); +#endif +#endif +} + void ble_phy_disable(void) { @@ -1732,6 +1883,8 @@ ble_phy_disable(void) ble_phy_stop_usec_timer(); ble_phy_disable_irq_and_ppi(); + + ble_phy_dbg_clear_pins(); } uint32_t diff --git a/nimble/drivers/nrf5340/syscfg.yml b/nimble/drivers/nrf5340/syscfg.yml index dd8b93047c..ed82f6d604 100644 --- a/nimble/drivers/nrf5340/syscfg.yml +++ b/nimble/drivers/nrf5340/syscfg.yml @@ -21,3 +21,42 @@ syscfg.defs: description: > Enable SystemView tracing module for radio driver. value: 0 + + BLE_PHY_DBG_TIME_TXRXEN_READY_PIN: + description: > + When set to proper GPIO pin number, this pin will be set + to high state when radio is enabled (TASKS_TXEN or TASKS_RXEN) + and back to low state on radio EVENTS_READY. + This can be used to measure radio ram-up time. + + Note: + GPIO control for selected pin needs to be assigned to Network + Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on + Application Core. + value: -1 + + BLE_PHY_DBG_TIME_ADDRESS_END_PIN: + description: > + When set to proper GPIO pin number, this pin will be set + to high state on radio EVENTS_ADDRESS and back to low state + on radio EVENTS_END. + This can be used to measure radio pipeline delays. + + Note: + GPIO control for selected pin needs to be assigned to Network + Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on + Application Core. + value: -1 + + BLE_PHY_DBG_TIME_WFR_PIN: + description: > + When set to proper GPIO pin number, this pin will be set + to high state on radio EVENTS_RXREADY and back to low + state when wfr timer expires. + This can be used to check if wfr is calculated properly. + + Note: + GPIO control for selected pin needs to be assigned to Network + Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on + Application Core. + value: -1 diff --git a/nimble/drivers/plna/sky66112/pkg.yml b/nimble/drivers/plna/sky66112/pkg.yml new file mode 100644 index 0000000000..c3cb0fd322 --- /dev/null +++ b/nimble/drivers/plna/sky66112/pkg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/drivers/plna/sky66112 +pkg.description: Driver for SKY66112 front-end module +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.apis: + - ble_ll_pa + - ble_ll_lna +pkg.deps: + - nimble/controller + +pkg.init: + sky66112_init: 999 diff --git a/nimble/drivers/plna/sky66112/src/sky66112.c b/nimble/drivers/plna/sky66112/src/sky66112.c new file mode 100644 index 0000000000..09afe5f96e --- /dev/null +++ b/nimble/drivers/plna/sky66112/src/sky66112.c @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "syscfg/syscfg.h" +#include "hal/hal_gpio.h" +#include "controller/ble_ll_plna.h" + +#define NO_BYPASS \ + ((MYNEWT_VAL(SKY66112_TX_BYPASS) >= 0) && \ + (MYNEWT_VAL(SKY66112_RX_BYPASS) >= 0)) + +static void +sky66112_bypass(uint8_t enabled) +{ + if (NO_BYPASS) { + return; + } + + hal_gpio_write(MYNEWT_VAL(SKY66112_PIN_CPS), enabled); +} + +void +ble_ll_plna_pa_init(void) +{ + /* Nothing to do here */ +} + +void +ble_ll_plna_pa_enable(void) +{ + if (!MYNEWT_VAL(SKY66112_TX_BYPASS)) { + sky66112_bypass(0); + } +} + +void +ble_ll_plna_pa_disable(void) +{ + if (!MYNEWT_VAL(SKY66112_TX_BYPASS)) { + sky66112_bypass(1); + } +} + +void +ble_ll_plna_lna_init(void) +{ + /* Nothing to do here */ +} + +void +ble_ll_plna_lna_enable(void) +{ + if (!MYNEWT_VAL(SKY66112_RX_BYPASS)) { + sky66112_bypass(0); + } +} + +void +ble_ll_plna_lna_disable(void) +{ + if (!MYNEWT_VAL(SKY66112_RX_BYPASS)) { + sky66112_bypass(1); + } +} + +void +sky66112_init(void) +{ + int pin; + + /* Use CRX and CTX to enable sleep mode */ + pin = MYNEWT_VAL(SKY66112_PIN_CSD); + if (pin >= 0) { + hal_gpio_init_out(pin, 1); + } + + pin = MYNEWT_VAL(SKY66112_PIN_CPS); + if (NO_BYPASS) { + /* Disable bypass */ + if (pin >= 0) { + hal_gpio_init_out(pin, 0); + } + } else { + /* Enable bypass, we'll disable it when needed */ + assert(pin >= 0); + hal_gpio_init_out(pin, 1); + } + + pin = MYNEWT_VAL(SKY66112_PIN_CHL); + if (pin >= 0) { + hal_gpio_init_out(pin, MYNEWT_VAL(SKY66112_TX_HP_MODE)); + } + + /* Select ANT1 */ + pin = MYNEWT_VAL(SKY66112_PIN_SEL); + if (pin >= 0) { + hal_gpio_init_out(pin, 0); + } +} diff --git a/nimble/drivers/plna/sky66112/syscfg.yml b/nimble/drivers/plna/sky66112/syscfg.yml new file mode 100644 index 0000000000..50434553a0 --- /dev/null +++ b/nimble/drivers/plna/sky66112/syscfg.yml @@ -0,0 +1,66 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + SKY66112_PIN_CSD: + description: > + GPIO pin number to control CSD signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_CPS: + description: > + GPIO pin number to control CPS signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_CHL: + description: > + GPIO pin number to control CHL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_SEL: + description: > + GPIO pin number to control SEL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_TX_HP_MODE: + description: > + Enables high-power mode for TX. + Only valid if CHL signal is controller by driver. + value: 0 + SKY66112_TX_BYPASS: + description: > + Enables bypass for TX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66112_RX_BYPASS: + description: > + Enables bypass for RX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + +syscfg.vals.!BLE_LL_PA: + # Enable TX bypass by default if PA is disabled + SKY66112_TX_BYPASS: 1 + +syscfg.vals.!BLE_LL_LNA: + # Enable RX bypass by default if LNA is disabled + SKY66112_RX_BYPASS: 1 diff --git a/nimble/host/include/host/ble_att.h b/nimble/host/include/host/ble_att.h index 391a992aeb..1427b3b33d 100644 --- a/nimble/host/include/host/ble_att.h +++ b/nimble/host/include/host/ble_att.h @@ -38,6 +38,7 @@ struct os_mbuf; #define BLE_ATT_UUID_SECONDARY_SERVICE 0x2801 #define BLE_ATT_UUID_INCLUDE 0x2802 #define BLE_ATT_UUID_CHARACTERISTIC 0x2803 +#define BLE_ATT_UUID_DESCRIPTOR 0x2902 #define BLE_ATT_ERR_INVALID_HANDLE 0x01 #define BLE_ATT_ERR_READ_NOT_PERMITTED 0x02 diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index ec795f0e21..63ae900da5 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -1160,7 +1160,19 @@ struct ble_gap_ext_adv_params { /** If perform high-duty directed advertising */ unsigned int high_duty_directed:1; - /** If use legacy PDUs for advertising */ + /** If use legacy PDUs for advertising. + * + * Valid combinations of the connectable, scannable, directed, + * high_duty_directed options with the legcy_pdu flag are: + * - IND -> legacy_pdu + connectable + scannable + * - LD_DIR -> legacy_pdu + connectable + directed + * - HD_DIR -> legacy_pdu + connectable + directed + high_duty_directed + * - SCAN -> legacy_pdu + scannable + * - NONCONN -> legacy_pdu + * + * Any other combination of these options combined with the legacy_pdu flag + * are invalid. + */ unsigned int legacy_pdu:1; /** If perform anonymous advertising */ @@ -1314,6 +1326,18 @@ int ble_gap_ext_adv_remove(uint8_t instance); * other error code on failure. */ int ble_gap_ext_adv_clear(void); + +/** + * Indicates whether an advertisement procedure is currently in progress on + * the specified Instance + * + * @param instance Instance Id + * + * @return 0 if there is no active advertising procedure for the instance, + * 1 otherwise + * + */ +int ble_gap_ext_adv_active(uint8_t instance); #endif /* Periodic Advertising */ @@ -1592,6 +1616,16 @@ int ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, * its last Scan Duration until it begins the * subsequent Scan Duration. Specify 0 to scan * continuously. Units are 1.28 second. + * @param filter_duplicates Set to enable packet filtering in the + * controller + * @param filter_policy Set the used filter policy. Valid values are: + * - BLE_HCI_SCAN_FILT_NO_WL + * - BLE_HCI_SCAN_FILT_USE_WL + * - BLE_HCI_SCAN_FILT_NO_WL_INITA + * - BLE_HCI_SCAN_FILT_USE_WL_INITA + * - BLE_HCI_SCAN_FILT_MAX + * This parameter is ignored unless + * @p filter_duplicates is set. * @param limited If limited discovery procedure should be used. * @param uncoded_params Additional arguments specifying the particulars * of the discovery procedure for uncoded PHY. diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index b06344fc2e..77028ce46d 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -894,3 +894,5 @@ int ble_gatts_start(void); */ #endif + +int ble_compute_db_hash(uint8_t db_hash[16]); \ No newline at end of file diff --git a/nimble/host/include/host/ble_store.h b/nimble/host/include/host/ble_store.h index 30a5666cfe..1f8a35cf9c 100644 --- a/nimble/host/include/host/ble_store.h +++ b/nimble/host/include/host/ble_store.h @@ -30,6 +30,7 @@ extern "C" { #define BLE_STORE_OBJ_TYPE_OUR_SEC 1 #define BLE_STORE_OBJ_TYPE_PEER_SEC 2 #define BLE_STORE_OBJ_TYPE_CCCD 3 +#define BLE_STORE_OBJ_TYPE_HASH 4 /** Failed to persist record; insufficient storage capacity. */ #define BLE_STORE_EVENT_OVERFLOW 1 @@ -120,6 +121,30 @@ struct ble_store_value_cccd { unsigned value_changed:1; }; +/** + * Used as a key for lookups of stored database hashes. + * This struct corresponds to the BLE_STORE_OBJ_TYPE_HASH store object type. + */ +struct ble_store_key_hash { + /** + * Key by peer identity address; + * peer_addr=BLE_ADDR_NONE means don't key off peer. + */ + ble_addr_t peer_addr; + + /** Number of results to skip; 0 means retrieve the first match. */ + uint8_t idx; +}; + +/** + * Represents the last stored server database hash for a paired client device. + * This struct corresponds to the BLE_STORE_OBJ_TYPE_HASH store object type. + */ +struct ble_store_value_hash{ + ble_addr_t peer_addr; + uint8_t db_hash[16]; +}; + /** * Used as a key for store lookups. This union must be accompanied by an * object type code to indicate which field is valid. @@ -127,6 +152,7 @@ struct ble_store_value_cccd { union ble_store_key { struct ble_store_key_sec sec; struct ble_store_key_cccd cccd; + struct ble_store_key_hash hash; }; /** @@ -136,6 +162,7 @@ union ble_store_key { union ble_store_value { struct ble_store_value_sec sec; struct ble_store_value_cccd cccd; + struct ble_store_value_hash hash; }; struct ble_store_status_event { @@ -266,10 +293,18 @@ int ble_store_read_cccd(const struct ble_store_key_cccd *key, int ble_store_write_cccd(const struct ble_store_value_cccd *value); int ble_store_delete_cccd(const struct ble_store_key_cccd *key); +int ble_store_read_hash(uint16_t conn_handle, + const struct ble_store_key_hash *key, + struct ble_store_value_hash *out_value); +int ble_store_write_hash(const struct ble_store_value_hash *value); +int ble_store_delete_hash(const struct ble_store_key_hash *key); + void ble_store_key_from_value_sec(struct ble_store_key_sec *out_key, const struct ble_store_value_sec *value); void ble_store_key_from_value_cccd(struct ble_store_key_cccd *out_key, const struct ble_store_value_cccd *value); +void ble_store_key_from_value_hash(struct ble_store_key_hash *out_key, + const struct ble_store_value_hash *value); void ble_store_key_from_value(int obj_type, union ble_store_key *out_key, diff --git a/nimble/host/mesh/include/mesh/access.h b/nimble/host/mesh/include/mesh/access.h index 9f923cb9e4..f552b584c2 100644 --- a/nimble/host/mesh/include/mesh/access.h +++ b/nimble/host/mesh/include/mesh/access.h @@ -10,6 +10,9 @@ #ifndef __BT_MESH_ACCESS_H #define __BT_MESH_ACCESS_H +#include "msg.h" +#include + /** * @brief Bluetooth Mesh Access Layer * @defgroup bt_mesh_access Bluetooth Mesh Access Layer @@ -138,50 +141,33 @@ struct bt_mesh_elem { #define BT_MESH_MODEL_ID_LIGHT_LC_SETUPSRV 0x1310 #define BT_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 -/** Message sending context. */ -struct bt_mesh_msg_ctx { - /** NetKey Index of the subnet to send the message on. */ - uint16_t net_idx; - - /** AppKey Index to encrypt the message with. */ - uint16_t app_idx; - - /** Remote address. */ - uint16_t addr; - - /** Destination address of a received message. Not used for sending. */ - uint16_t recv_dst; - - /** RSSI of received packet. Not used for sending. */ - int8_t recv_rssi; - - /** Received TTL value. Not used for sending. */ - uint8_t recv_ttl; - - /** Force sending reliably by using segment acknowledgement */ - bool send_rel; - - /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ - uint8_t send_ttl; -}; - struct bt_mesh_model_op { /* OpCode encoded using the BT_MESH_MODEL_OP_* macros */ const uint32_t opcode; - /* Minimum required message length */ - const size_t min_len; + /** Message length. If the message has variable length then this value + * indicates minimum message length and should be positive. Handler + * function should verify precise length based on the contents of the + * message. If the message has fixed length then this value should + * be negative. Use BT_MESH_LEN_* macros when defining this value. + */ + const ssize_t len; /* Message handler for the opcode */ - void (*const func)(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf); + int (*const func)(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf); }; #define BT_MESH_MODEL_OP_1(b0) (b0) #define BT_MESH_MODEL_OP_2(b0, b1) (((b0) << 8) | (b1)) #define BT_MESH_MODEL_OP_3(b0, cid) ((((b0) << 16) | 0xc00000) | (cid)) +/** Macro for encoding exact message length for fixed-length messages. */ +#define BT_MESH_LEN_EXACT(len) (-len) +/** Macro for encoding minimum message length for variable-length messages. */ +#define BT_MESH_LEN_MIN(len) (len) + #define BT_MESH_MODEL_OP_END { 0, 0, NULL } #define BT_MESH_MODEL_NO_OPS ((struct bt_mesh_model_op []) \ { BT_MESH_MODEL_OP_END }) @@ -189,55 +175,6 @@ struct bt_mesh_model_op { /** Helper to define an empty model array */ #define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){}) -/** Length of a short Mesh MIC. */ -#define BT_MESH_MIC_SHORT 4 -/** Length of a long Mesh MIC. */ -#define BT_MESH_MIC_LONG 8 - -/** @def BT_MESH_MODEL_OP_LEN - * - * @brief Helper to determine the length of an opcode. - * - * @param _op Opcode. - */ -#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) - -/** @def BT_MESH_MODEL_BUF_LEN - * - * @brief Helper for model message buffer length. - * - * Returns the length of a Mesh model message buffer, including the opcode - * length and a short MIC. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model payload. - */ -#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \ - (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT) - -/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC - * - * @brief Helper for model message buffer length. - * - * Returns the length of a Mesh model message buffer, including the opcode - * length and a long MIC. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model payload. - */ -#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \ - (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG) - -/** @def BT_MESH_MODEL_BUF_DEFINE - * - * @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model message payload. - */ -#define BT_MESH_MODEL_BUF(_op, _payload_len) \ - NET_BUF_SIMPLE(BT_MESH_MODEL_BUF_LEN(_op, (_payload_len))) - /** @def BT_MESH_MODEL_CB * * @brief Composition data SIG model entry with callback functions. @@ -384,17 +321,17 @@ struct bt_mesh_model_pub { /** The model the context belongs to. Initialized by the stack. */ struct bt_mesh_model *mod; - uint16_t addr; /**< Publish Address. */ - uint16_t key; /**< Publish AppKey Index. */ + uint16_t addr; /**< Publish Address. */ + uint16_t key:12, /**< Publish AppKey Index. */ + cred:1, /**< Friendship Credentials Flag. */ + send_rel:1, /**< Force reliable sending (segment acks) */ + fast_period:1; /**< Use FastPeriodDivisor */ uint8_t ttl; /**< Publish Time to Live. */ uint8_t retransmit; /**< Retransmit Count & Interval Steps. */ uint8_t period; /**< Publish Period. */ uint8_t period_div:4, /**< Divisor for the Period. */ - cred:1, /**< Friendship Credentials Flag. */ - send_rel:1, - fast_period:1,/**< Use FastPeriodDivisor */ - count:3; /**< Retransmissions left. */ + count:4; uint32_t period_start; /**< Start of the current period. */ @@ -436,7 +373,7 @@ struct bt_mesh_model_pub { int (*update)(struct bt_mesh_model *mod); /** Publish Period Timer. Only for stack-internal use. */ - struct k_delayed_work timer; + struct k_work_delayable timer; }; /** Model callback functions. */ @@ -495,14 +432,19 @@ struct bt_mesh_model_cb { void (*const reset)(struct bt_mesh_model *model); }; +/** Vendor model ID */ +struct bt_mesh_mod_id_vnd { + /** Vendor's company ID */ + uint16_t company; + /** Model ID */ + uint16_t id; +}; + /** Abstraction that describes a Mesh Model instance */ struct bt_mesh_model { union { const uint16_t id; - struct { - uint16_t company; - uint16_t id; - } vnd; + const struct bt_mesh_mod_id_vnd vnd; }; /* Internal information, mainly for persistent storage */ @@ -525,11 +467,10 @@ struct bt_mesh_model { const struct bt_mesh_model_cb * const cb; #if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) - /* Pointer to the next model in a model extension tree. */ + /* Pointer to the next model in a model extension list. */ struct bt_mesh_model *next; - /* Pointer to the first model this model extends. */ - struct bt_mesh_model *extends; #endif + /* Model-specific user data */ void *user_data; }; @@ -539,8 +480,6 @@ struct bt_mesh_send_cb { void (*end)(int err, void *cb_data); }; -void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode); - /** Special TTL value to request using configured default TTL */ #define BT_MESH_TTL_DEFAULT 0xff @@ -625,41 +564,49 @@ static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) /** @brief Immediately store the model's user data in persistent storage. * - * @param mod Mesh model. - * @param vnd This is a vendor model. - * @param name Name/key of the settings item. - * @param data Model data to store, or NULL to delete any model data. + * @param mod Mesh model. + * @param vnd This is a vendor model. + * @param name Name/key of the settings item. Only + * @ref SETTINGS_MAX_DIR_DEPTH bytes will be used at most. + * @param data Model data to store, or NULL to delete any model data. * @param data_len Length of the model data. * * @return 0 on success, or (negative) error code on failure. */ int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, - const char *name, const void *data, size_t data_len); + const char *name, const void *data, + size_t data_len); /** @brief Let a model extend another. * * Mesh models may be extended to reuse their functionality, forming a more * complex model. A Mesh model may extend any number of models, in any element. * The extensions may also be nested, ie a model that extends another may itself - * be extended. Extensions may not be cyclical, and a model can only be extended - * by one other model. + * be extended. * - * A set of models that extend each other form a model extension tree. + * A set of models that extend each other form a model extension list. * - * All models in an extension tree share one subscription list per element. The + * All models in an extension list share one subscription list per element. The * access layer will utilize the combined subscription list of all models in an - * extension tree and element, giving the models extended subscription list + * extension list and element, giving the models extended subscription list * capacity. * - * @param[in] mod Mesh model. - * @param[in] base_mod The model being extended. + * @param extending_mod Mesh model that is extending the base model. + * @param base_mod The model being extended. * * @retval 0 Successfully extended the base_mod model. - * @retval -EALREADY The base_mod model is already extended. */ -int bt_mesh_model_extend(struct bt_mesh_model *mod, +int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod); +/** @brief Check if model is extended by another model. + * + * @param model The model to check. + * + * @retval true If model is extended by another model, otherwise false + */ +bool bt_mesh_model_is_extended(struct bt_mesh_model *model); + /** Node Composition */ struct bt_mesh_comp { uint16_t cid; diff --git a/nimble/host/mesh/include/mesh/cdb.h b/nimble/host/mesh/include/mesh/cdb.h index 8f9a6bc9b9..fa691eb642 100644 --- a/nimble/host/mesh/include/mesh/cdb.h +++ b/nimble/host/mesh/include/mesh/cdb.h @@ -22,7 +22,6 @@ enum { BT_MESH_CDB_NODE_CONFIGURED, - BT_MESH_CDB_NODE_BLACKLISTED, BT_MESH_CDB_NODE_FLAG_COUNT }; @@ -40,7 +39,6 @@ struct bt_mesh_cdb_node { struct bt_mesh_cdb_subnet { uint16_t net_idx; - bool kr_flag; uint8_t kr_phase; struct { @@ -264,4 +262,4 @@ struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx); */ void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key); -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_ */ \ No newline at end of file +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_ */ diff --git a/nimble/host/mesh/include/mesh/cfg.h b/nimble/host/mesh/include/mesh/cfg.h index 378f0a0aa7..422ef3e661 100644 --- a/nimble/host/mesh/include/mesh/cfg.h +++ b/nimble/host/mesh/include/mesh/cfg.h @@ -35,6 +35,12 @@ enum bt_mesh_feat_state { BT_MESH_FEATURE_NOT_SUPPORTED, }; +/* Key Refresh Phase */ +#define BT_MESH_KR_NORMAL 0x00 +#define BT_MESH_KR_PHASE_1 0x01 +#define BT_MESH_KR_PHASE_2 0x02 +#define BT_MESH_KR_PHASE_3 0x03 + /* Legacy feature defines */ #define BT_MESH_RELAY_DISABLED BT_MESH_FEATURE_DISABLED #define BT_MESH_RELAY_ENABLED BT_MESH_FEATURE_ENABLED @@ -482,4 +488,4 @@ ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, * @} */ -#endif /* _BT_MESH_CFG_H_ */ \ No newline at end of file +#endif /* _BT_MESH_CFG_H_ */ diff --git a/nimble/host/mesh/include/mesh/cfg_cli.h b/nimble/host/mesh/include/mesh/cfg_cli.h index bd2f9fe5bb..86716f3162 100644 --- a/nimble/host/mesh/include/mesh/cfg_cli.h +++ b/nimble/host/mesh/include/mesh/cfg_cli.h @@ -24,10 +24,7 @@ extern "C" { /** Mesh Configuration Client Model Context */ struct bt_mesh_cfg_cli { struct bt_mesh_model *model; - - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; + struct bt_mesh_msg_ack_ctx ack_ctx; }; extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; @@ -40,10 +37,16 @@ extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb; int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status); int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, - uint8_t *status, struct os_mbuf *comp); + uint8_t *rsp, struct os_mbuf *comp); int bt_mesh_cfg_beacon_get(uint16_t net_idx, uint16_t addr, uint8_t *status); +int bt_mesh_cfg_krp_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, + uint8_t *status, uint8_t *phase); + +int bt_mesh_cfg_krp_set(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, + uint8_t transition, uint8_t *status, uint8_t *phase); + int bt_mesh_cfg_beacon_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status); int bt_mesh_cfg_ttl_get(uint16_t net_idx, uint16_t addr, uint8_t *ttl); @@ -156,7 +159,8 @@ int bt_mesh_cfg_mod_app_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a #define BT_MESH_PUB_PERIOD_10MIN(steps) (((steps) & BIT_MASK(6)) | (3 << 6)) struct bt_mesh_cfg_mod_pub { - uint16_t addr; + uint16_t addr; + const uint8_t *uuid; uint16_t app_idx; bool cred_flag; uint8_t ttl; @@ -265,9 +269,72 @@ int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_cfg_hb_pub *pub, uint8_t *status); +int bt_mesh_cfg_mod_sub_del_all(uint16_t net_idx, uint16_t addr, + uint16_t elem_addr, uint16_t mod_id, + uint8_t *status); + +int bt_mesh_cfg_mod_sub_del_all_vnd(uint16_t net_idx, uint16_t addr, + uint16_t elem_addr, uint16_t mod_id, + uint16_t cid, uint8_t *status); + +int bt_mesh_cfg_net_key_update(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, const uint8_t net_key[16], + uint8_t *status); + +int bt_mesh_cfg_app_key_update(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint16_t key_app_idx, + const uint8_t app_key[16], uint8_t *status); + +int bt_mesh_cfg_node_identity_set(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint8_t new_identity, + uint8_t *status, uint8_t *identity); + +int bt_mesh_cfg_node_identity_get(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint8_t *status, + uint8_t *identity); + +int bt_mesh_cfg_lpn_timeout_get(uint16_t net_idx, uint16_t addr, + uint16_t unicast_addr, int32_t *polltimeout); + int32_t bt_mesh_cfg_cli_timeout_get(void); void bt_mesh_cfg_cli_timeout_set(int32_t timeout); +struct bt_mesh_comp_p0 { + /** Company ID */ + uint16_t cid; + /** Product ID */ + uint16_t pid; + /** Version ID */ + uint16_t vid; + /** Replay protection list size */ + uint16_t crpl; + /** Supported features, see @ref BT_MESH_FEAT_SUPPORTED. */ + uint16_t feat; + + struct os_mbuf *_buf; +}; + +struct bt_mesh_comp_p0_elem { + /** Element location */ + uint16_t loc; + /** The number of SIG models in this element */ + size_t nsig; + /** The number of vendor models in this element */ + size_t nvnd; + + uint8_t *_buf; +}; + +int bt_mesh_comp_p0_get(struct bt_mesh_comp_p0 *comp, + struct os_mbuf *buf); + +struct bt_mesh_comp_p0_elem *bt_mesh_comp_p0_elem_pull(const struct bt_mesh_comp_p0 *comp, + struct bt_mesh_comp_p0_elem *elem); + +uint16_t bt_mesh_comp_p0_elem_mod(struct bt_mesh_comp_p0_elem *elem, int idx); + +struct bt_mesh_mod_id_vnd bt_mesh_comp_p0_elem_mod_vnd(struct bt_mesh_comp_p0_elem *elem, int idx); + #ifdef __cplusplus } #endif diff --git a/nimble/host/mesh/include/mesh/glue.h b/nimble/host/mesh/include/mesh/glue.h index 8c9166c259..58e3e2d8de 100644 --- a/nimble/host/mesh/include/mesh/glue.h +++ b/nimble/host/mesh/include/mesh/glue.h @@ -51,6 +51,19 @@ extern "C" { #endif +#define SETTINGS_MAX_DIR_DEPTH 8 /* max depth of settings tree */ + +/** Key size used in Bluetooth's ECC domain. */ +#define BT_ECC_KEY_SIZE 32 + /** Length of a Bluetooth ECC public key coordinate. */ +#define BT_PUB_KEY_COORD_LEN (BT_ECC_KEY_SIZE) + /** Length of a Bluetooth ECC public key. */ +#define BT_PUB_KEY_LEN (2 * (BT_PUB_KEY_COORD_LEN)) + /** Length of a Bluetooth ECC private key. */ +#define BT_PRIV_KEY_LEN (BT_ECC_KEY_SIZE) + /** Length of a Bluetooth Diffie-Hellman key. */ +#define BT_DH_KEY_LEN (BT_ECC_KEY_SIZE) + /** @brief Helper to declare elements of bt_data arrays * * This macro is mainly for creating an array of struct bt_data @@ -144,6 +157,10 @@ extern "C" { #define ASSERT_NOT_CHAIN(om) (void)(om) #endif +#define CHECKIF(expr) \ + __ASSERT_NO_MSG(!(expr)); \ + if (0) + #define __packed __attribute__((__packed__)) #define MSEC_PER_SEC (1000) @@ -241,11 +258,18 @@ static inline void net_buf_simple_reset(struct os_mbuf *om) net_buf_simple_init(om, 0); } +struct bt_le_ext_adv_start_param { + uint16_t timeout; + + uint8_t num_events; +}; + void net_buf_put(struct ble_npl_eventq *fifo, struct os_mbuf *buf); void * net_buf_ref(struct os_mbuf *om); void net_buf_unref(struct os_mbuf *om); uint16_t net_buf_simple_pull_le16(struct os_mbuf *om); uint16_t net_buf_simple_pull_be16(struct os_mbuf *om); +uint32_t net_buf_simple_pull_le24(struct os_mbuf *om); uint32_t net_buf_simple_pull_be32(struct os_mbuf *om); uint32_t net_buf_simple_pull_le32(struct os_mbuf *om); uint8_t net_buf_simple_pull_u8(struct os_mbuf *om); @@ -305,15 +329,84 @@ struct bt_pub_key_cb { * * @param key The local public key, or NULL in case of no key. */ - void (*func)(const uint8_t key[64]); + void (*func)(const uint8_t key[BT_PUB_KEY_LEN]); struct bt_pub_key_cb *_next; }; -typedef void (*bt_dh_key_cb_t)(const uint8_t key[32]); -int bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb); +/** LE Advertising Parameters. */ +struct bt_le_adv_param { + /** + * @brief Local identity. + * + * @note When extended advertising @kconfig{CONFIG_BT_EXT_ADV} is not + * enabled or not supported by the controller it is not possible + * to scan and advertise simultaneously using two different + * random addresses. + */ + uint8_t id; + + /** + * @brief Advertising Set Identifier, valid range 0x00 - 0x0f. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + **/ + uint8_t sid; + + /** + * @brief Secondary channel maximum skip count. + * + * Maximum advertising events the advertiser can skip before it must + * send advertising data on the secondary advertising channel. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + */ + uint8_t secondary_max_skip; + + /** Bit-field of advertising options */ + uint32_t options; + + /** Minimum Advertising Interval (N * 0.625 milliseconds) + * Minimum Advertising Interval shall be less than or equal to the + * Maximum Advertising Interval. The Minimum Advertising Interval and + * Maximum Advertising Interval should not be the same value (as stated + * in Bluetooth Core Spec 5.2, section 7.8.5) + * Range: 0x0020 to 0x4000 + */ + uint32_t interval_min; + + /** Maximum Advertising Interval (N * 0.625 milliseconds) + * Minimum Advertising Interval shall be less than or equal to the + * Maximum Advertising Interval. The Minimum Advertising Interval and + * Maximum Advertising Interval should not be the same value (as stated + * in Bluetooth Core Spec 5.2, section 7.8.5) + * Range: 0x0020 to 0x4000 + */ + uint32_t interval_max; + + /** + * @brief Directed advertising to peer + * + * When this parameter is set the advertiser will send directed + * advertising to the remote device. + * + * The advertising type will either be high duty cycle, or low duty + * cycle if the BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY option is enabled. + * When using @ref BT_LE_ADV_OPT_EXT_ADV then only low duty cycle is + * allowed. + * + * In case of connectable high duty cycle if the connection could not + * be established within the timeout the connected() callback will be + * called with the status set to @ref BT_HCI_ERR_ADV_TIMEOUT. + */ + const bt_addr_le_t *peer; +}; + +typedef void (*bt_dh_key_cb_t)(const uint8_t key[BT_DH_KEY_LEN]); +int bt_dh_key_gen(const uint8_t remote_pk[BT_PUB_KEY_LEN], bt_dh_key_cb_t cb); int bt_pub_key_gen(struct bt_pub_key_cb *new_cb); uint8_t *bt_pub_key_get(void); +void bt_conn_get_info(struct ble_hs_conn *conn, struct ble_gap_conn_desc *desc); int bt_rand(void *buf, size_t len); const char * bt_hex(const void *buf, size_t len); int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data); @@ -327,24 +420,28 @@ void bt_mesh_register_gatt(void); int bt_le_adv_start(const struct ble_gap_adv_params *param, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len); -int bt_le_adv_stop(bool proxy); -struct k_delayed_work { +int bt_le_adv_stop(); + +struct k_work_delayable { struct ble_npl_callout work; }; void k_work_init(struct ble_npl_callout *work, ble_npl_event_fn handler); -void k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f); -void k_delayed_work_cancel(struct k_delayed_work *w); -bool k_delayed_work_pending(struct k_delayed_work *w); -void k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms); +void k_work_init_delayable(struct k_work_delayable *w, ble_npl_event_fn *f); +void k_work_cancel_delayable(struct k_work_delayable *w); +bool k_work_delayable_is_pending(struct k_work_delayable *w); +void k_work_reschedule(struct k_work_delayable *w, uint32_t ms); int64_t k_uptime_get(void); uint32_t k_uptime_get_32(void); +int64_t k_uptime_delta(int64_t *reftime); void k_sleep(int32_t duration); void k_work_submit(struct ble_npl_callout *w); void k_work_add_arg(struct ble_npl_callout *w, void *arg); -void k_delayed_work_add_arg(struct k_delayed_work *w, void *arg); -uint32_t k_delayed_work_remaining_get(struct k_delayed_work *w); +void k_work_add_arg_delayable(struct k_work_delayable *w, void *arg); +ble_npl_time_t k_work_delayable_remaining_get(struct k_work_delayable *w); +void k_work_schedule(struct k_work_delayable *w, uint32_t ms); +uint32_t k_ticks_to_ms_floor32(ble_npl_time_t ticks); static inline void net_buf_simple_save(struct os_mbuf *buf, struct net_buf_simple_state *state) @@ -353,6 +450,8 @@ static inline void net_buf_simple_save(struct os_mbuf *buf, state->len = buf->om_len; } +void net_buf_simple_clone(const struct os_mbuf *original, struct os_mbuf *clone); + static inline void net_buf_simple_restore(struct os_mbuf *buf, struct net_buf_simple_state *state) { @@ -405,13 +504,15 @@ static inline unsigned int find_msb_set(uint32_t op) #define CONFIG_BT_MESH_PROVISIONER BLE_MESH_PROVISIONER #define CONFIG_BT_MESH_PROV_DEVICE BLE_MESH_PROV_DEVICE #define CONFIG_BT_MESH_CDB BLE_MESH_CDB +#define CONFIG_BT_MESH_DEBUG_CFG BLE_MESH_DEBUG_CFG +#define CONFIG_BT_MESH_DEBUG_ADV BLE_MESH_DEBUG_ADV /* Above flags are used with IS_ENABLED macro */ #define IS_ENABLED(config) MYNEWT_VAL(config) #define CONFIG_BT_MESH_LPN_GROUPS MYNEWT_VAL(BLE_MESH_LPN_GROUPS) #define CONFIG_BT_MESH_ADV_BUF_COUNT MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT) -#define CONFIG_BT_MESH_SEG_BUFS MYNEWT_VAL(BLE_MESH_SEG_BUFS ) +#define CONFIG_BT_MESH_SEG_BUFS MYNEWT_VAL(BLE_MESH_SEG_BUFS) #define CONFIG_BT_MESH_FRIEND_QUEUE_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE) #define CONFIG_BT_MESH_FRIEND_RECV_WIN MYNEWT_VAL(BLE_MESH_FRIEND_RECV_WIN) #define CONFIG_BT_MESH_LPN_POLL_TIMEOUT MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT) @@ -424,6 +525,7 @@ static inline unsigned int find_msb_set(uint32_t op) #define CONFIG_BT_MESH_APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT) #define CONFIG_BT_MESH_SUBNET_COUNT MYNEWT_VAL(BLE_MESH_SUBNET_COUNT) #define CONFIG_BT_MESH_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_STORE_TIMEOUT) +#define CONFIG_BT_MESH_IV_UPDATE_SEQ_LIMIT MYNEWT_VAL(BLE_MESH_IV_UPDATE_SEQ_LIMIT) #define CONFIG_BT_MESH_IVU_DIVIDER MYNEWT_VAL(BLE_MESH_IVU_DIVIDER) #define CONFIG_BT_DEVICE_NAME MYNEWT_VAL(BLE_MESH_DEVICE_NAME) #define CONFIG_BT_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX) @@ -431,6 +533,7 @@ static inline unsigned int find_msb_set(uint32_t op) #define CONFIG_BT_MESH_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX) #define CONFIG_BT_MESH_RX_SEG_MSG_COUNT MYNEWT_VAL(BLE_MESH_RX_SEG_MSG_COUNT) #define CONFIG_BT_MESH_LABEL_COUNT MYNEWT_VAL(BLE_MESH_LABEL_COUNT) +#define CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE MYNEWT_VAL(BLE_MESH_MODEL_VND_MSG_CID_FORCE) #define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT) #define CONFIG_BT_GATT_PROXY_ENABLED MYNEWT_VAL(BLE_MESH_GATT_PROXY_ENABLED) #define CONFIG_BT_MESH_DEFAULT_TTL MYNEWT_VAL(BLE_MESH_DEFAULT_TTL) @@ -443,6 +546,7 @@ static inline unsigned int find_msb_set(uint32_t op) #define CONFIG_BT_MESH_RELAY MYNEWT_VAL(BLE_MESH_RELAY) #define CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT MYNEWT_VAL(BLE_MESH_RELAY_RETRANSMIT_COUNT) #define CONFIG_BT_MESH_GATT_PROXY_ENABLED MYNEWT_VAL(BLE_MESH_GATT_PROXY_ENABLED) +#define CONFIG_BT_MESH_PROXY_MSG_LEN MYNEWT_VAL(BLE_MESH_PROXY_MSG_LEN) #define printk console_printf @@ -471,6 +575,10 @@ static inline void k_sem_give(struct k_sem *sem) ble_npl_sem_release(sem); } +static inline void k_sem_reset(struct k_sem *sem) +{ + ble_npl_sem_init(sem, 0); +} /* Helpers to access the storage array, since we don't have access to its * type at this point anymore. */ @@ -525,7 +633,7 @@ settings_load(void) #endif /* MYNEWT_VAL(MYNEWT_VAL_BLE_MESH_SETTINGS) */ -#define BUILD_ASSERT(cond) _Static_assert(cond, "") +#define BUILD_ASSERT(cond, msg) _Static_assert(cond, msg) /* Memory slabs/blocks */ diff --git a/nimble/host/mesh/include/mesh/health_cli.h b/nimble/host/mesh/include/mesh/health_cli.h index e9efe4b1f9..cb14ee6bcd 100644 --- a/nimble/host/mesh/include/mesh/health_cli.h +++ b/nimble/host/mesh/include/mesh/health_cli.h @@ -29,9 +29,7 @@ struct bt_mesh_health_cli { uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count); - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; + struct bt_mesh_msg_ack_ctx ack_ctx; }; extern const struct bt_mesh_model_op bt_mesh_health_cli_op[]; diff --git a/nimble/host/mesh/include/mesh/health_srv.h b/nimble/host/mesh/include/mesh/health_srv.h index ad79e368da..980e757486 100644 --- a/nimble/host/mesh/include/mesh/health_srv.h +++ b/nimble/host/mesh/include/mesh/health_srv.h @@ -65,7 +65,7 @@ struct bt_mesh_health_srv { const struct bt_mesh_health_srv_cb *cb; /* Attention Timer state */ - struct k_delayed_work attn_timer; + struct k_work_delayable attn_timer; }; int bt_mesh_fault_update(struct bt_mesh_elem *elem); diff --git a/nimble/host/mesh/include/mesh/heartbeat.h b/nimble/host/mesh/include/mesh/heartbeat.h index b9990f6fdc..2e4986094d 100644 --- a/nimble/host/mesh/include/mesh/heartbeat.h +++ b/nimble/host/mesh/include/mesh/heartbeat.h @@ -120,4 +120,4 @@ extern struct bt_mesh_hb_cb hb_cb; * @} */ -#endif /* _BLUETOOTH_MESH_HEARTBEAT_H_ */ \ No newline at end of file +#endif /* _BLUETOOTH_MESH_HEARTBEAT_H_ */ diff --git a/nimble/host/mesh/include/mesh/main.h b/nimble/host/mesh/include/mesh/main.h index 2bcb05c830..6e9d2e629d 100644 --- a/nimble/host/mesh/include/mesh/main.h +++ b/nimble/host/mesh/include/mesh/main.h @@ -101,6 +101,23 @@ struct bt_mesh_prov { /** Out of Band information field. */ bt_mesh_prov_oob_info_t oob_info; + /** Pointer to Public Key in big-endian for OOB public key type support. + * + * Remember to enable @option{CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY} + * when initializing this parameter. + * + * Must be used together with @ref bt_mesh_prov::private_key_be. + */ + const uint8_t *public_key_be; + /** Pointer to Private Key in big-endian for OOB public key type support. + * + * Remember to enable @option{CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY} + * when initializing this parameter. + * + * Must be used together with @ref bt_mesh_prov::public_key_be. + */ + const uint8_t *private_key_be; + /** Static OOB value */ const uint8_t *static_val; /** Static OOB value length */ @@ -270,11 +287,11 @@ int bt_mesh_input_number(uint32_t num); /** @brief Provide Device public key. * - * @param public_key Device public key. + * @param public_key Device public key in big-endian. * * @return Zero on success or (negative) error code otherwise. */ -int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]); +int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[BT_PUB_KEY_LEN]); /** @brief Use Input OOB authentication. * @@ -548,6 +565,19 @@ void bt_mesh_lpn_set_cb(void (*cb)(uint16_t friend_addr, bool established)); */ int bt_mesh_friend_terminate(uint16_t lpn_addr); +/** @brief Store pending RPL entry(ies) in the persistent storage. + * + * This API allows the user to store pending RPL entry(ies) in the persistent + * storage without waiting for the timeout. + * + * @note When flash is used as the persistent storage, calling this API too + * frequently may wear it out. + * + * @param addr Address of the node which RPL entry needs to be stored or + * @ref BT_MESH_ADDR_ALL_NODES to store all pending RPL entries. + */ +void bt_mesh_rpl_pending_store(uint16_t addr); + #ifdef __cplusplus } #endif diff --git a/nimble/host/mesh/include/mesh/mesh.h b/nimble/host/mesh/include/mesh/mesh.h index b9bc24fb18..c644d0bb0b 100644 --- a/nimble/host/mesh/include/mesh/mesh.h +++ b/nimble/host/mesh/include/mesh/mesh.h @@ -15,6 +15,7 @@ #include "os/os_mbuf.h" #include "glue.h" +#include "msg.h" #include "access.h" #include "main.h" #include "cfg.h" @@ -27,5 +28,6 @@ #include "cfg.h" #include "heartbeat.h" #include "../src/app_keys.h" +#include "../src/net.h" #endif /* __BT_MESH_H */ diff --git a/nimble/host/mesh/include/mesh/msg.h b/nimble/host/mesh/include/mesh/msg.h new file mode 100644 index 0000000000..e327545b12 --- /dev/null +++ b/nimble/host/mesh/include/mesh/msg.h @@ -0,0 +1,225 @@ +/** @file + * @brief Bluetooth Mesh Message APIs. + */ + +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ + +/** + * @brief Bluetooth Mesh Message API + * @defgroup bt_mesh_msg Bluetooth Mesh Message API + * @ingroup bt_mesh + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Length of a short Mesh MIC. */ +#define BT_MESH_MIC_SHORT 4 +/** Length of a long Mesh MIC. */ +#define BT_MESH_MIC_LONG 8 + +/** @def BT_MESH_MODEL_OP_LEN + * + * @brief Helper to determine the length of an opcode. + * + * @param _op Opcode. + */ +#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) + + +/** @def BT_MESH_MODEL_BUF_LEN + * + * @brief Helper for model message buffer length. + * + * Returns the length of a Mesh model message buffer, including the opcode + * length and a short MIC. + * + * @param _op Opcode of the message. + * @param _payload_len Length of the model payload. + */ +#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \ + (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT) + + +/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC + * + * @brief Helper for model message buffer length. + * + * Returns the length of a Mesh model message buffer, including the opcode + * length and a long MIC. + * + * @param _op Opcode of the message. + * @param _payload_len Length of the model payload. + */ +#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \ + (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG) + + +/** @def BT_MESH_MODEL_BUF_DEFINE + * + * @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE_DEFINE. + * + * @param _buf Buffer name. + * @param _op Opcode of the message. + * @param _payload_len Length of the model message payload. + */ +#define BT_MESH_MODEL_BUF(_op, _payload_len) \ + NET_BUF_SIMPLE(BT_MESH_MODEL_BUF_LEN(_op, (_payload_len))) + + +/** Message sending context. */ +struct bt_mesh_msg_ctx { + /** NetKey Index of the subnet to send the message on. */ + uint16_t net_idx; + + /** AppKey Index to encrypt the message with. */ + uint16_t app_idx; + + /** Remote address. */ + uint16_t addr; + + /** Destination address of a received message. Not used for sending. */ + uint16_t recv_dst; + + /** RSSI of received packet. Not used for sending. */ + int8_t recv_rssi; + + /** Received TTL value. Not used for sending. */ + uint8_t recv_ttl; + + /** Force sending reliably by using segment acknowledgment */ + bool send_rel; + + /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ + uint8_t send_ttl; +}; + +/** @brief Initialize a model message. + * + * Clears the message buffer contents, and encodes the given opcode. + * The message buffer will be ready for filling in payload data. + * + * @param msg Message buffer. + * @param opcode Opcode to encode. + */ +void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode); + +/** + * Acknowledged message context for tracking the status of model messages pending a response. + */ +struct bt_mesh_msg_ack_ctx { + struct k_sem sem; /**< Sync semaphore. */ + uint32_t op; /**< Opcode we're waiting for. */ + uint16_t dst; /**< Address of the node that should respond. */ + void *user_data; /**< User specific parameter. */ +}; + +/** @brief Initialize an acknowledged message context. + * + * Initializes semaphore used for synchronization between @ref bt_mesh_msg_ack_ctx_wait and + * @ref bt_mesh_msg_ack_ctx_rx calls. Call this function before using @ref bt_mesh_msg_ack_ctx. + * + * @param ack Acknowledged message context to initialize. + */ +static inline void bt_mesh_msg_ack_ctx_init(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_init(&ack->sem, 0, 1); +} + +/** @brief Reset the synchronization semaphore in an acknowledged message context. + * + * This function aborts call to @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Acknowledged message context to be reset. + */ +static inline void bt_mesh_msg_ack_ctx_reset(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_reset(&ack->sem); +} + +/** @brief Clear parameters of an acknowledged message context. + * + * This function clears the opcode, remote address and user data set + * by @ref bt_mesh_msg_ack_ctx_prepare. + * + * @param ack Acknowledged message context to be cleared. + */ +void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack); + +/** @brief Prepare an acknowledged message context for the incoming message to wait. + * + * This function sets the opcode, remote address of the incoming message and stores the user data. + * Use this function before calling @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Acknowledged message context to prepare. + * @param op The message OpCode. + * @param dst Destination address of the message. + * @param user_data User data for the acknowledged message context. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t dst, void *user_data); +/** @brief Check if the acknowledged message context is initialized with an opcode. + * + * @param ack Acknowledged message context. + * + * @return true if the acknowledged message context is initialized with an opcode, + * false otherwise. + */ +static inline bool bt_mesh_msg_ack_ctx_busy(struct bt_mesh_msg_ack_ctx *ack) +{ + return (ack->op != 0); +} + +/** @brief Wait for a message acknowledge. + * + * This function blocks execution until @ref bt_mesh_msg_ack_ctx_rx is called or by timeout. + * + * @param ack Acknowledged message context of the message to wait for. + * @param timeout Wait timeout. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, int32_t timeout); + +/** @brief Mark a message as acknowledged. + * + * This function unblocks call to @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Context of a message to be acknowledged. + */ +static inline void bt_mesh_msg_ack_ctx_rx(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_give(&ack->sem); +} + +/** @brief Check if an opcode and address of a message matches the expected one. + * + * @param ack Acknowledged message context to be checked. + * @param op OpCode of the incoming message. + * @param addr Source address of the incoming message. + * @param user_data If not NULL, returns a user data stored in the acknowledged message context + * by @ref bt_mesh_msg_ack_ctx_prepare. + * + * @return true if the incoming message matches the expected one, false otherwise. + */ +bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t addr, void **user_data); + +#ifdef __cplusplus +} +#endif +/** + * @} + */ +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ */ diff --git a/nimble/host/mesh/src/access.c b/nimble/host/mesh/src/access.c index da077182ab..2c07b09478 100644 --- a/nimble/host/mesh/src/access.c +++ b/nimble/host/mesh/src/access.c @@ -10,6 +10,7 @@ #define MESH_LOG_MODULE BLE_MESH_ACCESS_LOG #include +#include #include #include "mesh/mesh.h" @@ -21,12 +22,33 @@ #include "transport.h" #include "access.h" #include "foundation.h" +#include "settings.h" #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) #include "mesh/model_cli.h" #endif +/* bt_mesh_model.flags */ +enum { + BT_MESH_MOD_BIND_PENDING = BIT(0), + BT_MESH_MOD_SUB_PENDING = BIT(1), + BT_MESH_MOD_PUB_PENDING = BIT(2), + BT_MESH_MOD_EXTENDED = BIT(3), +}; + +/* Model publication information for persistent storage. */ +struct mod_pub_val { + uint16_t addr; + uint16_t key; + uint8_t ttl; + uint8_t retransmit; + uint8_t period; + uint8_t period_div:4, + cred:1; +}; + static const struct bt_mesh_comp *dev_comp; static uint16_t dev_primary_addr; +static void (*msg_cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, @@ -127,7 +149,7 @@ static void publish_sent(int err, void *user_data) if (delay) { BT_DBG("Publishing next time in %dms", (int) delay); - k_delayed_work_submit(&mod->pub->timer, delay); + k_work_schedule(&mod->pub->timer, delay); } } @@ -138,6 +160,7 @@ static void publish_start(uint16_t duration, int err, void *user_data) if (err) { BT_ERR("Failed to publish: err %d", err); + publish_sent(err, user_data); return; } @@ -152,7 +175,7 @@ static const struct bt_mesh_send_cb pub_sent_cb = { .end = publish_sent, }; -static int publish_retransmit(struct bt_mesh_model *mod) +static int publish_transmit(struct bt_mesh_model *mod) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct bt_mesh_model_pub *pub = mod->pub; @@ -171,67 +194,68 @@ static int publish_retransmit(struct bt_mesh_model *mod) net_buf_simple_init(sdu, 0); net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len); - pub->count--; - err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod); os_mbuf_free_chain(sdu); return err; } -static void publish_retransmit_end(int err, struct bt_mesh_model_pub *pub) +static int pub_period_start(struct bt_mesh_model_pub *pub) { - /* Cancel all retransmits for this publish attempt */ - pub->count = 0U; - /* Make sure the publish timer gets reset */ - publish_sent(err, pub->mod); + int err; + + pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); + + if (!pub->update) { + return 0; + } + + err = pub->update(pub->mod); + if (err) { + /* Skip this publish attempt. */ + BT_DBG("Update failed, skipping publish (err: %d)", err); + pub->count = 0; + pub->period_start = k_uptime_get_32(); + publish_sent(err, pub->mod); + return err; + } + + return 0; } static void mod_publish(struct ble_npl_event *work) { struct bt_mesh_model_pub *pub = ble_npl_event_get_arg(work); - int32_t period_ms; int err; - BT_DBG(""); + if (pub->addr == BT_MESH_ADDR_UNASSIGNED || + atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { + /* Publication is no longer active, but the cancellation of the + * delayed work failed. Abandon recurring timer. + */ + return; + } - period_ms = bt_mesh_model_pub_period_get(pub->mod); - BT_DBG("period %u ms", (unsigned) period_ms); + BT_DBG(""); if (pub->count) { - err = publish_retransmit(pub->mod); + pub->count--; + } else { + /* First publication in this period */ + err = pub_period_start(pub); if (err) { - BT_ERR("Failed to retransmit (err %d)", err); - - pub->count = 0; - - /* Continue with normal publication */ - if (period_ms) { - k_delayed_work_submit(&pub->timer, period_ms); - } + return; } - - return; } - if (!period_ms) { - return; - } - - __ASSERT_NO_MSG(pub->update != NULL); - - err = pub->update(pub->mod); + err = publish_transmit(pub->mod); if (err) { - /* Cancel this publish attempt. */ - BT_DBG("Update failed, skipping publish (err: %d)", err); - pub->period_start = k_uptime_get_32(); - publish_retransmit_end(err, pub); - return; - } + BT_ERR("Failed to publish (err %d)", err); + if (pub->count == BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit)) { + pub->period_start = k_uptime_get_32(); + } - err = bt_mesh_model_publish(pub->mod); - if (err) { - BT_ERR("Publishing failed (err %d)", err); + publish_sent(err, pub->mod); } } @@ -268,6 +292,30 @@ struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_ } } +#if defined(CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE) +static int bt_mesh_vnd_mod_msg_cid_check(struct bt_mesh_model *mod) +{ + uint16_t cid; + const struct bt_mesh_model_op *op; + + for (op = mod->op; op->func; op++) { + cid = (uint16_t)(op->opcode & 0xffff); + + if (cid == mod->vnd.company) { + continue; + } + + BT_ERR("Invalid vendor model(company:0x%04x" + " id:0x%04x) message opcode 0x%08x", + mod->vnd.company, mod->vnd.id, op->opcode); + + return -EINVAL; + } + + return 0; +} +#endif + static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { @@ -280,8 +328,8 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, if (mod->pub) { mod->pub->mod = mod; - k_delayed_work_init(&mod->pub->timer, mod_publish); - k_delayed_work_add_arg(&mod->pub->timer, mod->pub); + k_work_init_delayable(&mod->pub->timer, mod_publish); + k_work_add_arg_delayable(&mod->pub->timer, mod->pub); } for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { @@ -291,6 +339,13 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, mod->elem_idx = elem - dev_comp->elem; if (vnd) { mod->mod_idx = mod - elem->vnd_models; + + if (CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE) { + *err = bt_mesh_vnd_mod_msg_cid_check(mod); + if (*err) { + return; + } + } } else { mod->mod_idx = mod - elem->models; } @@ -305,7 +360,7 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp) int err; /* There must be at least one element */ - if (!comp->elem_count) { + if (!comp || !comp->elem_count) { return -EINVAL; } @@ -366,8 +421,7 @@ struct find_group_visitor_ctx { uint16_t addr; }; -static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *user_data) +static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod, void *user_data) { struct find_group_visitor_ctx *ctx = user_data; @@ -392,8 +446,7 @@ uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr) .addr = addr, }; - bt_mesh_model_tree_walk(bt_mesh_model_root(*mod), - find_group_mod_visitor, &ctx); + bt_mesh_model_extensions_walk(*mod, find_group_mod_visitor, &ctx); *mod = ctx.mod; return ctx.entry; @@ -431,24 +484,67 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) { uint16_t index; + if (!BT_MESH_ADDR_IS_UNICAST(addr)) { + return NULL; + } + + index = addr - dev_comp->elem[0].addr; + if (index >= dev_comp->elem_count) { + return NULL; + } + + return &dev_comp->elem[index]; +} + +bool bt_mesh_has_addr(uint16_t addr) +{ + uint16_t index; + if (BT_MESH_ADDR_IS_UNICAST(addr)) { - index = (addr - dev_comp->elem[0].addr); - if (index < dev_comp->elem_count) { - return &dev_comp->elem[index]; - } else { - return NULL; - } + return bt_mesh_elem_find(addr) != NULL; + } + + if (MYNEWT_VAL(BLE_MESH_ACCESS_LAYER_MSG) && msg_cb) { + return true; } for (index = 0; index < dev_comp->elem_count; index++) { struct bt_mesh_elem *elem = &dev_comp->elem[index]; if (bt_mesh_elem_find_group(elem, addr)) { - return elem; + return true; } } - return NULL; + return false; +} + +#if MYNEWT_VAL(BLE_MESH_ACCESS_LAYER_MSG) +void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf)) +{ + msg_cb = cb; +} +#endif + +int bt_mesh_msg_send(struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf, uint16_t src_addr, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + struct bt_mesh_net_tx tx = { + .ctx = ctx, + .src = src_addr, + }; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx.ctx->net_idx, + tx.ctx->app_idx, tx.ctx->addr); + BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); + + if (!bt_mesh_is_provisioned()) { + BT_ERR("Local node is not yet provisioned"); + return -EAGAIN; + } + + return bt_mesh_trans_send(&tx, buf, cb, cb_data); } uint8_t bt_mesh_elem_count(void) @@ -456,7 +552,7 @@ uint8_t bt_mesh_elem_count(void) return dev_comp->elem_count; } -static bool model_has_key(struct bt_mesh_model *mod, uint16_t key) +bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key) { int i; @@ -486,15 +582,37 @@ static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst) return mod->elem_idx == 0; } -static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, - uint8_t model_count, uint32_t opcode, - struct bt_mesh_model **model) +static const struct bt_mesh_model_op *find_op(struct bt_mesh_elem *elem, + uint32_t opcode, struct bt_mesh_model **model) { uint8_t i; + uint8_t count; + /* This value shall not be used in shipping end products. */ + uint32_t cid = UINT32_MAX; + struct bt_mesh_model *models; - for (i = 0; i < model_count; i++) { + /* SIG models cannot contain 3-byte (vendor) OpCodes, and + * vendor models cannot contain SIG (1- or 2-byte) OpCodes, so + * we only need to do the lookup in one of the model lists. + */ + if (BT_MESH_MODEL_OP_LEN(opcode) < 3) { + models = elem->models; + count = elem->model_count; + } else { + models = elem->vnd_models; + count = elem->vnd_model_count; + + cid = (uint16_t)(opcode & 0xffff); + } + + for (i = 0U; i < count; i++) { const struct bt_mesh_model_op *op; + if (CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE && + cid != UINT32_MAX && + cid != models[i].vnd.company) { + continue; + } *model = &models[i]; for (op = (*model)->op; op->func; op++) { @@ -548,10 +666,9 @@ static int get_opcode(struct os_mbuf *buf, uint32_t *opcode) void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) { - struct bt_mesh_model *models, *model; + struct bt_mesh_model *model; const struct bt_mesh_model_op *op; uint32_t opcode; - uint8_t count; int i; BT_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx, @@ -566,28 +683,16 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) BT_DBG("OpCode 0x%08x", (unsigned) opcode); for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; struct net_buf_simple_state state; - /* SIG models cannot contain 3-byte (vendor) OpCodes, and - * vendor models cannot contain SIG (1- or 2-byte) OpCodes, so - * we only need to do the lookup in one of the model lists. - */ - if (BT_MESH_MODEL_OP_LEN(opcode) < 3) { - models = elem->models; - count = elem->model_count; - } else { - models = elem->vnd_models; - count = elem->vnd_model_count; - } + op = find_op(&dev_comp->elem[i], opcode, &model); - op = find_op(models, count, opcode, &model); if (!op) { BT_DBG("No OpCode 0x%08x for elem %d", opcode, i); continue; } - if (!model_has_key(model, rx->ctx.app_idx)) { + if (!bt_mesh_model_has_key(model, rx->ctx.app_idx)) { continue; } @@ -595,9 +700,13 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) continue; } - if (buf->om_len < op->min_len) { + if ((op->len >= 0) && (buf->om_len < (size_t)op->len)) { BT_ERR("Too short message for OpCode 0x%08x", opcode); continue; + } else if ((op->len < 0) && (buf->om_len != (size_t)(-op->len))) { + BT_ERR("Invalid message size for OpCode 0x%08x", + opcode); + continue; } /* The callback will likely parse the buffer, so @@ -605,138 +714,64 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) * receive the message. */ net_buf_simple_save(buf, &state); - op->func(model, &rx->ctx, buf); + (void)op->func(model, &rx->ctx, buf); net_buf_simple_restore(buf, &state); } -} -void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode) -{ - net_buf_simple_init(msg, 0); - - switch (BT_MESH_MODEL_OP_LEN(opcode)) { - case 1: - net_buf_simple_add_u8(msg, opcode); - break; - case 2: - net_buf_simple_add_be16(msg, opcode); - break; - case 3: - net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); - /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 - * will declare the opcode in this way. - */ - net_buf_simple_add_le16(msg, opcode & 0xffff); - break; - default: - BT_WARN("Unknown opcode format"); - break; + if (MYNEWT_VAL(BLE_MESH_ACCESS_LAYER_MSG) && msg_cb) { + msg_cb(opcode, &rx->ctx, buf); } } -static int model_send(struct bt_mesh_model *model, - struct bt_mesh_net_tx *tx, bool implicit_bind, - struct os_mbuf *msg, - const struct bt_mesh_send_cb *cb, void *cb_data) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->ctx->net_idx, - tx->ctx->app_idx, tx->ctx->addr); - BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_len)); - - if (!bt_mesh_is_provisioned()) { - BT_ERR("Local node is not yet provisioned"); - return -EAGAIN; - } - - if (net_buf_simple_tailroom(msg) < 4) { - BT_ERR("Not enough tailroom for TransMIC"); - return -EINVAL; - } - - if (msg->om_len > BT_MESH_TX_SDU_MAX - 4) { - BT_ERR("Too big message"); - return -EMSGSIZE; - } - - if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) { - BT_ERR("Model not bound to AppKey 0x%04x", tx->ctx->app_idx); - return -EINVAL; - } - - return bt_mesh_trans_send(tx, msg, cb, cb_data); -} - -int bt_mesh_model_send(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, +int bt_mesh_model_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *msg, const struct bt_mesh_send_cb *cb, void *cb_data) { - struct bt_mesh_net_tx tx = { - .ctx = ctx, - .src = bt_mesh_model_elem(model)->addr, - }; + if (!bt_mesh_model_has_key(model, ctx->app_idx)) { + BT_ERR("Model not bound to AppKey 0x%04x", ctx->app_idx); + return -EINVAL; + } - return model_send(model, &tx, false, msg, cb, cb_data); + return bt_mesh_msg_send(ctx, msg, bt_mesh_model_elem(model)->addr, cb, cb_data); } int bt_mesh_model_publish(struct bt_mesh_model *model) { - struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct bt_mesh_model_pub *pub = model->pub; - struct bt_mesh_msg_ctx ctx = { - .addr = pub->addr, - .send_ttl = pub->ttl, - .send_rel = pub->send_rel, - .app_idx = pub->key, - }; - struct bt_mesh_net_tx tx = { - .ctx = &ctx, - .src = bt_mesh_model_elem(model)->addr, - }; - int err; - - BT_DBG(""); if (!pub) { - err = -ENOTSUP; - goto done; + return -ENOTSUP; } + BT_DBG(""); + if (pub->addr == BT_MESH_ADDR_UNASSIGNED) { - err = -EADDRNOTAVAIL; - goto done; + return -EADDRNOTAVAIL; } - if (pub->msg->om_len + 4 > BT_MESH_TX_SDU_MAX) { + if (!pub->msg || !pub->msg->om_len) { + BT_ERR("No publication message"); + return -EINVAL; + } + + if (pub->msg->om_len + BT_MESH_MIC_SHORT > BT_MESH_TX_SDU_MAX) { BT_ERR("Message does not fit maximum SDU size"); - err = -EMSGSIZE; - goto done; + return -EMSGSIZE; } if (pub->count) { BT_WARN("Clearing publish retransmit timer"); - k_delayed_work_cancel(&pub->timer); } - net_buf_simple_init(sdu, 0); - net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len); - - tx.friend_cred = pub->cred; - - pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); + /* Account for initial transmission */ + pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit) + 1; BT_DBG("Publish Retransmit Count %u Interval %ums", pub->count, BT_MESH_PUB_TRANSMIT_INT(pub->retransmit)); - err = model_send(model, &tx, true, sdu, &pub_sent_cb, model); - if (err) { - publish_retransmit_end(err, pub); - } + k_work_reschedule(&pub->timer, K_NO_WAIT); -done: - os_mbuf_free_chain(sdu); - return err; + return 0; } struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, @@ -773,76 +808,506 @@ const struct bt_mesh_comp *bt_mesh_comp_get(void) return dev_comp; } -struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod) +void bt_mesh_model_extensions_walk(struct bt_mesh_model *model, + enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, + void *user_data), + void *user_data) { -#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS - while (mod->next) { - mod = mod->next; +#ifndef CONFIG_BT_MESH_MODEL_EXTENSIONS + (void)cb(model, user_data); + return; +#else + struct bt_mesh_model *it; + + if (cb(model, user_data) == BT_MESH_WALK_STOP || !model->next) { + return; + } + /* List is circular. Step through all models until we reach the start: */ + for (it = model->next; it != model; it = it->next) { + if (cb(it, user_data) == BT_MESH_WALK_STOP) { + return; + } } #endif - return mod; } -void bt_mesh_model_tree_walk(struct bt_mesh_model *root, - enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, - uint32_t depth, - void *user_data), - void *user_data) +#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) +int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod) { - struct bt_mesh_model *m = root; - int depth = 0; - /* 'skip' is set to true when we ascend from child to parent node. - * In that case, we want to skip calling the callback on the parent - * node and we don't want to descend onto a child node as those - * nodes have already been visited. - */ - bool skip = false; + struct bt_mesh_model *a = extending_mod; + struct bt_mesh_model *b = base_mod; + struct bt_mesh_model *a_next = a->next; + struct bt_mesh_model *b_next = b->next; + struct bt_mesh_model *it; + + base_mod->flags |= BT_MESH_MOD_EXTENDED; + + if (a == b) { + return 0; + } - do { - if (!skip && - cb(m, (uint32_t)depth, user_data) == BT_MESH_WALK_STOP) { + /* Check if a's list contains b */ + for (it = a; (it != NULL) && (it->next != a); it = it->next) { + if (it == b) { + return 0; + } + } + + /* Merge lists */ + if (a_next) { + b->next = a_next; + } else { + b->next = a; + } + + if (b_next) { + a->next = b_next; + } else { + a->next = b; + } + + return 0; +} +#endif + +bool bt_mesh_model_is_extended(struct bt_mesh_model *model) +{ + return model->flags & BT_MESH_MOD_EXTENDED; +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int mod_set_bind(struct bt_mesh_model *mod, char *val) +{ + int len, err, i; + + /* Start with empty array regardless of cleared or set value */ + for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { + mod->keys[i] = BT_MESH_KEY_UNUSED; + } + + if (!val) { + BT_DBG("Cleared bindings for model"); + return 0; + } + + len = sizeof(mod->keys); + err = settings_bytes_from_str(val, mod->keys, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + BT_DBG("Decoded %u bound keys for model", len / sizeof(mod->keys[0])); + return 0; +} + +static int mod_set_sub(struct bt_mesh_model *mod, char *val) +{ + int len, err; + + /* Start with empty array regardless of cleared or set value */ + memset(mod->groups, 0, sizeof(mod->groups)); + + if (!val) { + BT_DBG("Cleared subscriptions for model"); + return 0; + } + + len = sizeof(mod->groups); + err = settings_bytes_from_str(val, mod->groups, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + BT_DBG("Decoded %u subscribed group addresses for model", + len / sizeof(mod->groups[0])); + return 0; +} + +static int mod_set_pub(struct bt_mesh_model *mod, char *val) +{ + struct mod_pub_val pub; + int len, err; + + if (!mod->pub) { + BT_WARN("Model has no publication context!"); + return -EINVAL; + } + + if (!val) { + mod->pub->addr = BT_MESH_ADDR_UNASSIGNED; + mod->pub->key = 0; + mod->pub->cred = 0; + mod->pub->ttl = 0; + mod->pub->period = 0; + mod->pub->retransmit = 0; + mod->pub->period_div = pub.period_div; + mod->pub->count = 0; + + BT_DBG("Cleared publication for model"); + return 0; + } + + len = sizeof(pub); + err = settings_bytes_from_str(val, &pub, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + if (len != sizeof(pub)) { + BT_ERR("Invalid length for model publication"); + return -EINVAL; + } + + mod->pub->addr = pub.addr; + mod->pub->key = pub.key; + mod->pub->cred = pub.cred; + mod->pub->ttl = pub.ttl; + mod->pub->period = pub.period; + mod->pub->retransmit = pub.retransmit; + mod->pub->period_div = pub.period_div; + mod->pub->count = 0; + + BT_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", + pub.addr, pub.key); + + return 0; +} + +static int mod_data_set(struct bt_mesh_model *mod, + char *name, char *len_rd) +{ + char *next; + + settings_name_next(name, &next); + + if (mod->cb && mod->cb->settings_set) { + return mod->cb->settings_set(mod, next, len_rd); + } + + return 0; +} + +static int mod_set(bool vnd, int argc, char **argv, char *val) +{ + struct bt_mesh_model *mod; + uint8_t elem_idx, mod_idx; + uint16_t mod_key; + + if (argc < 2) { + BT_ERR("Too small argc (%d)", argc); + return -ENOENT; + } + + mod_key = strtol(argv[0], NULL, 16); + elem_idx = mod_key >> 8; + mod_idx = mod_key; + + BT_DBG("Decoded mod_key 0x%04x as elem_idx %u mod_idx %u", + mod_key, elem_idx, mod_idx); + + mod = bt_mesh_model_get(vnd, elem_idx, mod_idx); + if (!mod) { + BT_ERR("Failed to get model for elem_idx %u mod_idx %u", + elem_idx, mod_idx); + return -ENOENT; + } + + if (!strcmp(argv[1], "bind")) { + return mod_set_bind(mod, val); + } + + if (!strcmp(argv[1], "sub")) { + return mod_set_sub(mod, val); + } + + if (!strcmp(argv[1], "pub")) { + return mod_set_pub(mod, val); + } + + if (!strcmp(argv[1], "data")) { + return mod_data_set(mod, argv[1], val); + } + + BT_WARN("Unknown module key %s", argv[1]); + return -ENOENT; +} + +static int sig_mod_set(int argc, char **argv, char *val) +{ + return mod_set(false, argc, argv, val); +} + +static int vnd_mod_set(int argc, char **argv, char *val) +{ + return mod_set(true, argc, argv, val); +} + +static void encode_mod_path(struct bt_mesh_model *mod, bool vnd, + const char *key, char *path, size_t path_len) +{ + uint16_t mod_key = (((uint16_t)mod->elem_idx << 8) | mod->mod_idx); + + if (vnd) { + snprintk(path, path_len, "bt_mesh/v/%x/%s", mod_key, key); + } else { + snprintk(path, path_len, "bt_mesh/s/%x/%s", mod_key, key); + } +} + +static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd) +{ + uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT]; + char buf[BT_SETTINGS_SIZE(sizeof(keys))]; + char path[20]; + int i, count, err; + char *val; + + for (i = 0, count = 0; i < ARRAY_SIZE(mod->keys); i++) { + if (mod->keys[i] != BT_MESH_KEY_UNUSED) { + keys[count++] = mod->keys[i]; + BT_DBG("model key 0x%04x", mod->keys[i]); + } + } + + if (count) { + val = settings_str_from_bytes(keys, count * sizeof(keys[0]), + buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model bindings as value"); return; } -#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) - if (!skip && m->extends) { - m = m->extends; - depth++; - } else if (m->flags & BT_MESH_MOD_NEXT_IS_PARENT) { - m = m->next; - depth--; - skip = true; - } else { - m = m->next; - skip = false; + } else { + val = NULL; + } + + encode_mod_path(mod, vnd, "bind", path, sizeof(path)); + + BT_DBG("Saving %s as %s", path, val ? val : "(null)"); + err = settings_save_one(path, val); + if (err) { + BT_ERR("Failed to store bind"); + } else { + BT_DBG("Stored bind"); + } +} + +static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) +{ + uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT]; + char buf[BT_SETTINGS_SIZE(sizeof(groups))]; + char path[20]; + int i, count, err; + char *val; + + for (i = 0, count = 0; i < CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) { + if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { + groups[count++] = mod->groups[i]; + } + } + + if (count) { + val = settings_str_from_bytes(groups, count * sizeof(groups[0]), + buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model subscription as value"); + return; } -#endif - } while (m && depth > 0); + } else { + val = NULL; + } + + encode_mod_path(mod, vnd, "sub", path, sizeof(path)); + + BT_DBG("Saving %s as %s", path, val ? val : "(null)"); + err = settings_save_one(path, val); + if (err) { + BT_ERR("Failed to store sub"); + } else { + BT_DBG("Stored sub"); + } } -#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) -int bt_mesh_model_extend(struct bt_mesh_model *mod, - struct bt_mesh_model *base_mod) -{ - /* Form a cyclical LCRS tree: - * The extends-pointer points to the first child, and the next-pointer - * points to the next sibling. The last sibling is marked by the - * BT_MESH_MOD_NEXT_IS_PARENT flag, and its next-pointer points back to - * the parent. This way, the whole tree is accessible from any node. - * - * We add children (extend them) by inserting them as the first child. - */ - if (base_mod->next) { - return -EALREADY; +static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; + struct mod_pub_val pub; + char path[20]; + char *val; + int err; + + if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + val = NULL; + } else { + pub.addr = mod->pub->addr; + pub.key = mod->pub->key; + pub.ttl = mod->pub->ttl; + pub.retransmit = mod->pub->retransmit; + pub.period = mod->pub->period; + pub.period_div = mod->pub->period_div; + pub.cred = mod->pub->cred; + + val = settings_str_from_bytes(&pub, sizeof(pub), buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model publication as value"); + return; + } } - if (mod->extends) { - base_mod->next = mod->extends; + encode_mod_path(mod, vnd, "pub", path, sizeof(path)); + + BT_DBG("Saving %s as %s", path, val ? val : "(null)"); + err = settings_save_one(path, val); + if (err) { + BT_ERR("Failed to store pub"); } else { - base_mod->next = mod; - base_mod->flags |= BT_MESH_MOD_NEXT_IS_PARENT; + BT_DBG("Stored pub"); } +} - mod->extends = base_mod; - return 0; +static void store_pending_mod(struct bt_mesh_model *mod, + struct bt_mesh_elem *elem, bool vnd, + bool primary, void *user_data) +{ + if (!mod->flags) { + return; + } + + if (mod->flags & BT_MESH_MOD_BIND_PENDING) { + mod->flags &= ~BT_MESH_MOD_BIND_PENDING; + store_pending_mod_bind(mod, vnd); + } + + if (mod->flags & BT_MESH_MOD_SUB_PENDING) { + mod->flags &= ~BT_MESH_MOD_SUB_PENDING; + store_pending_mod_sub(mod, vnd); + } + + if (mod->flags & BT_MESH_MOD_PUB_PENDING) { + mod->flags &= ~BT_MESH_MOD_PUB_PENDING; + store_pending_mod_pub(mod, vnd); + } +} + +void bt_mesh_model_pending_store(void) +{ + bt_mesh_model_foreach(store_pending_mod, NULL); +} + +void bt_mesh_model_bind_store(struct bt_mesh_model *mod) +{ + mod->flags |= BT_MESH_MOD_BIND_PENDING; + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); +} + +void bt_mesh_model_sub_store(struct bt_mesh_model *mod) +{ + mod->flags |= BT_MESH_MOD_SUB_PENDING; + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); +} + +void bt_mesh_model_pub_store(struct bt_mesh_model *mod) +{ + mod->flags |= BT_MESH_MOD_PUB_PENDING; + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); +} + +int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, + const char *name, const void *data, + size_t data_len) +{ + char path[30]; + char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; + char *val; + int err; + + encode_mod_path(mod, vnd, "data", path, sizeof(path)); + if (name) { + strcat(path, "/"); + strncat(path, name, SETTINGS_MAX_DIR_DEPTH); + } + + if (data_len) { + val = settings_str_from_bytes(data, data_len, buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model publication as value"); + return -EINVAL; + } + err = settings_save_one(path, val); + } else { + err = settings_save_one(path, NULL); + } + + if (err) { + BT_ERR("Failed to store %s value", path); + } else { + BT_DBG("Stored %s value", path); + } + return err; } #endif + +static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + if (mod->pub && mod->pub->update && + mod->pub->addr != BT_MESH_ADDR_UNASSIGNED) { + int32_t ms = bt_mesh_model_pub_period_get(mod); + + if (ms > 0) { + BT_DBG("Starting publish timer (period %u ms)", ms); + k_work_schedule(&mod->pub->timer, K_MSEC(ms)); + } + } + + if (!IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { + return; + } + + for (int i = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { + bt_mesh_lpn_group_add(mod->groups[i]); + } + } +} + +void bt_mesh_model_settings_commit(void) +{ + bt_mesh_model_foreach(commit_mod, NULL); +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_sig_mod_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = sig_mod_set, + .ch_commit = NULL, + .ch_export = NULL, +}; + +static struct conf_handler bt_mesh_vnd_mod_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = vnd_mod_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_access_init(void) +{ + #if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_sig_mod_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_access conf"); + rc = conf_register(&bt_mesh_vnd_mod_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_access conf"); + #endif +} diff --git a/nimble/host/mesh/src/access.h b/nimble/host/mesh/src/access.h index affba538f2..217f4abe0f 100644 --- a/nimble/host/mesh/src/access.h +++ b/nimble/host/mesh/src/access.h @@ -11,14 +11,6 @@ #include "mesh/mesh.h" -/* bt_mesh_model.flags */ -enum { - BT_MESH_MOD_BIND_PENDING = BIT(0), - BT_MESH_MOD_SUB_PENDING = BIT(1), - BT_MESH_MOD_PUB_PENDING = BIT(2), - BT_MESH_MOD_NEXT_IS_PARENT = BIT(3), -}; - /* Tree walk return codes */ enum bt_mesh_walk { BT_MESH_WALK_STOP, @@ -29,15 +21,16 @@ void bt_mesh_elem_register(struct bt_mesh_elem *elem, uint8_t count); uint8_t bt_mesh_elem_count(void); -/* Find local element based on unicast or group address */ +/* Find local element based on unicast address */ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); -struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod); -void bt_mesh_model_tree_walk(struct bt_mesh_model *root, - enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, - uint32_t depth, - void *user_data), - void *user_data); +bool bt_mesh_has_addr(uint16_t addr); +bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key); + +void bt_mesh_model_extensions_walk(struct bt_mesh_model *root, + enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, + void *user_data), + void *user_data); uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr); @@ -61,4 +54,35 @@ struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf); int bt_mesh_comp_register(const struct bt_mesh_comp *comp); + +void bt_mesh_model_pending_store(void); +void bt_mesh_model_bind_store(struct bt_mesh_model *mod); +void bt_mesh_model_sub_store(struct bt_mesh_model *mod); +void bt_mesh_model_pub_store(struct bt_mesh_model *mod); +void bt_mesh_model_settings_commit(void); + +/** @brief Register a callback function hook for mesh model messages. + * + * Register a callback function to act as a hook for recieving mesh model layer messages + * directly to the application without having instantiated the relevant models. + * + * @param cb A pointer to the callback function. + */ +void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf)); + +/** @brief Send a mesh model message. + * + * Send a mesh model layer message out into the mesh network without having instantiated + * the relevant mesh models. + * + * @param ctx The Bluetooth mesh message context. + * @param buf The message payload. + * + * @return 0 on success or negative error code on failure. + */ +int bt_mesh_msg_send(struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf, uint16_t src_addr, + const struct bt_mesh_send_cb *cb, void *cb_data); + +void bt_mesh_access_init(void); #endif diff --git a/nimble/host/mesh/src/adv.c b/nimble/host/mesh/src/adv.c index 7e0e1927fa..d7a8c123c9 100644 --- a/nimble/host/mesh/src/adv.c +++ b/nimble/host/mesh/src/adv.c @@ -13,7 +13,6 @@ #include "mesh/mesh.h" #include "host/ble_hs_adv.h" #include "host/ble_gap.h" -#include "nimble/hci_common.h" #include "mesh/porting.h" #include "adv.h" @@ -23,41 +22,26 @@ #include "prov.h" #include "proxy.h" -/* Convert from ms to 0.625ms units */ -#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) - /* Window and Interval are equal for continuous scanning */ -#define MESH_SCAN_INTERVAL_MS 30 -#define MESH_SCAN_WINDOW_MS 30 -#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_MS 100 -#define ADV_INT_FAST_MS 20 +#define MESH_SCAN_INTERVAL BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_INTERVAL_MS) +#define MESH_SCAN_WINDOW BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_WINDOW_MS) -static int32_t adv_int_min = ADV_INT_DEFAULT_MS; +const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES] = { + [BT_MESH_ADV_PROV] = BT_DATA_MESH_PROV, + [BT_MESH_ADV_DATA] = BT_DATA_MESH_MESSAGE, + [BT_MESH_ADV_BEACON] = BT_DATA_MESH_BEACON, + [BT_MESH_ADV_URI] = BT_DATA_URI, +}; -/* TinyCrypt PRNG consumes a lot of stack space, so we need to have - * an increased call stack whenever it's used. - */ -#if MYNEWT -OS_TASK_STACK_DEFINE(g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); -struct os_task adv_task; -#endif - -static struct ble_npl_eventq adv_queue; extern uint8_t g_mesh_addr_type; -static int adv_initialized = false; - -static os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE( - MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE)]; struct os_mbuf_pool adv_os_mbuf_pool; -static struct os_mempool adv_buf_mempool; +struct ble_npl_eventq bt_mesh_adv_queue; + +os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE( + MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE)]; +struct os_mempool adv_buf_mempool; static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT]; @@ -66,143 +50,6 @@ static struct bt_mesh_adv *adv_alloc(int id) return &adv_pool[id]; } -static inline void adv_send_start(uint16_t duration, int err, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->start) { - cb->start(duration, err, cb_data); - } -} - -static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->end) { - cb->end(err, cb_data); - } -} - -static inline void adv_send(struct os_mbuf *buf) -{ - static const uint8_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_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON, - [BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI, -} ; - - const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb; - void *cb_data = BT_MESH_ADV(buf)->cb_data; - struct ble_gap_adv_params param = { 0 }; - uint16_t duration, adv_int; - struct bt_data ad; - int err; - - adv_int = max(adv_int_min, - BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit)); -#if MYNEWT_VAL(BLE_CONTROLLER) - duration = ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10)); -#else - duration = (MESH_SCAN_WINDOW_MS + - ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10))); -#endif - - BT_DBG("type %u om_len %u: %s", BT_MESH_ADV(buf)->type, - buf->om_len, bt_hex(buf->om_data, buf->om_len)); - BT_DBG("count %u interval %ums duration %ums", - BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, - duration); - - ad.type = adv_type[BT_MESH_ADV(buf)->type]; - ad.data_len = buf->om_len; - ad.data = buf->om_data; - - param.itvl_min = ADV_SCAN_UNIT(adv_int); - param.itvl_max = param.itvl_min; - param.conn_mode = BLE_GAP_CONN_MODE_NON; - - err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); - net_buf_unref(buf); - adv_send_start(duration, err, cb, cb_data); - if (err) { - BT_ERR("Advertising failed: err %d", err); - return; - } - - BT_DBG("Advertising started. Sleeping %u ms", duration); - - k_sleep(K_MSEC(duration)); - - err = bt_le_adv_stop(false); - adv_send_end(err, cb, cb_data); - if (err) { - BT_ERR("Stopping advertising failed: err %d", err); - return; - } - - BT_DBG("Advertising stopped"); -} - -void -mesh_adv_thread(void *args) -{ - static struct ble_npl_event *ev; - struct os_mbuf *buf; -#if (MYNEWT_VAL(BLE_MESH_PROXY)) - int32_t timeout; -#endif - - BT_DBG("started"); - - while (1) { -#if (MYNEWT_VAL(BLE_MESH_PROXY)) - ev = ble_npl_eventq_get(&adv_queue, 0); - while (!ev) { - timeout = bt_mesh_proxy_adv_start(); - BT_DBG("Proxy Advertising up to %d ms", (int) timeout); - - // FIXME: should we redefine K_SECONDS macro instead in glue? - if (timeout != K_FOREVER) { - timeout = ble_npl_time_ms_to_ticks32(timeout); - } - - ev = ble_npl_eventq_get(&adv_queue, timeout); - bt_mesh_proxy_adv_stop(); - } -#else - ev = ble_npl_eventq_get(&adv_queue, BLE_NPL_TIME_FOREVER); -#endif - - if (!ev || !ble_npl_event_get_arg(ev)) { - continue; - } - - buf = ble_npl_event_get_arg(ev); - - /* busy == 0 means this was canceled */ - if (BT_MESH_ADV(buf)->busy) { - BT_MESH_ADV(buf)->busy = 0; - adv_send(buf); - } else { - net_buf_unref(buf); - } - - /* os_sched(NULL); */ - } -} - -void bt_mesh_adv_update(void) -{ - static struct ble_npl_event ev = { }; - - BT_DBG(""); - - ble_npl_eventq_put(&adv_queue, &ev); -} - 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, @@ -252,7 +99,8 @@ void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb, BT_MESH_ADV(buf)->cb_data = cb_data; BT_MESH_ADV(buf)->busy = 1; - net_buf_put(&adv_queue, net_buf_ref(buf)); + 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, @@ -306,42 +154,6 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi, } } -void bt_mesh_adv_init(void) -{ - int rc; - - /* Advertising should only be initialized once. Calling - * os_task init the second time will result in an assert. */ - if (adv_initialized) { - return; - } - - rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, - adv_buf_mem, "adv_buf_pool"); - assert(rc == 0); - - rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool, - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, - MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)); - assert(rc == 0); - - ble_npl_eventq_init(&adv_queue); - -#if MYNEWT - os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL, - MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER, - g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); -#endif - - /* 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_MS; - } - - adv_initialized = true; -} - int ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg) { diff --git a/nimble/host/mesh/src/adv.h b/nimble/host/mesh/src/adv.h index 779ee58ed5..aa83a47b86 100644 --- a/nimble/host/mesh/src/adv.h +++ b/nimble/host/mesh/src/adv.h @@ -14,32 +14,59 @@ #define BT_MESH_ADV(om) (*(struct bt_mesh_adv **) OS_MBUF_USRHDR(om)) +#define BT_MESH_ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) +#define BT_MESH_SCAN_INTERVAL_MS 30 +#define BT_MESH_SCAN_WINDOW_MS 30 + #define BT_MESH_ADV_DATA_SIZE 31 /* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ -#define BT_MESH_ADV_USER_DATA_SIZE (sizeof(struct bt_mesh_adv *)) +#define BT_MESH_ADV_USER_DATA_SIZE 4 #define BT_MESH_MBUF_HEADER_SIZE (sizeof(struct os_mbuf_pkthdr) + \ BT_MESH_ADV_USER_DATA_SIZE +\ sizeof(struct os_mbuf)) +/* We declare it as extern here to share it between 'adv' and 'adv_legacy' */ +extern struct os_mbuf_pool adv_os_mbuf_pool; +extern struct ble_npl_eventq bt_mesh_adv_queue; +extern struct os_mempool adv_buf_mempool; +extern os_membuf_t adv_buf_mem[]; + enum bt_mesh_adv_type { BT_MESH_ADV_PROV, BT_MESH_ADV_DATA, BT_MESH_ADV_BEACON, BT_MESH_ADV_URI, + + BT_MESH_ADV_TYPES, }; typedef void (*bt_mesh_adv_func_t)(struct os_mbuf *buf, uint16_t duration, int err, void *user_data); + +static inline void adv_send_start(uint16_t duration, int err, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + if (cb && cb->start) { + cb->start(duration, err, cb_data); + } +} + struct bt_mesh_adv { + /** Fragments associated with this buffer. */ + struct os_mbuf *frags; + const struct bt_mesh_send_cb *cb; void *cb_data; uint8_t type:2, - busy:1; + started:1, + busy:1; + uint8_t xmit; uint8_t flags; @@ -69,6 +96,36 @@ void bt_mesh_adv_init(void); int bt_mesh_scan_enable(void); int bt_mesh_scan_disable(void); +int bt_mesh_adv_enable(void); +void bt_mesh_adv_buf_ready(void); + +int bt_mesh_adv_start(const struct ble_gap_adv_params *param, int32_t duration, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len); + +static inline void bt_mesh_adv_send_start(uint16_t duration, int err, + struct bt_mesh_adv *adv) +{ + if (!adv->started) { + adv->started = 1; + + if (adv->cb && adv->cb->start) { + adv->cb->start(duration, err, adv->cb_data); + } + + if (err) { + adv->cb = NULL; + } + } +} + +static inline void bt_mesh_adv_send_end( + int err, struct bt_mesh_adv const *adv) +{ + if (adv->started && adv->cb && adv->cb->end) { + adv->cb->end(err, adv->cb_data); + } +} int ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg); #endif diff --git a/nimble/host/mesh/src/adv_ext.c b/nimble/host/mesh/src/adv_ext.c new file mode 100644 index 0000000000..07c693dea1 --- /dev/null +++ b/nimble/host/mesh/src/adv_ext.c @@ -0,0 +1,345 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define MESH_LOG_MODULE BLE_MESH_ADV_LOG + + +#include "adv.h" +#include "net.h" +#include "proxy.h" +#include "pb_gatt_srv.h" +#include "syscfg/syscfg.h" +#include "host/ble_gap.h" + +#if MYNEWT_VAL(BLE_MESH_ADV_EXT) +/* Convert from ms to 0.625ms units */ +#define ADV_INT_FAST_MS 20 +#define BT_ID_DEFAULT 0 + +static struct ble_gap_ext_adv_params adv_param = { + .itvl_min = BT_MESH_ADV_SCAN_UNIT(ADV_INT_FAST_MS), + .itvl_max = BT_MESH_ADV_SCAN_UNIT(ADV_INT_FAST_MS), +}; + +bool ext_adv_configured = false; + +enum { + /** Controller is currently advertising */ + ADV_FLAG_ACTIVE, + /** Currently performing proxy advertising */ + ADV_FLAG_PROXY, + /** The send-call has been scheduled. */ + ADV_FLAG_SCHEDULED, + /** Custom adv params have been set, we need to update the parameters on + * the next send. + */ + ADV_FLAG_UPDATE_PARAMS, + + /* Number of adv flags. */ + ADV_FLAGS_NUM +}; + +static struct { + ATOMIC_DEFINE(flags, ADV_FLAGS_NUM); + struct bt_le_ext_adv *instance; + struct os_mbuf *buf; + int64_t timestamp; + struct k_work_delayable work; +} adv; + + +static void schedule_send(void) +{ + int64_t timestamp = adv.timestamp; + int64_t delta; + + if (atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) { + ble_gap_ext_adv_stop(BT_ID_DEFAULT); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + } + + if (atomic_test_bit(adv.flags, ADV_FLAG_ACTIVE) || + atomic_test_and_set_bit(adv.flags, ADV_FLAG_SCHEDULED)) { + return; + } + + /* The controller will send the next advertisement immediately. + * Introduce a delay here to avoid sending the next mesh packet closer + * to the previous packet than what's permitted by the specification. + */ + delta = k_uptime_delta(×tamp); + k_work_reschedule(&adv.work, K_MSEC(ADV_INT_FAST_MS - delta)); +} + +static int +ble_mesh_ext_adv_event_handler(struct ble_gap_event *event, void *arg) +{ + int64_t duration; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + if (atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) { + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + schedule_send(); + } + break; + case BLE_GAP_EVENT_ADV_COMPLETE: + /* Calling k_uptime_delta on a timestamp moves it to the current time. + * This is essential here, as schedule_send() uses the end of the event + * as a reference to avoid sending the next advertisement too soon. + */ + duration = k_uptime_delta(&adv.timestamp); + + BT_DBG("Advertising stopped after %u ms", (uint32_t)duration); + + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + + if (!atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) { + net_buf_unref(adv.buf); + } + + schedule_send(); + break; + default: + return 0; + } + return 0; +} + +static int adv_start(const struct ble_gap_ext_adv_params *param, + uint32_t timeout, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len) +{ + int err; + struct os_mbuf *ad_data; + struct os_mbuf *sd_data; + + ad_data = os_msys_get_pkthdr(BLE_HS_ADV_MAX_SZ, 0); + assert(ad_data); + sd_data = os_msys_get_pkthdr(BLE_HS_ADV_MAX_SZ, 0); + assert(sd_data); + if (!adv.instance) { + BT_ERR("Mesh advertiser not enabled"); + err = -ENODEV; + goto error; + } + + if (atomic_test_and_set_bit(adv.flags, ADV_FLAG_ACTIVE)) { + BT_ERR("Advertiser is busy"); + err = -EBUSY; + goto error; + } + + if (atomic_test_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS)) { + err = ble_gap_ext_adv_configure(BT_ID_DEFAULT, param, NULL, + ble_mesh_ext_adv_event_handler, NULL); + if (err) { + BT_ERR("Failed updating adv params: %d", err); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + goto error; + } + + atomic_set_bit_to(adv.flags, ADV_FLAG_UPDATE_PARAMS, + param != &adv_param); + } + + assert(ad_data); + err = os_mbuf_append(ad_data, ad, ad_len); + if (err) { + goto error; + } + + err = ble_gap_ext_adv_set_data(BT_ID_DEFAULT, ad_data); + if (err) { + BT_ERR("Failed setting adv data: %d", err); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + goto error; + } + + err = os_mbuf_append(sd_data, sd, sd_len); + if (err) { + goto error; + } + err = ble_gap_ext_adv_rsp_set_data(BT_ID_DEFAULT, sd_data); + if (err) { + BT_ERR("Failed setting scan response data: %d", err); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + goto error; + } + + adv.timestamp = k_uptime_get(); + + err = ble_gap_ext_adv_start(BT_ID_DEFAULT, timeout, 0); + if (err) { + BT_ERR("Advertising failed: err %d", err); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + } + +error: + if (ad_data) { + os_mbuf_free_chain(ad_data); + } + + if (sd_data) { + os_mbuf_free_chain(sd_data); + } + return err; +} + +static int buf_send(struct os_mbuf *buf) +{ + static const uint8_t bt_mesh_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_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON, + [BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI, + }; + + struct bt_le_ext_adv_start_param start = { + .num_events = + BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, + }; + uint16_t duration, adv_int; + struct bt_data ad; + int err; + + adv_int = MAX(ADV_INT_FAST_MS, + BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit)); + /* Upper boundary estimate: */ + duration = start.num_events * (adv_int + 10); + + BT_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type, + buf->om_len, bt_hex(buf->om_data, buf->om_len)); + BT_DBG("count %u interval %ums duration %ums", + BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, + duration); + + ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type]; + ad.data_len = buf->om_len; + ad.data = buf->om_data; + + /* Only update advertising parameters if they're different */ + if (adv_param.itvl_min != BT_MESH_ADV_SCAN_UNIT(adv_int)) { + adv_param.itvl_min = BT_MESH_ADV_SCAN_UNIT(adv_int); + adv_param.itvl_max = adv_param.itvl_min; + atomic_set_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS); + } + + err = adv_start(&adv_param, duration, &ad, 1, NULL, 0); + if (!err) { + adv.buf = net_buf_ref(buf); + } + + bt_mesh_adv_send_start(duration, err, BT_MESH_ADV(buf)); + + return err; +} + +static void send_pending_adv(struct ble_npl_event *work) +{ + struct os_mbuf *buf; + int err; + + atomic_clear_bit(adv.flags, ADV_FLAG_SCHEDULED); + + while ((buf = net_buf_get(&bt_mesh_adv_queue, K_NO_WAIT))) { + /* busy == 0 means this was canceled */ + if (!BT_MESH_ADV(buf)->busy) { + net_buf_unref(buf); + continue; + } + + BT_MESH_ADV(buf)->busy = 0U; + err = buf_send(buf); + + net_buf_unref(buf); + + if (!err) { + return; /* Wait for advertising to finish */ + } + } + + if (!MYNEWT_VAL(BLE_MESH_GATT_SERVER)) { + return; + } + + /* No more pending buffers */ + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + err = bt_mesh_proxy_adv_start(); + BT_DBG("Proxy Advertising"); + } + } else if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + err = bt_mesh_pb_gatt_adv_start(); + BT_DBG("PB-GATT Advertising"); + } + + if (!err) { + atomic_set_bit(adv.flags, ADV_FLAG_PROXY); + } +} + +void bt_mesh_adv_update(void) +{ + BT_DBG(""); + + schedule_send(); +} + +void bt_mesh_adv_buf_ready(void) +{ + schedule_send(); +} + +void bt_mesh_adv_init(void) +{ + int rc; + + rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, + adv_buf_mem, "adv_buf_pool"); + assert(rc == 0); + + rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool, + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, + MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)); + assert(rc == 0); + + ble_npl_eventq_init(&bt_mesh_adv_queue); + + k_work_init_delayable(&adv.work, send_pending_adv); +} + +int bt_mesh_adv_enable(void) +{ + /* No need to initialize extended advertiser instance here */ + return 0; +} + +int bt_mesh_adv_start(const struct ble_gap_adv_params *param, int32_t duration, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len) +{ + static uint32_t adv_timeout; + struct ble_gap_ext_adv_params params = { + .itvl_min = param->itvl_min, + .itvl_max = param->itvl_max + }; + + /* In NimBLE duration is in ms, not 10ms units */ + adv_timeout = (duration == BLE_HS_FOREVER) ? 0 : duration; + + BT_DBG("Start advertising %d ms", duration); + + atomic_set_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS); + + return adv_start(¶ms, adv_timeout, ad, ad_len, sd, sd_len); +} +#endif diff --git a/nimble/host/mesh/src/adv_legacy.c b/nimble/host/mesh/src/adv_legacy.c new file mode 100644 index 0000000000..e495dd614c --- /dev/null +++ b/nimble/host/mesh/src/adv_legacy.c @@ -0,0 +1,244 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define MESH_LOG_MODULE BLE_MESH_ADV_LOG + +#include "adv.h" +#include "net.h" +#include "foundation.h" +#include "beacon.h" +#include "prov.h" +#include "proxy.h" +#include "mesh/glue.h" +#include "pb_gatt_srv.h" + +#if MYNEWT_VAL(BLE_MESH_ADV_LEGACY) +/* Convert from ms to 0.625ms units */ +#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) + +#if (MYNEWT_VAL(BSP_NRF51) && !MYNEWT_VAL(BLE_CONTROLLER)) +#define CONFIG_BT_CTLR_LOW_LAT 1 +#else +#define CONFIG_BT_CTLR_LOW_LAT 0 +#endif + +/* Pre-5.0 controllers enforce a minimum interval of 100ms + * whereas 5.0+ controllers can go down to 20ms. + */ +#define ADV_INT_DEFAULT_MS 100 +#define ADV_INT_FAST_MS 20 + +static int32_t adv_int_min = ADV_INT_DEFAULT_MS; + +static int adv_initialized = false; +/* TinyCrypt PRNG consumes a lot of stack space, so we need to have + * an increased call stack whenever it's used. + */ +#if MYNEWT +OS_TASK_STACK_DEFINE(g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); +struct os_task adv_task; +#endif + +static int32_t adv_timeout; + +static inline void adv_send(struct os_mbuf *buf) +{ + static const uint8_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_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON, + [BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI, + }; + + struct ble_gap_adv_params param = { 0 }; + uint16_t duration, adv_int; + struct bt_data ad; + int err; + + adv_int = max(adv_int_min, + BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit)); +#if MYNEWT_VAL(BLE_CONTROLLER) + duration = ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * + (adv_int + 10)); +#else + /* Zephyr Bluetooth Low Energy Controller for mesh stack uses + * pre-emptible continuous scanning, allowing advertising events to be + * transmitted without delay when advertising is enabled. No need to + * compensate with scan window duration. + * An advertising event could be delayed by upto one interval when + * advertising is stopped and started in quick succession, hence add + * advertising interval to the total advertising duration. + */ + duration = (adv_int + + ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * + (adv_int + 10))); + + /* Zephyr Bluetooth Low Energy Controller built for nRF51x SoCs use + * CONFIG_BT_CTLR_LOW_LAT=y, and continuous scanning cannot be + * pre-empted, hence, scanning will block advertising events from + * being transmitted. Increase the advertising duration by the + * amount of scan window duration to compensate for the blocked + * advertising events. + */ + if (CONFIG_BT_CTLR_LOW_LAT) { + duration += BT_MESH_SCAN_WINDOW_MS; + } +#endif + + BT_DBG("type %u om_len %u: %s", BT_MESH_ADV(buf)->type, + buf->om_len, bt_hex(buf->om_data, buf->om_len)); + BT_DBG("count %u interval %ums duration %ums", + BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, + duration); + + ad.type = adv_type[BT_MESH_ADV(buf)->type]; + ad.data_len = buf->om_len; + ad.data = buf->om_data; + + param.itvl_min = ADV_SCAN_UNIT(adv_int); + param.itvl_max = param.itvl_min; + param.conn_mode = BLE_GAP_CONN_MODE_NON; + + int64_t time = k_uptime_get(); + + err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); + + bt_mesh_adv_send_start(duration, err, BT_MESH_ADV(buf)); + if (err) { + BT_ERR("Advertising failed: err %d", err); + return; + } + + BT_DBG("Advertising started. Sleeping %u ms", duration); + + k_sleep(K_MSEC(duration)); + + err = bt_le_adv_stop(); + if (err) { + BT_ERR("Stopping advertising failed: err %d", err); + return; + } + + BT_DBG("Advertising stopped (%u ms)", (uint32_t) k_uptime_delta(&time)); +} + +void +mesh_adv_thread(void *args) +{ + static struct ble_npl_event *ev; + struct os_mbuf *buf; + + BT_DBG("started"); + + while (1) { + if (MYNEWT_VAL(BLE_MESH_GATT_SERVER)) { + ev = ble_npl_eventq_get(&bt_mesh_adv_queue, 0); + while (!ev) { + /* Adv timeout may be set by a call from proxy + * to bt_mesh_adv_start: + */ + adv_timeout = K_FOREVER; + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + bt_mesh_proxy_adv_start(); + BT_DBG("Proxy Advertising up to %d ms", (int) adv_timeout); + } + } else if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + bt_mesh_pb_gatt_adv_start(); + BT_DBG("PB-GATT Advertising up to %d ms", (int) adv_timeout); + } + + ev = ble_npl_eventq_get(&bt_mesh_adv_queue, ble_npl_time_ms_to_ticks32(adv_timeout)); + bt_le_adv_stop(); + } + } else { + ev = ble_npl_eventq_get(&bt_mesh_adv_queue, BLE_NPL_TIME_FOREVER); + } + if (!ev || !ble_npl_event_get_arg(ev)) { + continue; + } + + buf = ble_npl_event_get_arg(ev); + + /* busy == 0 means this was canceled */ + if (BT_MESH_ADV(buf)->busy) { + BT_MESH_ADV(buf)->busy = 0; + adv_send(buf); + } + + net_buf_unref(buf); + + /* os_sched(NULL); */ + } +} + +void bt_mesh_adv_update(void) +{ + static struct ble_npl_event ev = { }; + + BT_DBG(""); + + ble_npl_eventq_put(&bt_mesh_adv_queue, &ev); +} + +void bt_mesh_adv_buf_ready(void) +{ + /* Will be handled automatically */ +} + +void bt_mesh_adv_init(void) +{ + int rc; + + /* Advertising should only be initialized once. Calling + * os_task init the second time will result in an assert. */ + if (adv_initialized) { + return; + } + + rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, + adv_buf_mem, "adv_buf_pool"); + assert(rc == 0); + + rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool, + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, + MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)); + assert(rc == 0); + + ble_npl_eventq_init(&bt_mesh_adv_queue); + +#if MYNEWT + os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL, + MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER, + g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); +#endif + + /* 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_MS; + } + + adv_initialized = true; +} + +int bt_mesh_adv_enable(void) +{ + /* Dummy function - in legacy adv thread is started on init*/ + return 0; +} + +int bt_mesh_adv_start(const struct ble_gap_adv_params *param, int32_t duration, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len) +{ + adv_timeout = duration; + return bt_le_adv_start(param, ad, ad_len, sd, sd_len); +} +#endif diff --git a/nimble/host/mesh/src/app_keys.c b/nimble/host/mesh/src/app_keys.c index 9582bbd045..cfe82576ab 100644 --- a/nimble/host/mesh/src/app_keys.c +++ b/nimble/host/mesh/src/app_keys.c @@ -22,41 +22,184 @@ #include "subnet.h" #define MESH_LOG_MODULE BLE_MESH_LOG + #include "log/log.h" -static struct bt_mesh_app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = { +/* Tracking of what storage changes are pending for App Keys. We track this in + * a separate array here instead of within the respective bt_mesh_app_key + * struct itselve, since once a key gets deleted its struct becomes invalid + * and may be reused for other keys. + */ +struct app_key_update { + uint16_t key_idx:12, /* AppKey Index */ + valid:1, /* 1 if this entry is valid, 0 if not */ + clear:1; /* 1 if key needs clearing, 0 if storing */ +}; + +/* AppKey information for persistent storage. */ +struct app_key_val { + uint16_t net_idx; + bool updated; + uint8_t val[2][16]; +} __packed; + +/** Mesh Application Key. */ +struct app_key { + uint16_t net_idx; + uint16_t app_idx; + bool updated; + struct bt_mesh_app_cred { + uint8_t id; + uint8_t val[16]; + } keys[2]; +}; + +static struct app_key_update app_key_updates[CONFIG_BT_MESH_APP_KEY_COUNT]; + +static struct app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = { [0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = { .app_idx = BT_MESH_KEY_UNUSED, .net_idx = BT_MESH_KEY_UNUSED, } }; -static void app_key_evt(struct bt_mesh_app_key *app, enum bt_mesh_key_evt evt) +static struct app_key *app_get(uint16_t app_idx) { + for (int i = 0; i < ARRAY_SIZE(apps); i++) { + if (apps[i].app_idx == app_idx) { + return &apps[i]; + } + } + + return NULL; +} + +static void clear_app_key(uint16_t app_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[20]; + int err; + + BT_DBG("AppKeyIndex 0x%03x", app_idx); + + snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); + } else { + BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); + } +#endif +} + +static void store_app_key(uint16_t app_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + const struct app_key *app; + struct app_key_val key; + char path[20]; + char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; + int err; + char *str; + + snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx); + + app = app_get(app_idx); + if (!app) { + BT_WARN("ApKeyIndex 0x%03x not found", app_idx); + return; + } + + key.net_idx = app->net_idx, + key.updated = app->updated, + + memcpy(key.val[0], app->keys[0].val, 16); + memcpy(key.val[1], app->keys[1].val, 16); + str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); + + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store AppKey"); + } else { + BT_DBG("Stored AppKey %s value"); + } +#endif +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct app_key_update *app_key_update_find(uint16_t key_idx, + struct app_key_update **free_slot) + { + struct app_key_update *match; int i; - for (i = 0; i < (sizeof(bt_mesh_app_key_cb_list)/sizeof(void *)); i++) { - if (bt_mesh_app_key_cb_list[i]) { - BT_DBG("app_key_evt %d", i); - bt_mesh_app_key_cb_list[i] (app->app_idx, app->net_idx, evt); + match = NULL; + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(app_key_updates); i++) { + struct app_key_update *update = &app_key_updates[i]; + + if (!update->valid) { + *free_slot = update; + continue; + } + + if (update->key_idx == key_idx) { + match = update; } } + + return match; } +#endif -struct bt_mesh_app_key *app_get(uint16_t app_idx) +static void update_app_key_settings(uint16_t app_idx, bool store) { - for (int i = 0; i < ARRAY_SIZE(apps); i++) { - if (apps[i].app_idx == app_idx) { - return &apps[i]; +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + struct app_key_update *update, *free_slot; + uint8_t clear = store ? 0U : 1U; + + BT_DBG("AppKeyIndex 0x%03x", app_idx); + + update = app_key_update_find(app_idx, &free_slot); + if (update) { + update->clear = clear; + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_APP_KEYS_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_app_key(app_idx); + } else { + clear_app_key(app_idx); } + return; } - return NULL; + free_slot->valid = 1U; + free_slot->key_idx = app_idx; + free_slot->clear = clear; + + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_APP_KEYS_PENDING); +#endif } -static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx) +static void app_key_evt(struct app_key *app, enum bt_mesh_key_evt evt) { - struct bt_mesh_app_key *app = NULL; + int i; + + for (i = 0; i < (sizeof(bt_mesh_app_key_cb_list)/sizeof(void *)); i++) { + if (bt_mesh_app_key_cb_list[i]) { + BT_DBG("app_key_evt %d", i); + bt_mesh_app_key_cb_list[i] (app->app_idx, app->net_idx, evt); + } + } +} + +static struct app_key *app_key_alloc(uint16_t app_idx) +{ + struct app_key *app = NULL; for (int i = 0; i < ARRAY_SIZE(apps); i++) { /* Check for already existing app_key */ @@ -72,12 +215,12 @@ static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx) return app; } -static void app_key_del(struct bt_mesh_app_key *app) +static void app_key_del(struct app_key *app) { BT_DBG("AppIdx 0x%03x", app->app_idx); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_app_key(app->app_idx); + update_app_key_settings(app->app_idx, false); } app_key_evt(app, BT_MESH_KEY_DELETED); @@ -87,7 +230,7 @@ static void app_key_del(struct bt_mesh_app_key *app) (void)memset(app->keys, 0, sizeof(app->keys)); } -static void app_key_revoke(struct bt_mesh_app_key *app) +static void app_key_revoke(struct app_key *app) { if (!app->updated) { return; @@ -98,7 +241,7 @@ static void app_key_revoke(struct bt_mesh_app_key *app) app->updated = false; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_app_key(app->app_idx); + update_app_key_settings(app->app_idx, true); } app_key_evt(app, BT_MESH_KEY_REVOKED); @@ -112,7 +255,7 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) } for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; + struct app_key *app = &apps[i]; if (app->app_idx == BT_MESH_KEY_UNUSED) { continue; @@ -140,7 +283,7 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, bt_mesh_subnet_cb_list[0] = subnet_evt; } - struct bt_mesh_app_key *app; + struct app_key *app; BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx, bt_hex(key, 16)); @@ -156,7 +299,7 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, if (app->app_idx == app_idx) { if (app->net_idx != net_idx) { - return STATUS_INVALID_BINDING; + return STATUS_INVALID_NETKEY; } if (memcmp(key, app->keys[0].val, 16)) { @@ -179,7 +322,7 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing AppKey persistently"); - bt_mesh_store_app_key(app->app_idx); + update_app_key_settings(app->app_idx, true); } app_key_evt(app, BT_MESH_KEY_ADDED); @@ -187,22 +330,10 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, return STATUS_SUCCESS; } -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) -{ - struct bt_mesh_app_key *app; - - app = app_get(app_idx); - if (app) { - return app; - } - - return NULL; -} - uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, const uint8_t key[16]) { - struct bt_mesh_app_key *app; + struct app_key *app; struct bt_mesh_subnet *sub; BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx, @@ -250,7 +381,7 @@ uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing AppKey persistently"); - bt_mesh_store_app_key(app->app_idx); + update_app_key_settings(app->app_idx, true); } app_key_evt(app, BT_MESH_KEY_UPDATED); @@ -260,7 +391,7 @@ uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx) { - struct bt_mesh_app_key *app; + struct app_key *app; BT_DBG("AppIdx 0x%03x", app_idx); @@ -288,7 +419,7 @@ uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx) int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, const uint8_t old_key[16], const uint8_t new_key[16]) { - struct bt_mesh_app_key *app; + struct app_key *app; app = app_key_alloc(app_idx); if (!app) { @@ -337,7 +468,7 @@ ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, size_t count = 0; for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; + struct app_key *app = &apps[i]; if (app->app_idx == BT_MESH_KEY_UNUSED) { continue; @@ -364,9 +495,9 @@ ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, struct bt_mesh_subnet **sub, - const uint8_t *app_key[16], uint8_t *aid) + const uint8_t **app_key, uint8_t *aid) { - struct bt_mesh_app_key *app = NULL; + struct app_key *app = NULL; if (BT_MESH_IS_DEV_KEY(ctx->app_idx)) { /* With device keys, the application has to decide which subnet @@ -379,7 +510,7 @@ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, } if (ctx->app_idx == BT_MESH_KEY_DEV_REMOTE && - !bt_mesh_elem_find(ctx->addr)) { + !bt_mesh_has_addr(ctx->addr)) { struct bt_mesh_cdb_node *node; if (!IS_ENABLED(CONFIG_BT_MESH_CDB)) { @@ -462,7 +593,7 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, } for (i = 0; i < ARRAY_SIZE(apps); i++) { - const struct bt_mesh_app_key *app = &apps[i]; + const struct app_key *app = &apps[i]; const struct bt_mesh_app_cred *cred; if (app->app_idx == BT_MESH_KEY_UNUSED) { @@ -498,10 +629,89 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, void bt_mesh_app_keys_reset(void) { for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; + struct app_key *app = &apps[i]; if (app->app_idx != BT_MESH_KEY_UNUSED) { app_key_del(app); } } } + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int app_key_set(int argc, char **argv, char *val) +{ + struct app_key_val key; + uint16_t app_idx; + int len_rd, err; + + BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); + + app_idx = strtol(argv[0], NULL, 16); + len_rd = strtol(argv[1], NULL, 16); + + + if (!len_rd) { + return 0; + } + + err = settings_bytes_from_str(val, &key, &len_rd); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + err = bt_mesh_app_key_set(app_idx, key.net_idx, key.val[0], + key.updated ? key.val[1] : NULL); + if (err) { + BT_ERR("Failed to set \'app-key\'"); + return err; + } + + BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); + + return 0; +} +#endif + +void bt_mesh_app_key_pending_store(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(app_key_updates); i++) { + struct app_key_update *update = &app_key_updates[i]; + + if (!update->valid) { + continue; + } + + if (update->clear) { + clear_app_key(update->key_idx); + } else { + store_app_key(update->key_idx); + } + + update->valid = 0U; + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_app_key_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = app_key_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_app_key_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_app_key_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_app_key conf"); +#endif +} diff --git a/nimble/host/mesh/src/app_keys.h b/nimble/host/mesh/src/app_keys.h index d007b785f6..40df664506 100644 --- a/nimble/host/mesh/src/app_keys.h +++ b/nimble/host/mesh/src/app_keys.h @@ -10,28 +10,9 @@ #include "mesh/mesh.h" #include "subnet.h" -/** Mesh Application. */ -struct bt_mesh_app_key { - uint16_t net_idx; - uint16_t app_idx; - bool updated; - struct bt_mesh_app_cred { - uint8_t id; - uint8_t val[16]; - } keys[2]; -}; - /** @brief Reset the app keys module. */ void bt_mesh_app_keys_reset(void); -/** @brief Get the application key with the given AppIdx. - * - * @param app_idx App index. - * - * @return The matching application, or NULL if the application isn't known. - */ -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx); - /** @brief Initialize a new application key with the given parameters. * * @param app_idx AppIndex. @@ -60,7 +41,7 @@ int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, */ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, struct bt_mesh_subnet **sub, - const uint8_t *app_key[16], uint8_t *aid); + const uint8_t **app_key, uint8_t *aid); /** @brief Iterate through all matching application keys and call @c cb on each. * @@ -78,9 +59,10 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, const uint8_t key[16], void *cb_data), void *cb_data); -struct bt_mesh_app_key *app_get(uint16_t app_idx); - extern void (*bt_mesh_app_key_cb_list[1]) (uint16_t app_idx, uint16_t net_idx, enum bt_mesh_key_evt evt); -#endif /* _BT_MESH_APP_KEYS_H_ */ \ No newline at end of file +/** @brief Store pending application keys in persistent storage. */ +void bt_mesh_app_key_pending_store(void); +void bt_mesh_app_key_init(void); +#endif /* _BT_MESH_APP_KEYS_H_ */ diff --git a/nimble/host/mesh/src/beacon.c b/nimble/host/mesh/src/beacon.c index 6a5fc5a1cd..2b678f9008 100644 --- a/nimble/host/mesh/src/beacon.c +++ b/nimble/host/mesh/src/beacon.c @@ -34,7 +34,7 @@ /* 1 transmission, 20ms interval */ #define PROV_XMIT BT_MESH_TRANSMIT(0, 20) -static struct k_delayed_work beacon_timer; +static struct k_work_delayable beacon_timer; static int cache_check(struct bt_mesh_subnet *sub, void *beacon_data) { @@ -228,33 +228,30 @@ static void update_beacon_observation(void) static void beacon_send(struct ble_npl_event *work) { - /* Don't send anything if we have an active provisioning link */ - if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && bt_mesh_prov_active()) { - k_delayed_work_submit(&beacon_timer, - K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT))); - return; - } BT_DBG(""); if (bt_mesh_is_provisioned()) { + if (!bt_mesh_beacon_enabled() && + !atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { + return; + } + update_beacon_observation(); (void)bt_mesh_subnet_find(secure_beacon_send, NULL); - /* Only resubmit if beaconing is still enabled */ - if (bt_mesh_beacon_enabled() || - atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { - k_delayed_work_submit(&beacon_timer, - PROVISIONED_INTERVAL); - } + k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL); return; } if (IS_ENABLED(BLE_MESH_PB_ADV)) { - unprovisioned_beacon_send(); - k_delayed_work_submit(&beacon_timer, - K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT))); + /* Don't send anything if we have an active provisioning link */ + if (!bt_mesh_prov_active()) { + unprovisioned_beacon_send(); + } + + k_work_schedule(&beacon_timer, K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT))); } } @@ -426,22 +423,27 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) void bt_mesh_beacon_init(void) { - if (!bt_mesh_subnet_cb_list[1]) { + if (!bt_mesh_subnet_cb_list[1]) { bt_mesh_subnet_cb_list[1] = subnet_evt; } - k_delayed_work_init(&beacon_timer, beacon_send); + k_work_init_delayable(&beacon_timer, beacon_send); } void bt_mesh_beacon_ivu_initiator(bool enable) { atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_INITIATOR, enable); - if (enable) { - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); - } else if (!bt_mesh_beacon_enabled()) { - k_delayed_work_cancel(&beacon_timer); - } + /* Fire the beacon handler straight away if it's not already pending - + * in which case we'll fire according to the ongoing periodic sending. + * If beacons are disabled, the handler will exit early. + * + * An alternative solution would be to check whether beacons are enabled + * here, and cancel if not. As the cancel operation may fail, we would + * still have to implement an early exit mechanism, so we might as well + * just use this every time. + */ + k_work_schedule(&beacon_timer, K_NO_WAIT); } static void subnet_beacon_enable(struct bt_mesh_subnet *sub) @@ -454,19 +456,17 @@ static void subnet_beacon_enable(struct bt_mesh_subnet *sub) void bt_mesh_beacon_enable(void) { - if (!bt_mesh_is_provisioned()) { - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); - return; + if (bt_mesh_is_provisioned()) { + bt_mesh_subnet_foreach(subnet_beacon_enable); } - bt_mesh_subnet_foreach(subnet_beacon_enable); - - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); + k_work_reschedule(&beacon_timer, K_NO_WAIT); } void bt_mesh_beacon_disable(void) { if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { - k_delayed_work_cancel(&beacon_timer); + /* If this fails, we'll do an early exit in the work handler. */ + (void)k_work_cancel_delayable(&beacon_timer); } } diff --git a/nimble/host/mesh/src/cdb.c b/nimble/host/mesh/src/cdb.c index 459730ee76..98084ee3d0 100644 --- a/nimble/host/mesh/src/cdb.c +++ b/nimble/host/mesh/src/cdb.c @@ -4,11 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_CDB) -#define LOG_MODULE_NAME bt_mesh_cdb +#define MESH_LOG_MODULE BLE_MESH_LOG #include "log/log.h" +#include -#include "mesh/mesh.h" +#include "cdb_priv.h" #include "net.h" #include "rpl.h" #include "settings.h" @@ -16,6 +16,58 @@ #include "mesh/glue.h" #if MYNEWT_VAL(BLE_MESH_CDB) +/* Tracking of what storage changes are pending for App and Net Keys. We + * track this in a separate array here instead of within the respective + * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key + * gets deleted its struct becomes invalid and may be reused for other keys. + */ +struct key_update { + uint16_t key_idx:12, /* AppKey or NetKey Index */ + valid:1, /* 1 if this entry is valid, 0 if not */ + app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */ + clear:1; /* 1 if key needs clearing, 0 if storing */ +}; + +/* Tracking of what storage changes are pending for node settings. */ +struct node_update { + uint16_t addr; + bool clear; +}; + +/* Node information for persistent storage. */ +struct node_val { + uint16_t net_idx; + uint8_t num_elem; + uint8_t flags; +#define F_NODE_CONFIGURED 0x01 + uint8_t uuid[16]; + uint8_t dev_key[16]; +} __packed; + +/* NetKey storage information */ +struct net_key_val { + uint8_t kr_flag:1, + kr_phase:7; + uint8_t val[2][16]; +} __packed; + +/* AppKey information for persistent storage. */ +struct app_key_val { + uint16_t net_idx; + bool updated; + uint8_t val[2][16]; +} __packed; + +/* IV Index & IV Update information for persistent storage. */ +struct net_val { + uint32_t iv_index; + bool iv_update; +} __packed; + +static struct node_update cdb_node_updates[MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)]; +static struct key_update cdb_key_updates[MYNEWT_VAL(BLE_MESH_CDB_SUBNET_COUNT) + + MYNEWT_VAL(BLE_MESH_CDB_APP_KEY_COUNT)]; + struct bt_mesh_cdb bt_mesh_cdb = { .nodes = { [0 ... (CONFIG_BT_MESH_NODE_COUNT - 1)] = { @@ -107,6 +159,544 @@ static uint16_t find_lowest_free_addr(uint8_t num_elem) return addr; } +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int cdb_net_set(int argc, char *val) +{ + struct net_val net; + int len, err; + + len = sizeof(net); + err = settings_bytes_from_str(val, &net, &len); + if (err) { + BT_ERR("Failed to set \'cdb_net\'"); + return err; + } + + bt_mesh_cdb.iv_index = net.iv_index; + + if (net.iv_update) { + atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS); + } + + atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID); + + return 0; +} + +static int cdb_node_set(int argc, char *str) +{ + struct bt_mesh_cdb_node *node; + struct node_val val; + uint16_t addr; + int len, err; + + if (argc < 1) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + addr = strtol(str, NULL, 16); + len = sizeof(str); + + if (argc < 1) { + BT_DBG("val (null)"); + BT_DBG("Deleting node 0x%04x", addr); + + node = bt_mesh_cdb_node_get(addr); + if (node) { + bt_mesh_cdb_node_del(node, false); + } + + return 0; + } + + err = settings_bytes_from_str(str, &val, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + if (len != sizeof(struct node_val)) { + BT_ERR("Invalid length for node_val"); + return -EINVAL; + } + + node = bt_mesh_cdb_node_get(addr); + if (!node) { + node = bt_mesh_cdb_node_alloc(val.uuid, addr, val.num_elem, + val.net_idx); + } + + if (!node) { + BT_ERR("No space for a new node"); + return -ENOMEM; + } + + if (val.flags & F_NODE_CONFIGURED) { + atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED); + } + + memcpy(node->uuid, val.uuid, 16); + memcpy(node->dev_key, val.dev_key, 16); + + BT_DBG("Node 0x%04x recovered from storage", addr); + + return 0; +} + +static int cdb_subnet_set(int argc, char *name) +{ + struct bt_mesh_cdb_subnet *sub; + struct net_key_val key; + uint16_t net_idx; + int len, len_rd, err; + + if (!name) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + len_rd = sizeof(sub); + net_idx = strtol(name, NULL, 16); + sub = bt_mesh_cdb_subnet_get(net_idx); + + if (len_rd == 0) { + BT_DBG("val (null)"); + if (!sub) { + BT_ERR("No subnet with NetKeyIndex 0x%03x", net_idx); + return -ENOENT; + } + + BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx); + bt_mesh_cdb_subnet_del(sub, false); + return 0; + } + + len = sizeof(key); + err = settings_bytes_from_str(name, &key, &len); + if (err) { + BT_ERR("Failed to set \'net-key\'"); + return err; + } + + if (sub) { + BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx); + + sub->kr_phase = key.kr_phase; + memcpy(sub->keys[0].net_key, &key.val[0], 16); + memcpy(sub->keys[1].net_key, &key.val[1], 16); + + return 0; + } + + sub = bt_mesh_cdb_subnet_alloc(net_idx); + if (!sub) { + BT_ERR("No space to allocate a new subnet"); + return -ENOMEM; + } + + sub->kr_phase = key.kr_phase; + memcpy(sub->keys[0].net_key, &key.val[0], 16); + memcpy(sub->keys[1].net_key, &key.val[1], 16); + + BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); + + return 0; +} + +static int cdb_app_key_set(int argc, char *name) +{ + struct bt_mesh_cdb_app_key *app; + struct app_key_val key; + uint16_t app_idx; + int len_rd, err; + + app_idx = strtol(name, NULL, 16); + len_rd = sizeof(key); + + if (len_rd == 0) { + BT_DBG("val (null)"); + BT_DBG("Deleting AppKeyIndex 0x%03x", app_idx); + + app = bt_mesh_cdb_app_key_get(app_idx); + if (app) { + bt_mesh_cdb_app_key_del(app, false); + } + + return 0; + } + + err = settings_bytes_from_str(name, &key, &len_rd); + if (err) { + BT_ERR("Failed to set \'app-key\'"); + return err; + } + + app = bt_mesh_cdb_app_key_get(app_idx); + if (!app) { + app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx); + } + + if (!app) { + BT_ERR("No space for a new app key"); + return -ENOMEM; + } + + memcpy(app->keys[0].app_key, key.val[0], 16); + memcpy(app->keys[1].app_key, key.val[1], 16); + + BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); + + return 0; +} + +static int cdb_set(int argc, char **argv, char *name) +{ + int len; + char *next; + + if (argc < 1) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + if (!strcmp(name, "Net")) { + return cdb_net_set(1, name); + } + + len = settings_name_next(name, &next); + + if (!next) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + if (!strncmp(name, "Node", len)) { + return cdb_node_set(1, next); + } + + if (!strncmp(name, "Subnet", len)) { + return cdb_subnet_set(1, next); + } + + if (!strncmp(name, "AppKey", len)) { + return cdb_app_key_set(1, next); + } + + BT_WARN("Unknown module key %s", name); + return -ENOENT; +} +#endif + +static void store_cdb_node(const struct bt_mesh_cdb_node *node) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char buf[BT_SETTINGS_SIZE(sizeof(struct node_val))]; + struct node_val val; + char path[30]; + char *str; + int err; + + val.net_idx = node->net_idx; + val.num_elem = node->num_elem; + val.flags = 0; + + if (atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) { + val.flags |= F_NODE_CONFIGURED; + } + + memcpy(val.uuid, node->uuid, 16); + memcpy(val.dev_key, node->dev_key, 16); + + snprintk(path, sizeof(path), "bt_mesh/cdb/Node/%x", node->addr); + + str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode Node as value"); + return; + } + + + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store Node %s value", path); + } else { + BT_DBG("Stored Node %s value", path); + } +#endif +} + +static void clear_cdb_node(uint16_t addr) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[30]; + int err; + + BT_DBG("Node 0x%04x", addr); + + snprintk(path, sizeof(path), "bt_mesh/cdb/Node/%x", addr); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear Node 0x%04x", addr); + } else { + BT_DBG("Cleared Node 0x%04x", addr); + } +#endif +} + +static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))]; + struct net_key_val key; + char path[30]; + int err; + char *str; + + BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, + bt_hex(sub->keys[0].net_key, 16)); + + memcpy(&key.val[0], sub->keys[0].net_key, 16); + memcpy(&key.val[1], sub->keys[1].net_key, 16); + key.kr_flag = 0U; /* Deprecated */ + key.kr_phase = sub->kr_phase; + + snprintk(path, sizeof(path), "bt_mesh/cdb/Subnet/%x", sub->net_idx); + + + str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode Subnet as value"); + return; + } + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store Subnet value"); + } else { + BT_DBG("Stored Subnet value"); + } +#endif +} + +static void clear_cdb_subnet(uint16_t net_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[30]; + int err; + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + snprintk(path, sizeof(path), "bt_mesh/cdb/Subnet/%x", net_idx); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); + } else { + BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); + } +#endif +} + +static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; + struct app_key_val key; + char path[30]; + int err; + char *str; + + key.net_idx = app->net_idx; + key.updated = false; + memcpy(key.val[0], app->keys[0].app_key, 16); + memcpy(key.val[1], app->keys[1].app_key, 16); + + snprintk(path, sizeof(path), "bt_mesh/cdb/AppKey/%x", app->app_idx); + + str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store AppKey"); + } else { + BT_DBG("Stored AppKey"); + } +#endif +} + +static void clear_cdb_app_key(uint16_t app_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[30]; + int err; + + snprintk(path, sizeof(path), "bt_mesh/cdb/AppKey/%x", app_idx); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); + } else { + BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); + } +#endif +} + +static void schedule_cdb_store(int flag) +{ + atomic_set_bit(bt_mesh_cdb.flags, flag); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CDB_PENDING); +} + +static void update_cdb_net_settings(void) +{ + schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING); +} + +static struct node_update *cdb_node_update_find(uint16_t addr, + struct node_update **free_slot) +{ + struct node_update *match; + int i; + + match = NULL; + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(cdb_node_updates); i++) { + struct node_update *update = &cdb_node_updates[i]; + + if (update->addr == BT_MESH_ADDR_UNASSIGNED) { + *free_slot = update; + continue; + } + + if (update->addr == addr) { + match = update; + } + } + + return match; +} + +static void update_cdb_node_settings(const struct bt_mesh_cdb_node *node, + bool store) +{ + struct node_update *update, *free_slot; + + BT_DBG("Node 0x%04x", node->addr); + + update = cdb_node_update_find(node->addr, &free_slot); + if (update) { + update->clear = !store; + schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_cdb_node(node); + } else { + clear_cdb_node(node->addr); + } + return; + } + + free_slot->addr = node->addr; + free_slot->clear = !store; + + schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); +} + +static struct key_update *cdb_key_update_find(bool app_key, uint16_t key_idx, + struct key_update **free_slot) +{ + struct key_update *match; + int i; + + match = NULL; + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { + struct key_update *update = &cdb_key_updates[i]; + + if (!update->valid) { + *free_slot = update; + continue; + } + + if (update->app_key != app_key) { + continue; + } + + if (update->key_idx == key_idx) { + match = update; + } + } + + return match; +} + +static void update_cdb_subnet_settings(const struct bt_mesh_cdb_subnet *sub, + bool store) +{ + struct key_update *update, *free_slot; + uint8_t clear = store ? 0U : 1U; + + BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + + update = cdb_key_update_find(false, sub->net_idx, &free_slot); + if (update) { + update->clear = clear; + schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_cdb_subnet(sub); + } else { + clear_cdb_subnet(sub->net_idx); + } + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = sub->net_idx; + free_slot->app_key = 0U; + free_slot->clear = clear; + + schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); +} + +static void update_cdb_app_key_settings(const struct bt_mesh_cdb_app_key *key, + bool store) +{ + struct key_update *update, *free_slot; + uint8_t clear = store ? 0U : 1U; + + BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + + update = cdb_key_update_find(true, key->app_idx, &free_slot); + if (update) { + update->clear = clear; + schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_cdb_app_key(key); + } else { + clear_cdb_app_key(key->app_idx); + } + + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = key->app_idx; + free_slot->app_key = 1U; + free_slot->clear = clear; + + schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); +} + int bt_mesh_cdb_create(const uint8_t key[16]) { struct bt_mesh_cdb_subnet *sub; @@ -125,8 +715,8 @@ int bt_mesh_cdb_create(const uint8_t key[16]) bt_mesh_cdb.iv_index = 0; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); - bt_mesh_store_cdb_subnet(sub); + update_cdb_net_settings(); + update_cdb_subnet_settings(sub, true); } return 0; @@ -157,7 +747,7 @@ void bt_mesh_cdb_clear(void) } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); + update_cdb_net_settings(); } } @@ -171,7 +761,7 @@ void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update) iv_update); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); + update_cdb_net_settings(); } } @@ -204,7 +794,7 @@ void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store) BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store); if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_subnet(sub); + update_cdb_subnet_settings(sub, false); } sub->net_idx = BT_MESH_KEY_UNUSED; @@ -226,8 +816,8 @@ struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx) void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub) { - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_subnet(sub); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + update_cdb_subnet_settings(sub, true); } } @@ -235,7 +825,7 @@ uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub) { uint8_t flags = 0x00; - if (sub && sub->kr_flag) { + if (sub && SUBNET_KEY_TX_IDX(sub)) { flags |= BT_MESH_NET_FLAG_KR; } @@ -283,7 +873,7 @@ void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store) BT_DBG("Node addr 0x%04x store %u", node->addr, store); if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_node(node); + update_cdb_node_settings(node, false); } node->addr = BT_MESH_ADDR_UNASSIGNED; @@ -308,8 +898,8 @@ struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr) void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node) { - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_node(node); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + update_cdb_node_settings(node, true); } } @@ -356,10 +946,10 @@ void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store) BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store); if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_app_key(key); + update_cdb_app_key_settings(key, false); } - key->net_idx = BT_MESH_ADDR_UNASSIGNED; + key->net_idx = BT_MESH_KEY_UNUSED; memset(key->keys, 0, sizeof(key->keys)); } @@ -381,8 +971,172 @@ struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx) void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key) { - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_app_key(key); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + update_cdb_app_key_settings(key, true); + } +} + +static void clear_cdb_net(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[30]; + int err; + + snprintk(path, sizeof(path), "bt_mesh/cdb/Net"); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear Net"); + } else { + BT_DBG("Cleared NetKeyIndex 0x%03x"); } +#endif +} + +static void store_cdb_pending_net(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + struct net_val net; + int err; + char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))]; + char *str; + + BT_DBG(""); + + net.iv_index = bt_mesh_cdb.iv_index; + net.iv_update = atomic_test_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_IVU_IN_PROGRESS); + + str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode Network as value"); + return; + } + err = settings_save_one("bt_mesh/cdb/Net", str); + if (err) { + BT_ERR("Failed to store Network value"); + } else { + BT_DBG("Stored Network value"); + } +#endif +} + +static void store_cdb_pending_nodes(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cdb_node_updates); ++i) { + struct node_update *update = &cdb_node_updates[i]; + + if (update->addr == BT_MESH_ADDR_UNASSIGNED) { + continue; + } + + BT_DBG("addr: 0x%04x, clear: %d", update->addr, update->clear); + + if (update->clear) { + clear_cdb_node(update->addr); + } else { + struct bt_mesh_cdb_node *node; + + node = bt_mesh_cdb_node_get(update->addr); + if (node) { + store_cdb_node(node); + } else { + BT_WARN("Node 0x%04x not found", update->addr); + } + } + + update->addr = BT_MESH_ADDR_UNASSIGNED; + } +} + +static void store_cdb_pending_keys(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { + struct key_update *update = &cdb_key_updates[i]; + + if (!update->valid) { + continue; + } + + if (update->clear) { + if (update->app_key) { + clear_cdb_app_key(update->key_idx); + } else { + clear_cdb_subnet(update->key_idx); + } + } else { + if (update->app_key) { + struct bt_mesh_cdb_app_key *key; + + key = bt_mesh_cdb_app_key_get(update->key_idx); + if (key) { + store_cdb_app_key(key); + } else { + BT_WARN("AppKeyIndex 0x%03x not found", + update->key_idx); + } + } else { + struct bt_mesh_cdb_subnet *sub; + + sub = bt_mesh_cdb_subnet_get(update->key_idx); + if (sub) { + store_cdb_subnet(sub); + } else { + BT_WARN("NetKeyIndex 0x%03x not found", + update->key_idx); + } + } + } + + update->valid = 0U; + } +} + +void bt_mesh_cdb_pending_store(void) +{ + if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_SUBNET_PENDING)) { + if (atomic_test_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_VALID)) { + store_cdb_pending_net(); + } else { + clear_cdb_net(); + } + } + + if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_NODES_PENDING)) { + store_cdb_pending_nodes(); + } + + if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_KEYS_PENDING)) { + store_cdb_pending_keys(); + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_cdb_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = cdb_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_cdb_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_cdb_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_net conf"); +#endif } #endif diff --git a/nimble/host/mesh/src/cdb_priv.h b/nimble/host/mesh/src/cdb_priv.h new file mode 100644 index 0000000000..ff865a56fd --- /dev/null +++ b/nimble/host/mesh/src/cdb_priv.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* ommitted `bt_mesh_cdb_node_store` declaration - every header + * includes mesh/mesh.h, which already has it + * void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node); + */ +void bt_mesh_cdb_pending_store(void); +void bt_mesh_cdb_init(void); diff --git a/nimble/host/mesh/src/cfg.c b/nimble/host/mesh/src/cfg.c index 4e14925506..282aefaf43 100644 --- a/nimble/host/mesh/src/cfg.c +++ b/nimble/host/mesh/src/cfg.c @@ -15,6 +15,20 @@ #include "cfg.h" #include "mesh/glue.h" +#define MESH_LOG_MODULE BLE_MESH_LOG +#include "log/log.h" + +/* Miscellaneous configuration server model states */ +struct cfg_val { + uint8_t net_transmit; + uint8_t relay; + uint8_t relay_retransmit; + uint8_t beacon; + uint8_t gatt_proxy; + uint8_t frnd; + uint8_t default_ttl; +}; + void bt_mesh_beacon_set(bool beacon) { if (atomic_test_bit(bt_mesh.flags, BT_MESH_BEACON) == beacon) { @@ -31,7 +45,7 @@ void bt_mesh_beacon_set(bool beacon) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } } @@ -82,7 +96,7 @@ int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } return 0; @@ -111,7 +125,7 @@ int bt_mesh_default_ttl_set(uint8_t default_ttl) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } return 0; @@ -139,7 +153,7 @@ int bt_mesh_friend_set(enum bt_mesh_feat_state friendship) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } if (friendship == BT_MESH_FEATURE_DISABLED) { @@ -168,7 +182,7 @@ void bt_mesh_net_transmit_set(uint8_t xmit) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } } @@ -199,7 +213,7 @@ int bt_mesh_relay_set(enum bt_mesh_feat_state relay, uint8_t xmit) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } return 0; @@ -236,8 +250,115 @@ bool bt_mesh_fixed_group_match(uint16_t addr) } } -void bt_mesh_cfg_init(void) +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int cfg_set(int argc, char **argv, char *val) +{ + struct cfg_val cfg; + int len, err; + + BT_DBG("val %s", val ? val : "(null)"); + + if (!val) { + BT_DBG("Cleared configuration state"); + return 0; + } + + len = sizeof(cfg); + err = settings_bytes_from_str(val, &cfg, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(cfg)) { + BT_ERR("Unexpected value length (%d != %zu)", len, + sizeof(cfg)); + return -EINVAL; + } + + bt_mesh_net_transmit_set(cfg.net_transmit); + bt_mesh_relay_set(cfg.relay, cfg.relay_retransmit); + bt_mesh_beacon_set(cfg.beacon); + bt_mesh_gatt_proxy_set(cfg.gatt_proxy); + bt_mesh_friend_set(cfg.frnd); + bt_mesh_default_ttl_set(cfg.default_ttl); + + BT_DBG("Restored configuration state"); + + return 0; +} + +static void clear_cfg(void) +{ + int err; + + err = settings_save_one("bt_mesh/Cfg", NULL); + if (err) { + BT_ERR("Failed to clear configuration"); + } else { + BT_DBG("Cleared configuration"); + } +} + +static void store_pending_cfg(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct cfg_val))]; + struct cfg_val val; + char *str; + int err; + + val.net_transmit = bt_mesh_net_transmit_get(); + val.relay = bt_mesh_relay_get(); + val.relay_retransmit = bt_mesh_relay_retransmit_get(); + val.beacon = bt_mesh_beacon_enabled(); + val.gatt_proxy = bt_mesh_gatt_proxy_get(); + val.frnd = bt_mesh_friend_get(); + val.default_ttl = bt_mesh_default_ttl_get(); + + str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode configuration as value"); + return; + } + + BT_DBG("Saving configuration as value %s", str); + err = settings_save_one("bt_mesh/Cfg", str); + if (err) { + BT_ERR("Failed to store configuration"); + } else { + BT_DBG("Stored configuration"); + } +} + +void bt_mesh_cfg_pending_store(void) { + if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + store_pending_cfg(); + } else { + clear_cfg(); + } +} + +static struct conf_handler bt_mesh_cfg_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = cfg_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_cfg_default_set(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_cfg_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_settings conf"); +#endif + bt_mesh.default_ttl = CONFIG_BT_MESH_DEFAULT_TTL; bt_mesh.net_xmit = BT_MESH_TRANSMIT(CONFIG_BT_MESH_NETWORK_TRANSMIT_COUNT, @@ -264,4 +385,4 @@ void bt_mesh_cfg_init(void) if (CONFIG_BT_MESH_FRIEND_ENABLED) { atomic_set_bit(bt_mesh.flags, BT_MESH_FRIEND); } -} \ No newline at end of file +} diff --git a/nimble/host/mesh/src/cfg.h b/nimble/host/mesh/src/cfg.h index 6f58acf8b0..4901655f57 100644 --- a/nimble/host/mesh/src/cfg.h +++ b/nimble/host/mesh/src/cfg.h @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -void bt_mesh_cfg_init(void); +void bt_mesh_cfg_default_set(void); +void bt_mesh_cfg_pending_store(void); -bool bt_mesh_fixed_group_match(uint16_t addr); \ No newline at end of file +bool bt_mesh_fixed_group_match(uint16_t addr); diff --git a/nimble/host/mesh/src/cfg_cli.c b/nimble/host/mesh/src/cfg_cli.c index a87cd7bb9f..773bafa709 100644 --- a/nimble/host/mesh/src/cfg_cli.c +++ b/nimble/host/mesh/src/cfg_cli.c @@ -25,7 +25,7 @@ #define DUMMY_2_BYTE_OP BT_MESH_MODEL_OP_2(0xff, 0xff) struct comp_data { - uint8_t *status; + uint8_t *page; struct os_mbuf *comp; }; @@ -33,9 +33,9 @@ static int32_t msg_timeout = K_SECONDS(5); static struct bt_mesh_cfg_cli *cli; -static void comp_data_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int comp_data_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct comp_data *param; size_t to_copy; @@ -44,24 +44,26 @@ static void comp_data_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_DEV_COMP_DATA_STATUS) { - BT_WARN("Unexpected Composition Data Status"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_DEV_COMP_DATA_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - - *(param->status) = net_buf_simple_pull_u8(buf); + if (param->page) { + *(param->page) = net_buf_simple_pull_u8(buf); + } to_copy = min(net_buf_simple_tailroom(param->comp), buf->om_len); net_buf_simple_add_mem(param->comp, buf->om_data, to_copy); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void state_status_u8(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf, - uint32_t expect_status) +static int state_status_u8(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf, + uint32_t expect_status) { uint8_t *status; @@ -69,44 +71,92 @@ static void state_status_u8(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != expect_status) { - BT_WARN("Unexpected Status (0x%08x != 0x%08x)", - (unsigned) cli->op_pending, (unsigned) expect_status); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, expect_status, ctx->addr, + (void **)&status)) { + return -ENOENT; } - status = cli->op_param; *status = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void beacon_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int beacon_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { - state_status_u8(model, ctx, buf, OP_BEACON_STATUS); + return state_status_u8(model, ctx, buf, OP_BEACON_STATUS); } -static void ttl_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int ttl_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { - state_status_u8(model, ctx, buf, OP_DEFAULT_TTL_STATUS); + return state_status_u8(model, ctx, buf, OP_DEFAULT_TTL_STATUS); } -static void friend_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int friend_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { - state_status_u8(model, ctx, buf, OP_FRIEND_STATUS); + return state_status_u8(model, ctx, buf, OP_FRIEND_STATUS); } -static void gatt_proxy_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int gatt_proxy_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) +{ + return state_status_u8(model, ctx, buf, OP_GATT_PROXY_STATUS); +} + +static int transmit_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + return state_status_u8(model, ctx, buf, OP_NET_TRANSMIT_STATUS); +} + + struct krp_param { + uint8_t *status; + uint16_t net_idx; + uint8_t *phase; +}; + +static int krp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { - state_status_u8(model, ctx, buf, OP_GATT_PROXY_STATUS); + struct krp_param *param; + uint16_t net_idx; + uint8_t status, phase; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, + bt_hex(buf->om_data, buf->om_len)); + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_KRP_STATUS, ctx->addr, (void **)¶m)) { + return -ENOENT; + } + + status = net_buf_simple_pull_u8(buf); + net_idx = net_buf_simple_pull_le16(buf) & 0xfff; + phase = net_buf_simple_pull_u8(buf); + + if (param->net_idx != net_idx) { + return -ENOENT; + } + + if (param->status) { + *param->status = status; + } + + if (param->phase) { + *param->phase = phase; + } + + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct relay_param { @@ -114,9 +164,9 @@ struct relay_param { uint8_t *transmit; }; -static void relay_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int relay_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { struct relay_param *param; @@ -124,16 +174,24 @@ static void relay_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_RELAY_STATUS) { - BT_WARN("Unexpected Relay Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_RELAY_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; *param->status = net_buf_simple_pull_u8(buf); *param->transmit = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; +} + +static int net_transmit_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + return state_status_u8(model, ctx, buf, OP_NET_TRANSMIT_STATUS); } struct net_key_param { @@ -141,9 +199,9 @@ struct net_key_param { uint16_t net_idx; }; -static void net_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct net_key_param *param; uint16_t net_idx; @@ -153,25 +211,26 @@ static void net_key_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_NET_KEY_STATUS) { - BT_WARN("Unexpected Net Key Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); net_idx = net_buf_simple_pull_le16(buf) & 0xfff; - param = cli->op_param; if (param->net_idx != net_idx) { BT_WARN("Net Key Status key index does not match"); - return; + return -ENOENT; } if (param->status) { *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct net_key_list_param { @@ -179,9 +238,9 @@ struct net_key_list_param { size_t *key_cnt; }; -static void net_key_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct net_key_list_param *param; int i; @@ -190,13 +249,11 @@ static void net_key_list(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_NET_KEY_LIST) { - BT_WARN("Unexpected Net Key List message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - for (i = 0; i < *param->key_cnt && buf->om_len >= 3; i += 2) { key_idx_unpack(buf, ¶m->keys[i], ¶m->keys[i + 1]); } @@ -205,29 +262,37 @@ static void net_key_list(struct bt_mesh_model *model, param->keys[i++] = net_buf_simple_pull_le16(buf) & 0xfff; } + if (buf->om_len > 0) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + *param->key_cnt = i; - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void node_reset_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) +static int node_reset_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { bool *param = NULL; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x", - ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x", ctx->net_idx, + ctx->app_idx, ctx->addr); - if (cli->op_pending != OP_NODE_RESET_STATUS) { - BT_WARN("Unexpected Node Reset Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NODE_RESET_STATUS, + ctx->addr, (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - if (param) { *param = true; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct app_key_param { @@ -236,9 +301,9 @@ struct app_key_param { uint16_t app_idx; }; -static void app_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int app_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { struct app_key_param *param; uint16_t net_idx, app_idx; @@ -248,25 +313,26 @@ static void app_key_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_APP_KEY_STATUS) { - BT_WARN("Unexpected App Key Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_APP_KEY_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); key_idx_unpack(buf, &net_idx, &app_idx); - param = cli->op_param; if (param->net_idx != net_idx || param->app_idx != app_idx) { BT_WARN("App Key Status key indices did not match"); - return; + return -ENOENT; } if (param->status) { *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct app_key_list_param { @@ -276,9 +342,9 @@ struct app_key_list_param { size_t *key_cnt; }; -static void app_key_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int app_key_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct app_key_list_param *param; uint16_t net_idx; @@ -289,18 +355,17 @@ static void app_key_list(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_APP_KEY_LIST) { - BT_WARN("Unexpected App Key List message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_APP_KEY_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); net_idx = net_buf_simple_pull_le16(buf) & 0xfff; - param = cli->op_param; if (param->net_idx != net_idx) { BT_WARN("App Key List Net Key index did not match"); - return; + return -ENOENT; } for (i = 0; i < *param->key_cnt && buf->om_len >= 3; i += 2) { @@ -311,12 +376,19 @@ static void app_key_list(struct bt_mesh_model *model, param->keys[i++] = net_buf_simple_pull_le16(buf) & 0xfff; } + if (buf->om_len > 0U) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EINVAL; + } + *param->key_cnt = i; if (param->status) { *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct mod_app_param { @@ -327,9 +399,9 @@ struct mod_app_param { uint16_t cid; }; -static void mod_app_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int mod_app_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { uint16_t elem_addr, mod_app_idx, mod_id, cid; struct mod_app_param *param; @@ -339,9 +411,14 @@ static void mod_app_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_MOD_APP_STATUS) { - BT_WARN("Unexpected Model App Status message"); - return; + if ((buf->om_len != 7U) && (buf->om_len != 9U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_APP_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); @@ -356,19 +433,20 @@ static void mod_app_status(struct bt_mesh_model *model, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_app_idx != mod_app_idx || param->mod_id != mod_id || param->cid != cid) { BT_WARN("Model App Status parameters did not match"); - return; + return -ENOENT; } if (param->status) { *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct mod_member_list_param { @@ -380,14 +458,19 @@ struct mod_member_list_param { size_t *member_cnt; }; -static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf, bool vnd) +static int mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf, bool vnd, + struct mod_member_list_param *param) { - struct mod_member_list_param *param; uint16_t elem_addr, mod_id, cid; uint8_t status; int i; + if ((vnd && buf->om_len < 7U) || (buf->om_len < 5U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + status = net_buf_simple_pull_u8(buf); elem_addr = net_buf_simple_pull_le16(buf); if (vnd) { @@ -396,16 +479,15 @@ static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_id != mod_id || (vnd && param->cid != cid)) { BT_WARN("Model Member List parameters did not match"); - return; + return -ENOENT; } - if (buf->om_len % 2) { - BT_WARN("Model Member List invalid length"); - return; + if (buf->om_len % 2U) { + BT_ERR("Model Member List invalid length"); + return -EMSGSIZE; } for (i = 0; i < *param->member_cnt && buf->om_len; i++) { @@ -417,39 +499,45 @@ static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void mod_app_list(struct bt_mesh_model *model, +static int mod_app_list(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_SIG_MOD_APP_LIST) { - BT_WARN("Unexpected Model App List message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_SIG_MOD_APP_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - mod_member_list_handle(ctx, buf, false); + return mod_member_list_handle(ctx, buf, false, param); } -static void mod_app_list_vnd(struct bt_mesh_model *model, +static int mod_app_list_vnd(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_VND_MOD_APP_LIST) { - BT_WARN("Unexpected Model App List Vendor message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_VND_MOD_APP_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - mod_member_list_handle(ctx, buf, true); + return mod_member_list_handle(ctx, buf, true, param); } struct mod_pub_param { @@ -460,7 +548,7 @@ struct mod_pub_param { struct bt_mesh_cfg_mod_pub *pub; }; -static void mod_pub_status(struct bt_mesh_model *model, +static int mod_pub_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf*buf) { @@ -472,16 +560,21 @@ static void mod_pub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_MOD_PUB_STATUS) { + if ((buf->om_len != 12U) && (buf->om_len != 14U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EINVAL; + } + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_PUB_STATUS, ctx->addr, + (void **)¶m)) { BT_WARN("Unexpected Model Pub Status message"); - return; + return -ENOENT; } - param = cli->op_param; if (param->cid != CID_NVAL) { if (buf->om_len < 14) { BT_WARN("Unexpected Mod Pub Status with SIG Model"); - return; + return -ENOENT; } cid = sys_get_le16(&buf->om_data[10]); @@ -489,7 +582,7 @@ static void mod_pub_status(struct bt_mesh_model *model, } else { if (buf->om_len > 12) { BT_WARN("Unexpected Mod Pub Status with Vendor Model"); - return; + return -ENOENT; } cid = CID_NVAL; @@ -498,7 +591,7 @@ static void mod_pub_status(struct bt_mesh_model *model, if (mod_id != param->mod_id || cid != param->cid) { BT_WARN("Mod Pub Model ID or Company ID mismatch"); - return; + return -ENOENT; } status = net_buf_simple_pull_u8(buf); @@ -507,7 +600,7 @@ static void mod_pub_status(struct bt_mesh_model *model, if (elem_addr != param->elem_addr) { BT_WARN("Model Pub Status for unexpected element (0x%04x)", elem_addr); - return; + return -ENOENT; } if (param->status) { @@ -524,7 +617,9 @@ static void mod_pub_status(struct bt_mesh_model *model, param->pub->transmit = net_buf_simple_pull_u8(buf); } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct mod_sub_param { @@ -536,9 +631,9 @@ struct mod_sub_param { uint16_t cid; }; -static void mod_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int mod_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { uint16_t elem_addr, sub_addr, mod_id, cid; struct mod_sub_param *param; @@ -548,9 +643,14 @@ static void mod_sub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_MOD_SUB_STATUS) { - BT_WARN("Unexpected Model Subscription Status message"); - return; + if ((buf->om_len != 7U) && (buf->om_len != 9U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EINVAL; + } + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); @@ -565,12 +665,11 @@ static void mod_sub_status(struct bt_mesh_model *model, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_id != mod_id || (param->expect_sub && *param->expect_sub != sub_addr) || param->cid != cid) { BT_WARN("Model Subscription Status parameters did not match"); - return; + return -ENOENT; } if (param->sub_addr) { @@ -581,39 +680,45 @@ static void mod_sub_status(struct bt_mesh_model *model, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void mod_sub_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_MOD_SUB_LIST) { - BT_WARN("Unexpected Model Subscription List message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - mod_member_list_handle(ctx, buf, false); + return mod_member_list_handle(ctx, buf, false, param); } -static void mod_sub_list_vnd(struct bt_mesh_model *model, +static int mod_sub_list_vnd(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_MOD_SUB_LIST_VND) { - BT_WARN("Unexpected Model Subscription List Vendor message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_LIST_VND, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - mod_member_list_handle(ctx, buf, true); + return mod_member_list_handle(ctx, buf, true,param); } struct hb_sub_param { @@ -621,9 +726,9 @@ struct hb_sub_param { struct bt_mesh_cfg_hb_sub *sub; }; -static void hb_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int hb_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { struct hb_sub_param *param; @@ -631,13 +736,11 @@ static void hb_sub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_HEARTBEAT_SUB_STATUS) { - BT_WARN("Unexpected Heartbeat Subscription Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_HEARTBEAT_SUB_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - *param->status = net_buf_simple_pull_u8(buf); param->sub->src = net_buf_simple_pull_le16(buf); @@ -647,7 +750,9 @@ static void hb_sub_status(struct bt_mesh_model *model, param->sub->min = net_buf_simple_pull_u8(buf); param->sub->max = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct hb_pub_param { @@ -655,7 +760,7 @@ struct hb_pub_param { struct bt_mesh_cfg_hb_pub *pub; }; -static void hb_pub_status(struct bt_mesh_model *model, +static int hb_pub_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -665,13 +770,11 @@ static void hb_pub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (cli->op_pending != OP_HEARTBEAT_PUB_STATUS) { - BT_WARN("Unexpected Heartbeat Publication Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_HEARTBEAT_PUB_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - *param->status = net_buf_simple_pull_u8(buf); if (param->pub) { @@ -683,30 +786,118 @@ static void hb_pub_status(struct bt_mesh_model *model, param->pub->net_idx = net_buf_simple_pull_u8(buf); } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; +} + +struct node_idt_param { + uint8_t *status; + uint16_t net_idx; + uint8_t *identity; +}; + +static int node_identity_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct node_idt_param *param; + uint16_t net_idx, identity; + uint8_t status; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, + bt_hex(buf->om_data, buf->om_len)); + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NODE_IDENTITY_STATUS, + ctx->addr, (void **)¶m)) { + return -ENOENT; + } + + status = net_buf_simple_pull_u8(buf); + net_idx = net_buf_simple_pull_le16(buf) & 0xfff; + identity = net_buf_simple_pull_u8(buf); + + if (param && param->status) { + *param->status = status; + } + + if (param->net_idx != net_idx) { + return -ENOENT; + } + + if (param && param->identity) { + *param->identity = identity; + } + + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; +} + +struct lpn_timeout_param { + uint16_t unicast_addr; + int32_t *polltimeout; +}; + +static int lpn_timeout_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct lpn_timeout_param *param; + uint16_t unicast_addr; + int32_t polltimeout; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, + bt_hex(buf->om_data, buf->om_len)); + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_LPN_TIMEOUT_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; + } + + unicast_addr = net_buf_simple_pull_le16(buf); + polltimeout = net_buf_simple_pull_le24(buf); + + if (param->unicast_addr != unicast_addr) { + return -ENOENT; + } + + if (param->polltimeout) { + *param->polltimeout = polltimeout; + } + + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { - { OP_DEV_COMP_DATA_STATUS, 15, comp_data_status }, - { OP_BEACON_STATUS, 1, beacon_status }, - { OP_DEFAULT_TTL_STATUS, 1, ttl_status }, - { OP_FRIEND_STATUS, 1, friend_status }, - { OP_GATT_PROXY_STATUS, 1, gatt_proxy_status }, - { OP_RELAY_STATUS, 2, relay_status }, - { OP_NET_KEY_STATUS, 3, net_key_status }, - { OP_NET_KEY_LIST, 0, net_key_list }, - { OP_APP_KEY_STATUS, 4, app_key_status }, - { OP_APP_KEY_LIST, 3, app_key_list }, - { OP_MOD_APP_STATUS, 7, mod_app_status }, - { OP_SIG_MOD_APP_LIST, 5, mod_app_list}, - { OP_VND_MOD_APP_LIST, 7, mod_app_list_vnd}, - { OP_MOD_PUB_STATUS, 12, mod_pub_status }, - { OP_MOD_SUB_STATUS, 7, mod_sub_status }, - { OP_MOD_SUB_LIST, 5, mod_sub_list}, - { OP_MOD_SUB_LIST_VND, 7, mod_sub_list_vnd}, - { OP_HEARTBEAT_SUB_STATUS, 9, hb_sub_status }, - { OP_HEARTBEAT_PUB_STATUS, 10, hb_pub_status }, - { OP_NODE_RESET_STATUS, 0, node_reset_status}, + { OP_DEV_COMP_DATA_STATUS, BT_MESH_LEN_MIN(15), comp_data_status }, + { OP_BEACON_STATUS, BT_MESH_LEN_EXACT(1), beacon_status }, + { OP_DEFAULT_TTL_STATUS, BT_MESH_LEN_EXACT(1), ttl_status }, + { OP_FRIEND_STATUS, BT_MESH_LEN_EXACT(1), friend_status }, + { OP_GATT_PROXY_STATUS, BT_MESH_LEN_EXACT(1), gatt_proxy_status }, + { OP_RELAY_STATUS, BT_MESH_LEN_EXACT(2), relay_status }, + { OP_NET_TRANSMIT_STATUS, BT_MESH_LEN_EXACT(1), net_transmit_status }, + { OP_NET_KEY_STATUS, BT_MESH_LEN_EXACT(3), net_key_status }, + { OP_NET_KEY_LIST, BT_MESH_LEN_MIN(0), net_key_list }, + { OP_APP_KEY_STATUS, BT_MESH_LEN_EXACT(4), app_key_status }, + { OP_APP_KEY_LIST, BT_MESH_LEN_MIN(3), app_key_list }, + { OP_MOD_APP_STATUS, BT_MESH_LEN_MIN(7), mod_app_status }, + { OP_SIG_MOD_APP_LIST, BT_MESH_LEN_MIN(5), mod_app_list }, + { OP_VND_MOD_APP_LIST, BT_MESH_LEN_MIN(7), mod_app_list_vnd }, + { OP_MOD_PUB_STATUS, BT_MESH_LEN_MIN(12), mod_pub_status }, + { OP_MOD_SUB_STATUS, BT_MESH_LEN_MIN(7), mod_sub_status }, + { OP_MOD_SUB_LIST, BT_MESH_LEN_MIN(5), mod_sub_list }, + { OP_MOD_SUB_LIST_VND, BT_MESH_LEN_MIN(7), mod_sub_list_vnd }, + { OP_HEARTBEAT_SUB_STATUS, BT_MESH_LEN_EXACT(9), hb_sub_status }, + { OP_HEARTBEAT_PUB_STATUS, BT_MESH_LEN_EXACT(10), hb_pub_status }, + { OP_NODE_RESET_STATUS, BT_MESH_LEN_EXACT(0), node_reset_status }, + { OP_NODE_IDENTITY_STATUS, BT_MESH_LEN_EXACT(4), node_identity_status}, + { OP_LPN_TIMEOUT_STATUS, BT_MESH_LEN_EXACT(5), lpn_timeout_status }, + { OP_NET_TRANSMIT_STATUS, BT_MESH_LEN_EXACT(1), transmit_status}, + { OP_KRP_STATUS, BT_MESH_LEN_EXACT(4), krp_status}, BT_MESH_MODEL_OP_END, }; @@ -733,7 +924,7 @@ static int cfg_cli_init(struct bt_mesh_model *model) */ model->keys[0] = BT_MESH_KEY_DEV_ANY; - k_sem_init(&cli->op_sync, 0, 1); + bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); return 0; } @@ -742,43 +933,18 @@ const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb = { .init = cfg_cli_init, }; -static int cli_prepare(void *param, uint32_t op) +static int cli_prepare(void *param, uint32_t op, uint16_t addr) { if (!cli) { BT_ERR("No available Configuration Client context!"); return -EINVAL; } - if (cli->op_pending) { - BT_WARN("Another synchronous operation pending"); - return -EBUSY; - } - - cli->op_param = param; - cli->op_pending = op; - - return 0; -} - -static void cli_reset(void) -{ - cli->op_pending = 0; - cli->op_param = NULL; -} - -static int cli_wait(void) -{ - int err; - - err = k_sem_take(&cli->op_sync, msg_timeout); - - cli_reset(); - - return err; + return bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, op, addr, param); } int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, - uint8_t *status, struct os_mbuf *comp) + uint8_t *rsp, struct os_mbuf *comp) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEV_COMP_DATA_GET, 1); struct bt_mesh_msg_ctx ctx = { @@ -788,12 +954,12 @@ int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, .send_ttl = BT_MESH_TTL_DEFAULT, }; struct comp_data param = { - .status = status, + .page = rsp, .comp = comp, }; int err; - err = cli_prepare(¶m, OP_DEV_COMP_DATA_STATUS); + err = cli_prepare(¶m, OP_DEV_COMP_DATA_STATUS, addr); if (err) { goto done; } @@ -804,11 +970,11 @@ int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -826,7 +992,7 @@ static int get_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t r }; int err; - err = cli_prepare(val, rsp); + err = cli_prepare(val, rsp, addr); if (err) { goto done; } @@ -836,11 +1002,11 @@ static int get_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t r err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -858,7 +1024,7 @@ static int set_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t r }; int err; - err = cli_prepare(val, rsp); + err = cli_prepare(val, rsp, addr); if (err) { goto done; } @@ -869,11 +1035,11 @@ static int set_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t r err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -885,6 +1051,75 @@ int bt_mesh_cfg_beacon_get(uint16_t net_idx, uint16_t addr, uint8_t *status) status); } +int bt_mesh_cfg_krp_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, + uint8_t *status, uint8_t *phase) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_KRP_GET, 2); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct krp_param param = { + .status = status, + .phase = phase, + }; + int err; + + err = cli_prepare(¶m, OP_KRP_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_KRP_GET); + net_buf_simple_add_le16(msg, key_net_idx); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + +int bt_mesh_cfg_krp_set(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, + uint8_t transition, uint8_t *status, uint8_t *phase) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_KRP_SET, 3); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct krp_param param = { + .status = status, + .phase = phase, + }; + int err; + + err = cli_prepare(¶m, OP_KRP_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_KRP_SET); + net_buf_simple_add_le16(msg, key_net_idx); + net_buf_simple_add_u8(msg, transition); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + int bt_mesh_cfg_beacon_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status) { return set_state_u8(net_idx, addr, OP_BEACON_SET, OP_BEACON_STATUS, @@ -958,7 +1193,7 @@ int bt_mesh_cfg_relay_get(uint16_t net_idx, uint16_t addr, uint8_t *status, }; int err; - err = cli_prepare(¶m, OP_RELAY_STATUS); + err = cli_prepare(¶m, OP_RELAY_STATUS, addr); if (err) { goto done; } @@ -968,11 +1203,11 @@ int bt_mesh_cfg_relay_get(uint16_t net_idx, uint16_t addr, uint8_t *status, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -994,7 +1229,7 @@ int bt_mesh_cfg_relay_set(uint16_t net_idx, uint16_t addr, uint8_t new_relay, }; int err; - err = cli_prepare(¶m, OP_RELAY_STATUS); + err = cli_prepare(¶m, OP_RELAY_STATUS, addr); if (err) { goto done; } @@ -1006,11 +1241,11 @@ int bt_mesh_cfg_relay_set(uint16_t net_idx, uint16_t addr, uint8_t new_relay, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1032,7 +1267,7 @@ int bt_mesh_cfg_net_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_id }; int err; - err = cli_prepare(¶m, OP_NET_KEY_STATUS); + err = cli_prepare(¶m, OP_NET_KEY_STATUS, addr); if (err) { goto done; } @@ -1044,21 +1279,62 @@ int bt_mesh_cfg_net_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_id err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; } +int bt_mesh_cfg_net_key_update(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, const uint8_t net_key[16], + uint8_t *status) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_UPDATE, 18); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct net_key_param param = { + .status = status, + .net_idx = key_net_idx, + }; + int err; + + err = cli_prepare(¶m, OP_NET_KEY_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_NET_KEY_UPDATE); + net_buf_simple_add_le16(msg, key_net_idx); + net_buf_simple_add_mem(msg, net_key, 16); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, size_t *key_cnt) { @@ -1075,7 +1351,7 @@ int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, }; int err; - err = cli_prepare(¶m, OP_NET_KEY_LIST); + err = cli_prepare(¶m, OP_NET_KEY_LIST, addr); if (err) { return err; } @@ -1085,12 +1361,12 @@ int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } os_mbuf_free_chain(msg); - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, @@ -1109,7 +1385,7 @@ int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, }; int err; - err = cli_prepare(¶m, OP_NET_KEY_STATUS); + err = cli_prepare(¶m, OP_NET_KEY_STATUS, addr); if (err) { goto done; } @@ -1120,16 +1396,16 @@ int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1153,7 +1429,7 @@ int bt_mesh_cfg_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_id }; int err; - err = cli_prepare(¶m, OP_APP_KEY_STATUS); + err = cli_prepare(¶m, OP_APP_KEY_STATUS, addr); if (err) { goto done; } @@ -1165,21 +1441,63 @@ int bt_mesh_cfg_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_id err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; } +int bt_mesh_cfg_app_key_update(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint16_t key_app_idx, + const uint8_t app_key[16], uint8_t *status) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_UPDATE, 19); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct app_key_param param = { + .status = status, + .net_idx = key_net_idx, + .app_idx = key_app_idx, + }; + int err; + + err = cli_prepare(¶m, OP_APP_KEY_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_APP_KEY_UPDATE); + key_idx_pack(msg, key_net_idx, key_app_idx); + net_buf_simple_add_mem(msg, app_key, 16); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_RESET, 0); @@ -1196,7 +1514,7 @@ int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status) *status = false; } - err = cli_prepare(status, OP_NODE_RESET_STATUS); + err = cli_prepare(status, OP_NODE_RESET_STATUS, addr); if (err) { goto done; } @@ -1206,16 +1524,16 @@ int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status) err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); if (err) { @@ -1243,7 +1561,7 @@ int bt_mesh_cfg_app_key_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_id }; int err; - err = cli_prepare(¶m, OP_APP_KEY_LIST); + err = cli_prepare(¶m, OP_APP_KEY_LIST, addr); if (err) { os_mbuf_free_chain(msg); return err; @@ -1256,12 +1574,12 @@ int bt_mesh_cfg_app_key_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_id if (err) { BT_ERR("model_send() failed (err %d)", err); os_mbuf_free_chain(msg); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } os_mbuf_free_chain(msg); - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, @@ -1281,7 +1599,7 @@ int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, }; int err; - err = cli_prepare(¶m, OP_APP_KEY_STATUS); + err = cli_prepare(¶m, OP_APP_KEY_STATUS, addr); if (err) { os_mbuf_free_chain(msg); return err; @@ -1294,18 +1612,18 @@ int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, if (err) { BT_ERR("model_send() failed (err %d)", err); os_mbuf_free_chain(msg); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); os_mbuf_free_chain(msg); return 0; } os_mbuf_free_chain(msg); - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } static int mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1328,7 +1646,7 @@ static int mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, }; int err; - err = cli_prepare(¶m, OP_MOD_APP_STATUS); + err = cli_prepare(¶m, OP_MOD_APP_STATUS, addr); if (err) { goto done; } @@ -1346,16 +1664,16 @@ static int mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1400,7 +1718,7 @@ static int mod_app_unbind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, }; int err; - err = cli_prepare(¶m, OP_MOD_APP_STATUS); + err = cli_prepare(¶m, OP_MOD_APP_STATUS, addr); if (err) { goto done; } @@ -1418,12 +1736,12 @@ static int mod_app_unbind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); err = 0; goto done; } @@ -1433,7 +1751,7 @@ static int mod_app_unbind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, if (err) { return err; } else { - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } } @@ -1479,7 +1797,7 @@ static int mod_member_list_get(uint32_t op, uint32_t expect_op, uint16_t net_idx }; int err; - err = cli_prepare(¶m, expect_op); + err = cli_prepare(¶m, expect_op, addr); if (err) { goto done; } @@ -1500,11 +1818,11 @@ static int mod_member_list_get(uint32_t op, uint32_t expect_op, uint16_t net_idx err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1528,7 +1846,7 @@ int bt_mesh_cfg_mod_app_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a } return mod_member_list_get(OP_VND_MOD_APP_GET, OP_VND_MOD_APP_LIST, - net_idx, addr, elem_addr, mod_id, CID_NVAL, + net_idx, addr, elem_addr, mod_id, cid, status, apps, app_cnt); } @@ -1551,14 +1869,17 @@ static int mod_sub(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_a }; int err; - err = cli_prepare(¶m, OP_MOD_SUB_STATUS); + err = cli_prepare(¶m, OP_MOD_SUB_STATUS, addr); if (err) { goto done; } bt_mesh_model_msg_init(msg, op); net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_le16(msg, sub_addr); + + if (sub_addr != BT_MESH_ADDR_UNASSIGNED) { + net_buf_simple_add_le16(msg, sub_addr); + } if (cid != CID_NVAL) { net_buf_simple_add_le16(msg, cid); @@ -1569,17 +1890,17 @@ static int mod_sub(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_a err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); err = 0; goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1588,6 +1909,10 @@ static int mod_sub(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_a int bt_mesh_cfg_mod_sub_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint8_t *status) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_ADD, net_idx, addr, elem_addr, sub_addr, mod_id, CID_NVAL, status); } @@ -1596,7 +1921,7 @@ int bt_mesh_cfg_mod_sub_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a uint16_t sub_addr, uint16_t mod_id, uint16_t cid, uint8_t *status) { - if (cid == CID_NVAL) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr) || cid == CID_NVAL) { return -EINVAL; } @@ -1607,15 +1932,27 @@ int bt_mesh_cfg_mod_sub_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a int bt_mesh_cfg_mod_sub_del(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint8_t *status) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_DEL, net_idx, addr, elem_addr, sub_addr, mod_id, CID_NVAL, status); } +int bt_mesh_cfg_mod_sub_del_all(uint16_t net_idx, uint16_t addr, + uint16_t elem_addr, uint16_t mod_id, + uint8_t *status) +{ + return mod_sub(OP_MOD_SUB_DEL_ALL, net_idx, addr, elem_addr, + BT_MESH_ADDR_UNASSIGNED, mod_id, CID_NVAL, status); +} + int bt_mesh_cfg_mod_sub_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid, uint8_t *status) { - if (cid == CID_NVAL) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr) || cid == CID_NVAL) { return -EINVAL; } @@ -1623,9 +1960,25 @@ int bt_mesh_cfg_mod_sub_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a mod_id, cid, status); } +int bt_mesh_cfg_mod_sub_del_all_vnd(uint16_t net_idx, uint16_t addr, + uint16_t elem_addr, uint16_t mod_id, + uint16_t cid, uint8_t *status) +{ + if (cid == CID_NVAL) { + return -EINVAL; + } + + return mod_sub(OP_MOD_SUB_DEL_ALL, net_idx, addr, elem_addr, + BT_MESH_ADDR_UNASSIGNED, mod_id, cid, status); +} + int bt_mesh_cfg_mod_sub_overwrite(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint8_t *status) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_OVERWRITE, net_idx, addr, elem_addr, sub_addr, mod_id, CID_NVAL, status); } @@ -1634,7 +1987,7 @@ int bt_mesh_cfg_mod_sub_overwrite_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid, uint8_t *status) { - if (cid == CID_NVAL) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr) || cid == CID_NVAL) { return -EINVAL; } @@ -1662,13 +2015,13 @@ static int mod_sub_va(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t ele }; int err; - err = cli_prepare(¶m, OP_MOD_SUB_STATUS); + err = cli_prepare(¶m, OP_MOD_SUB_STATUS, addr); if (err) { goto done; } BT_DBG("net_idx 0x%04x addr 0x%04x elem_addr 0x%04x label %s", - net_idx, addr, elem_addr, label); + net_idx, addr, elem_addr, bt_hex(label, 16)); BT_DBG("mod_id 0x%04x cid 0x%04x", mod_id, cid); bt_mesh_model_msg_init(msg, op); @@ -1684,16 +2037,16 @@ static int mod_sub_va(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t ele err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1779,7 +2132,7 @@ int bt_mesh_cfg_mod_sub_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a } return mod_member_list_get(OP_MOD_SUB_GET_VND, OP_MOD_SUB_LIST_VND, - net_idx, addr, elem_addr, mod_id, CID_NVAL, + net_idx, addr, elem_addr, mod_id, cid, status, subs, sub_cnt); } @@ -1803,7 +2156,7 @@ static int mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, }; int err; - err = cli_prepare(¶m, OP_MOD_PUB_STATUS); + err = cli_prepare(¶m, OP_MOD_PUB_STATUS, addr); if (err) { goto done; } @@ -1821,16 +2174,16 @@ static int mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1875,7 +2228,7 @@ static int mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, }; int err; - err = cli_prepare(¶m, OP_MOD_PUB_STATUS); + err = cli_prepare(¶m, OP_MOD_PUB_STATUS, addr); if (err) { goto done; } @@ -1898,38 +2251,101 @@ static int mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; } +static int mod_pub_va_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, + uint16_t mod_id, uint16_t cid, + struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_VA_SET, 27); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct mod_pub_param param = { + .mod_id = mod_id, + .cid = cid, + .elem_addr = elem_addr, + .status = status, + .pub = pub, + }; + int err; + + err = cli_prepare(¶m, OP_MOD_PUB_STATUS, addr); + if (err) { + return err; + } + BT_DBG("app_idx 0x%04x", pub->app_idx); + bt_mesh_model_msg_init(msg, OP_MOD_PUB_VA_SET); + + net_buf_simple_add_le16(msg, elem_addr); + net_buf_simple_add_mem(msg, pub->uuid, 16); + net_buf_simple_add_le16(msg, (pub->app_idx | (pub->cred_flag << 12))); + net_buf_simple_add_u8(msg, pub->ttl); + net_buf_simple_add_u8(msg, pub->period); + net_buf_simple_add_u8(msg, pub->transmit); + + if (cid != CID_NVAL) { + net_buf_simple_add_le16(msg, cid); + } + + net_buf_simple_add_le16(msg, mod_id); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + + int bt_mesh_cfg_mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t mod_id, struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) { - return mod_pub_set(net_idx, addr, elem_addr, mod_id, CID_NVAL, - pub, status); + if (pub->uuid) { + return mod_pub_va_set(net_idx, addr, elem_addr, mod_id, CID_NVAL, pub, status); + } else { + return mod_pub_set(net_idx, addr, elem_addr, mod_id, CID_NVAL, pub, status); + } } int bt_mesh_cfg_mod_pub_set_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, - struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) + uint16_t mod_id, uint16_t cid, struct bt_mesh_cfg_mod_pub *pub, + uint8_t *status) { if (cid == CID_NVAL) { return -EINVAL; } - return mod_pub_set(net_idx, addr, elem_addr, mod_id, cid, pub, status); + if (pub->uuid) { + return mod_pub_va_set(net_idx, addr, elem_addr, mod_id, cid, pub, status); + } else { + return mod_pub_set(net_idx, addr, elem_addr, mod_id, cid, pub, status); + } } int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr, @@ -1948,7 +2364,7 @@ int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr, }; int err; - err = cli_prepare(¶m, OP_HEARTBEAT_SUB_STATUS); + err = cli_prepare(¶m, OP_HEARTBEAT_SUB_STATUS, addr); if (err) { goto done; } @@ -1961,16 +2377,16 @@ int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1992,7 +2408,7 @@ int bt_mesh_cfg_hb_sub_get(uint16_t net_idx, uint16_t addr, }; int err; - err = cli_prepare(¶m, OP_HEARTBEAT_SUB_STATUS); + err = cli_prepare(¶m, OP_HEARTBEAT_SUB_STATUS, addr); if (err) { goto done; } @@ -2002,16 +2418,16 @@ int bt_mesh_cfg_hb_sub_get(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -2032,7 +2448,7 @@ int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, }; int err; - err = cli_prepare(¶m, OP_HEARTBEAT_PUB_STATUS); + err = cli_prepare(¶m, OP_HEARTBEAT_PUB_STATUS, addr); if (err) { goto done; } @@ -2048,16 +2464,16 @@ int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -2079,7 +2495,7 @@ int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, }; int err; - err = cli_prepare(¶m, OP_HEARTBEAT_PUB_STATUS); + err = cli_prepare(¶m, OP_HEARTBEAT_PUB_STATUS, addr); if (err) { goto done; } @@ -2089,21 +2505,138 @@ int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; } +int bt_mesh_cfg_node_identity_set(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint8_t new_identity, + uint8_t *status, uint8_t *identity) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_SET, 4); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct node_idt_param param = { + .status = status, + .net_idx = key_net_idx, + .identity = identity, + }; + int err; + + err = cli_prepare(¶m, OP_NODE_IDENTITY_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_NODE_IDENTITY_SET); + net_buf_simple_add_le16(msg, key_net_idx); + net_buf_simple_add_u8(msg, new_identity); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + +int bt_mesh_cfg_node_identity_get(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint8_t *status, + uint8_t *identity) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_GET, 2); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct node_idt_param param = { + .status = status, + .net_idx = key_net_idx, + .identity = identity, + }; + int err; + + err = cli_prepare(¶m, OP_NODE_IDENTITY_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_NODE_IDENTITY_GET); + net_buf_simple_add_le16(msg, key_net_idx); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + +int bt_mesh_cfg_lpn_timeout_get(uint16_t net_idx, uint16_t addr, + uint16_t unicast_addr, int32_t *polltimeout) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_LPN_TIMEOUT_GET, 2); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct lpn_timeout_param param = { + .unicast_addr = unicast_addr, + .polltimeout = polltimeout, + }; + int err; + + err = cli_prepare(¶m, OP_LPN_TIMEOUT_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_LPN_TIMEOUT_GET); + net_buf_simple_add_le16(msg, unicast_addr); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + int32_t bt_mesh_cfg_cli_timeout_get(void) { return msg_timeout; @@ -2114,4 +2647,68 @@ void bt_mesh_cfg_cli_timeout_set(int32_t timeout) msg_timeout = timeout; } +int bt_mesh_comp_p0_get(struct bt_mesh_comp_p0 *page, + struct os_mbuf *buf) +{ + if (buf->om_len < 10) { + return -EINVAL; + } + + page->cid = net_buf_simple_pull_le16(buf); + page->pid = net_buf_simple_pull_le16(buf); + page->vid = net_buf_simple_pull_le16(buf); + page->crpl = net_buf_simple_pull_le16(buf); + page->feat = net_buf_simple_pull_le16(buf); + page->_buf = buf; + + return 0; +} + +struct bt_mesh_comp_p0_elem *bt_mesh_comp_p0_elem_pull(const struct bt_mesh_comp_p0 *page, + struct bt_mesh_comp_p0_elem *elem) +{ + size_t modlist_size; + + if (page->_buf->om_len < 4) { + return NULL; + } + + elem->loc = net_buf_simple_pull_le16(page->_buf); + elem->nsig = net_buf_simple_pull_u8(page->_buf); + elem->nvnd = net_buf_simple_pull_u8(page->_buf); + + modlist_size = elem->nsig * 2 + elem->nvnd * 4; + + if (page->_buf->om_len < modlist_size) { + return NULL; + } + + elem->_buf = net_buf_simple_pull_mem(page->_buf, modlist_size); + + return elem; +} + +uint16_t bt_mesh_comp_p0_elem_mod(struct bt_mesh_comp_p0_elem *elem, int idx) + { + CHECKIF(idx >= elem->nsig) { + return 0xffff; + } + + return sys_get_le16(&elem->_buf[idx * 2]); +} + +struct bt_mesh_mod_id_vnd bt_mesh_comp_p0_elem_mod_vnd(struct bt_mesh_comp_p0_elem *elem, int idx) + { + CHECKIF(idx >= elem->nvnd) { + return (struct bt_mesh_mod_id_vnd){ 0xffff, 0xffff }; + } + + size_t offset = elem->nsig * 2 + idx * 4; + struct bt_mesh_mod_id_vnd mod = { + .company = sys_get_le16(&elem->_buf[offset]), + .id = sys_get_le16(&elem->_buf[offset + 2]), + }; + + return mod; +} #endif diff --git a/nimble/host/mesh/src/cfg_srv.c b/nimble/host/mesh/src/cfg_srv.c index 8a085bd710..2af24370e3 100644 --- a/nimble/host/mesh/src/cfg_srv.c +++ b/nimble/host/mesh/src/cfg_srv.c @@ -109,12 +109,13 @@ static int comp_get_page_0(struct os_mbuf *buf) return 0; } -static void dev_comp_data_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int dev_comp_data_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); uint8_t page; + int err; BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, @@ -129,7 +130,8 @@ static void dev_comp_data_get(struct bt_mesh_model *model, bt_mesh_model_msg_init(sdu, OP_DEV_COMP_DATA_STATUS); net_buf_simple_add_u8(sdu, page); - if (comp_get_page_0(sdu) < 0) { + err = comp_get_page_0(sdu); + if (err) { BT_ERR("Unable to get composition page 0"); goto done; } @@ -140,6 +142,7 @@ static void dev_comp_data_get(struct bt_mesh_model *model, done: os_mbuf_free_chain(sdu); + return err; } static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, @@ -200,17 +203,20 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, model->pub->count = 0; if (model->pub->update) { - k_delayed_work_cancel(&model->pub->timer); + /* If this fails, the timer will check pub->addr and + * exit without transmitting. + */ + (void)k_work_cancel_delayable(&model->pub->timer); } if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_pub(model); + bt_mesh_model_pub_store(model); } return STATUS_SUCCESS; } - if (!bt_mesh_app_key_exists(app_idx)) { + if (!bt_mesh_app_key_exists(app_idx) || !bt_mesh_model_has_key(model, app_idx)) { return STATUS_INVALID_APPKEY; } @@ -238,14 +244,17 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, BT_DBG("period %u ms", (unsigned) period_ms); if (period_ms > 0) { - k_delayed_work_submit(&model->pub->timer, period_ms); + k_work_reschedule(&model->pub->timer, period_ms); } else { - k_delayed_work_cancel(&model->pub->timer); + /* If this fails, publication will stop after the + * ongoing set of retransmits. + */ + k_work_cancel_delayable(&model->pub->timer); } } if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_pub(model); + bt_mesh_model_pub_store(model); } return STATUS_SUCCESS; @@ -273,7 +282,7 @@ uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) model->keys[i] = key_idx; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_bind(model); + bt_mesh_model_bind_store(model); } return STATUS_SUCCESS; @@ -301,7 +310,7 @@ uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store) model->keys[i] = BT_MESH_KEY_UNUSED; if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_bind(model); + bt_mesh_model_bind_store(model); } if (model->pub && model->pub->key == key_idx) { @@ -313,10 +322,10 @@ uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store) return STATUS_SUCCESS; } -static void send_app_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint8_t status, - uint16_t app_idx, uint16_t net_idx) +static int send_app_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint8_t status, + uint16_t app_idx, uint16_t net_idx) { struct os_mbuf *msg = NET_BUF_SIMPLE( BT_MESH_MODEL_BUF_LEN(OP_APP_KEY_STATUS, 4)); @@ -330,11 +339,12 @@ static void send_app_key_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void app_key_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int app_key_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t key_net_idx, key_app_idx; uint8_t status; @@ -345,10 +355,10 @@ static void app_key_add(struct bt_mesh_model *model, status = bt_mesh_app_key_add(key_app_idx, key_net_idx, buf->om_data); - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); + return send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } -static void app_key_update(struct bt_mesh_model *model, +static int app_key_update(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -361,7 +371,7 @@ static void app_key_update(struct bt_mesh_model *model, status = bt_mesh_app_key_update(key_app_idx, key_net_idx, buf->om_data); BT_DBG("status 0x%02x", status); - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); + return send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } static void mod_app_key_del(struct bt_mesh_model *mod, @@ -381,9 +391,9 @@ static void app_key_evt(uint16_t app_idx, uint16_t net_idx, } } -static void app_key_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int app_key_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t key_net_idx, key_app_idx; uint8_t status; @@ -394,15 +404,15 @@ static void app_key_del(struct bt_mesh_model *model, status = bt_mesh_app_key_del(key_app_idx, key_net_idx); - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); + return send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } /* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */ #define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) -static void app_key_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int app_key_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_LIST, @@ -412,10 +422,12 @@ static void app_key_get(struct bt_mesh_model *model, uint8_t status; ssize_t count; int i; + int err = 0; get_idx = net_buf_simple_pull_le16(buf); if (get_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", get_idx); + err = -EINVAL; goto done; } @@ -455,10 +467,11 @@ static void app_key_get(struct bt_mesh_model *model, } done: - os_mbuf_free_chain(msg); + os_mbuf_free_chain(msg); + return err; } -static void beacon_get(struct bt_mesh_model *model, +static int beacon_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -474,13 +487,16 @@ static void beacon_get(struct bt_mesh_model *model, if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { BT_ERR("Unable to send Config Beacon Status response"); } + + return 0; os_mbuf_free_chain(msg); } -static void beacon_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int beacon_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { + int err = 0; struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_BEACON_STATUS, 1); BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", @@ -489,6 +505,7 @@ static void beacon_set(struct bt_mesh_model *model, if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { BT_WARN("Invalid Config Beacon value 0x%02x", buf->om_data[0]); + err = -EINVAL; goto done; } @@ -503,12 +520,12 @@ static void beacon_set(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); - + return err; } -static void default_ttl_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int default_ttl_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEFAULT_TTL_STATUS, 1); @@ -524,12 +541,12 @@ static void default_ttl_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); - + return 0; } -static void default_ttl_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int default_ttl_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEFAULT_TTL_STATUS, 1); int err; @@ -553,9 +570,10 @@ static void default_ttl_set(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + return err; } -static void send_gatt_proxy_status(struct bt_mesh_model *model, +static int send_gatt_proxy_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_GATT_PROXY_STATUS, 1); @@ -569,20 +587,21 @@ static void send_gatt_proxy_status(struct bt_mesh_model *model, os_mbuf_free_chain(msg); + return 0; } -static void gatt_proxy_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int gatt_proxy_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - send_gatt_proxy_status(model, ctx); + return send_gatt_proxy_status(model, ctx); } -static void gatt_proxy_set(struct bt_mesh_model *model, +static int gatt_proxy_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -592,15 +611,15 @@ static void gatt_proxy_set(struct bt_mesh_model *model, if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { BT_WARN("Invalid GATT Proxy value 0x%02x", buf->om_data[0]); - return; + return -EINVAL; } (void)bt_mesh_gatt_proxy_set(buf->om_data[0]); - send_gatt_proxy_status(model, ctx); + return send_gatt_proxy_status(model, ctx); } -static void net_transmit_get(struct bt_mesh_model *model, +static int net_transmit_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -619,11 +638,12 @@ static void net_transmit_get(struct bt_mesh_model *model, os_mbuf_free_chain(msg); + return 0; } -static void net_transmit_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_transmit_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_TRANSMIT_STATUS, 1); @@ -645,9 +665,11 @@ static void net_transmit_set(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void relay_get(struct bt_mesh_model *model, +static int relay_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -667,13 +689,15 @@ static void relay_get(struct bt_mesh_model *model, os_mbuf_free_chain(msg); + return 0; } -static void relay_set(struct bt_mesh_model *model, +static int relay_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_STATUS, 2); + int err = 0; BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, @@ -681,6 +705,7 @@ static void relay_set(struct bt_mesh_model *model, if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { BT_WARN("Invalid Relay value 0x%02x", buf->om_data[0]); + err = -EINVAL; goto done; } @@ -696,14 +721,14 @@ static void relay_set(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); - + return err; } -static void send_mod_pub_status(struct bt_mesh_model *cfg_mod, - struct bt_mesh_msg_ctx *ctx, - uint16_t elem_addr, uint16_t pub_addr, - bool vnd, struct bt_mesh_model *mod, - uint8_t status, uint8_t *mod_id) +static int send_mod_pub_status(struct bt_mesh_model *cfg_mod, + struct bt_mesh_msg_ctx *ctx, + uint16_t elem_addr, uint16_t pub_addr, + bool vnd, struct bt_mesh_model *mod, + uint8_t status, uint8_t *mod_id) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_STATUS, 14); @@ -737,11 +762,12 @@ static void send_mod_pub_status(struct bt_mesh_model *cfg_mod, } os_mbuf_free_chain(msg); + return 0; } -static void mod_pub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_pub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, pub_addr = 0; struct bt_mesh_model *mod; @@ -749,10 +775,15 @@ static void mod_pub_get(struct bt_mesh_model *model, uint8_t *mod_id, status; bool vnd; + if ((buf->om_len != 4U) && (buf->om_len != 6U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } mod_id = buf->om_data; @@ -782,11 +813,11 @@ static void mod_pub_get(struct bt_mesh_model *model, status = STATUS_SUCCESS; send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + return send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); } -static void mod_pub_set(struct bt_mesh_model *model, +static int mod_pub_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -797,10 +828,15 @@ static void mod_pub_set(struct bt_mesh_model *model, uint8_t *mod_id; bool vnd; + if ((buf->om_len != 11U) && (buf->om_len != 13U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } pub_addr = net_buf_simple_pull_le16(buf); @@ -811,7 +847,7 @@ static void mod_pub_set(struct bt_mesh_model *model, pub_ttl = net_buf_simple_pull_u8(buf); if (pub_ttl > BT_MESH_TTL_MAX && pub_ttl != BT_MESH_TTL_DEFAULT) { BT_ERR("Invalid TTL value 0x%02x", pub_ttl); - return; + return -EINVAL; } pub_period = net_buf_simple_pull_u8(buf); @@ -844,8 +880,8 @@ static void mod_pub_set(struct bt_mesh_model *model, pub_period, retransmit, true); send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + return send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); } static size_t mod_sub_list_clear(struct bt_mesh_model *mod) @@ -880,9 +916,9 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) return clear_count; } -static void mod_pub_va_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_pub_va_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; uint16_t elem_addr, pub_addr, pub_app_idx; @@ -892,10 +928,15 @@ static void mod_pub_va_set(struct bt_mesh_model *model, uint8_t *mod_id; bool vnd; + if ((buf->om_len != 25U) && (buf->om_len != 27U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } label_uuid = net_buf_simple_pull_mem(buf, 16); @@ -905,7 +946,7 @@ static void mod_pub_va_set(struct bt_mesh_model *model, pub_ttl = net_buf_simple_pull_u8(buf); if (pub_ttl > BT_MESH_TTL_MAX && pub_ttl != BT_MESH_TTL_DEFAULT) { BT_ERR("Invalid TTL value 0x%02x", pub_ttl); - return; + return -EINVAL; } pub_period = net_buf_simple_pull_u8(buf); @@ -947,14 +988,14 @@ static void mod_pub_va_set(struct bt_mesh_model *model, } send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + return send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); } -static void send_mod_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status, - uint16_t elem_addr, uint16_t sub_addr, uint8_t *mod_id, - bool vnd) +static int send_mod_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, uint8_t status, + uint16_t elem_addr, uint16_t sub_addr, uint8_t *mod_id, + bool vnd) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_SUB_STATUS, 9); @@ -978,11 +1019,13 @@ static void send_mod_sub_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void mod_sub_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -992,10 +1035,15 @@ static void mod_sub_add(struct bt_mesh_model *model, uint16_t *entry; bool vnd; + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } sub_addr = net_buf_simple_pull_le16(buf); @@ -1040,7 +1088,7 @@ static void mod_sub_add(struct bt_mesh_model *model, status = STATUS_SUCCESS; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { @@ -1049,13 +1097,13 @@ static void mod_sub_add(struct bt_mesh_model *model, send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static void mod_sub_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -1065,10 +1113,15 @@ static void mod_sub_del(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } sub_addr = net_buf_simple_pull_le16(buf); @@ -1110,17 +1163,16 @@ static void mod_sub_del(struct bt_mesh_model *model, *match = BT_MESH_ADDR_UNASSIGNED; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *user_data) +static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, void *user_data) { if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups)); @@ -1131,9 +1183,9 @@ static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, return BT_MESH_WALK_CONTINUE; } -static void mod_sub_overwrite(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_overwrite(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -1142,10 +1194,15 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } sub_addr = net_buf_simple_pull_le16(buf); @@ -1174,14 +1231,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, } if (ARRAY_SIZE(mod->groups) > 0) { - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), - mod_sub_clear_visitor, NULL); + bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); mod->groups[0] = sub_addr; status = STATUS_SUCCESS; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { @@ -1193,13 +1249,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } -static void mod_sub_del_all(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_del_all(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct bt_mesh_model *mod; struct bt_mesh_elem *elem; @@ -1208,10 +1264,15 @@ static void mod_sub_del_all(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 4U) && (buf->om_len != 6U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } BT_DBG("elem_addr 0x%04x", elem_addr); @@ -1232,18 +1293,17 @@ static void mod_sub_del_all(struct bt_mesh_model *model, goto send_status; } - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_clear_visitor, - NULL); + bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } status = STATUS_SUCCESS; send_status: - send_mod_sub_status(model, ctx, status, elem_addr, - BT_MESH_ADDR_UNASSIGNED, mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, + BT_MESH_ADDR_UNASSIGNED, mod_id, vnd); } struct mod_sub_list_ctx { @@ -1251,8 +1311,7 @@ struct mod_sub_list_ctx { struct os_mbuf *msg; }; -static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *ctx) +static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, void *ctx) { struct mod_sub_list_ctx *visit = ctx; int count = 0; @@ -1283,19 +1342,21 @@ static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, return BT_MESH_WALK_CONTINUE; } -static void mod_sub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct mod_sub_list_ctx visit_ctx; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint16_t addr, id; + int err = 0; addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -1328,8 +1389,7 @@ static void mod_sub_get(struct bt_mesh_model *model, visit_ctx.msg = msg; visit_ctx.elem_idx = mod->elem_idx; - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor, - &visit_ctx); + bt_mesh_model_extensions_walk(mod, mod_sub_list_visitor, &visit_ctx); send_list: if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { @@ -1339,21 +1399,24 @@ static void mod_sub_get(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + return err; } -static void mod_sub_get_vnd(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_get_vnd(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct mod_sub_list_ctx visit_ctx; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint16_t company, addr, id; + int err = 0; addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -1390,8 +1453,7 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, visit_ctx.msg = msg; visit_ctx.elem_idx = mod->elem_idx; - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor, - &visit_ctx); + bt_mesh_model_extensions_walk(mod, mod_sub_list_visitor, &visit_ctx); send_list: if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { @@ -1401,11 +1463,12 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + return err; } -static void mod_sub_va_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_va_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -1416,10 +1479,15 @@ static void mod_sub_va_add(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 20U) && (buf->om_len != 22U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } label_uuid = net_buf_simple_pull_mem(buf, 16); @@ -1470,19 +1538,19 @@ static void mod_sub_va_add(struct bt_mesh_model *model, } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } status = STATUS_SUCCESS; send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static void mod_sub_va_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_va_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -1493,10 +1561,15 @@ static void mod_sub_va_del(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 20U) && (buf->om_len != 22U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } label_uuid = net_buf_simple_pull_mem(buf, 16); @@ -1535,7 +1608,7 @@ static void mod_sub_va_del(struct bt_mesh_model *model, *match = BT_MESH_ADDR_UNASSIGNED; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } status = STATUS_SUCCESS; @@ -1544,13 +1617,13 @@ static void mod_sub_va_del(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static void mod_sub_va_overwrite(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_va_overwrite(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; struct bt_mesh_model *mod; @@ -1560,10 +1633,15 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 20U) && (buf->om_len != 22U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } label_uuid = net_buf_simple_pull_mem(buf, 16); @@ -1589,12 +1667,11 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, if (ARRAY_SIZE(mod->groups) > 0) { status = bt_mesh_va_add(label_uuid, &sub_addr); if (status == STATUS_SUCCESS) { - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), - mod_sub_clear_visitor, NULL); + bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); mod->groups[0] = sub_addr; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { @@ -1606,13 +1683,13 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static void send_net_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint16_t idx, uint8_t status) +static int send_net_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint16_t idx, uint8_t status) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_STATUS, 3); @@ -1626,9 +1703,11 @@ static void send_net_key_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void net_key_add(struct bt_mesh_model *model, +static int net_key_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1638,18 +1717,18 @@ static void net_key_add(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } BT_DBG("idx 0x%04x", idx); status = bt_mesh_subnet_add(idx, buf->om_data); - send_net_key_status(model, ctx, idx, status); + return send_net_key_status(model, ctx, idx, status); } -static void net_key_update(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_update(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t status; uint16_t idx; @@ -1657,24 +1736,24 @@ static void net_key_update(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } status = bt_mesh_subnet_update(idx, buf->om_data); - send_net_key_status(model, ctx, idx, status); + return send_net_key_status(model, ctx, idx, status); } -static void net_key_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t del_idx; del_idx = net_buf_simple_pull_le16(buf); if (del_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", del_idx); - return; + return -EINVAL; } BT_DBG("idx 0x%04x", del_idx); @@ -1683,19 +1762,18 @@ static void net_key_del(struct bt_mesh_model *model, * The NetKey List must contain a minimum of one NetKey. */ if (ctx->net_idx == del_idx) { - send_net_key_status(model, ctx, del_idx, + return send_net_key_status(model, ctx, del_idx, STATUS_CANNOT_REMOVE); - return; } - bt_mesh_subnet_del(del_idx); + (void)bt_mesh_subnet_del(del_idx); - send_net_key_status(model, ctx, del_idx, STATUS_SUCCESS); + return send_net_key_status(model, ctx, del_idx, STATUS_SUCCESS); } -static void net_key_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_LIST, @@ -1724,12 +1802,13 @@ static void net_key_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void send_node_id_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint8_t status, - uint16_t net_idx, uint8_t node_id) +static int send_node_id_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint8_t status, + uint16_t net_idx, uint8_t node_id) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_STATUS, 4); @@ -1743,11 +1822,13 @@ static void send_node_id_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void node_identity_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int node_identity_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { enum bt_mesh_feat_state node_id; uint8_t status; @@ -1760,17 +1841,17 @@ static void node_identity_get(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } status = bt_mesh_subnet_node_id_get(idx, &node_id); - send_node_id_status(model, ctx, status, idx, node_id); + return send_node_id_status(model, ctx, status, idx, node_id); } -static void node_identity_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int node_identity_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t node_id, status; uint16_t idx; @@ -1782,30 +1863,28 @@ static void node_identity_set(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_WARN("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } node_id = net_buf_simple_pull_u8(buf); if (node_id != 0x00 && node_id != 0x01) { BT_WARN("Invalid Node ID value 0x%02x", node_id); - return; + return -EINVAL; } status = bt_mesh_subnet_node_id_set(idx, node_id); if (status == STATUS_INVALID_NETKEY) { - send_node_id_status(model, ctx, status, idx, - BT_MESH_NODE_IDENTITY_STOPPED); - return; + return send_node_id_status(model, ctx, status, idx, + BT_MESH_NODE_IDENTITY_STOPPED); } if (status == STATUS_FEAT_NOT_SUPP) { /* Should return success, even if feature isn't supported: */ - send_node_id_status(model, ctx, STATUS_SUCCESS, idx, - BT_MESH_NODE_IDENTITY_NOT_SUPPORTED); - return; + return send_node_id_status(model, ctx, STATUS_SUCCESS, idx, + BT_MESH_NODE_IDENTITY_NOT_SUPPORTED); } - send_node_id_status(model, ctx, status, idx, node_id); + return send_node_id_status(model, ctx, status, idx, node_id); } static void create_mod_app_status(struct os_mbuf *msg, @@ -1826,9 +1905,9 @@ static void create_mod_app_status(struct os_mbuf *msg, } } -static void mod_app_bind(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_app_bind(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_STATUS, 9); uint16_t elem_addr, key_app_idx; @@ -1836,10 +1915,17 @@ static void mod_app_bind(struct bt_mesh_model *model, struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; + int err = 0; + + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -1883,13 +1969,14 @@ static void mod_app_bind(struct bt_mesh_model *model, } done: - os_mbuf_free_chain(msg); + os_mbuf_free_chain(msg); + return err; } -static void mod_app_unbind(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_app_unbind(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_STATUS, 9); uint16_t elem_addr, key_app_idx; @@ -1897,10 +1984,17 @@ static void mod_app_unbind(struct bt_mesh_model *model, struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; + int err = 0; + + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -1937,14 +2031,16 @@ static void mod_app_unbind(struct bt_mesh_model *model, } done: - os_mbuf_free_chain(msg); + os_mbuf_free_chain(msg); + + return err; } #define KEY_LIST_LEN (MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT) * 2) -static void mod_app_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_app_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(max(BT_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, 9 + KEY_LIST_LEN), @@ -1956,10 +2052,17 @@ static void mod_app_get(struct bt_mesh_model *model, uint8_t *mod_id, status; uint16_t elem_addr; bool vnd; + int err = 0; + + if ((buf->om_len != 4U) && (buf->om_len != 6U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -2015,13 +2118,31 @@ static void mod_app_get(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + + return err; } -static void node_reset(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static void reset_send_start(uint16_t duration, int err, void *cb_data) +{ + if (err) { + BT_ERR("Sending Node Reset Status failed (err %d)", err); + bt_mesh_reset(); + } +} + +static void reset_send_end(int err, void *cb_data) +{ + bt_mesh_reset(); +} + +static int node_reset(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { - static struct bt_mesh_proxy_idle_cb proxy_idle = {.cb = bt_mesh_reset}; + static const struct bt_mesh_send_cb reset_cb = { + .start = reset_send_start, + .end = reset_send_end, + }; struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_RESET_STATUS, 0); @@ -2029,30 +2150,19 @@ static void node_reset(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - bt_mesh_model_msg_init(msg, OP_NODE_RESET_STATUS); - /* Send the response first since we wont have any keys left to - * send it later. - */ - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + if (bt_mesh_model_send(model, ctx, msg, &reset_cb, NULL)) { BT_ERR("Unable to send Node Reset Status"); } - if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - bt_mesh_reset(); - return; - } + os_mbuf_free_chain(msg); - /* If the response goes to a proxy node, we'll wait for the sending to - * complete before moving on. - */ - bt_mesh_proxy_on_idle(&proxy_idle); - os_mbuf_free_chain(msg); + return 0; } -static void send_friend_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) +static int send_friend_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_FRIEND_STATUS, 1); @@ -2062,23 +2172,26 @@ static void send_friend_status(struct bt_mesh_model *model, if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { BT_ERR("Unable to send Friend Status"); } - os_mbuf_free_chain(msg); + + os_mbuf_free_chain(msg); + + return 0; } -static void friend_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int friend_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - send_friend_status(model, ctx); + return send_friend_status(model, ctx); } -static void friend_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int friend_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, @@ -2086,22 +2199,23 @@ static void friend_set(struct bt_mesh_model *model, if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { BT_WARN("Invalid Friend value 0x%02x", buf->om_data[0]); - return; + return -EINVAL; } (void)bt_mesh_friend_set(buf->om_data[0]); - send_friend_status(model, ctx); + return send_friend_status(model, ctx); } -static void lpn_timeout_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int lpn_timeout_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_LPN_TIMEOUT_STATUS, 5); struct bt_mesh_friend *frnd; + int32_t timeout_steps; uint16_t lpn_addr; - int32_t timeout; + int err = 0; lpn_addr = net_buf_simple_pull_le16(buf); @@ -2111,6 +2225,7 @@ static void lpn_timeout_get(struct bt_mesh_model *model, /* check if it's the address of the Low Power Node? */ if (!BT_MESH_ADDR_IS_UNICAST(lpn_addr)) { BT_WARN("Invalid LPNAddress; ignoring msg"); + err = -EINVAL; goto done; } @@ -2118,20 +2233,21 @@ static void lpn_timeout_get(struct bt_mesh_model *model, net_buf_simple_add_le16(msg, lpn_addr); if (!IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - timeout = 0; + timeout_steps = 0; goto send_rsp; } frnd = bt_mesh_friend_find(BT_MESH_KEY_ANY, lpn_addr, true, true); if (!frnd) { - timeout = 0; + timeout_steps = 0; goto send_rsp; } - timeout = k_delayed_work_remaining_get(&frnd->timer) / 100; + /* PollTimeout should be reported in steps of 100ms. */ + timeout_steps = frnd->poll_to / 100; send_rsp: - net_buf_simple_add_le24(msg, timeout); + net_buf_simple_add_le24(msg, timeout_steps); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { BT_ERR("Unable to send LPN PollTimeout Status"); @@ -2139,11 +2255,13 @@ static void lpn_timeout_get(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + + return err; } -static void send_krp_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint16_t idx, uint8_t phase, uint8_t status) +static int send_krp_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint16_t idx, uint8_t phase, uint8_t status) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_KRP_STATUS, 4); @@ -2158,10 +2276,12 @@ static void send_krp_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t kr_phase, status; uint16_t idx; @@ -2169,18 +2289,18 @@ static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } BT_DBG("idx 0x%04x", idx); status = bt_mesh_subnet_kr_phase_get(idx, &kr_phase); - send_krp_status(model, ctx, idx, kr_phase, status); + return send_krp_status(model, ctx, idx, kr_phase, status); } -static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t phase, status; uint16_t idx; @@ -2190,16 +2310,16 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } status = bt_mesh_subnet_kr_phase_set(idx, &phase); if (status == STATUS_CANNOT_UPDATE) { BT_ERR("Invalid kr phase transition 0x%02x", phase); - return; + return -EINVAL; } - send_krp_status(model, ctx, idx, phase, status); + return send_krp_status(model, ctx, idx, phase, status); } static uint8_t hb_pub_count_log(uint16_t val) @@ -2224,9 +2344,9 @@ struct hb_pub_param { uint16_t net_idx; } __packed; -static void hb_pub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status, - const struct bt_mesh_hb_pub *pub) +static int hb_pub_send_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, uint8_t status, + const struct bt_mesh_hb_pub *pub) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_STATUS, 10); @@ -2248,9 +2368,11 @@ static void hb_pub_send_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void heartbeat_pub_get(struct bt_mesh_model *model, +static int heartbeat_pub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2260,12 +2382,12 @@ static void heartbeat_pub_get(struct bt_mesh_model *model, bt_mesh_hb_pub_get(&pub); - hb_pub_send_status(model, ctx, STATUS_SUCCESS, &pub); + return hb_pub_send_status(model, ctx, STATUS_SUCCESS, &pub); } -static void heartbeat_pub_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int heartbeat_pub_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct hb_pub_param *param = (void *)buf->om_data; struct bt_mesh_hb_pub pub; @@ -2298,22 +2420,22 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, if (param->ttl > BT_MESH_TTL_MAX && param->ttl != BT_MESH_TTL_DEFAULT) { BT_ERR("Invalid TTL value 0x%02x", param->ttl); - return; + return -EINVAL; } if (pub.net_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", pub.net_idx); - return; + return -EINVAL; } status = bt_mesh_hb_pub_set(&pub); rsp: - hb_pub_send_status(model, ctx, status, &pub); + return hb_pub_send_status(model, ctx, status, &pub); } -static void hb_sub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - const struct bt_mesh_hb_sub *sub) +static int hb_sub_send_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const struct bt_mesh_hb_sub *sub) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_STATUS, 9); BT_DBG("src 0x%04x ", ctx->addr); @@ -2334,11 +2456,13 @@ static void hb_sub_send_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void heartbeat_sub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int heartbeat_sub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct bt_mesh_hb_sub sub; @@ -2346,17 +2470,18 @@ static void heartbeat_sub_get(struct bt_mesh_model *model, bt_mesh_hb_sub_get(&sub); - hb_sub_send_status(model, ctx, &sub); + return hb_sub_send_status(model, ctx, &sub); } -static void heartbeat_sub_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int heartbeat_sub_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t period_log, status; struct bt_mesh_hb_sub sub; uint16_t sub_src, sub_dst; uint32_t period; + int err; BT_DBG("src 0x%04x", ctx->addr); @@ -2369,7 +2494,7 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, if (period_log > 0x11) { BT_WARN("Prohibited subscription period 0x%02x", period_log); - return; + return -EINVAL; } period = bt_mesh_hb_pwr2(period_log); @@ -2379,7 +2504,7 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, /* All errors are caused by invalid packets, which should be * ignored. */ - return; + return -EINVAL; } bt_mesh_hb_sub_get(&sub); @@ -2387,61 +2512,74 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, /* MESH/NODE/CFG/HBS/BV-01-C expects the MinHops to be 0x7f after * disabling subscription, but 0x00 for subsequent Get requests. */ - if (!period_log) { + if (sub.src == BT_MESH_ADDR_UNASSIGNED || !period_log) { sub.min_hops = BT_MESH_TTL_MAX; } - hb_sub_send_status(model, ctx, &sub); + err = hb_sub_send_status(model, ctx, &sub); + if (err) { + return err; + } + + /* MESH/NODE/CFG/HBS/BV-02-C expects us to return previous + * count value and then reset it to 0. + */ + if (sub.src != BT_MESH_ADDR_UNASSIGNED && + sub.dst != BT_MESH_ADDR_UNASSIGNED && !period) { + bt_mesh_hb_sub_reset_count(); + } + + return 0; } const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = { - { OP_DEV_COMP_DATA_GET, 1, dev_comp_data_get }, - { OP_APP_KEY_ADD, 19, app_key_add }, - { OP_APP_KEY_UPDATE, 19, app_key_update }, - { OP_APP_KEY_DEL, 3, app_key_del }, - { OP_APP_KEY_GET, 2, app_key_get }, - { OP_BEACON_GET, 0, beacon_get }, - { OP_BEACON_SET, 1, beacon_set }, - { OP_DEFAULT_TTL_GET, 0, default_ttl_get }, - { OP_DEFAULT_TTL_SET, 1, default_ttl_set }, - { OP_GATT_PROXY_GET, 0, gatt_proxy_get }, - { OP_GATT_PROXY_SET, 1, gatt_proxy_set }, - { OP_NET_TRANSMIT_GET, 0, net_transmit_get }, - { OP_NET_TRANSMIT_SET, 1, net_transmit_set }, - { OP_RELAY_GET, 0, relay_get }, - { OP_RELAY_SET, 2, relay_set }, - { OP_MOD_PUB_GET, 4, mod_pub_get }, - { OP_MOD_PUB_SET, 11, mod_pub_set }, - { OP_MOD_PUB_VA_SET, 24, mod_pub_va_set }, - { OP_MOD_SUB_ADD, 6, mod_sub_add }, - { OP_MOD_SUB_VA_ADD, 20, mod_sub_va_add }, - { OP_MOD_SUB_DEL, 6, mod_sub_del }, - { OP_MOD_SUB_VA_DEL, 20, mod_sub_va_del }, - { OP_MOD_SUB_OVERWRITE, 6, mod_sub_overwrite }, - { OP_MOD_SUB_VA_OVERWRITE, 20, mod_sub_va_overwrite }, - { OP_MOD_SUB_DEL_ALL, 4, mod_sub_del_all }, - { OP_MOD_SUB_GET, 4, mod_sub_get }, - { OP_MOD_SUB_GET_VND, 6, mod_sub_get_vnd }, - { OP_NET_KEY_ADD, 18, net_key_add }, - { OP_NET_KEY_UPDATE, 18, net_key_update }, - { OP_NET_KEY_DEL, 2, net_key_del }, - { OP_NET_KEY_GET, 0, net_key_get }, - { OP_NODE_IDENTITY_GET, 2, node_identity_get }, - { OP_NODE_IDENTITY_SET, 3, node_identity_set }, - { OP_MOD_APP_BIND, 6, mod_app_bind }, - { OP_MOD_APP_UNBIND, 6, mod_app_unbind }, - { OP_SIG_MOD_APP_GET, 4, mod_app_get }, - { OP_VND_MOD_APP_GET, 6, mod_app_get }, - { OP_NODE_RESET, 0, node_reset }, - { OP_FRIEND_GET, 0, friend_get }, - { OP_FRIEND_SET, 1, friend_set }, - { OP_LPN_TIMEOUT_GET, 2, lpn_timeout_get }, - { OP_KRP_GET, 2, krp_get }, - { OP_KRP_SET, 3, krp_set }, - { OP_HEARTBEAT_PUB_GET, 0, heartbeat_pub_get }, - { OP_HEARTBEAT_PUB_SET, 9, heartbeat_pub_set }, - { OP_HEARTBEAT_SUB_GET, 0, heartbeat_sub_get }, - { OP_HEARTBEAT_SUB_SET, 5, heartbeat_sub_set }, + { OP_DEV_COMP_DATA_GET, BT_MESH_LEN_EXACT(1), dev_comp_data_get }, + { OP_APP_KEY_ADD, BT_MESH_LEN_EXACT(19), app_key_add }, + { OP_APP_KEY_UPDATE, BT_MESH_LEN_EXACT(19), app_key_update }, + { OP_APP_KEY_DEL, BT_MESH_LEN_EXACT(3), app_key_del }, + { OP_APP_KEY_GET, BT_MESH_LEN_EXACT(2), app_key_get }, + { OP_BEACON_GET, BT_MESH_LEN_EXACT(0), beacon_get }, + { OP_BEACON_SET, BT_MESH_LEN_EXACT(1), beacon_set }, + { OP_DEFAULT_TTL_GET, BT_MESH_LEN_EXACT(0), default_ttl_get }, + { OP_DEFAULT_TTL_SET, BT_MESH_LEN_EXACT(1), default_ttl_set }, + { OP_GATT_PROXY_GET, BT_MESH_LEN_EXACT(0), gatt_proxy_get }, + { OP_GATT_PROXY_SET, BT_MESH_LEN_EXACT(1), gatt_proxy_set }, + { OP_NET_TRANSMIT_GET, BT_MESH_LEN_EXACT(0), net_transmit_get }, + { OP_NET_TRANSMIT_SET, BT_MESH_LEN_EXACT(1), net_transmit_set }, + { OP_RELAY_GET, BT_MESH_LEN_EXACT(0), relay_get }, + { OP_RELAY_SET, BT_MESH_LEN_EXACT(2), relay_set }, + { OP_MOD_PUB_GET, BT_MESH_LEN_MIN(4), mod_pub_get }, + { OP_MOD_PUB_SET, BT_MESH_LEN_MIN(11), mod_pub_set }, + { OP_MOD_PUB_VA_SET, BT_MESH_LEN_MIN(25), mod_pub_va_set }, + { OP_MOD_SUB_ADD, BT_MESH_LEN_MIN(6), mod_sub_add }, + { OP_MOD_SUB_VA_ADD, BT_MESH_LEN_MIN(20), mod_sub_va_add }, + { OP_MOD_SUB_DEL, BT_MESH_LEN_MIN(6), mod_sub_del }, + { OP_MOD_SUB_VA_DEL, BT_MESH_LEN_MIN(20), mod_sub_va_del }, + { OP_MOD_SUB_OVERWRITE, BT_MESH_LEN_MIN(6), mod_sub_overwrite }, + { OP_MOD_SUB_VA_OVERWRITE, BT_MESH_LEN_MIN(20), mod_sub_va_overwrite }, + { OP_MOD_SUB_DEL_ALL, BT_MESH_LEN_MIN(4), mod_sub_del_all }, + { OP_MOD_SUB_GET, BT_MESH_LEN_EXACT(4), mod_sub_get }, + { OP_MOD_SUB_GET_VND, BT_MESH_LEN_EXACT(6), mod_sub_get_vnd }, + { OP_NET_KEY_ADD, BT_MESH_LEN_EXACT(18), net_key_add }, + { OP_NET_KEY_UPDATE, BT_MESH_LEN_EXACT(18), net_key_update }, + { OP_NET_KEY_DEL, BT_MESH_LEN_EXACT(2), net_key_del }, + { OP_NET_KEY_GET, BT_MESH_LEN_EXACT(0), net_key_get }, + { OP_NODE_IDENTITY_GET, BT_MESH_LEN_EXACT(2), node_identity_get }, + { OP_NODE_IDENTITY_SET, BT_MESH_LEN_EXACT(3), node_identity_set }, + { OP_MOD_APP_BIND, BT_MESH_LEN_MIN(6), mod_app_bind }, + { OP_MOD_APP_UNBIND, BT_MESH_LEN_MIN(6), mod_app_unbind }, + { OP_SIG_MOD_APP_GET, BT_MESH_LEN_MIN(4), mod_app_get }, + { OP_VND_MOD_APP_GET, BT_MESH_LEN_MIN(6), mod_app_get }, + { OP_NODE_RESET, BT_MESH_LEN_EXACT(0), node_reset }, + { OP_FRIEND_GET, BT_MESH_LEN_EXACT(0), friend_get }, + { OP_FRIEND_SET, BT_MESH_LEN_EXACT(1), friend_set }, + { OP_LPN_TIMEOUT_GET, BT_MESH_LEN_EXACT(2), lpn_timeout_get }, + { OP_KRP_GET, BT_MESH_LEN_EXACT(2), krp_get }, + { OP_KRP_SET, BT_MESH_LEN_EXACT(3), krp_set }, + { OP_HEARTBEAT_PUB_GET, BT_MESH_LEN_EXACT(0), heartbeat_pub_get }, + { OP_HEARTBEAT_PUB_SET, BT_MESH_LEN_EXACT(9), heartbeat_pub_set }, + { OP_HEARTBEAT_SUB_GET, BT_MESH_LEN_EXACT(0), heartbeat_sub_get }, + { OP_HEARTBEAT_SUB_SET, BT_MESH_LEN_EXACT(5), heartbeat_sub_set }, BT_MESH_MODEL_OP_END, }; @@ -2484,7 +2622,7 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, if (IS_ENABLED(CONFIG_BT_SETTINGS)) { if (clear_count) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } } @@ -2493,7 +2631,7 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, } } -void bt_mesh_cfg_reset(void) +void bt_mesh_model_reset(void) { bt_mesh_model_foreach(mod_reset, NULL); } diff --git a/nimble/host/mesh/src/crypto.h b/nimble/host/mesh/src/crypto.h index 637d13e724..dbdedf1fd6 100644 --- a/nimble/host/mesh/src/crypto.h +++ b/nimble/host/mesh/src/crypto.h @@ -70,7 +70,7 @@ static inline int bt_mesh_beacon_key(const uint8_t net_key[16], } int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, - const uint8_t net_id[16], uint32_t iv_index, + const uint8_t net_id[8], uint32_t iv_index, uint8_t auth[8]); static inline int bt_mesh_app_id(const uint8_t app_key[16], uint8_t app_id[1]) diff --git a/nimble/host/mesh/src/foundation.h b/nimble/host/mesh/src/foundation.h index 012afbbb07..21734047ec 100644 --- a/nimble/host/mesh/src/foundation.h +++ b/nimble/host/mesh/src/foundation.h @@ -115,7 +115,7 @@ #define STATUS_UNSPECIFIED 0x10 #define STATUS_INVALID_BINDING 0x11 -void bt_mesh_cfg_reset(void); +void bt_mesh_model_reset(void); void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time); diff --git a/nimble/host/mesh/src/friend.c b/nimble/host/mesh/src/friend.c index 9a83c87fc5..4ce0bbdece 100644 --- a/nimble/host/mesh/src/friend.c +++ b/nimble/host/mesh/src/friend.c @@ -42,8 +42,6 @@ static struct os_mempool friend_buf_mempool; #define NET_BUF_FRAGS BIT(0) -#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). */ @@ -66,12 +64,19 @@ static struct friend_adv { uint16_t app_idx; } adv_pool[FRIEND_BUF_COUNT]; +#define FRIEND_ADV(buf) CONTAINER_OF(BT_MESH_ADV(buf), struct friend_adv, adv) + static struct bt_mesh_adv *adv_alloc(int id) { adv_pool[id].app_idx = BT_MESH_KEY_UNUSED; return &adv_pool[id].adv; } +static bool friend_is_allocated(const struct bt_mesh_friend *frnd) +{ + return frnd->subnet != NULL; +} + static bool is_lpn_unicast(struct bt_mesh_friend *frnd, uint16_t addr) { if (frnd->lpn == BT_MESH_ADDR_UNASSIGNED) { @@ -91,7 +96,7 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (valid && !frnd->subnet) { + if (valid && !friend_is_allocated(frnd)) { continue; } @@ -125,6 +130,7 @@ static void purge_buffers(struct net_buf_slist_t *list) while (!net_buf_slist_is_empty(list)) { struct os_mbuf *buf; buf = (void *)net_buf_slist_get(list); + BT_MESH_ADV(buf)->frags = NULL; BT_MESH_ADV(buf)->flags &= ~NET_BUF_FRAGS; net_buf_unref(buf); } @@ -150,16 +156,11 @@ static void friend_clear(struct bt_mesh_friend *frnd) BT_DBG("LPN 0x%04x", frnd->lpn); - k_delayed_work_cancel(&frnd->timer); + (void)k_work_cancel_delayable(&frnd->timer); memset(frnd->cred, 0, sizeof(frnd->cred)); if (frnd->last) { - /* Cancel the sending if necessary */ - if (frnd->pending_buf) { - BT_MESH_ADV(frnd->last)->busy = 0; - } - net_buf_unref(frnd->last); frnd->last = NULL; } @@ -192,7 +193,7 @@ void bt_mesh_friends_clear(void) for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (!frnd->subnet) { + if (!friend_is_allocated(frnd)) { continue; } @@ -211,7 +212,7 @@ void bt_mesh_friend_sec_update(uint16_t net_idx) for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (!frnd->subnet) { + if (!friend_is_allocated(frnd)) { continue; } @@ -345,7 +346,12 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, struct unseg_app_sdu_meta *meta) { uint16_t app_idx = FRIEND_ADV(buf)->app_idx; - struct bt_mesh_net_rx net; + struct bt_mesh_net_rx net = { + .ctx = { + .app_idx = app_idx, + .net_idx = frnd->subnet->net_idx, + }, + }; int err; meta->subnet = frnd->subnet; @@ -379,15 +385,21 @@ static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd, const struct unseg_app_sdu_meta *meta) { struct net_buf_simple_state state; + struct os_mbuf *in = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); + struct os_mbuf *out = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); int err; - BT_DBG(""); - net_buf_simple_save(buf, &state); - net_buf_simple_pull_mem(buf, 10); - buf->om_len -= 4; + /* Direct the input buffer at the Upper Transport Access PDU, accounting for + * the network header and the 1 byte lower transport header + */ + net_buf_simple_clone(buf, in); + net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN); + net_buf_simple_pull(buf, 1); + in->om_len -= BT_MESH_MIC_SHORT;; - err = bt_mesh_app_decrypt(meta->key, &meta->crypto, buf, buf); + net_buf_simple_clone(in, out); + err = bt_mesh_app_decrypt(meta->key, &meta->crypto, in, out); net_buf_simple_restore(buf, &state); net_buf_unref(buf); @@ -404,8 +416,9 @@ static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd, BT_DBG(""); net_buf_simple_save(buf, &state); - net_buf_simple_pull_mem(buf, 10); - buf->om_len -= 4; + net_buf_simple_pull_mem(buf, BT_MESH_NET_HDR_LEN); + net_buf_simple_pull_mem(buf, 1); + buf->om_len -= BT_MESH_MIC_SHORT; err = bt_mesh_app_encrypt(meta->key, &meta->crypto, buf); @@ -437,12 +450,19 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, return 0; } + BT_DBG("Re-encrypting friend pdu (SeqNum %06x -> %06x)", + meta.crypto.seq_num, bt_mesh.seq); + + meta.crypto.seq_num = bt_mesh.seq; + err = unseg_app_sdu_decrypt(frnd, buf, &meta); if (err) { BT_WARN("Decryption failed! %d", err); return err; } + meta.crypto.seq_num = bt_mesh.seq; + err = unseg_app_sdu_encrypt(frnd, buf, &meta); if (err) { BT_WARN("Re-encryption failed! %d", err); @@ -452,14 +472,14 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, } static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf, - bool master_cred) + bool flooding_cred) { const struct bt_mesh_net_cred *cred; uint32_t iv_index; uint16_t src; int err; - if (master_cred) { + if (flooding_cred) { cred = &frnd->subnet->keys[SUBNET_KEY_TX_IDX(frnd->subnet)] .msg; } else { @@ -468,7 +488,7 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf, src = sys_get_be16(&buf->om_data[5]); - if (bt_mesh_elem_find(src)) { + if (bt_mesh_has_addr(src)) { uint32_t seq; if (FRIEND_ADV(buf)->app_idx != BT_MESH_KEY_UNUSED) { @@ -516,8 +536,8 @@ static struct os_mbuf *encode_friend_ctl(struct bt_mesh_friend *frnd, info.src = bt_mesh_primary_addr(); info.dst = frnd->lpn; - info.ctl = 1; - info.ttl = 0; + info.ctl = 1U; + info.ttl = 0U; memset(info.seq, 0, sizeof(info.seq)); @@ -532,7 +552,7 @@ static struct os_mbuf *encode_update(struct bt_mesh_friend *frnd, uint8_t md) struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*upd)); struct os_mbuf *buf; - __ASSERT_NO_MSG(frnd->subnet); + __ASSERT_NO_MSG(friend_is_allocated(frnd)); BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); @@ -589,7 +609,7 @@ static void friend_recv_delay(struct bt_mesh_friend *frnd) int32_t delay = recv_delay(frnd); frnd->pending_req = 1; - k_delayed_work_submit(&frnd->timer, K_MSEC(delay)); + k_work_reschedule(&frnd->timer, K_MSEC(delay)); BT_DBG("Waiting RecvDelay of %d ms", delay); } @@ -756,7 +776,7 @@ static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; - k_delayed_work_submit(&frnd->clear.timer, + k_work_reschedule(&frnd->clear.timer, K_SECONDS(frnd->clear.repeat_sec)); frnd->clear.repeat_sec *= 2; } @@ -795,6 +815,11 @@ static void clear_timeout(struct ble_npl_event *work) struct bt_mesh_friend *frnd = ble_npl_event_get_arg(work); uint32_t duration; + if (frnd->clear.frnd == BT_MESH_ADDR_UNASSIGNED) { + /* Failed cancelling timer, return early. */ + return; + } + BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); duration = k_uptime_get_32() - frnd->clear.start; @@ -851,7 +876,8 @@ int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, return 0; } - k_delayed_work_cancel(&frnd->clear.timer); + /* If this fails, the unassigned check will make the handler return early. */ + (void)k_work_cancel_delayable(&frnd->clear.timer); frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED; return 0; @@ -1016,12 +1042,12 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) (unsigned) frnd->poll_to); if (BT_MESH_ADDR_IS_UNICAST(frnd->clear.frnd) && - !bt_mesh_elem_find(frnd->clear.frnd)) { + !bt_mesh_has_addr(frnd->clear.frnd)) { clear_procedure_start(frnd); } delay = offer_delay(frnd, rx->ctx.recv_rssi, msg->criteria); - k_delayed_work_submit(&frnd->timer, K_MSEC(delay)); + k_work_reschedule(&frnd->timer, K_MSEC(delay)); enqueue_offer(frnd, rx->ctx.recv_rssi); @@ -1138,12 +1164,13 @@ static void buf_send_end(int err, void *user_data) } if (frnd->established) { - k_delayed_work_submit(&frnd->timer, frnd->poll_to); + /* Always restart poll timeout timer after sending */ + k_work_reschedule(&frnd->timer, K_MSEC(frnd->poll_to)); BT_DBG("Waiting %u ms for next poll", (unsigned) frnd->poll_to); } else { /* Friend offer timeout is 1 second */ - k_delayed_work_submit(&frnd->timer, K_SECONDS(1)); + k_work_reschedule(&frnd->timer, K_SECONDS(1)); BT_DBG("Waiting for first poll"); } } @@ -1187,9 +1214,13 @@ static void friend_timeout(struct ble_npl_event *work) .start = buf_send_start, .end = buf_send_end, }; - + struct os_mbuf *buf; uint8_t md; + if (!friend_is_allocated(frnd)) { + return; + } + __ASSERT_NO_MSG(frnd->pending_buf == 0); BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn, @@ -1225,16 +1256,24 @@ static void friend_timeout(struct ble_npl_event *work) /* Clear the flag we use for segment tracking */ BT_MESH_ADV(frnd->last)->flags &= ~NET_BUF_FRAGS; - BT_MESH_ADV(frnd->last)->flags = 0; + BT_MESH_ADV(frnd->last)->frags = NULL; BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x", frnd->last, frnd->lpn); frnd->queue_size--; send_last: + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, FRIEND_XMIT, K_NO_WAIT); + if (!buf) { + BT_ERR("Unable to allocate friend adv buffer"); + return; + } + + net_buf_add_mem(buf, frnd->last->om_data, frnd->last->om_len); frnd->pending_req = 0; frnd->pending_buf = 1; - bt_mesh_adv_send(frnd->last, &buf_sent_cb, frnd); + bt_mesh_adv_send(buf, &buf_sent_cb, frnd); + net_buf_unref(buf); } static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) @@ -1306,10 +1345,10 @@ int bt_mesh_friend_init(void) net_buf_slist_init(&frnd->queue); - k_delayed_work_init(&frnd->timer, friend_timeout); - k_delayed_work_add_arg(&frnd->timer, frnd); - k_delayed_work_init(&frnd->clear.timer, clear_timeout); - k_delayed_work_add_arg(&frnd->clear.timer, frnd); + k_work_init_delayable(&frnd->timer, friend_timeout); + k_work_add_arg_delayable(&frnd->timer, frnd); + k_work_init_delayable(&frnd->clear.timer, clear_timeout); + k_work_add_arg_delayable(&frnd->clear.timer, frnd); for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) { net_buf_slist_init(&frnd->seg[j].queue); @@ -1371,7 +1410,8 @@ static void friend_purge_old_ack(struct bt_mesh_friend *frnd, uint64_t *seq_auth net_buf_slist_remove(&frnd->queue, prev, cur); frnd->queue_size--; - + /* Make sure old slist entry state doesn't remain */ + BT_MESH_ADV(buf)->frags = NULL; net_buf_unref(buf); break; } @@ -1391,7 +1431,7 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, * this rx function. These packets have already been added to the * queue, and should be ignored. */ - if (bt_mesh_elem_find(rx->ctx.addr)) { + if (bt_mesh_has_addr(rx->ctx.addr)) { return; } @@ -1612,6 +1652,7 @@ static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, uint16_t add BT_DBG("PENDING SEGMENTS %d", pending_segments); /* Make sure old slist entry state doesn't remain */ + BT_MESH_ADV(buf)->frags = NULL; BT_MESH_ADV(buf)->flags &= ~NET_BUF_FRAGS; net_buf_unref(buf); @@ -1650,6 +1691,11 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, continue; } + if (friend_lpn_matches(frnd, rx->sub->net_idx, + rx->ctx.addr)) { + continue; + } + if (!friend_queue_prepare_space(frnd, rx->ctx.addr, seq_auth, seg_count)) { continue; diff --git a/nimble/host/mesh/src/glue.c b/nimble/host/mesh/src/glue.c index aab7f37414..c00af9477e 100644 --- a/nimble/host/mesh/src/glue.c +++ b/nimble/host/mesh/src/glue.c @@ -22,6 +22,7 @@ #include "mesh/glue.h" #include "adv.h" +#include "../src/ble_hs_conn_priv.h" #ifndef MYNEWT #include "nimble/nimble_port.h" #endif @@ -104,6 +105,10 @@ net_buf_unref(struct os_mbuf *om) } adv = BT_MESH_ADV(om); + if (adv->started && adv->cb && adv->cb->end) { + adv->cb->end(0, adv->cb_data); + } + if (--adv->ref_cnt > 0) { return; } @@ -112,6 +117,14 @@ net_buf_unref(struct os_mbuf *om) os_mbuf_free_chain(om); } + +void net_buf_simple_clone(const struct os_mbuf *original, + struct os_mbuf *clone) +{ + memcpy(clone, original, sizeof(struct os_mbuf)); +} + + int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data) { @@ -142,6 +155,20 @@ net_buf_simple_pull_le16(struct os_mbuf *om) return val; } +uint32_t +net_buf_simple_pull_le24(struct os_mbuf *om) +{ + uint32_t val; + struct os_mbuf *old = om; + + om = os_mbuf_pullup(om, 3); + assert(om == old); + val = get_le24(om->om_data); + os_mbuf_adj(om, 3); + + return val; +} + uint16_t net_buf_simple_pull_be16(struct os_mbuf *om) { @@ -399,7 +426,7 @@ k_work_init(struct ble_npl_callout *work, ble_npl_event_fn handler) } void -k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f) +k_work_init_delayable(struct k_work_delayable *w, ble_npl_event_fn *f) { #ifndef MYNEWT ble_npl_callout_init(&w->work, nimble_port_get_dflt_eventq(), f, NULL); @@ -409,26 +436,37 @@ k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f) } bool -k_delayed_work_pending(struct k_delayed_work *w) +k_work_delayable_is_pending(struct k_work_delayable *w) { return ble_npl_callout_is_active(&w->work); } void -k_delayed_work_cancel(struct k_delayed_work *w) +k_work_cancel_delayable(struct k_work_delayable *w) { ble_npl_callout_stop(&w->work); } void -k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms) +k_work_schedule(struct k_work_delayable *w, uint32_t ms) { - uint32_t ticks; + uint32_t ticks; - if (ble_npl_time_ms_to_ticks(ms, &ticks) != 0) { - assert(0); - } - ble_npl_callout_reset(&w->work, ticks); + if (ble_npl_time_ms_to_ticks(ms, &ticks) != 0) { + assert(0); + } + ble_npl_callout_reset(&w->work, ticks); +} + +void +k_work_reschedule(struct k_work_delayable *w, uint32_t ms) +{ + uint32_t ticks; + + if (ble_npl_time_ms_to_ticks(ms, &ticks) != 0) { + assert(0); + } + ble_npl_callout_reset(&w->work, ticks); } void @@ -444,13 +482,13 @@ k_work_add_arg(struct ble_npl_callout *w, void *arg) } void -k_delayed_work_add_arg(struct k_delayed_work *w, void *arg) +k_work_add_arg_delayable(struct k_work_delayable *w, void *arg) { k_work_add_arg(&w->work, arg); } -uint32_t -k_delayed_work_remaining_get (struct k_delayed_work *w) +ble_npl_time_t +k_work_delayable_remaining_get (struct k_work_delayable *w) { int sr; ble_npl_time_t t; @@ -461,7 +499,13 @@ k_delayed_work_remaining_get (struct k_delayed_work *w) OS_EXIT_CRITICAL(sr); - return ble_npl_time_ticks_to_ms32(t); + return t; +} + +uint32_t +k_ticks_to_ms_floor32(ble_npl_time_t ticks) +{ + return ble_npl_time_ticks_to_ms32(ticks); } int64_t k_uptime_get(void) @@ -475,6 +519,17 @@ uint32_t k_uptime_get_32(void) return k_uptime_get(); } +int64_t k_uptime_delta(int64_t *reftime) +{ + int64_t uptime, delta; + + uptime = k_uptime_get(); + delta = uptime - *reftime; + *reftime = uptime; + + return delta; +} + void k_sleep(int32_t duration) { uint32_t ticks; @@ -502,6 +557,33 @@ bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb) return 0; } +void +bt_conn_get_info(struct ble_hs_conn *conn, + struct ble_gap_conn_desc *desc) +{ + struct ble_hs_conn_addrs addrs; + + ble_hs_conn_addrs(conn, &addrs); + + desc->our_id_addr = addrs.our_id_addr; + desc->peer_id_addr = addrs.peer_id_addr; + desc->our_ota_addr = addrs.our_ota_addr; + desc->peer_ota_addr = addrs.peer_ota_addr; + + desc->conn_handle = conn->bhc_handle; + desc->conn_itvl = conn->bhc_itvl; + desc->conn_latency = conn->bhc_latency; + desc->supervision_timeout = conn->bhc_supervision_timeout; + desc->master_clock_accuracy = conn->bhc_master_clock_accuracy; + desc->sec_state = conn->bhc_sec_state; + + if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { + desc->role = BLE_GAP_ROLE_MASTER; + } else { + desc->role = BLE_GAP_ROLE_SLAVE; + } +} + int bt_rand(void *buf, size_t len) { @@ -705,24 +787,6 @@ bt_le_adv_start(const struct ble_gap_adv_params *param, return err; } - -int bt_le_adv_stop(bool proxy) -{ -#if MYNEWT_VAL(BLE_MESH_PROXY) - int rc; - - if (proxy) { - rc = ble_gap_ext_adv_stop(BT_MESH_ADV_GATT_INST); - } else { - rc = ble_gap_ext_adv_stop(BT_MESH_ADV_INST); - } - - return rc; -#else - return ble_gap_ext_adv_stop(BT_MESH_ADV_INST); -#endif -} - #else int @@ -769,14 +833,13 @@ bt_le_adv_start(const struct ble_gap_adv_params *param, return 0; } +#endif -int bt_le_adv_stop(bool proxy) +int bt_le_adv_stop() { - return ble_gap_adv_stop(); + return ble_gap_adv_stop(); } -#endif - #if MYNEWT_VAL(BLE_MESH_PROXY) int bt_mesh_proxy_svcs_register(void); #endif @@ -906,6 +969,7 @@ int create_free_list(struct k_mem_slab *slab) uint32_t j; char *p; + /* blocks must be word aligned */ if(((slab->block_size | (uintptr_t)slab->buffer) & (sizeof(void *) - 1)) != 0) { return -EINVAL; diff --git a/nimble/host/mesh/src/health_cli.c b/nimble/host/mesh/src/health_cli.c index 76d639c5f3..caa70215b7 100644 --- a/nimble/host/mesh/src/health_cli.c +++ b/nimble/host/mesh/src/health_cli.c @@ -33,9 +33,9 @@ struct health_fault_param { size_t *fault_count; }; -static void health_fault_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct health_fault_param *param; uint8_t test_id; @@ -45,23 +45,21 @@ static void health_fault_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (health_cli->op_pending != OP_HEALTH_FAULT_STATUS) { - BT_WARN("Unexpected Health Fault Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_HEALTH_FAULT_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = health_cli->op_param; - test_id = net_buf_simple_pull_u8(buf); if (param->expect_test_id && test_id != *param->expect_test_id) { BT_WARN("Health fault with unexpected Test ID"); - return; + return -ENOENT; } cid = net_buf_simple_pull_le16(buf); if (cid != param->cid) { BT_WARN("Health fault with unexpected Company ID"); - return; + return -ENOENT; } if (param->test_id) { @@ -76,12 +74,14 @@ static void health_fault_status(struct bt_mesh_model *model, memcpy(param->faults, buf->om_data, *param->fault_count); - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); + + return 0; } -static void health_current_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_current_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct bt_mesh_health_cli *cli = model->user_data; uint8_t test_id; @@ -99,19 +99,21 @@ static void health_current_status(struct bt_mesh_model *model, if (!cli->current_status) { BT_WARN("No Current Status callback available"); - return; + return 0; } cli->current_status(cli, ctx->addr, test_id, cid, buf->om_data, buf->om_len); + + return 0; } struct health_period_param { uint8_t *divisor; }; -static void health_period_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_period_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct health_period_param *param; @@ -119,23 +121,23 @@ static void health_period_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (health_cli->op_pending != OP_HEALTH_PERIOD_STATUS) { - BT_WARN("Unexpected Health Period Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_HEALTH_PERIOD_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = health_cli->op_param; - *param->divisor = net_buf_simple_pull_u8(buf); - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); + + return 0; } struct health_attention_param { uint8_t *attention; }; -static void health_attention_status(struct bt_mesh_model *model, +static int health_attention_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -145,61 +147,36 @@ static void health_attention_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (health_cli->op_pending != OP_ATTENTION_STATUS) { - BT_WARN("Unexpected Health Attention Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_ATTENTION_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = health_cli->op_param; - if (param->attention) { *param->attention = net_buf_simple_pull_u8(buf); } - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); + + return 0; } const struct bt_mesh_model_op bt_mesh_health_cli_op[] = { - { OP_HEALTH_FAULT_STATUS, 3, health_fault_status }, - { OP_HEALTH_CURRENT_STATUS, 3, health_current_status }, - { OP_HEALTH_PERIOD_STATUS, 1, health_period_status }, - { OP_ATTENTION_STATUS, 1, health_attention_status }, + { OP_HEALTH_FAULT_STATUS, BT_MESH_LEN_MIN(3), health_fault_status }, + { OP_HEALTH_CURRENT_STATUS, BT_MESH_LEN_MIN(3), health_current_status }, + { OP_HEALTH_PERIOD_STATUS, BT_MESH_LEN_EXACT(1), health_period_status }, + { OP_ATTENTION_STATUS, BT_MESH_LEN_EXACT(1), health_attention_status }, BT_MESH_MODEL_OP_END, }; -static int cli_prepare(void *param, uint32_t op) +static int cli_prepare(void *param, uint32_t op, uint16_t addr) { if (!health_cli) { BT_ERR("No available Health Client context!"); return -EINVAL; } - if (health_cli->op_pending) { - BT_WARN("Another synchronous operation pending"); - return -EBUSY; - } - - health_cli->op_param = param; - health_cli->op_pending = op; - - return 0; -} - -static void cli_reset(void) -{ - health_cli->op_pending = 0; - health_cli->op_param = NULL; -} - -static int cli_wait(void) -{ - int err; - - err = k_sem_take(&health_cli->op_sync, msg_timeout); - - cli_reset(); - - return err; + return bt_mesh_msg_ack_ctx_prepare(&health_cli->ack_ctx, op, addr, param); } int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *attention) @@ -215,7 +192,7 @@ int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *atten }; int err; - err = cli_prepare(¶m, OP_ATTENTION_STATUS); + err = cli_prepare(¶m, OP_ATTENTION_STATUS, addr); if (err) { goto done; } @@ -225,11 +202,11 @@ int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *atten err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -249,7 +226,7 @@ int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attent }; int err; - err = cli_prepare(¶m, OP_ATTENTION_STATUS); + err = cli_prepare(¶m, OP_ATTENTION_STATUS, addr); if (err) { goto done; } @@ -265,16 +242,16 @@ int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attent err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } if (!updated_attention) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -293,7 +270,7 @@ int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor) }; int err; - err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS); + err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS, addr); if (err) { goto done; } @@ -303,11 +280,11 @@ int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor) err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -327,7 +304,7 @@ int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, }; int err; - err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS); + err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS, addr); if (err) { goto done; } @@ -343,16 +320,16 @@ int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } if (!updated_divisor) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -376,7 +353,7 @@ int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { goto done; } @@ -393,16 +370,16 @@ int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } if (!faults) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -426,7 +403,7 @@ int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { goto done; } @@ -442,16 +419,16 @@ int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } if (!test_id) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -475,7 +452,7 @@ int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { goto done; } @@ -486,11 +463,11 @@ int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -532,14 +509,14 @@ static int health_cli_init(struct bt_mesh_model *model) cli = model->user_data; cli->model = model; - - k_sem_init(&cli->op_sync, 0, 1); + msg_timeout = 2 * MSEC_PER_SEC; /* Set the default health client pointer */ if (!health_cli) { health_cli = cli; } + bt_mesh_msg_ack_ctx_init(&health_cli->ack_ctx); return 0; } diff --git a/nimble/host/mesh/src/health_srv.c b/nimble/host/mesh/src/health_srv.c index dd90533be8..4065d24f83 100644 --- a/nimble/host/mesh/src/health_srv.c +++ b/nimble/host/mesh/src/health_srv.c @@ -67,7 +67,6 @@ static size_t health_get_current(struct bt_mesh_model *mod, uint8_t *test_id, *company_ptr; uint16_t company_id; uint8_t fault_count; - int err; bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS); @@ -77,6 +76,8 @@ static size_t health_get_current(struct bt_mesh_model *mod, if (srv->cb && srv->cb->fault_get_cur) { fault_count = net_buf_simple_tailroom(msg); + int err; + err = srv->cb->fault_get_cur(mod, test_id, &company_id, net_buf_simple_tail(msg), &fault_count); @@ -99,9 +100,9 @@ static size_t health_get_current(struct bt_mesh_model *mod, return fault_count; } -static void health_fault_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); uint16_t company_id; @@ -117,11 +118,13 @@ static void health_fault_get(struct bt_mesh_model *model, } os_mbuf_free_chain(sdu); + + return 0; } -static void health_fault_clear_unrel(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_clear_unrel(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct bt_mesh_health_srv *srv = model->user_data; uint16_t company_id; @@ -131,13 +134,15 @@ static void health_fault_clear_unrel(struct bt_mesh_model *model, BT_DBG("company_id 0x%04x", company_id); if (srv->cb && srv->cb->fault_clear) { - srv->cb->fault_clear(model, company_id); + return srv->cb->fault_clear(model, company_id); } + + return 0; } -static void health_fault_clear(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_clear(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct bt_mesh_health_srv *srv = model->user_data; @@ -148,7 +153,12 @@ static void health_fault_clear(struct bt_mesh_model *model, BT_DBG("company_id 0x%04x", company_id); if (srv->cb && srv->cb->fault_clear) { - srv->cb->fault_clear(model, company_id); + int err; + + err = srv->cb->fault_clear(model, company_id); + if (err) { + return err; + } } health_get_registered(model, company_id, sdu); @@ -158,9 +168,11 @@ static void health_fault_clear(struct bt_mesh_model *model, } os_mbuf_free_chain(sdu); + + return 0; } -static void health_fault_test_unrel(struct bt_mesh_model *model, +static int health_fault_test_unrel(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -174,18 +186,21 @@ static void health_fault_test_unrel(struct bt_mesh_model *model, BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); if (srv->cb && srv->cb->fault_test) { - srv->cb->fault_test(model, test_id, company_id); + return srv->cb->fault_test(model, test_id, company_id); } + + return 0; } -static void health_fault_test(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_test(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct bt_mesh_health_srv *srv = model->user_data; uint16_t company_id; uint8_t test_id; + int err = 0; BT_DBG(""); @@ -195,11 +210,10 @@ static void health_fault_test(struct bt_mesh_model *model, BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); if (srv->cb && srv->cb->fault_test) { - int err; - err = srv->cb->fault_test(model, test_id, company_id); if (err) { BT_WARN("Running fault test failed with err %d", err); + goto done; } } @@ -212,16 +226,19 @@ static void health_fault_test(struct bt_mesh_model *model, done: os_mbuf_free_chain(sdu); + + return err; } -static void send_attention_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) +static int send_attention_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_STATUS, 1); struct bt_mesh_health_srv *srv = model->user_data; uint8_t time; - time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000; + time = k_ticks_to_ms_floor32( + k_work_delayable_remaining_get(&srv->attn_timer)) / 1000; BT_DBG("%u second%s", time, (time == 1) ? "" : "s"); bt_mesh_model_msg_init(msg, OP_ATTENTION_STATUS); @@ -233,18 +250,20 @@ static void send_attention_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void attention_get(struct bt_mesh_model *model, +static int attention_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - send_attention_status(model, ctx); + return send_attention_status(model, ctx); } -static void attention_set_unrel(struct bt_mesh_model *model, +static int attention_set_unrel(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -255,20 +274,27 @@ static void attention_set_unrel(struct bt_mesh_model *model, BT_DBG("%u second%s", time, (time == 1) ? "" : "s"); bt_mesh_attention(model, time); + + return 0; } -static void attention_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int attention_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { + int err; + BT_DBG(""); - attention_set_unrel(model, ctx, buf); + err = attention_set_unrel(model, ctx, buf); + if (err) { + return err; + } - send_attention_status(model, ctx); + return send_attention_status(model, ctx); } -static void send_health_period_status(struct bt_mesh_model *model, +static int send_health_period_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_PERIOD_STATUS, 1); @@ -282,18 +308,20 @@ static void send_health_period_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void health_period_get(struct bt_mesh_model *model, +static int health_period_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - send_health_period_status(model, ctx); + return send_health_period_status(model, ctx); } -static void health_period_set_unrel(struct bt_mesh_model *model, +static int health_period_set_unrel(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -302,37 +330,44 @@ static void health_period_set_unrel(struct bt_mesh_model *model, period = net_buf_simple_pull_u8(buf); if (period > 15) { BT_WARN("Prohibited period value %u", period); - return; + return -EINVAL; } BT_DBG("period %u", period); model->pub->period_div = period; + + return 0; } -static void health_period_set(struct bt_mesh_model *model, +static int health_period_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + int err; + BT_DBG(""); - health_period_set_unrel(model, ctx, buf); + err = health_period_set_unrel(model, ctx, buf); + if (err) { + return err; + } - send_health_period_status(model, ctx); + return send_health_period_status(model, ctx); } const struct bt_mesh_model_op bt_mesh_health_srv_op[] = { - { OP_HEALTH_FAULT_GET, 2, health_fault_get }, - { OP_HEALTH_FAULT_CLEAR, 2, health_fault_clear }, - { OP_HEALTH_FAULT_CLEAR_UNREL, 2, health_fault_clear_unrel }, - { OP_HEALTH_FAULT_TEST, 3, health_fault_test }, - { OP_HEALTH_FAULT_TEST_UNREL, 3, health_fault_test_unrel }, - { OP_HEALTH_PERIOD_GET, 0, health_period_get }, - { OP_HEALTH_PERIOD_SET, 1, health_period_set }, - { OP_HEALTH_PERIOD_SET_UNREL, 1, health_period_set_unrel }, - { OP_ATTENTION_GET, 0, attention_get }, - { OP_ATTENTION_SET, 1, attention_set }, - { OP_ATTENTION_SET_UNREL, 1, attention_set_unrel }, + { OP_HEALTH_FAULT_GET, BT_MESH_LEN_EXACT(2), health_fault_get }, + { OP_HEALTH_FAULT_CLEAR, BT_MESH_LEN_EXACT(2), health_fault_clear }, + { OP_HEALTH_FAULT_CLEAR_UNREL, BT_MESH_LEN_EXACT(2), health_fault_clear_unrel }, + { OP_HEALTH_FAULT_TEST, BT_MESH_LEN_EXACT(3), health_fault_test }, + { OP_HEALTH_FAULT_TEST_UNREL, BT_MESH_LEN_EXACT(3), health_fault_test_unrel }, + { OP_HEALTH_PERIOD_GET, BT_MESH_LEN_EXACT(0), health_period_get }, + { OP_HEALTH_PERIOD_SET, BT_MESH_LEN_EXACT(1), health_period_set }, + { OP_HEALTH_PERIOD_SET_UNREL, BT_MESH_LEN_EXACT(1), health_period_set_unrel }, + { OP_ATTENTION_GET, BT_MESH_LEN_EXACT(0), attention_get }, + { OP_ATTENTION_SET, BT_MESH_LEN_EXACT(1), attention_set }, + { OP_ATTENTION_SET_UNREL, BT_MESH_LEN_EXACT(1), attention_set_unrel }, BT_MESH_MODEL_OP_END, }; @@ -400,8 +435,8 @@ static int health_srv_init(struct bt_mesh_model *model) model->pub->update = health_pub_update; - k_delayed_work_init(&srv->attn_timer, attention_off); - k_delayed_work_add_arg(&srv->attn_timer, srv); + k_work_init_delayable(&srv->attn_timer, attention_off); + k_work_add_arg_delayable(&srv->attn_timer, srv); srv->model = model; @@ -433,17 +468,8 @@ void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time) srv = model->user_data; } - if (time) { - if (srv->cb && srv->cb->attn_on) { - srv->cb->attn_on(model); - } - - k_delayed_work_submit(&srv->attn_timer, time * 1000); - } else { - k_delayed_work_cancel(&srv->attn_timer); - - if (srv->cb && srv->cb->attn_off) { - srv->cb->attn_off(model); - } + if ((time > 0) && srv->cb && srv->cb->attn_on) { + srv->cb->attn_on(model); } + k_work_reschedule(&srv->attn_timer, K_SECONDS(time)); } diff --git a/nimble/host/mesh/src/heartbeat.c b/nimble/host/mesh/src/heartbeat.c index 538a1cb662..faf2f76611 100644 --- a/nimble/host/mesh/src/heartbeat.c +++ b/nimble/host/mesh/src/heartbeat.c @@ -17,12 +17,22 @@ #include "foundation.h" #include "mesh/glue.h" +/* Heartbeat Publication information for persistent storage. */ +struct hb_pub_val { + uint16_t dst; + uint8_t period; + uint8_t ttl; + uint16_t feat; + uint16_t net_idx:12, + indefinite:1; +}; + struct bt_mesh_hb_cb hb_cb; static struct bt_mesh_hb_pub pub; static struct bt_mesh_hb_sub sub; -static struct k_delayed_work sub_timer; -static struct k_delayed_work pub_timer; +static struct k_work_delayable sub_timer; +static struct k_work_delayable pub_timer; static int64_t sub_remaining(void) { @@ -30,13 +40,15 @@ static int64_t sub_remaining(void) return 0U; } - return k_delayed_work_remaining_get(&sub_timer) / MSEC_PER_SEC; + uint32_t rem_ms = k_ticks_to_ms_floor32( + k_work_delayable_remaining_get(&sub_timer)); + return rem_ms / MSEC_PER_SEC; } static void hb_publish_end_cb(int err, void *cb_data) { if (pub.period && pub.count > 1) { - k_delayed_work_submit(&pub_timer, K_SECONDS(pub.period)); + k_work_reschedule(&pub_timer, K_SECONDS(pub.period)); } if (pub.count != 0xffff) { @@ -87,9 +99,11 @@ static int heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data) .xmit = bt_mesh_net_transmit_get(), }; - /* Do nothing if heartbeat publication is not enabled */ - if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { - return 0U; + /* Do nothing if heartbeat publication is not enabled or the subnet is + * removed. + */ + if (!tx.sub || pub.dst == BT_MESH_ADDR_UNASSIGNED) { + return 0; } hb.init_ttl = pub.ttl; @@ -136,6 +150,11 @@ static void hb_publish(struct ble_npl_event *work) BT_DBG("hb_pub.count: %u", pub.count); + /* Fast exit if disabled or expired */ + if (pub.period == 0U || pub.count == 0U) { + return; + } + sub = bt_mesh_subnet_get(pub.net_idx); if (!sub) { BT_ERR("No matching subnet for idx 0x%02x", pub.net_idx); @@ -143,10 +162,6 @@ static void hb_publish(struct ble_npl_event *work) return; } - if (pub.count == 0U) { - return; - } - err = heartbeat_send(&publish_cb, NULL); if (err) { hb_publish_end_cb(err, NULL); @@ -173,8 +188,8 @@ int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) return 0; } - if (!k_delayed_work_pending(&sub_timer)) { - BT_DBG("Heartbeat subscription period expired"); + if (!k_work_delayable_is_pending(&sub_timer)) { + BT_DBG("Heartbeat subscription inactive"); return 0; } @@ -203,7 +218,7 @@ static void pub_disable(void) pub.ttl = 0U; pub.period = 0U; - k_delayed_work_cancel(&pub_timer); + k_work_cancel_delayable(&pub_timer); } uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub) @@ -213,7 +228,8 @@ uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub) if (IS_ENABLED(CONFIG_BT_SETTINGS) && bt_mesh_is_provisioned()) { - bt_mesh_store_hb_pub(); + bt_mesh_settings_store_schedule( + BT_MESH_SETTINGS_HB_PUB_PENDING); } return STATUS_SUCCESS; @@ -234,15 +250,15 @@ uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub) /* The first Heartbeat message shall be published as soon as possible * after the Heartbeat Publication Period state has been configured for * periodic publishing. + * + * If the new configuration disables publishing this flushes + * the work item. */ - if (pub.period && pub.count) { - k_delayed_work_submit(&pub_timer, K_NO_WAIT); - } else { - k_delayed_work_cancel(&pub_timer); - } + k_work_reschedule(&pub_timer, K_NO_WAIT); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_hb_pub(); + bt_mesh_settings_store_schedule( + BT_MESH_SETTINGS_HB_PUB_PENDING); } return STATUS_SUCCESS; @@ -280,9 +296,7 @@ uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period) sub.min_hops = 0U; sub.max_hops = 0U; sub.count = 0U; - sub.period = sub.period - sub_remaining(); - k_delayed_work_cancel(&sub_timer); - notify_sub_end(); + sub.period = 0U; } else if (period) { sub.src = src; sub.dst = dst; @@ -290,19 +304,26 @@ uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period) sub.max_hops = 0U; sub.count = 0U; sub.period = period; - k_delayed_work_submit(&sub_timer, K_SECONDS(period)); } else { /* Clearing the period should stop heartbeat subscription * without clearing the parameters, so we can still read them. */ - sub.period = sub.period - sub_remaining(); - k_delayed_work_cancel(&sub_timer); - notify_sub_end(); + sub.period = 0U; } + /* Start the timer, which notifies immediately if the new + * configuration disables the subscription. + */ + k_work_reschedule(&sub_timer, K_SECONDS(sub.period)); + return STATUS_SUCCESS; } +void bt_mesh_hb_sub_reset_count(void) +{ + sub.count = 0; +} + void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get) { *get = sub; @@ -325,27 +346,119 @@ void bt_mesh_hb_feature_changed(uint16_t features) void bt_mesh_hb_init(void) { pub.net_idx = BT_MESH_KEY_UNUSED; - k_delayed_work_init(&pub_timer, hb_publish); - k_delayed_work_init(&sub_timer, sub_end); + k_work_init_delayable(&pub_timer, hb_publish); + k_work_init_delayable(&sub_timer, sub_end); } void bt_mesh_hb_start(void) { if (pub.count && pub.period) { BT_DBG("Starting heartbeat publication"); - k_delayed_work_submit(&pub_timer, K_NO_WAIT); + k_work_reschedule(&pub_timer, K_NO_WAIT); } } void bt_mesh_hb_suspend(void) { - k_delayed_work_cancel(&pub_timer); + (void)k_work_cancel_delayable(&pub_timer); } void bt_mesh_hb_resume(void) { if (pub.period && pub.count) { BT_DBG("Starting heartbeat publication"); - k_delayed_work_submit(&pub_timer, K_NO_WAIT); + k_work_reschedule(&pub_timer, K_NO_WAIT); + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int hb_pub_set(int argc, char **argv, char *val) +{ + struct bt_mesh_hb_pub pub; + struct hb_pub_val hb_val; + int len, err; + BT_DBG("val %s", val ? val : "(null)"); + len = sizeof(hb_val); + err = settings_bytes_from_str(val, &hb_val, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + if (len != sizeof(hb_val)) { + BT_ERR("Unexpected value length (%d != %zu)", len, + sizeof(hb_val)); + return -EINVAL; + } + pub.dst = hb_val.dst; + pub.period = bt_mesh_hb_pwr2(hb_val.period); + pub.ttl = hb_val.ttl; + pub.feat = hb_val.feat; + pub.net_idx = hb_val.net_idx; + if (hb_val.indefinite) { + pub.count = 0xffff; + } else { + pub.count = 0; + } + (void) bt_mesh_hb_pub_set(&pub); + + BT_DBG("Restored heartbeat publication"); + + return 0; +} + +void bt_mesh_hb_pub_pending_store(void) +{ + struct bt_mesh_hb_pub pub; + char buf[BT_SETTINGS_SIZE(sizeof(struct hb_pub_val))]; + struct hb_pub_val val; + int err; + char *str; + + bt_mesh_hb_pub_get(&pub); + if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { + err = settings_save_one("bt_mesh/HBPub", NULL); + } else { + val.indefinite = (pub.count == 0xffff); + val.dst = pub.dst; + val.period = bt_mesh_hb_log(pub.period); + val.ttl = pub.ttl; + val.feat = pub.feat; + val.net_idx = pub.net_idx; + + str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode configuration as value"); + return; + } + + BT_DBG("Saving configuration as value %s", str); + err = settings_save_one("bt_mesh/HBPub", str); + } + + if (err) { + BT_ERR("Failed to store Heartbeat Publication"); + } else { + BT_DBG("Stored Heartbeat Publication"); } } + +static struct conf_handler bt_mesh_hb_pub_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = hb_pub_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_hb_pub_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_hb_pub_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_hb_pub conf"); +#endif +} diff --git a/nimble/host/mesh/src/heartbeat.h b/nimble/host/mesh/src/heartbeat.h index c43683fef0..a036366637 100644 --- a/nimble/host/mesh/src/heartbeat.h +++ b/nimble/host/mesh/src/heartbeat.h @@ -38,3 +38,6 @@ void bt_mesh_hb_feature_changed(uint16_t features); uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *hb_pub); uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period); +void bt_mesh_hb_sub_reset_count(void); +void bt_mesh_hb_pub_pending_store(void); +void bt_mesh_hb_pub_init(void); diff --git a/nimble/host/mesh/src/light_model.c b/nimble/host/mesh/src/light_model.c index bc4792c637..e7199519bb 100644 --- a/nimble/host/mesh/src/light_model.c +++ b/nimble/host/mesh/src/light_model.c @@ -55,4 +55,3 @@ int light_model_light_lightness_set(struct bt_mesh_model *model, int16_t lightne { return light_model_gen_level_set(model, lightness); } - diff --git a/nimble/host/mesh/src/lpn.c b/nimble/host/mesh/src/lpn.c index bd48c0883e..1d2f229e6b 100644 --- a/nimble/host/mesh/src/lpn.c +++ b/nimble/host/mesh/src/lpn.c @@ -148,6 +148,24 @@ static inline void group_clear(atomic_t *target, atomic_t *source) static void clear_friendship(bool force, bool disable); +static int32_t poll_timeout(struct bt_mesh_lpn *lpn) +{ + /* If we're waiting for segment acks keep polling at high freq */ + if (bt_mesh_tx_in_progress()) { + return min(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); + } + + if (lpn->poll_timeout < POLL_TIMEOUT_MAX(lpn)) { + lpn->poll_timeout *= 2; + lpn->poll_timeout = min(lpn->poll_timeout, + POLL_TIMEOUT_MAX(lpn)); + } + + BT_DBG("Poll Timeout is %ums", (unsigned) lpn->poll_timeout); + + return lpn->poll_timeout; +} + static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; @@ -164,7 +182,7 @@ static void friend_clear_sent(int err, void *user_data) } lpn_set_state(BT_MESH_LPN_CLEAR); - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_TIMEOUT); + k_work_reschedule(&lpn->timer, FRIEND_REQ_TIMEOUT); } static const struct bt_mesh_send_cb clear_sent_cb = { @@ -211,7 +229,8 @@ static void clear_friendship(bool force, bool disable) bt_mesh_rx_reset(); - k_delayed_work_cancel(&lpn->timer); + lpn_set_state(BT_MESH_LPN_DISABLED); + k_work_cancel_delayable(&lpn->timer); if (lpn->clear_success) { lpn->old_friend = BT_MESH_ADDR_UNASSIGNED; @@ -229,7 +248,7 @@ static void clear_friendship(bool force, bool disable) lpn->recv_win = 0; lpn->queue_size = 0; lpn->disable = 0; - lpn->sent_req = 0; + lpn->sent_req = 0U; lpn->established = 0; lpn->clear_success = 0; lpn->sub = NULL; @@ -246,13 +265,12 @@ static void clear_friendship(bool force, bool disable) bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER); - if (disable) { + if (!disable) { lpn_set_state(BT_MESH_LPN_DISABLED); + k_work_reschedule(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); return; } - lpn_set_state(BT_MESH_LPN_ENABLED); - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); } static void friend_req_sent(uint16_t duration, int err, void *user_data) @@ -267,10 +285,10 @@ static void friend_req_sent(uint16_t duration, int err, void *user_data) lpn->adv_duration = duration; if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_WAIT); + k_work_reschedule(&lpn->timer, FRIEND_REQ_WAIT); lpn_set_state(BT_MESH_LPN_REQ_WAIT); } else { - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, duration + FRIEND_REQ_TIMEOUT); lpn_set_state(BT_MESH_LPN_WAIT_OFFER); } @@ -331,7 +349,7 @@ static void req_sent(uint16_t duration, int err, void *user_data) if (err) { BT_ERR("Sending request failed (err %d)", err); - lpn->sent_req = 0; + lpn->sent_req = 0U; group_zero(lpn->pending); return; } @@ -344,11 +362,11 @@ static void req_sent(uint16_t duration, int err, void *user_data) /* We start scanning a bit early to elimitate risk of missing * response data due to HCI and other latencies. */ - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, LPN_RECV_DELAY - SCAN_LATENCY); } else { lpn_set_state(BT_MESH_LPN_WAIT_UPDATE); - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, LPN_RECV_DELAY + duration + lpn->recv_win); } @@ -441,7 +459,7 @@ int bt_mesh_lpn_set(bool enable) } else { if (IS_ENABLED(CONFIG_BT_MESH_LPN_AUTO) && lpn->state == BT_MESH_LPN_TIMER) { - k_delayed_work_cancel(&lpn->timer); + k_work_cancel_delayable(&lpn->timer); lpn_set_state(BT_MESH_LPN_DISABLED); } else { bt_mesh_lpn_disable(false); @@ -459,11 +477,14 @@ static void friend_response_received(struct bt_mesh_lpn *lpn) lpn->fsn++; } - k_delayed_work_cancel(&lpn->timer); bt_mesh_scan_disable(); lpn_set_state(BT_MESH_LPN_ESTABLISHED); lpn->req_attempts = 0; - lpn->sent_req = 0; + lpn->sent_req = 0U; + + int32_t timeout = poll_timeout(lpn); + + k_work_reschedule(&lpn->timer, K_MSEC(timeout)); } void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) @@ -472,7 +493,19 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) if (lpn->state == BT_MESH_LPN_TIMER) { BT_DBG("Restarting establishment timer"); - k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); + k_work_reschedule(&lpn->timer, LPN_AUTO_TIMEOUT); + return; + } + + if (lpn->state != BT_MESH_LPN_WAIT_UPDATE) { + return; + } + + /* If the message was a Friend control message, it's possible that a + * Poll was already queued for sending. In this case, we're already in + * a different state. + */ + if (lpn->state != BT_MESH_LPN_WAIT_UPDATE) { return; } @@ -545,7 +578,6 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, } } /* TODO: Add offer acceptance criteria check */ - k_delayed_work_cancel(&lpn->timer); lpn->recv_win = msg->recv_win; lpn->queue_size = msg->queue_size; @@ -730,7 +762,7 @@ static void update_timeout(struct bt_mesh_lpn *lpn) BT_WARN("No response from Friend during ReceiveWindow"); bt_mesh_scan_disable(); lpn_set_state(BT_MESH_LPN_ESTABLISHED); - k_delayed_work_submit(&lpn->timer, POLL_RETRY_TIMEOUT); + k_work_reschedule(&lpn->timer, POLL_RETRY_TIMEOUT); } else { if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { bt_mesh_scan_disable(); @@ -738,7 +770,7 @@ static void update_timeout(struct bt_mesh_lpn *lpn) if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { BT_WARN("Retrying first Friend Poll"); - lpn->sent_req = 0; + lpn->sent_req = 0U; if (send_friend_poll() == 0) { return; } @@ -775,7 +807,7 @@ static void lpn_timeout(struct ble_npl_event *work) break; case BT_MESH_LPN_REQ_WAIT: bt_mesh_scan_enable(); - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, lpn->adv_duration + FRIEND_REQ_SCAN); lpn_set_state(BT_MESH_LPN_WAIT_OFFER); break; @@ -787,13 +819,13 @@ static void lpn_timeout(struct ble_npl_event *work) lpn->lpn_counter++; lpn_set_state(BT_MESH_LPN_ENABLED); lpn->sent_req = 0U; - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); + k_work_reschedule(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); break; case BT_MESH_LPN_ESTABLISHED: if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { uint8_t req = lpn->sent_req; - lpn->sent_req = 0; + lpn->sent_req = 0U; if (!req || req == TRANS_CTL_OP_FRIEND_POLL) { send_friend_poll(); @@ -810,7 +842,7 @@ static void lpn_timeout(struct ble_npl_event *work) clear_friendship(false, false); break; case BT_MESH_LPN_RECV_DELAY: - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, lpn->adv_duration + SCAN_LATENCY + lpn->recv_win); bt_mesh_scan_enable(); @@ -856,24 +888,6 @@ void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count) sub_update(TRANS_CTL_OP_FRIEND_SUB_REM); } -static int32_t poll_timeout(struct bt_mesh_lpn *lpn) -{ - /* If we're waiting for segment acks keep polling at high freq */ - if (bt_mesh_tx_in_progress()) { - return min(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); - } - - if (lpn->poll_timeout < POLL_TIMEOUT_MAX(lpn)) { - lpn->poll_timeout *= 2; - lpn->poll_timeout = min(lpn->poll_timeout, - POLL_TIMEOUT_MAX(lpn)); - } - - BT_DBG("Poll Timeout is %ums", (unsigned) lpn->poll_timeout); - - return lpn->poll_timeout; -} - int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) { @@ -932,12 +946,6 @@ int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, send_friend_poll(); } - if (!lpn->sent_req) { - int32_t timeout = poll_timeout(lpn); - - k_delayed_work_submit(&lpn->timer, K_MSEC(timeout)); - } - return 0; } @@ -972,7 +980,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, if (!lpn->established) { /* This is normally checked on the transport layer, however - * in this state we're also still accepting master + * in this state we're also still accepting flooding * credentials so we need to ensure the right ones (Friend * Credentials) were used for this message. */ @@ -1020,12 +1028,6 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, send_friend_poll(); } - if (!lpn->sent_req) { - int32_t timeout = poll_timeout(lpn); - - k_delayed_work_submit(&lpn->timer, K_MSEC(timeout)); - } - return 0; } @@ -1073,9 +1075,7 @@ int bt_mesh_lpn_init(void) BT_DBG(""); - lpn->groups_changed = 0; - - k_delayed_work_init(&lpn->timer, lpn_timeout); + k_work_init_delayable(&lpn->timer, lpn_timeout); if (lpn->state == BT_MESH_LPN_ENABLED) { if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { @@ -1091,7 +1091,7 @@ int bt_mesh_lpn_init(void) if (IS_ENABLED(CONFIG_BT_MESH_LPN_AUTO)) { BT_DBG("Waiting %u ms for messages", LPN_AUTO_TIMEOUT); lpn_set_state(BT_MESH_LPN_TIMER); - k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); + k_work_reschedule(&lpn->timer, LPN_AUTO_TIMEOUT); } } diff --git a/nimble/host/mesh/src/lpn.h b/nimble/host/mesh/src/lpn.h index 90de2ca086..cb2e1f2fef 100644 --- a/nimble/host/mesh/src/lpn.h +++ b/nimble/host/mesh/src/lpn.h @@ -47,15 +47,6 @@ static inline bool bt_mesh_lpn_waiting_update(void) #endif } -static inline bool bt_mesh_lpn_timer(void) -{ -#if MYNEWT_VAL(BLE_MESH_LOW_POWER) && MYNEWT_VAL(BLE_MESH_LPN_AUTO) - return (bt_mesh.lpn.state == BT_MESH_LPN_TIMER); -#else - return false; -#endif -} - void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx); void bt_mesh_lpn_group_add(uint16_t group); diff --git a/nimble/host/mesh/src/mesh.c b/nimble/host/mesh/src/mesh.c index bbb4ee3d22..6ab71e8b11 100644 --- a/nimble/host/mesh/src/mesh.c +++ b/nimble/host/mesh/src/mesh.c @@ -35,6 +35,7 @@ #include "shell.h" #include "mesh_priv.h" #include "settings.h" +#include "pb_gatt_srv.h" uint8_t g_mesh_addr_type; @@ -44,7 +45,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, uint8_t flags, uint32_t iv_index, uint16_t addr, const uint8_t dev_key[16]) { - bool pb_gatt_enabled; int err; BT_INFO("Primary Element: 0x%04x", addr); @@ -55,32 +55,16 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, return -EALREADY; } - if ((MYNEWT_VAL(BLE_MESH_PB_GATT))) { - if (bt_mesh_proxy_prov_disable(false) == 0) { - pb_gatt_enabled = true; - } else { - pb_gatt_enabled = false; - } - } else { - pb_gatt_enabled = false; - } - /* * FIXME: * Should net_key and iv_index be over-ridden? */ - if (IS_ENABLED(BLE_MESH_CDB)) { + if (IS_ENABLED(CONFIG_BT_MESH_CDB) && + atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) { const struct bt_mesh_comp *comp; const struct bt_mesh_prov *prov; struct bt_mesh_cdb_node *node; - if (!atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_VALID)) { - BT_ERR("No valid network"); - atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - return -EINVAL; - } - comp = bt_mesh_comp_get(); if (comp == NULL) { BT_ERR("Failed to get node composition"); @@ -108,7 +92,7 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, memcpy(node->dev_key, dev_key, 16); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_node(node); + bt_mesh_cdb_node_store(node); } } @@ -116,10 +100,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, if (err) { atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - if (MYNEWT_VAL(BLE_MESH_PB_GATT) && pb_gatt_enabled) { - bt_mesh_proxy_prov_enable(); - } - return err; } @@ -134,6 +114,10 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, bt_mesh_lpn_group_add(BT_MESH_ADDR_ALL_NODES); } + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_net_pending_net_store(); + } + bt_mesh_start(); return 0; @@ -166,14 +150,15 @@ void bt_mesh_reset(void) } bt_mesh.iv_index = 0U; + bt_mesh.ivu_duration = 0; bt_mesh.seq = 0U; memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags)); - k_delayed_work_cancel(&bt_mesh.ivu_timer); - - bt_mesh_cfg_reset(); + k_work_cancel_delayable(&bt_mesh.ivu_timer); + bt_mesh_model_reset(); + bt_mesh_cfg_default_set(); bt_mesh_trans_reset(); bt_mesh_app_keys_reset(); bt_mesh_net_keys_reset(); @@ -195,11 +180,11 @@ void bt_mesh_reset(void) } if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) { - bt_mesh_proxy_gatt_disable(); + (void)bt_mesh_proxy_gatt_disable(); } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_net(); + bt_mesh_net_clear(); } memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); @@ -236,7 +221,10 @@ static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, { if (mod->pub && mod->pub->update) { mod->pub->count = 0; - k_delayed_work_cancel(&mod->pub->timer); + /* If this fails, the work handler will check the suspend call + * and exit without transmitting. + */ + (void)k_work_cancel_delayable(&mod->pub->timer); } } @@ -277,7 +265,8 @@ static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, int32_t period_ms = bt_mesh_model_pub_period_get(mod); if (period_ms) { - k_delayed_work_submit(&mod->pub->timer, period_ms); + k_work_reschedule(&mod->pub->timer, + K_MSEC(period_ms)); } } } @@ -338,7 +327,18 @@ int bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov, } #endif - bt_mesh_cfg_init(); + bt_mesh_app_key_init(); + bt_mesh_access_init(); + bt_mesh_hb_pub_init(); + bt_mesh_rpl_init(); + bt_mesh_net_key_init(); +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + bt_mesh_va_init(); +#endif +#if CONFIG_BT_MESH_CDB + bt_mesh_cdb_init(); +#endif + bt_mesh_cfg_default_set(); bt_mesh_net_init(); bt_mesh_trans_init(); bt_mesh_hb_init(); @@ -365,16 +365,30 @@ static void model_start(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, int bt_mesh_start(void) { + int err; + + err = bt_mesh_adv_enable(); + if (err) { + BT_ERR("Failed enabling advertiser"); + return err; + } + if (bt_mesh_beacon_enabled()) { bt_mesh_beacon_enable(); } else { bt_mesh_beacon_disable(); } - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && - bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED) { - bt_mesh_proxy_gatt_enable(); - bt_mesh_adv_update(); + if (!IS_ENABLED(CONFIG_BT_MESH_PROV) || !bt_mesh_prov_active() || + bt_mesh_prov_link.bearer->type == BT_MESH_PROV_ADV) { + if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + (void)bt_mesh_pb_gatt_disable(); + } + + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + (void)bt_mesh_proxy_gatt_enable(); + bt_mesh_adv_update(); + } } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { diff --git a/nimble/host/mesh/src/model_cli.c b/nimble/host/mesh/src/model_cli.c index 9755ec1fd9..22f9b99ee8 100644 --- a/nimble/host/mesh/src/model_cli.c +++ b/nimble/host/mesh/src/model_cli.c @@ -26,7 +26,7 @@ struct gen_level_param { int16_t *level; }; -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -41,7 +41,7 @@ static void gen_onoff_status(struct bt_mesh_model *model, if (cli->op_pending != OP_GEN_ONOFF_STATUS) { BT_WARN("Unexpected Generic OnOff Status message"); - return; + return -ENOENT; } param = cli->op_param; @@ -54,9 +54,11 @@ static void gen_onoff_status(struct bt_mesh_model *model, BT_DBG("state: %d", state); k_sem_give(&cli->op_sync); + + return 0; } -static void gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -71,7 +73,7 @@ static void gen_level_status(struct bt_mesh_model *model, if (cli->op_pending != OP_GEN_LEVEL_STATUS) { BT_WARN("Unexpected Generic LEVEL Status message"); - return; + return -EINVAL; } param = cli->op_param; @@ -84,6 +86,8 @@ static void gen_level_status(struct bt_mesh_model *model, BT_DBG("level: %d", level); k_sem_give(&cli->op_sync); + + return 0; } const struct bt_mesh_model_op gen_onoff_cli_op[] = { @@ -298,4 +302,3 @@ int bt_mesh_gen_level_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx, os_mbuf_free_chain(msg); return err; } - diff --git a/nimble/host/mesh/src/model_srv.c b/nimble/host/mesh/src/model_srv.c index b6f34360aa..96981cbab6 100644 --- a/nimble/host/mesh/src/model_srv.c +++ b/nimble/host/mesh/src/model_srv.c @@ -15,9 +15,10 @@ static struct bt_mesh_gen_onoff_srv *gen_onoff_srv; static struct bt_mesh_gen_level_srv *gen_level_srv; static struct bt_mesh_light_lightness_srv *light_lightness_srv; -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { + int err; struct bt_mesh_gen_onoff_srv *cb = model->user_data; struct os_mbuf *msg = NET_BUF_SIMPLE(3); uint8_t *state; @@ -30,23 +31,26 @@ static void gen_onoff_status(struct bt_mesh_model *model, BT_DBG("state: %d", *state); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + err = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (err) { BT_ERR("Send status failed"); } os_mbuf_free_chain(msg); + + return err; } -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -58,23 +62,26 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, BT_DBG("state: %d", state); if (cb && cb->set) { - cb->set(model, state); + return cb->set(model, state); } + + return 0; } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); gen_onoff_set_unack(model, ctx, buf); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { + int err; struct bt_mesh_gen_level_srv *cb = model->user_data; struct os_mbuf *msg = NET_BUF_SIMPLE(4); int16_t *level; @@ -87,23 +94,25 @@ static void gen_level_status(struct bt_mesh_model *model, BT_DBG("level: %d", *level); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + err = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (err) { BT_ERR("Send status failed"); } os_mbuf_free_chain(msg); + return err; } -static void gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - gen_level_status(model, ctx); + return gen_level_status(model, ctx); } -static void gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct bt_mesh_gen_level_srv *cb = model->user_data; @@ -113,21 +122,24 @@ static void gen_level_set_unack(struct bt_mesh_model *model, BT_DBG("level: %d", level); if (cb && cb->set) { - cb->set(model, level); + return cb->set(model, level); } + + return 0; } -static void gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { gen_level_set_unack(model, ctx, buf); - gen_level_status(model, ctx); + return gen_level_status(model, ctx); } -static void light_lightness_status(struct bt_mesh_model *model, +static int light_lightness_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { + int err; struct bt_mesh_light_lightness_srv *cb = model->user_data; struct os_mbuf *msg = NET_BUF_SIMPLE(4); int16_t *lightness; @@ -140,23 +152,25 @@ static void light_lightness_status(struct bt_mesh_model *model, BT_DBG("lightness: %d", *lightness); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + err = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (err) { BT_ERR("Send status failed"); } os_mbuf_free_chain(msg); + return err; } -static void light_lightness_get(struct bt_mesh_model *model, +static int light_lightness_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - light_lightness_status(model, ctx); + return light_lightness_status(model, ctx); } -static void light_lightness_set_unack(struct bt_mesh_model *model, +static int light_lightness_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct bt_mesh_light_lightness_srv *cb = model->user_data; @@ -166,16 +180,18 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, BT_DBG("lightness: %d", lightness); if (cb && cb->set) { - cb->set(model, lightness); + return cb->set(model, lightness); } + + return 0; } -static void light_lightness_set(struct bt_mesh_model *model, +static int light_lightness_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { light_lightness_set_unack(model, ctx, buf); - light_lightness_status(model, ctx); + return light_lightness_status(model, ctx); } const struct bt_mesh_model_op gen_onoff_srv_op[] = { diff --git a/nimble/host/mesh/src/msg.c b/nimble/host/mesh/src/msg.c new file mode 100644 index 0000000000..b788ffe1e9 --- /dev/null +++ b/nimble/host/mesh/src/msg.c @@ -0,0 +1,84 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mesh/mesh.h" + +void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode) +{ + net_buf_simple_init(msg, 0); + + switch (BT_MESH_MODEL_OP_LEN(opcode)) { + case 1: + net_buf_simple_add_u8(msg, opcode); + break; + case 2: + net_buf_simple_add_be16(msg, opcode); + break; + case 3: + net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); + /* Using LE for the CID since the model layer is defined as + * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 + * will declare the opcode in this way. + */ + net_buf_simple_add_le16(msg, opcode & 0xffff); + break; + default: + BT_WARN("Unknown opcode format"); + break; + } +} + +void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack) +{ + ack->op = 0U; + ack->user_data = NULL; + ack->dst = BT_MESH_ADDR_UNASSIGNED; +} + +int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t dst, void *user_data) +{ + if (ack->op) { + BT_WARN("Another synchronous operation pending"); + return -EBUSY; + } + + ack->op = op; + ack->user_data = user_data; + ack->dst = dst; + + return 0; +} + +int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, int32_t timeout) +{ + int err; + + err = k_sem_take(&ack->sem, timeout); + bt_mesh_msg_ack_ctx_clear(ack); + + if (err == -EAGAIN) { + return -ETIMEDOUT; + } + + return err; +} + +bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t addr, void **user_data) +{ + if (ack->op != op || (BT_MESH_ADDR_IS_UNICAST(ack->dst) && ack->dst != addr)) { + return false; + } + + if (user_data != NULL) { + *user_data = ack->user_data; + } + + return true; +} diff --git a/nimble/host/mesh/src/net.c b/nimble/host/mesh/src/net.c index 8b86935d31..229e40546e 100644 --- a/nimble/host/mesh/src/net.c +++ b/nimble/host/mesh/src/net.c @@ -34,20 +34,12 @@ #include "mesh/glue.h" #include "mesh/slist.h" -/* Minimum valid Mesh Network PDU length. The Network headers - * themselves take up 9 bytes. After that there is a minumum of 1 byte - * payload for both CTL=1 and CTL=0 PDUs (smallest OpCode is 1 byte). CTL=1 - * PDUs must use a 64-bit (8 byte) NetMIC, whereas CTL=0 PDUs have at least - * a 32-bit (4 byte) NetMIC and AppMIC giving again a total of 8 bytes. - */ -#define BT_MESH_NET_MIN_PDU_LEN (BT_MESH_NET_HDR_LEN + 1 + 8) - #define LOOPBACK_MAX_PDU_LEN (BT_MESH_NET_HDR_LEN + 16) #define LOOPBACK_USER_DATA_SIZE sizeof(struct bt_mesh_subnet *) #define LOOPBACK_BUF_SUB(buf) (*(struct bt_mesh_subnet **)net_buf_user_data(buf)) /* Seq limit after IV Update is triggered */ -#define IV_UPDATE_SEQ_LIMIT 8000000 +#define IV_UPDATE_SEQ_LIMIT CONFIG_BT_MESH_IV_UPDATE_SEQ_LIMIT #define IVI(pdu) ((pdu)[0] >> 7) #define NID(pdu) ((pdu)[0] & 0x7f) @@ -57,6 +49,31 @@ #define SRC(pdu) (sys_get_be16(&(pdu)[5])) #define DST(pdu) (sys_get_be16(&(pdu)[7])) +/** Define CONFIG_BT_MESH_SEQ_STORE_RATE even if settings are disabled to + * compile the code. + */ +#ifndef CONFIG_BT_SETTINGS +#define CONFIG_BT_MESH_SEQ_STORE_RATE 1 +#endif + +/* Mesh network information for persistent storage. */ +struct net_val { + uint16_t primary_addr; + uint8_t dev_key[16]; +} __packed; + +/* Sequence number information for persistent storage. */ +struct seq_val { + uint8_t val[3]; +} __packed; + +/* IV Index & IV Update information for persistent storage. */ +struct iv_val { + uint32_t iv_index; + uint8_t iv_update:1, + iv_duration:7; +} __packed; + static struct { uint32_t src : 15, /* MSb of source is always 0 */ seq : 17; @@ -68,6 +85,15 @@ struct bt_mesh_net bt_mesh = { .local_queue = STAILQ_HEAD_INITIALIZER(bt_mesh.local_queue), }; +/* Mesh Profile Specification 3.10.6 + * The node shall not execute more than one IV Index Recovery within a period of + * 192 hours. + * + * Mark that the IV Index Recovery has been done to prevent two recoveries to be + * done before a normal IV Index update has been completed within 96h+96h. + */ +static bool ivi_was_recovered; + static struct os_mbuf_pool loopback_os_mbuf_pool; static struct os_mempool loopback_buf_mempool; os_membuf_t loopback_mbuf_membuf[ @@ -120,6 +146,30 @@ static void msg_cache_add(struct bt_mesh_net_rx *rx) msg_cache_next %= ARRAY_SIZE(msg_cache); } +static void store_iv(bool only_duration) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING); + + if (!only_duration) { + /* Always update Seq whenever IV changes */ + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING); + } +#endif +} + +static void store_seq(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + if (CONFIG_BT_MESH_SEQ_STORE_RATE > 1 && + (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)) { + return; + } + + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING); +#endif +} + int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], uint32_t iv_index) { @@ -147,17 +197,18 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, BT_MESH_IV_UPDATE(flags)); - /* Set minimum required hours, since the 96-hour minimum requirement - * doesn't apply straight after provisioning (since we can't know how - * long has actually passed since the network changed its state). + /* If IV Update is already in progress, set minimum required hours, + * since the 96-hour minimum requirement doesn't apply in this case straight + * after provisioning. */ - bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS; + if (BT_MESH_IV_UPDATE(flags)) { + bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing network information persistently"); - bt_mesh_store_net(); - bt_mesh_store_subnet(idx); - bt_mesh_store_iv(false); + bt_mesh_subnet_store(idx); + store_iv(false); } return 0; @@ -221,24 +272,24 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) return false; } - if (iv_index > bt_mesh.iv_index + 1) { + if ((iv_index > bt_mesh.iv_index + 1) || + (iv_index == bt_mesh.iv_index + 1 && !iv_update)) { + if (ivi_was_recovered) { + BT_ERR("IV Index Recovery before minimum delay"); + return false; + } + /* The Mesh profile specification allows to initiate an + * IV Index Recovery procedure if previous IV update has + * been missed. This allows the node to remain + * functional. + */ BT_WARN("Performing IV Index Recovery"); + ivi_was_recovered = true; bt_mesh_rpl_clear(); bt_mesh.iv_index = iv_index; bt_mesh.seq = 0; goto do_update; } - - if (iv_index == bt_mesh.iv_index + 1 && !iv_update) { - BT_WARN("Ignoring new index in normal mode"); - return false; - } - - if (!iv_update) { - /* Nothing to do */ - BT_DBG("Already in Normal state"); - return false; - } } if (!(IS_ENABLED(CONFIG_BT_MESH_IV_UPDATE_TEST) && @@ -256,41 +307,42 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) return false; } -do_update: - atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv_update); - bt_mesh.ivu_duration = 0U; - if (iv_update) { bt_mesh.iv_index = iv_index; BT_DBG("IV Update state entered. New index 0x%08x", (unsigned) bt_mesh.iv_index); bt_mesh_rpl_reset(); + ivi_was_recovered = false; } else { BT_DBG("Normal mode entered"); bt_mesh.seq = 0; } - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); +do_update: + atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv_update); + bt_mesh.ivu_duration = 0U; + + k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); /* Notify other modules */ if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { bt_mesh_friend_sec_update(BT_MESH_KEY_ANY); } + bt_mesh_subnet_foreach(bt_mesh_beacon_update); + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) { bt_mesh_proxy_beacon_send(NULL); } - bt_mesh_subnet_foreach(bt_mesh_beacon_update); - if (MYNEWT_VAL(BLE_MESH_CDB)) { bt_mesh_cdb_iv_update(iv_index, iv_update); } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(false); + store_iv(false); } return true; @@ -301,7 +353,7 @@ uint32_t bt_mesh_next_seq(void) uint32_t seq = bt_mesh.seq++; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_seq(); + store_seq(); } if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) && @@ -346,14 +398,14 @@ static void bt_mesh_net_local(struct ble_npl_event *work) rx.ctx.addr, rx.seq, sub); (void) bt_mesh_trans_recv(buf, &rx); - net_buf_unref(buf); + os_mbuf_free_chain(buf); } } static const struct bt_mesh_net_cred *net_tx_cred_get(struct bt_mesh_net_tx *tx) { -#if defined(BLE_MESH_LOW_POWER) - if (tx->friend_cred && bt_mesh_lpn_established()) { +#if IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) + if (tx->friend_cred && bt_mesh.lpn.frnd) { return &bt_mesh.lpn.cred[SUBNET_KEY_TX_IDX(tx->sub)]; } #endif @@ -428,7 +480,7 @@ static int loopback(const struct bt_mesh_net_tx *tx, const uint8_t *data, { struct os_mbuf *buf; - buf = os_mbuf_get_pkthdr(&loopback_os_mbuf_pool, 0); + buf = os_mbuf_get_pkthdr(&loopback_os_mbuf_pool, BT_MESH_NET_HDR_LEN); if (!buf) { BT_WARN("Unable to allocate loopback"); return -ENOMEM; @@ -470,7 +522,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, /* Deliver to local network interface if necessary */ if (bt_mesh_fixed_group_match(tx->ctx->addr) || - bt_mesh_elem_find(tx->ctx->addr)) { + bt_mesh_has_addr(tx->ctx->addr)) { err = loopback(tx, buf->om_data, buf->om_len); /* Local unicast messages should not go out to network */ @@ -498,12 +550,13 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, goto done; } + BT_MESH_ADV(buf)->cb = cb; + BT_MESH_ADV(buf)->cb_data = cb_data; + /* Deliver to GATT Proxy Clients if necessary. */ if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && bt_mesh_proxy_relay(buf, tx->ctx->addr) && BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - /* Notify completion if this only went through the Mesh Proxy */ - send_cb_finalize(cb, cb_data); err = 0; goto done; @@ -567,7 +620,7 @@ static bool net_decrypt(struct bt_mesh_net_rx *rx, struct os_mbuf *in, return false; } - if (bt_mesh_elem_find(rx->ctx.addr)) { + if (bt_mesh_has_addr(rx->ctx.addr)) { BT_DBG("Dropping locally originated packet"); return false; } @@ -665,7 +718,7 @@ static void bt_mesh_net_relay(struct os_mbuf *sbuf, bt_hex(buf->om_data, buf->om_len)); /* When the Friend node relays message for lpn, the message will be - * retransmitted using the managed master security credentials and + * 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) && @@ -702,6 +755,11 @@ int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if, 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)); @@ -754,7 +812,7 @@ int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if, 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(29); + 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; @@ -773,7 +831,7 @@ void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, net_buf_simple_save(buf, &state); rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) || - bt_mesh_elem_find(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) { @@ -815,6 +873,10 @@ void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, 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); @@ -825,10 +887,10 @@ static void ivu_refresh(struct ble_npl_event *work) if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(true); + store_iv(true); } - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); + k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); return; } @@ -836,15 +898,169 @@ static void ivu_refresh(struct ble_npl_event *work) bt_mesh_beacon_ivu_initiator(true); bt_mesh_net_iv_update(bt_mesh.iv_index, false); } else if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(true); + 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 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, +}; + +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, +}; + +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, +}; +#endif + void bt_mesh_net_init(void) { int rc; - k_delayed_work_init(&bt_mesh.ivu_timer, ivu_refresh); +#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"); +#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); @@ -855,7 +1071,153 @@ void bt_mesh_net_init(void) 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)); + 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); +} +#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); + } +} diff --git a/nimble/host/mesh/src/net.h b/nimble/host/mesh/src/net.h index f4b1192b2c..b8147b4d86 100644 --- a/nimble/host/mesh/src/net.h +++ b/nimble/host/mesh/src/net.h @@ -25,6 +25,19 @@ CONFIG_BT_MESH_IVU_DIVIDER) #define BT_MESH_IVU_TIMEOUT K_HOURS(BT_MESH_IVU_HOURS) +/* Minimum valid Mesh Network PDU length. The Network headers + * themselves take up 9 bytes. After that there is a minimum of 1 byte + * payload for both CTL=1 and CTL=0 PDUs (smallest OpCode is 1 byte). CTL=1 + * PDUs must use a 64-bit (8 byte) NetMIC, whereas CTL=0 PDUs have at least + * a 32-bit (4 byte) NetMIC and AppMIC giving again a total of 8 bytes. + */ +#define BT_MESH_NET_MIN_PDU_LEN (BT_MESH_NET_HDR_LEN + 1 + 8) +/* Maximum valid Mesh Network PDU length. The longest packet can either be a + * transport control message (CTL=1) of 12 bytes + 8 bytes of NetMIC, or an + * access message (CTL=0) of 16 bytes + 4 bytes of NetMIC. + */ +#define BT_MESH_NET_MAX_PDU_LEN (BT_MESH_NET_HDR_LEN + 16 + 4) + struct bt_mesh_net_cred; struct bt_mesh_node { @@ -61,7 +74,7 @@ struct bt_mesh_friend { uint16_t sub_list[FRIEND_SUB_LIST_SIZE]; - struct k_delayed_work timer; + struct k_work_delayable timer; struct bt_mesh_friend_seg { struct net_buf_slist_t queue; @@ -83,7 +96,7 @@ struct bt_mesh_friend { uint32_t start; /* Clear Procedure start */ uint16_t frnd; /* Previous Friend's address */ uint16_t repeat_sec; /* Repeat timeout in seconds */ - struct k_delayed_work timer; /* Repeat timer */ + struct k_work_delayable timer; /* Repeat timer */ } clear; }; @@ -147,7 +160,7 @@ struct bt_mesh_lpn { uint16_t adv_duration; /* Next LPN related action timer */ - struct k_delayed_work timer; + struct k_work_delayable timer; /* Subscribed groups */ uint16_t groups[LPN_GROUPS]; @@ -171,17 +184,6 @@ enum { BT_MESH_IVU_TEST, /* IV Update test mode */ BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */ - /* pending storage actions, must reside within first 32 flags */ - BT_MESH_RPL_PENDING, - BT_MESH_KEYS_PENDING, - BT_MESH_NET_PENDING, - BT_MESH_IV_PENDING, - BT_MESH_SEQ_PENDING, - BT_MESH_HB_PUB_PENDING, - BT_MESH_CFG_PENDING, - BT_MESH_MOD_PENDING, - BT_MESH_VA_PENDING, - /* Feature flags */ BT_MESH_RELAY, BT_MESH_BEACON, @@ -219,7 +221,7 @@ struct bt_mesh_net { uint8_t default_ttl; /* Timer to track duration in current IV Update state */ - struct k_delayed_work ivu_timer; + struct k_work_delayable ivu_timer; uint8_t dev_key[16]; }; @@ -269,7 +271,12 @@ extern struct bt_mesh_net bt_mesh; static inline void *net_buf_user_data(const struct os_mbuf *buf) { - return (void *)buf->om_data; + /* In Zephyr at the end of net_buf (which is ported as os_mbuf) is place + * for user_data, which is array of octets, just like os_mbuf's om_data. Let's just + * use last octets (starting at start of om_data + total size of data mbuf can hold - + * intended user_data size) of om_data as Zephyr's user_data. + */ + return (void *)(buf->om_data + buf->om_omp->omp_databuf_len - MYNEWT_VAL(BLE_MESH_NET_BUF_USER_DATA_SIZE)); } int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], @@ -296,7 +303,11 @@ uint32_t bt_mesh_next_seq(void); void bt_mesh_net_init(void); void bt_mesh_net_header_parse(struct os_mbuf *buf, struct bt_mesh_net_rx *rx); - +void bt_mesh_net_pending_net_store(void); +void bt_mesh_net_pending_iv_store(void); +void bt_mesh_net_pending_seq_store(void); +void bt_mesh_net_clear(void); +void bt_mesh_net_settings_commit(void); static inline void send_cb_finalize(const struct bt_mesh_send_cb *cb, void *cb_data) diff --git a/nimble/host/mesh/src/pb_adv.c b/nimble/host/mesh/src/pb_adv.c index 28391b1883..1fa2c35b24 100644 --- a/nimble/host/mesh/src/pb_adv.c +++ b/nimble/host/mesh/src/pb_adv.c @@ -55,10 +55,10 @@ /* Acked messages, will do retransmissions manually, taking acks into account: */ #define RETRANSMITS_RELIABLE 0 -/* Unacked messages: */ -#define RETRANSMITS_UNRELIABLE 2 /* PDU acks: */ #define RETRANSMITS_ACK 2 +/* Link close retransmits: */ +#define RETRANSMITS_LINK_CLOSE 2 enum { ADV_LINK_ACTIVE, /* Link has been opened */ @@ -105,11 +105,11 @@ struct pb_adv { void *cb_data; /* Retransmit timer */ - struct k_delayed_work retransmit; + struct k_work_delayable retransmit; } tx; /* Protocol timeout */ - struct k_delayed_work prot_timer; + struct k_work_delayable prot_timer; }; struct prov_rx { @@ -125,20 +125,28 @@ static void gen_prov_ack_send(uint8_t xact_id); static void link_open(struct prov_rx *rx, struct os_mbuf *buf); static void link_ack(struct prov_rx *rx, struct os_mbuf *buf); static void link_close(struct prov_rx *rx, struct os_mbuf *buf); +static void prov_link_close(enum prov_bearer_link_status status); +static void close_link(enum prov_bearer_link_status status); static void buf_sent(int err, void *user_data) { BT_DBG("buf_send"); - if (!link.tx.buf[0]) { + if (atomic_test_and_clear_bit(link.flags, ADV_LINK_CLOSING)) { + close_link(PROV_BEARER_LINK_STATUS_SUCCESS); return; } +} - BT_DBG("submit retransmit"); - k_delayed_work_submit(&link.tx.retransmit, RETRANSMIT_TIMEOUT); +static void buf_start(uint16_t duration, int err, void *user_data) +{ + if (err) { + buf_sent(err, user_data); + } } static struct bt_mesh_send_cb buf_sent_cb = { + .start = buf_start, .end = buf_sent, }; @@ -180,7 +188,12 @@ static void prov_clear_tx(void) { BT_DBG(""); - k_delayed_work_cancel(&link.tx.retransmit); + /* If this fails, the work handler will not find any buffers to send, + * and return without rescheduling. The work handler also checks the + * LINK_ACTIVE flag, so if this call is part of reset_adv_link, it'll + * exit early. + */ + (void)k_work_cancel_delayable(&link.tx.retransmit); free_segments(); } @@ -190,7 +203,10 @@ static void reset_adv_link(void) BT_DBG(""); prov_clear_tx(); - k_delayed_work_cancel(&link.prot_timer); + /* If this fails, the work handler will exit early on the LINK_ACTIVE + * check. + */ + (void)k_work_cancel_delayable(&link.prot_timer); if (atomic_test_bit(link.flags, ADV_PROVISIONER)) { /* Clear everything except the retransmit and protocol timer @@ -257,7 +273,7 @@ static void prov_failed(uint8_t err) static void prov_msg_recv(void) { - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); if (!bt_mesh_fcs_check(link.rx.buf, link.rx.fcs)) { BT_ERR("Incorrect FCS"); @@ -278,10 +294,14 @@ static void prov_msg_recv(void) static void protocol_timeout(struct ble_npl_event *work) { + if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { + return; + } + BT_DBG(""); link.rx.seg = 0U; - close_link(PROV_BEARER_LINK_STATUS_TIMEOUT); + prov_link_close(PROV_BEARER_LINK_STATUS_TIMEOUT); } /******************************************************************************* * Generic provisioning @@ -543,8 +563,6 @@ static void send_reliable(void) { int i; - link.tx.start = k_uptime_get(); - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { struct os_mbuf *buf = link.tx.buf[i]; @@ -552,19 +570,20 @@ static void send_reliable(void) break; } - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); + if (BT_MESH_ADV(buf)->busy) { + continue; } + + BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); + + bt_mesh_adv_send(buf, NULL, NULL); } + + k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT); } static void prov_retransmit(struct ble_npl_event *work) { - int32_t timeout_ms; - int i; - BT_DBG(""); if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { @@ -572,63 +591,25 @@ static void prov_retransmit(struct ble_npl_event *work) return; } - /* - * According to mesh profile spec (5.3.1.4.3), the close message should - * be restransmitted at least three times. Retransmit the link_close - * message until CLOSING_TIMEOUT has elapsed. - */ - if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) { - timeout_ms = CLOSING_TIMEOUT; - } else { - timeout_ms = TRANSACTION_TIMEOUT; - } - - if (k_uptime_get() - link.tx.start > timeout_ms) { - if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) { - close_link(PROV_BEARER_LINK_STATUS_SUCCESS); - } else { - BT_WARN("Giving up transaction"); - close_link(PROV_BEARER_LINK_STATUS_TIMEOUT); - } - + if (k_uptime_get() - link.tx.start > TRANSACTION_TIMEOUT) { + BT_WARN("Giving up transaction"); + prov_link_close(PROV_BEARER_LINK_STATUS_FAIL); return; } - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct os_mbuf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - if (BT_MESH_ADV(buf)->busy) { - continue; - } - - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - } - } + send_reliable(); } -static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len, - bool reliable) +static struct os_mbuf *ctl_buf_create(uint8_t op, const void *data, uint8_t data_len, + uint8_t retransmits) { struct os_mbuf *buf; BT_DBG("op 0x%02x data_len %u", op, data_len); - prov_clear_tx(); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - buf = adv_buf_create(reliable ? RETRANSMITS_RELIABLE : - RETRANSMITS_UNRELIABLE); + buf = adv_buf_create(retransmits); if (!buf) { - return -ENOBUFS; + return NULL; } net_buf_add_be32(buf, link.id); @@ -636,16 +617,36 @@ static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len, net_buf_add_u8(buf, 0x00); net_buf_add_u8(buf, GPC_CTL(op)); net_buf_add_mem(buf, data, data_len); + return buf; +} - if (reliable) { - link.tx.buf[0] = buf; - send_reliable(); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - net_buf_unref(buf); +static int bearer_ctl_send(struct os_mbuf *buf) +{ + if (!buf) { + return -ENOMEM; } + prov_clear_tx(); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); + + link.tx.start = k_uptime_get(); + link.tx.buf[0] = buf; + send_reliable(); return 0; + } + +static int bearer_ctl_send_unacked(struct os_mbuf *buf) +{ + if (!buf) { + return -ENOMEM; + } + + prov_clear_tx(); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); + + bt_mesh_adv_send(buf, &buf_sent_cb, NULL); + net_buf_unref(buf); + return 0; } static int prov_send_adv(struct os_mbuf *msg, @@ -655,7 +656,7 @@ static int prov_send_adv(struct os_mbuf *msg, uint8_t seg_len, seg_id; prov_clear_tx(); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); start = adv_buf_create(RETRANSMITS_RELIABLE); if (!start) { @@ -673,6 +674,7 @@ static int prov_send_adv(struct os_mbuf *msg, link.tx.buf[0] = start; link.tx.cb = cb; link.tx.cb_data = cb_data; + link.tx.start = k_uptime_get(); BT_DBG("xact_id: 0x%x len: %u", link.tx.id, msg->om_len); @@ -720,6 +722,8 @@ static int prov_send_adv(struct os_mbuf *msg, static void link_open(struct prov_rx *rx, struct os_mbuf *buf) { + int err; + BT_DBG("len %u", buf->om_len); if (buf->om_len < 16) { @@ -729,13 +733,14 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf) if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { /* Send another link ack if the provisioner missed the last */ - if (link.id == rx->link_id) { - BT_DBG("Resending link ack"); - bearer_ctl_send(LINK_ACK, NULL, 0, false); - } else { + if (link.id != rx->link_id) { BT_DBG("Ignoring bearer open: link already active"); + return; } + BT_DBG("Resending link ack"); + /* Ignore errors, message will be attempted again if we keep receiving link open: */ + (void)bearer_ctl_send_unacked(ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK)); return; } @@ -748,7 +753,11 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf) atomic_set_bit(link.flags, ADV_LINK_ACTIVE); net_buf_simple_reset(link.rx.buf); - bearer_ctl_send(LINK_ACK, NULL, 0, false); + err = bearer_ctl_send_unacked(ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK)); + if (err) { + reset_adv_link(); + return; + } link.cb->link_opened(&pb_adv, link.cb_data); } @@ -812,8 +821,16 @@ void bt_mesh_pb_adv_recv(struct os_mbuf *buf) static int prov_link_open(const uint8_t uuid[16], int32_t timeout, const struct prov_bearer_cb *cb, void *cb_data) { + int err; + BT_DBG("uuid %s", bt_hex(uuid, 16)); + err = bt_mesh_adv_enable(); + if (err) { + BT_ERR("Failed enabling advertiser"); + return err; + } + if (atomic_test_and_set_bit(link.flags, ADV_LINK_ACTIVE)) { return -EBUSY; } @@ -828,13 +845,19 @@ static int prov_link_open(const uint8_t uuid[16], int32_t timeout, net_buf_simple_reset(link.rx.buf); - bearer_ctl_send(LINK_OPEN, uuid, 16, true); - - return 0; + return bearer_ctl_send(ctl_buf_create(LINK_OPEN, uuid, 16, RETRANSMITS_RELIABLE)); } static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data) { + int err; + + err = bt_mesh_adv_enable(); + if (err) { + BT_ERR("Failed enabling advertiser"); + return err; + } + if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { return -EBUSY; } @@ -844,7 +867,7 @@ static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data) link.cb = cb; link.cb_data = cb_data; - /* Make sure we're scanning for provisioning inviations */ + /* Make sure we're scanning for provisioning invitations */ bt_mesh_scan_enable(); /* Enable unprovisioned beacon sending */ bt_mesh_beacon_enable(); @@ -858,13 +881,14 @@ static void prov_link_close(enum prov_bearer_link_status status) return; } - bearer_ctl_send(LINK_CLOSE, &status, 1, true); + /* Ignore errors, the link will time out eventually if this doesn't get sent */ + bearer_ctl_send_unacked(ctl_buf_create(LINK_CLOSE, &status, 1, RETRANSMITS_LINK_CLOSE)); } void pb_adv_init(void) { - k_delayed_work_init(&link.prot_timer, protocol_timeout); - k_delayed_work_init(&link.tx.retransmit, prov_retransmit); + k_work_init_delayable(&link.prot_timer, protocol_timeout); + k_work_init_delayable(&link.tx.retransmit, prov_retransmit); if (!rx_buf) { rx_buf = NET_BUF_SIMPLE(65); diff --git a/nimble/host/mesh/src/pb_gatt.c b/nimble/host/mesh/src/pb_gatt.c index a8f73787dd..9a0d7091e1 100644 --- a/nimble/host/mesh/src/pb_gatt.c +++ b/nimble/host/mesh/src/pb_gatt.c @@ -6,6 +6,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ + #define MESH_LOG_MODULE BLE_MESH_PROV_LOG #include "mesh/mesh.h" @@ -14,20 +15,28 @@ #include "proxy.h" #include "adv.h" #include "prov.h" +#include "syscfg/syscfg.h" +#include "pb_gatt_srv.h" + +#if MYNEWT_VAL(BLE_MESH_PB_GATT) +struct prov_bearer_send_cb { + prov_bearer_send_complete_t cb; + void *cb_data; +}; struct prov_link { uint16_t conn_handle; const struct prov_bearer_cb *cb; void *cb_data; + struct prov_bearer_send_cb comp; struct { uint8_t id; /* Transaction ID */ uint8_t prev_id; /* Previous Transaction ID */ uint8_t seg; /* Bit-field of unreceived segments */ uint8_t last_seg; /* Last segment (to check length) */ uint8_t fcs; /* Expected FCS value */ - struct os_mbuf *buf; } rx; - struct k_delayed_work prot_timer; + struct k_work_delayable prot_timer; }; static struct prov_link link; @@ -36,9 +45,8 @@ static void reset_state(void) { link.conn_handle = BLE_HS_CONN_HANDLE_NONE; - k_delayed_work_cancel(&link.prot_timer); - - link.rx.buf = bt_mesh_proxy_get_buf(); + /* If this fails, the protocol timeout handler will exit early. */ + (void)k_work_cancel_delayable(&link.prot_timer); } static void link_closed(enum prov_bearer_link_status status) @@ -54,6 +62,11 @@ static void link_closed(enum prov_bearer_link_status status) static void protocol_timeout(struct ble_npl_event *work) { + if (!link.conn_handle) { + /* Already disconnected */ + return; + } + BT_DBG("Protocol timeout"); link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT); @@ -73,7 +86,7 @@ int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf) return -EINVAL; } - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); link.cb->recv(&pb_gatt, link.cb_data, buf); @@ -89,7 +102,7 @@ int bt_mesh_pb_gatt_open(uint16_t conn_handle) } link.conn_handle = conn_handle; - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); link.cb->link_opened(&pb_gatt, link.cb_data); @@ -115,7 +128,7 @@ int bt_mesh_pb_gatt_close(uint16_t conn_handle) static int link_accept(const struct prov_bearer_cb *cb, void *cb_data) { - bt_mesh_proxy_prov_enable(); + (void)bt_mesh_pb_gatt_enable(); bt_mesh_adv_update(); link.cb = cb; @@ -131,9 +144,12 @@ static int buf_send(struct os_mbuf *buf, prov_bearer_send_complete_t cb, return -ENOTCONN; } - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + link.comp.cb = cb; + link.comp.cb_data = cb_data; - return bt_mesh_proxy_send(link.conn_handle, BT_MESH_PROXY_PROV, buf); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); + + return bt_mesh_pb_gatt_send(link.conn_handle, buf); } static void clear_tx(void) @@ -143,7 +159,7 @@ static void clear_tx(void) void pb_gatt_init(void) { - k_delayed_work_init(&link.prot_timer, protocol_timeout); + k_work_init_delayable(&link.prot_timer, protocol_timeout); } void pb_gatt_reset(void) @@ -155,4 +171,5 @@ const struct prov_bearer pb_gatt = { .link_accept = link_accept, .send = buf_send, .clear_tx = clear_tx, -}; \ No newline at end of file +}; +#endif diff --git a/nimble/host/mesh/src/pb_gatt_srv.c b/nimble/host/mesh/src/pb_gatt_srv.c new file mode 100644 index 0000000000..ee37819d5c --- /dev/null +++ b/nimble/host/mesh/src/pb_gatt_srv.c @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define MESH_LOG_MODULE BLE_MESH_PROV_LOG + +#include "mesh_priv.h" +#include "adv.h" +#include "net.h" +#include "rpl.h" +#include "transport.h" +#include "prov.h" +#include "beacon.h" +#include "foundation.h" +#include "access.h" +#include "proxy.h" +#include "proxy_msg.h" +#include "pb_gatt_srv.h" +#include "syscfg/syscfg.h" +#include "services/gatt/ble_svc_gatt.h" +#include "../../host/src/ble_hs_priv.h" + +#if defined(CONFIG_BT_MESH_PB_GATT_USE_DEVICE_NAME) +#define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME +#else +#define ADV_OPT_USE_NAME 0 +#endif + +#define ADV_OPT_PROV \ +.conn_mode = (BLE_GAP_CONN_MODE_UND), \ +.disc_mode = (BLE_GAP_DISC_MODE_GEN), + +#if MYNEWT_VAL(BLE_MESH_PB_GATT) +/** @def BT_UUID_MESH_PROV + * @brief Mesh Provisioning Service + */ +ble_uuid16_t BT_UUID_MESH_PROV = BLE_UUID16_INIT(0x1827); +#define BT_UUID_MESH_PROV_VAL 0x1827 +/** @def BT_UUID_MESH_PROXY + * @brief Mesh Proxy Service + */ +ble_uuid16_t BT_UUID_MESH_PROXY = BLE_UUID16_INIT(0x1828); +#define BT_UUID_MESH_PROXY_VAL 0x1828 +/** @def BT_UUID_GATT_CCC + * @brief GATT Client Characteristic Configuration + */ +ble_uuid16_t BT_UUID_GATT_CCC = BLE_UUID16_INIT(0x2902); +#define BT_UUID_GATT_CCC_VAL 0x2902 +/** @def BT_UUID_MESH_PROV_DATA_IN + * @brief Mesh Provisioning Data In + */ +ble_uuid16_t BT_UUID_MESH_PROV_DATA_IN = BLE_UUID16_INIT(0x2adb); +#define BT_UUID_MESH_PROV_DATA_IN_VAL 0x2adb +/** @def BT_UUID_MESH_PROV_DATA_OUT + * @brief Mesh Provisioning Data Out + */ +ble_uuid16_t BT_UUID_MESH_PROV_DATA_OUT = BLE_UUID16_INIT(0x2adc); +#define BT_UUID_MESH_PROV_DATA_OUT_VAL 0x2adc +/** @def BT_UUID_MESH_PROXY_DATA_IN + * @brief Mesh Proxy Data In + */ +ble_uuid16_t BT_UUID_MESH_PROXY_DATA_IN = BLE_UUID16_INIT(0x2add); +#define BT_UUID_MESH_PROXY_DATA_IN_VAL 0x2add +/** @def BT_UUID_MESH_PROXY_DATA_OUT + * @brief Mesh Proxy Data Out + */ +ble_uuid16_t BT_UUID_MESH_PROXY_DATA_OUT = BLE_UUID16_INIT(0x2ade); +#define BT_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade +#define BT_UUID_16_ENCODE(w16) \ + (((w16) >> 0) & 0xFF), \ + (((w16) >> 8) & 0xFF) + +static bool prov_fast_adv; + +struct svc_handles svc_handles; +static atomic_t pending_notifications; + +static int gatt_send(uint16_t conn_handle, + const void *data, uint16_t len); + +static struct bt_mesh_proxy_role *cli; + +static void proxy_msg_recv(struct bt_mesh_proxy_role *role) +{ + switch (role->msg_type) { + case BT_MESH_PROXY_PROV: + BT_DBG("Mesh Provisioning PDU"); + bt_mesh_pb_gatt_recv(role->conn_handle, role->buf); + break; + default: + BT_WARN("Unhandled Message Type 0x%02x", role->msg_type); + break; + } +} + +static bool service_registered; + +static int gatt_recv_proxy(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + const uint8_t *data = ctxt->om->om_data; + uint16_t len = ctxt->om->om_len; + struct bt_mesh_proxy_client *client = find_client(conn_handle); + + if (len < 1) { + BT_WARN("Too small Proxy PDU"); + return -EINVAL; + } + + if (PDU_TYPE(data) == BT_MESH_PROXY_PROV) { + BT_WARN("Proxy PDU type doesn't match GATT service"); + return -EINVAL; + } + + return bt_mesh_proxy_msg_recv(client->cli, data, len); +} + +static int gatt_recv_prov(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + const uint8_t *data = ctxt->om->om_data; + uint16_t len = ctxt->om->om_len; + + if (conn_handle != cli->conn_handle) { + BT_WARN("conn_handle != cli->conn_handle"); + return -ENOTCONN; + } + + if (len < 1) { + BT_WARN("Too small Proxy PDU"); + return -EINVAL; + } + + if (PDU_TYPE(data) != BT_MESH_PROXY_PROV) { + BT_WARN("Proxy PDU type doesn't match GATT service"); + return -EINVAL; + } + + return bt_mesh_proxy_msg_recv(cli, data, len); +} + +void gatt_connected_pb_gatt(uint16_t conn_handle, uint8_t err) +{ + 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 || bt_mesh_is_provisioned()) { + return; + } + + cli = bt_mesh_proxy_role_setup(conn_handle, gatt_send, proxy_msg_recv); + + BT_DBG("conn %p err 0x%02x", (void *)conn, err); +} + +void gatt_disconnected_pb_gatt(uint16_t conn_handle, uint8_t reason) +{ + 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; + } + + if (cli) { + bt_mesh_proxy_role_cleanup(cli); + cli = NULL; + } + + BT_DBG("conn %p reason 0x%02x", (void *)conn, reason); + + bt_mesh_pb_gatt_close(conn_handle); + + if (bt_mesh_is_provisioned()) { + (void)bt_mesh_pb_gatt_disable(); + } +} + +int prov_ccc_write(uint16_t conn_handle, uint8_t type) +{ + if (cli->conn_handle != conn_handle) { + BT_ERR("No PB-GATT Client found"); + return -ENOTCONN; + } + + if (type != BLE_GAP_EVENT_SUBSCRIBE) { + BT_WARN("Client wrote instead enabling notify"); + return BT_GATT_ERR(EINVAL); + } + + bt_mesh_pb_gatt_open(conn_handle); + + return 0; +} + +/* Mesh Provisioning Service Declaration */ + +static int +dummy_access_cb(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + /* + * We should never never enter this callback - it's attached to notify-only + * characteristic which are notified directly from mbuf. And we can't pass + * NULL as access_cb because gatts will assert on init... + */ + BLE_HS_DBG_ASSERT(0); + return 0; +} + +static const struct ble_gatt_svc_def svc_defs [] = { + { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_IN_VAL), + .access_cb = gatt_recv_proxy, + .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), + .access_cb = dummy_access_cb, + .flags = BLE_GATT_CHR_F_NOTIFY, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), + .access_cb = gatt_recv_prov, + .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), + .access_cb = dummy_access_cb, + .flags = BLE_GATT_CHR_F_NOTIFY, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, { + 0, /* No more services. */ + }, +}; + +void resolve_svc_handles(void) +{ + int rc; + + /* Either all handles are already resolved, or none of them */ + if (svc_handles.prov_data_out_h) { + return; + } + + /* + * We assert if attribute is not found since at this stage all attributes + * shall be already registered and thus shall be found. + */ + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), + &svc_handles.proxy_h); + assert(rc == 0); + + rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), + BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), + NULL, &svc_handles.proxy_data_out_h); + assert(rc == 0); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), + &svc_handles.prov_h); + assert(rc == 0); + + rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), + BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), + NULL, &svc_handles.prov_data_in_h); + assert(rc == 0); + + rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), + BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), + NULL, &svc_handles.prov_data_out_h); + assert(rc == 0); +} + + +int bt_mesh_proxy_svcs_register(void) +{ + int rc; + + rc = ble_gatts_count_cfg(svc_defs); + assert(rc == 0); + + rc = ble_gatts_add_svcs(svc_defs); + assert(rc == 0); + + return 0; +} + +int bt_mesh_pb_gatt_enable(void) +{ + int rc; + uint16_t handle; + 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_PROV_VAL), &handle); + assert(rc == 0); + ble_gatts_svc_set_visibility(handle, 1); + /* FIXME: figure out end handle */ + ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); + + service_registered = true; + prov_fast_adv = true; + + return 0; +} + +int bt_mesh_pb_gatt_disable(void) +{ + uint16_t handle; + int rc; + + BT_DBG(""); + + if (!service_registered) { + return -EALREADY; + } + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); + assert(rc == 0); + ble_gatts_svc_set_visibility(handle, 0); + /* FIXME: figure out end handle */ + ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); + service_registered = false; + + bt_mesh_adv_update(); + + return 0; +} + +static uint8_t prov_svc_data[20] = { + BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL), +}; + +static const struct bt_data prov_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_PROV_VAL)), + BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), +}; + +int bt_mesh_pb_gatt_send(uint16_t conn_handle, struct os_mbuf *buf) +{ + if (!cli || cli->conn_handle != conn_handle) { + BT_ERR("No PB-GATT Client found"); + return -ENOTCONN; + } + + return bt_mesh_proxy_msg_send(cli, BT_MESH_PROXY_PROV, buf); +} + +static size_t gatt_prov_adv_create(struct bt_data prov_sd[1]) +{ + const struct bt_mesh_prov *prov = bt_mesh_prov_get(); + size_t uri_len; + + memcpy(prov_svc_data + 2, prov->uuid, 16); + sys_put_be16(prov->oob_info, prov_svc_data + 18); + + if (!prov->uri) { + return 0; + } + + 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"); + return 0; + } + + prov_sd[0].type = BT_DATA_URI; + prov_sd[0].data_len = uri_len; + prov_sd[0].data = (const uint8_t *)prov->uri; + + return 1; +} + +static int gatt_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_gattc_notify_custom(conn_handle, svc_handles.prov_data_out_h, om); + notify_complete(); + + if (!err) { + atomic_inc(&pending_notifications); + } + + return err; +} + +int bt_mesh_pb_gatt_adv_start(void) +{ + BT_DBG(""); + + if (!service_registered || bt_mesh_is_provisioned()) { + return -ENOTSUP; + } + + struct ble_gap_adv_params fast_adv_param = { + ADV_OPT_PROV + ADV_FAST_INT + }; +#if ADV_OPT_USE_NAME + const char *name = CONFIG_BT_DEVICE_NAME; + size_t name_len = strlen(name); + struct bt_data prov_sd = { + .type = BT_DATA_NAME_COMPLETE, + .data_len = name_len, + .data = (void *)name + }; +#else + struct bt_data *prov_sd = NULL; +#endif + + size_t prov_sd_len; + int err; + + prov_sd_len = gatt_prov_adv_create(prov_sd); + + if (!prov_fast_adv) { + struct ble_gap_adv_params slow_adv_param = { + ADV_OPT_PROV + ADV_SLOW_INT + }; + + return bt_mesh_adv_start(&slow_adv_param, K_FOREVER, prov_ad, + ARRAY_SIZE(prov_ad), prov_sd, prov_sd_len); + } + + /* Advertise 60 seconds using fast interval */ + err = bt_mesh_adv_start(&fast_adv_param, (60 * MSEC_PER_SEC), + prov_ad, ARRAY_SIZE(prov_ad), + prov_sd, prov_sd_len); + if (!err) { + prov_fast_adv = false; + } + + return err; +} +#endif diff --git a/nimble/host/mesh/src/pb_gatt_srv.h b/nimble/host/mesh/src/pb_gatt_srv.h new file mode 100644 index 0000000000..a5ebce5283 --- /dev/null +++ b/nimble/host/mesh/src/pb_gatt_srv.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __PB_GATT_SRV_H__ +#define __PB_GATT_SRV_H__ + +int bt_mesh_pb_gatt_send(uint16_t conn_handle, struct os_mbuf *buf); + +int bt_mesh_pb_gatt_enable(void); +int bt_mesh_pb_gatt_disable(void); + +int prov_ccc_write(uint16_t conn_handle, uint8_t type); +void gatt_disconnected_pb_gatt(uint16_t conn_handle, uint8_t err); +void gatt_connected_pb_gatt(uint16_t conn_handle, uint8_t err); +void resolve_svc_handles(void); + +int bt_mesh_pb_gatt_adv_start(void); + +extern struct svc_handles { + uint16_t proxy_h; + uint16_t proxy_data_out_h; + uint16_t prov_h; + uint16_t prov_data_in_h; + uint16_t prov_data_out_h; +} svc_handles; + +#endif /* __PB_GATT_SRV_H__ */ diff --git a/nimble/host/mesh/src/prov.c b/nimble/host/mesh/src/prov.c index ba514dde97..cdadbb45ba 100644 --- a/nimble/host/mesh/src/prov.c +++ b/nimble/host/mesh/src/prov.c @@ -25,6 +25,10 @@ struct bt_mesh_prov_link bt_mesh_prov_link; const struct bt_mesh_prov *bt_mesh_prov; +/* Verify specification defined length: */ +BUILD_ASSERT(sizeof(bt_mesh_prov_link.conf_inputs) == 145, + "Confirmation inputs shall be 145 bytes"); + static void pub_key_ready(const uint8_t *pkey) { if (!pkey) { @@ -34,18 +38,18 @@ static void pub_key_ready(const uint8_t *pkey) BT_DBG("Local public key ready"); } -int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[64])) +int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[BT_PUB_KEY_LEN])) { BT_DBG("bt_mesh_prov_reset_state"); int err; static struct bt_pub_key_cb pub_key_cb; - const size_t offset = offsetof(struct bt_mesh_prov_link, dhkey); + const size_t offset = offsetof(struct bt_mesh_prov_link, auth); pub_key_cb.func = func ? func : pub_key_ready; /* Disable Attention Timer if it was set */ - if (bt_mesh_prov_link.conf_inputs[0]) { + if (bt_mesh_prov_link.conf_inputs.invite[0]) { bt_mesh_attention(NULL, 0); } @@ -95,10 +99,98 @@ static bt_mesh_input_action_t input_action(uint8_t action) } } -int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size) +static int check_output_auth(bt_mesh_output_action_t output, uint8_t size) +{ + if (!output) { + return -EINVAL; + } + + if (!(bt_mesh_prov->output_actions & output)) { + return -EINVAL; + } + + if (size > bt_mesh_prov->output_size) { + return -EINVAL; + } + + return 0; +} + +static int check_input_auth(bt_mesh_input_action_t input, uint8_t size) +{ + if (!input) { + return -EINVAL; + } + + if (!(bt_mesh_prov->input_actions & input)) { + return -EINVAL; + } + + if (size > bt_mesh_prov->input_size) { + return -EINVAL; + } + + return 0; +} + +static void get_auth_string(char *str, uint8_t size) +{ + uint64_t value; + + bt_rand(&value, sizeof(value)); + + static const char characters[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + for (int i = 0; i < size; i++) { + /* pull base-36 digits: */ + int idx = value % 36; + + value = value / 36; + str[i] = characters[idx]; + } + + str[size] = '\0'; + + memcpy(bt_mesh_prov_link.auth, str, size); + memset(bt_mesh_prov_link.auth + size, 0, + sizeof(bt_mesh_prov_link.auth) - size); +} + +static uint32_t get_auth_number(bt_mesh_output_action_t output, + bt_mesh_input_action_t input, uint8_t size) + { + const uint32_t divider[PROV_IO_OOB_SIZE_MAX] = { 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000 }; + uint32_t num = 0; + + bt_rand(&num, sizeof(num)); + + if (output == BT_MESH_BLINK || + output == BT_MESH_BEEP || + output == BT_MESH_VIBRATE || + input == BT_MESH_PUSH || + input == BT_MESH_TWIST) { + /* According to the Bluetooth Mesh Profile + * Specification Section 5.4.2.4, blink, beep + * vibrate, push and twist should be a random integer + * between 0 and 10^size, *exclusive*: + */ + num = (num % (divider[size - 1] - 1)) + 1; + } else { + num %= divider[size - 1]; + } + + sys_put_be32(num, &bt_mesh_prov_link.auth[12]); + memset(bt_mesh_prov_link.auth, 0, 12); + + return num; + } + +int bt_mesh_prov_auth(bool is_provisioner, uint8_t method, uint8_t action, uint8_t size) { bt_mesh_output_action_t output; bt_mesh_input_action_t input; + int err; switch (method) { case AUTH_METHOD_NO_OOB: @@ -119,77 +211,63 @@ int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size) case AUTH_METHOD_OUTPUT: output = output_action(action); - if (!output) { - return -EINVAL; - } + if (is_provisioner) { + if (output == BT_MESH_DISPLAY_STRING) { + input = BT_MESH_ENTER_STRING; + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); + } else { + input = BT_MESH_ENTER_NUMBER; + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + } - if (!(bt_mesh_prov->output_actions & output)) { - return -EINVAL; + return bt_mesh_prov->input(input, size); } - if (size > bt_mesh_prov->output_size) { - return -EINVAL; + err = check_output_auth(output, size); + if (err) { + return err; } - atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); - if (output == BT_MESH_DISPLAY_STRING) { - unsigned char str[9]; - uint8_t i; - - bt_rand(str, size); - - /* Normalize to '0' .. '9' & 'A' .. 'Z' */ - for (i = 0; i < size; i++) { - str[i] %= 36; - if (str[i] < 10) { - str[i] += '0'; - } else { - str[i] += 'A' - 10; - } - } - str[size] = '\0'; + char str[9]; - memcpy(bt_mesh_prov_link.auth, str, size); - memset(bt_mesh_prov_link.auth + size, 0, - sizeof(bt_mesh_prov_link.auth) - size); - - return bt_mesh_prov->output_string((char *)str); - } else { - uint32_t div[8] = { 10, 100, 1000, 10000, 100000, - 1000000, 10000000, 100000000 }; - uint32_t num; - - bt_rand(&num, sizeof(num)); - num %= div[size - 1]; - - sys_put_be32(num, &bt_mesh_prov_link.auth[12]); - memset(bt_mesh_prov_link.auth, 0, 12); - - return bt_mesh_prov->output_number(output, num); + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + get_auth_string(str, size); + return bt_mesh_prov->output_string(str); } + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + return bt_mesh_prov->output_number(output, + get_auth_number(output, BT_MESH_NO_INPUT, size)); case AUTH_METHOD_INPUT: input = input_action(action); - if (!input) { - return -EINVAL; - } + if (!is_provisioner) { + err = check_input_auth(input, size); + if (err) { + return err; + } - if (!(bt_mesh_prov->input_actions & input)) { - return -EINVAL; - } + if (input == BT_MESH_ENTER_STRING) { + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); + } else { + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + } - if (size > bt_mesh_prov->input_size) { - return -EINVAL; + return bt_mesh_prov->input(input, size); } if (input == BT_MESH_ENTER_STRING) { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); - } else { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + char str[9]; + + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + get_auth_string(str, size); + return bt_mesh_prov->output_string(str); } - return bt_mesh_prov->input(input, size); + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + output = BT_MESH_DISPLAY_NUMBER; + return bt_mesh_prov->output_number(output, + get_auth_number(BT_MESH_NO_OUTPUT, input, size)); default: return -EINVAL; @@ -215,11 +293,16 @@ int bt_mesh_input_string(const char *str) { BT_DBG("%s", str); + if (strlen(str) > PROV_IO_OOB_SIZE_MAX || + strlen(str) > bt_mesh_prov_link.oob_size) { + return -ENOTSUP; + } + if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { return -EINVAL; } - strncpy((char *)bt_mesh_prov_link.auth, str, bt_mesh_prov->input_size); + strcpy((char *)bt_mesh_prov_link.auth, str); bt_mesh_prov_link.role->input_complete(); @@ -240,16 +323,16 @@ static void prov_recv(const struct prov_bearer *bearer, void *cb_data, struct os_mbuf *buf) { static const uint8_t op_len[10] = { - [PROV_INVITE] = 1, - [PROV_CAPABILITIES] = 11, - [PROV_START] = 5, - [PROV_PUB_KEY] = 64, - [PROV_INPUT_COMPLETE] = 0, - [PROV_CONFIRM] = 16, - [PROV_RANDOM] = 16, - [PROV_DATA] = 33, - [PROV_COMPLETE] = 0, - [PROV_FAILED] = 1, + [PROV_INVITE] = PDU_LEN_INVITE, + [PROV_CAPABILITIES] = PDU_LEN_CAPABILITIES, + [PROV_START] = PDU_LEN_START, + [PROV_PUB_KEY] = PDU_LEN_PUB_KEY, + [PROV_INPUT_COMPLETE] = PDU_LEN_INPUT_COMPLETE, + [PROV_CONFIRM] = PDU_LEN_CONFIRM, + [PROV_RANDOM] = PDU_LEN_RANDOM, + [PROV_DATA] = PDU_LEN_DATA, + [PROV_COMPLETE] = PDU_LEN_COMPLETE, + [PROV_FAILED] = PDU_LEN_FAILED, }; uint8_t type = buf->om_data[0]; @@ -257,7 +340,7 @@ static void prov_recv(const struct prov_bearer *bearer, void *cb_data, if (type >= ARRAY_SIZE(bt_mesh_prov_link.role->op)) { BT_ERR("Unknown provisioning PDU type 0x%02x", type); - bt_mesh_prov_link.role->error(PROV_ERR_NVAL_FMT); + bt_mesh_prov_link.role->error(PROV_ERR_NVAL_PDU); return; } diff --git a/nimble/host/mesh/src/prov.h b/nimble/host/mesh/src/prov.h index 89f027256a..d18ee0ebb7 100644 --- a/nimble/host/mesh/src/prov.h +++ b/nimble/host/mesh/src/prov.h @@ -56,10 +56,25 @@ #define PROV_NO_PDU 0xff +#define PDU_LEN_INVITE 1 +#define PDU_LEN_CAPABILITIES 11 +#define PDU_LEN_START 5 +#define PDU_LEN_PUB_KEY 64 +#define PDU_LEN_INPUT_COMPLETE 0 +#define PDU_LEN_CONFIRM 16 +#define PDU_LEN_RANDOM 16 +#define PDU_LEN_DATA 33 +#define PDU_LEN_COMPLETE 0 +#define PDU_LEN_FAILED 1 + +#define PDU_OP_LEN 1 + #define PROV_ALG_P256 0x00 +#define PROV_IO_OOB_SIZE_MAX 8 /* in bytes */ + #define PROV_BUF(len) \ - NET_BUF_SIMPLE(PROV_BEARER_BUF_HEADROOM + len) + NET_BUF_SIMPLE(PROV_BEARER_BUF_HEADROOM + PDU_OP_LEN + len) enum { WAIT_PUB_KEY, /* Waiting for local PubKey to be generated */ @@ -75,6 +90,7 @@ enum { WAIT_CONFIRM, /* Wait for send confirm */ WAIT_AUTH, /* Wait for auth response */ OOB_STATIC_KEY, /* OOB Static Authentication */ + WAIT_DH_KEY, /* Wait for DH Key */ NUM_FLAGS, }; @@ -103,14 +119,21 @@ struct bt_mesh_prov_link { uint8_t oob_size; /* Authen size */ uint8_t auth[16]; /* Authen value */ - uint8_t dhkey[32]; /* Calculated DHKey */ + uint8_t dhkey[BT_DH_KEY_LEN]; /* Calculated DHKey */ uint8_t expect; /* Next expected PDU */ - uint8_t conf[16]; /* Remote Confirmation */ + uint8_t conf[16]; /* Local/Remote Confirmation */ uint8_t rand[16]; /* Local Random */ uint8_t conf_salt[16]; /* ConfirmationSalt */ uint8_t conf_key[16]; /* ConfirmationKey */ - uint8_t conf_inputs[145]; /* ConfirmationInputs */ + /* ConfirmationInput fields: */ + struct { + uint8_t invite[PDU_LEN_INVITE]; + uint8_t capabilities[PDU_LEN_CAPABILITIES]; + uint8_t start[PDU_LEN_START]; + uint8_t pub_key_provisioner[PDU_LEN_PUB_KEY]; /* big-endian */ + uint8_t pub_key_device[PDU_LEN_PUB_KEY]; /* big-endian */ + } conf_inputs; uint8_t prov_salt[16]; /* Provisioning Salt */ }; @@ -129,11 +152,11 @@ static inline void bt_mesh_prov_buf_init(struct os_mbuf *buf, uint8_t type) net_buf_simple_add_u8(buf, type); } -int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[64])); +int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[BT_PUB_KEY_LEN])); bool bt_mesh_prov_active(void); -int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size); +int bt_mesh_prov_auth(bool is_provisioner, uint8_t method, uint8_t action, uint8_t size); int bt_mesh_pb_gatt_open(uint16_t conn_handle); int bt_mesh_pb_gatt_close(uint16_t conn_handle); diff --git a/nimble/host/mesh/src/prov_device.c b/nimble/host/mesh/src/prov_device.c index 38a96e7a6b..e9e2d2b122 100644 --- a/nimble/host/mesh/src/prov_device.c +++ b/nimble/host/mesh/src/prov_device.c @@ -21,6 +21,7 @@ #include "proxy.h" #include "prov.h" #include "settings.h" +#include "pb_gatt_srv.h" static void send_pub_key(void); static void pub_key_ready(const uint8_t *pkey); @@ -32,7 +33,7 @@ static int reset_state(void) static void prov_send_fail_msg(uint8_t err) { - struct os_mbuf *buf = PROV_BUF(2); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_FAILED); BT_DBG("%u", err); @@ -58,7 +59,7 @@ static void prov_fail(uint8_t reason) static void prov_invite(const uint8_t *data) { - struct os_mbuf *buf = PROV_BUF(12); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_CAPABILITIES); BT_DBG("Attention Duration: %u seconds", data[0]); @@ -66,7 +67,7 @@ static void prov_invite(const uint8_t *data) bt_mesh_attention(NULL, data[0]); } - bt_mesh_prov_link.conf_inputs[0] = data[0]; + memcpy(bt_mesh_prov_link.conf_inputs.invite, data, PDU_LEN_INVITE); bt_mesh_prov_buf_init(buf, PROV_CAPABILITIES); @@ -76,8 +77,9 @@ static void prov_invite(const uint8_t *data) /* Supported algorithms - FIPS P-256 Eliptic Curve */ net_buf_simple_add_be16(buf, BIT(PROV_ALG_P256)); - /* Public Key Type, Only "No OOB" Public Key is supported */ - net_buf_simple_add_u8(buf, PUB_KEY_NO_OOB); + /* Public Key Type */ + net_buf_simple_add_u8(buf, + bt_mesh_prov->public_key_be == NULL ? PUB_KEY_NO_OOB : PUB_KEY_OOB); /* Static OOB Type */ net_buf_simple_add_u8(buf, bt_mesh_prov->static_val ? BIT(0) : 0x00); @@ -94,7 +96,7 @@ static void prov_invite(const uint8_t *data) /* Input OOB Action */ net_buf_simple_add_be16(buf, bt_mesh_prov->input_actions); - memcpy(&bt_mesh_prov_link.conf_inputs[1], &buf->om_data[1], 11); + memcpy(bt_mesh_prov_link.conf_inputs.capabilities, &buf->om_data[1], PDU_LEN_CAPABILITIES); if (bt_mesh_prov_send(buf, NULL)) { BT_ERR("Failed to send capabilities"); @@ -118,17 +120,24 @@ static void prov_start(const uint8_t *data) return; } - if (data[1] != PUB_KEY_NO_OOB) { + if (data[1] > PUB_KEY_OOB || + (data[1] == PUB_KEY_OOB && + (!MYNEWT_VAL(BLE_MESH_PROV_OOB_PUBLIC_KEY) || !bt_mesh_prov->public_key_be))) { BT_ERR("Invalid public key type: 0x%02x", data[1]); prov_fail(PROV_ERR_NVAL_FMT); return; } - memcpy(&bt_mesh_prov_link.conf_inputs[12], data, 5); + atomic_set_bit_to(bt_mesh_prov_link.flags, OOB_PUB_KEY, data[1] == PUB_KEY_OOB); + + memcpy(bt_mesh_prov_link.conf_inputs.start, data, PDU_LEN_START); bt_mesh_prov_link.expect = PROV_PUB_KEY; + bt_mesh_prov_link.oob_method = data[2]; + bt_mesh_prov_link.oob_action = data[3]; + bt_mesh_prov_link.oob_size = data[4]; - if (bt_mesh_prov_auth(data[2], data[3], data[4]) < 0) { + if (bt_mesh_prov_auth(false, data[2], data[3], data[4]) < 0) { BT_ERR("Invalid authentication method: 0x%02x; " "action: 0x%02x; size: 0x%02x", data[2], data[3], data[4]); @@ -145,14 +154,15 @@ static void prov_start(const uint8_t *data) static void send_confirm(void) { - struct os_mbuf *cfm = PROV_BUF(17); + struct os_mbuf *cfm = PROV_BUF(PDU_LEN_CONFIRM); + + uint8_t *inputs = (uint8_t *)&bt_mesh_prov_link.conf_inputs; - BT_DBG("ConfInputs[0] %s", bt_hex(bt_mesh_prov_link.conf_inputs, 64)); - BT_DBG("ConfInputs[64] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[64], 64)); - BT_DBG("ConfInputs[128] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[128], 17)); + BT_DBG("ConfInputs[0] %s", bt_hex(inputs, 64)); + BT_DBG("ConfInputs[64] %s", bt_hex(&inputs[64], 64)); + BT_DBG("ConfInputs[128] %s", bt_hex(&inputs[128], 17)); - if (bt_mesh_prov_conf_salt(bt_mesh_prov_link.conf_inputs, - bt_mesh_prov_link.conf_salt)) { + if (bt_mesh_prov_conf_salt(inputs, bt_mesh_prov_link.conf_salt)) { BT_ERR("Unable to generate confirmation salt"); prov_fail(PROV_ERR_UNEXP_ERR); return; @@ -197,7 +207,7 @@ static void send_confirm(void) static void send_input_complete(void) { - struct os_mbuf *buf = PROV_BUF(1); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_INPUT_COMPLETE); bt_mesh_prov_buf_init(buf, PROV_INPUT_COMPLETE); if (bt_mesh_prov_send(buf, NULL)) { @@ -216,9 +226,19 @@ static void public_key_sent(int err, void *cb_data) } } +static void start_auth(void) +{ + if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) || + atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { + bt_mesh_prov_link.expect = PROV_NO_PDU; /* Wait for input */ + } else { + bt_mesh_prov_link.expect = PROV_CONFIRM; + } +} + static void send_pub_key(void) { - struct os_mbuf *buf = PROV_BUF(65); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_PUB_KEY); const uint8_t *key; key = bt_pub_key_get(); @@ -228,31 +248,38 @@ static void send_pub_key(void) return; } - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); - bt_mesh_prov_buf_init(buf, PROV_PUB_KEY); /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(buf, 32), &key[32], 32); + sys_memcpy_swap(net_buf_simple_add(buf, BT_PUB_KEY_COORD_LEN), key, BT_PUB_KEY_COORD_LEN); + sys_memcpy_swap(net_buf_simple_add(buf, BT_PUB_KEY_COORD_LEN), &key[BT_PUB_KEY_COORD_LEN], 32); + + BT_DBG("Local Public Key: %s", bt_hex(buf->om_data + 1, BT_PUB_KEY_LEN)); - /* PublicKeyRemote */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], &buf->om_data[1], 64); + /* PublicKeyDevice */ + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, &buf->om_data[1], PDU_LEN_PUB_KEY); if (bt_mesh_prov_send(buf, public_key_sent)) { BT_ERR("Failed to send Public Key"); return; } - if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) || - atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { - bt_mesh_prov_link.expect = PROV_NO_PDU; /* Wait for input */ - } else { - bt_mesh_prov_link.expect = PROV_CONFIRM; + start_auth(); +} + +static void dh_key_gen_complete(void) +{ + BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, BT_DH_KEY_LEN)); + + if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_DH_KEY) && + atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { + send_confirm(); + } else if (!atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { + send_pub_key(); } } -static void prov_dh_key_cb(const uint8_t dhkey[32]) +static void prov_dh_key_cb(const uint8_t dhkey[BT_DH_KEY_LEN]) { BT_DBG("%p", dhkey); @@ -262,25 +289,41 @@ static void prov_dh_key_cb(const uint8_t dhkey[32]) return; } - sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, 32); - - BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, 32)); + sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, BT_DH_KEY_LEN); - send_pub_key(); + dh_key_gen_complete(); } static void prov_dh_key_gen(void) { - uint8_t remote_pk_le[64], *remote_pk; + const uint8_t *remote_pk; + uint8_t remote_pk_le[BT_PUB_KEY_LEN]; + + remote_pk = bt_mesh_prov_link.conf_inputs.pub_key_provisioner; + if (MYNEWT_VAL(BLE_MESH_PROV_OOB_PUBLIC_KEY) && + atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { + if (uECC_valid_public_key(remote_pk, &curve_secp256r1)) { + BT_ERR("Public key is not valid"); + } else if (uECC_shared_secret(remote_pk, bt_mesh_prov->private_key_be, + bt_mesh_prov_link.dhkey, + &curve_secp256r1) != TC_CRYPTO_SUCCESS) { + BT_ERR("DHKey generation failed"); + } else { + dh_key_gen_complete(); + return; + } - remote_pk = &bt_mesh_prov_link.conf_inputs[17]; + prov_fail(PROV_ERR_UNEXP_ERR); + return; + } /* Copy remote key in little-endian for bt_dh_key_gen(). * X and Y halves are swapped independently. The bt_dh_key_gen() * will also take care of validating the remote public key. */ - sys_memcpy_swap(remote_pk_le, remote_pk, 32); - sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32); + sys_memcpy_swap(remote_pk_le, remote_pk, BT_PUB_KEY_COORD_LEN); + sys_memcpy_swap(&remote_pk_le[BT_PUB_KEY_COORD_LEN], &remote_pk[BT_PUB_KEY_COORD_LEN], + BT_PUB_KEY_COORD_LEN); if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) { BT_ERR("Failed to generate DHKey"); @@ -290,12 +333,27 @@ static void prov_dh_key_gen(void) static void prov_pub_key(const uint8_t *data) { - BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); + BT_DBG("Remote Public Key: %s", bt_hex(data, BT_PUB_KEY_LEN)); /* PublicKeyProvisioner */ - memcpy(&bt_mesh_prov_link.conf_inputs[17], data, 64); + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_provisioner, data, PDU_LEN_PUB_KEY); + + if (MYNEWT_VAL(BLE_MESH_PROV_OOB_PUBLIC_KEY) && + atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { + if (!bt_mesh_prov->public_key_be || !bt_mesh_prov->private_key_be) { + BT_ERR("Public or private key is not ready"); + prov_fail(PROV_ERR_UNEXP_ERR); + return; + } + + /* No swap needed since user provides public key in big-endian */ + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, bt_mesh_prov->public_key_be, + PDU_LEN_PUB_KEY); + + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_DH_KEY); - if (!bt_pub_key_get()) { + start_auth(); + } else if (!bt_pub_key_get()) { /* Clear retransmit timer */ bt_mesh_prov_link.bearer->clear_tx(); atomic_set_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY); @@ -331,7 +389,7 @@ static void notify_input_complete(void) static void send_random(void) { - struct os_mbuf *rnd = PROV_BUF(17); + struct os_mbuf *rnd = PROV_BUF(PDU_LEN_RANDOM); bt_mesh_prov_buf_init(rnd, PROV_RANDOM); net_buf_simple_add_mem(rnd, bt_mesh_prov_link.rand, 16); @@ -390,7 +448,9 @@ static void prov_confirm(const uint8_t *data) notify_input_complete(); - send_confirm(); + if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_DH_KEY)) { + send_confirm(); + } } static inline bool is_pb_gatt(void) @@ -401,7 +461,7 @@ static inline bool is_pb_gatt(void) static void prov_data(const uint8_t *data) { - struct os_mbuf *msg = PROV_BUF(1); + struct os_mbuf *msg = PROV_BUF(PDU_LEN_COMPLETE); uint8_t session_key[16]; uint8_t nonce[13]; uint8_t dev_key[16]; @@ -492,7 +552,8 @@ static void prov_data(const uint8_t *data) static void local_input_complete(void) { - if (atomic_test_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT)) { + if (atomic_test_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT) || + atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { send_input_complete(); } else { atomic_set_bit(bt_mesh_prov_link.flags, INPUT_COMPLETE); @@ -554,6 +615,10 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) return -EALREADY; } + if (bt_mesh_prov_active()) { + return -EBUSY; + } + if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && (bearers & BT_MESH_PROV_ADV)) { bt_mesh_beacon_disable(); @@ -562,7 +627,7 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && (bearers & BT_MESH_PROV_GATT)) { - bt_mesh_proxy_prov_disable(true); + (void)bt_mesh_pb_gatt_disable(); } return 0; diff --git a/nimble/host/mesh/src/provisioner.c b/nimble/host/mesh/src/provisioner.c index d69aa6650a..f4278e110b 100644 --- a/nimble/host/mesh/src/provisioner.c +++ b/nimble/host/mesh/src/provisioner.c @@ -3,6 +3,7 @@ /* * Copyright (c) 2017 Intel Corporation * Copyright (c) 2020 Lingao Meng + * Copyright (c) 2021 Manulytica Limited * * SPDX-License-Identifier: Apache-2.0 */ @@ -65,14 +66,15 @@ static void prov_fail(uint8_t reason) static void send_invite(void) { - struct os_mbuf *inv = PROV_BUF(2); + struct os_mbuf *inv = PROV_BUF(PDU_LEN_INVITE); BT_DBG(""); bt_mesh_prov_buf_init(inv, PROV_INVITE); net_buf_simple_add_u8(inv, prov_device.attention_duration); - bt_mesh_prov_link.conf_inputs[0] = prov_device.attention_duration; + memcpy(bt_mesh_prov_link.conf_inputs.invite, &prov_device.attention_duration, + PDU_LEN_INVITE); if (bt_mesh_prov_send(inv, NULL)) { BT_ERR("Failed to send invite"); @@ -95,54 +97,35 @@ static void start_sent(int err, void *cb_data) static void send_start(void) { BT_DBG(""); - uint8_t method, action; - struct os_mbuf *start = PROV_BUF(6); + struct os_mbuf *start = PROV_BUF(PDU_LEN_START); - const uint8_t *data = &bt_mesh_prov_link.conf_inputs[1 + 3]; + bool oob_pub_key = bt_mesh_prov_link.conf_inputs.capabilities[3] == PUB_KEY_OOB; bt_mesh_prov_buf_init(start, PROV_START); net_buf_simple_add_u8(start, PROV_ALG_P256); - if (atomic_test_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY) && - *data == PUB_KEY_OOB) { + memcpy(bt_mesh_prov_link.conf_inputs.start, &start->om_data[1], PDU_LEN_START); + + if (atomic_test_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY) && oob_pub_key) { net_buf_simple_add_u8(start, PUB_KEY_OOB); atomic_set_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY); } else { net_buf_simple_add_u8(start, PUB_KEY_NO_OOB); } - if (bt_mesh_prov_link.oob_method == AUTH_METHOD_INPUT) { - method = AUTH_METHOD_OUTPUT; - if (bt_mesh_prov_link.oob_action == INPUT_OOB_STRING) { - action = OUTPUT_OOB_STRING; - } else { - action = OUTPUT_OOB_NUMBER; - } - - } else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_OUTPUT) { - method = AUTH_METHOD_INPUT; - if (bt_mesh_prov_link.oob_action == OUTPUT_OOB_STRING) { - action = INPUT_OOB_STRING; - } else { - action = INPUT_OOB_NUMBER; - } - } else { - method = bt_mesh_prov_link.oob_method; - action = 0x00; - } - net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_method); net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_action); net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_size); - memcpy(&bt_mesh_prov_link.conf_inputs[12], &start->om_data[1], 5); + memcpy(bt_mesh_prov_link.conf_inputs.invite, &start->om_data[1], PDU_LEN_INVITE); - if (bt_mesh_prov_auth(method, action, bt_mesh_prov_link.oob_size) < 0) { + if (bt_mesh_prov_auth(true, bt_mesh_prov_link.oob_method, + bt_mesh_prov_link.oob_action, bt_mesh_prov_link.oob_size) < 0) { BT_ERR("Invalid authentication method: 0x%02x; " - "action: 0x%02x; size: 0x%02x", method, - action, bt_mesh_prov_link.oob_size); + "action: 0x%02x; size: 0x%02x", bt_mesh_prov_link.oob_method, + bt_mesh_prov_link.oob_action, bt_mesh_prov_link.oob_size); return; } @@ -168,9 +151,9 @@ static bool prov_check_method(struct bt_mesh_dev_capabilities *caps) } if (!(BIT(bt_mesh_prov_link.oob_action) & caps->input_actions)) { - BT_WARN("The required input action (0x%02x) " + BT_WARN("The required input action (0x%04x) " "not supported by the device (0x%02x)", - bt_mesh_prov_link.oob_action, caps->input_actions); + (uint16_t)BIT(bt_mesh_prov_link.oob_action), caps->input_actions); return false; } @@ -194,9 +177,9 @@ static bool prov_check_method(struct bt_mesh_dev_capabilities *caps) } if (!(BIT(bt_mesh_prov_link.oob_action) & caps->output_actions)) { - BT_WARN("The required output action (0x%02x) " + BT_WARN("The required output action (0x%04x) " "not supported by the device (0x%02x)", - bt_mesh_prov_link.oob_action, caps->output_actions); + (uint16_t)BIT(bt_mesh_prov_link.oob_action), caps->output_actions); return false; } @@ -226,9 +209,11 @@ static void prov_capabilities(const uint8_t *data) BT_DBG("Static OOB Type: 0x%02x", caps.static_oob); BT_DBG("Output OOB Size: %u", caps.output_size); - caps.output_actions = (bt_mesh_output_action_t)data[6]; + caps.output_actions = (bt_mesh_output_action_t) + (sys_get_be16(&data[6])); caps.input_size = data[8]; - caps.input_actions = (bt_mesh_input_action_t)data[9]; + caps.input_actions = (bt_mesh_input_action_t) + (sys_get_be16(&data[9])); BT_DBG("Output OOB Action: 0x%04x", caps.output_actions); BT_DBG("Input OOB Size: %u", caps.input_size); BT_DBG("Input OOB Action: 0x%04x", caps.input_actions); @@ -249,7 +234,7 @@ static void prov_capabilities(const uint8_t *data) return; } #endif - memcpy(&bt_mesh_prov_link.conf_inputs[1], data, 11); + memcpy(bt_mesh_prov_link.conf_inputs.capabilities, data, PDU_LEN_CAPABILITIES); if (bt_mesh_prov->capabilities) { bt_mesh_prov->capabilities(&caps); @@ -265,14 +250,14 @@ static void prov_capabilities(const uint8_t *data) static void send_confirm(void) { - struct os_mbuf *cfm = PROV_BUF(17); + struct os_mbuf *cfm = PROV_BUF(PDU_LEN_CONFIRM); + uint8_t *inputs = (uint8_t *)&bt_mesh_prov_link.conf_inputs; - BT_DBG("ConfInputs[0] %s", bt_hex(bt_mesh_prov_link.conf_inputs, 64)); - BT_DBG("ConfInputs[64] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[64], 64)); - BT_DBG("ConfInputs[128] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[128], 17)); + BT_DBG("ConfInputs[0] %s", bt_hex(inputs, 64)); + BT_DBG("ConfInputs[64] %s", bt_hex(&inputs[64], 64)); + BT_DBG("ConfInputs[128] %s", bt_hex(&inputs[128], 17)); - if (bt_mesh_prov_conf_salt(bt_mesh_prov_link.conf_inputs, - bt_mesh_prov_link.conf_salt)) { + if (bt_mesh_prov_conf_salt(inputs, bt_mesh_prov_link.conf_salt)) { BT_ERR("Unable to generate confirmation salt"); prov_fail(PROV_ERR_UNEXP_ERR); return; @@ -301,12 +286,14 @@ static void send_confirm(void) if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key, bt_mesh_prov_link.rand, bt_mesh_prov_link.auth, - net_buf_simple_add(cfm, 16))) { + bt_mesh_prov_link.conf)) { BT_ERR("Unable to generate confirmation value"); prov_fail(PROV_ERR_UNEXP_ERR); return; } + net_buf_simple_add_mem(cfm, bt_mesh_prov_link.conf, 16); + if (bt_mesh_prov_send(cfm, NULL)) { BT_ERR("Failed to send Provisioning Confirm"); return; @@ -324,13 +311,11 @@ static void public_key_sent(int err, void *cb_data) prov_dh_key_gen(); return; } - - bt_mesh_prov_link.expect = PROV_PUB_KEY; } static void send_pub_key(void) { - struct os_mbuf *buf = PROV_BUF(65); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_PUB_KEY); const uint8_t *key; key = bt_pub_key_get(); @@ -340,24 +325,27 @@ static void send_pub_key(void) return; } - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); + BT_DBG("Local Public Key: %s", bt_hex(key, BT_PUB_KEY_LEN)); bt_mesh_prov_buf_init(buf, PROV_PUB_KEY); /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(buf, 32), &key[32], 32); + sys_memcpy_swap(net_buf_simple_add(buf, BT_PUB_KEY_COORD_LEN), key, BT_PUB_KEY_COORD_LEN); + sys_memcpy_swap(net_buf_simple_add(buf, BT_PUB_KEY_COORD_LEN), &key[BT_PUB_KEY_COORD_LEN], + BT_PUB_KEY_COORD_LEN); /* PublicKeyProvisioner */ - memcpy(&bt_mesh_prov_link.conf_inputs[17], &buf->om_databuf[1], 64); + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_provisioner, &buf->om_data[1], PDU_LEN_PUB_KEY); if (bt_mesh_prov_send(buf, public_key_sent)) { BT_ERR("Failed to send Public Key"); return; } + + bt_mesh_prov_link.expect = PROV_PUB_KEY; } -static void prov_dh_key_cb(const uint8_t dhkey[32]) +static void prov_dh_key_cb(const uint8_t dhkey[BT_DH_KEY_LEN]) { BT_DBG("%p", dhkey); @@ -367,9 +355,9 @@ static void prov_dh_key_cb(const uint8_t dhkey[32]) return; } - sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, 32); + sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, BT_DH_KEY_LEN); - BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, 32)); + BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, BT_DH_KEY_LEN)); if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING) || atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) || @@ -383,16 +371,26 @@ static void prov_dh_key_cb(const uint8_t dhkey[32]) static void prov_dh_key_gen(void) { - uint8_t remote_pk_le[64], *remote_pk; + uint8_t remote_pk_le[BT_PUB_KEY_LEN]; + const uint8_t *remote_pk; + const uint8_t *local_pk; - remote_pk = &bt_mesh_prov_link.conf_inputs[81]; + local_pk = bt_mesh_prov_link.conf_inputs.pub_key_provisioner; + remote_pk = bt_mesh_prov_link.conf_inputs.pub_key_device; /* Copy remote key in little-endian for bt_dh_key_gen(). * X and Y halves are swapped independently. The bt_dh_key_gen() * will also take care of validating the remote public key. */ - sys_memcpy_swap(remote_pk_le, remote_pk, 32); - sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32); + sys_memcpy_swap(remote_pk_le, remote_pk, BT_PUB_KEY_COORD_LEN); + sys_memcpy_swap(&remote_pk_le[BT_PUB_KEY_COORD_LEN], &remote_pk[BT_PUB_KEY_COORD_LEN], + BT_PUB_KEY_COORD_LEN); + + if (!memcmp(local_pk, remote_pk, BT_PUB_KEY_LEN)) { + BT_ERR("Public keys are identical"); + prov_fail(PROV_ERR_NVAL_FMT); + return; + } if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) { BT_ERR("Failed to generate DHKey"); @@ -406,12 +404,12 @@ static void prov_dh_key_gen(void) static void prov_pub_key(const uint8_t *data) { - BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); + BT_DBG("Remote Public Key: %s", bt_hex(data, BT_PUB_KEY_LEN)); atomic_set_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY); /* PublicKeyDevice */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], data, 64); + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, data, BT_PUB_KEY_LEN); bt_mesh_prov_link.bearer->clear_tx(); prov_dh_key_gen(); @@ -453,7 +451,7 @@ static void prov_input_complete(const uint8_t *data) static void send_prov_data(void) { - struct os_mbuf *pdu = PROV_BUF(34); + struct os_mbuf *pdu = PROV_BUF(PDU_LEN_DATA); #if MYNEWT_VAL(BLE_MESH_CDB) struct bt_mesh_cdb_subnet *sub; #endif @@ -501,7 +499,7 @@ static void send_prov_data(void) #endif bt_mesh_prov_buf_init(pdu, PROV_DATA); #if MYNEWT_VAL(BLE_MESH_CDB) - net_buf_simple_add_mem(pdu, sub->keys[sub->kr_flag].net_key, 16); + net_buf_simple_add_mem(pdu, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_key, 16); net_buf_simple_add_be16(pdu, prov_device.node->net_idx); net_buf_simple_add_u8(pdu, bt_mesh_cdb_subnet_flags(sub)); net_buf_simple_add_be32(pdu, bt_mesh_cdb.iv_index); @@ -539,7 +537,7 @@ static void prov_complete(const uint8_t *data) #if MYNEWT_VAL(BLE_MESH_CDB) if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_node(node); + bt_mesh_cdb_node_store(node); } #endif @@ -554,7 +552,7 @@ static void prov_complete(const uint8_t *data) static void send_random(void) { - struct os_mbuf *rnd = PROV_BUF(17); + struct os_mbuf *rnd = PROV_BUF(PDU_LEN_RANDOM); bt_mesh_prov_buf_init(rnd, PROV_RANDOM); net_buf_simple_add_mem(rnd, bt_mesh_prov_link.rand, 16); @@ -609,6 +607,12 @@ static void prov_confirm(const uint8_t *data) { BT_DBG("Remote Confirm: %s", bt_hex(data, 16)); + if (!memcmp(data, bt_mesh_prov_link.conf, 16)) { + BT_ERR("Confirm value is identical to ours, rejecting."); + prov_fail(PROV_ERR_CFM_FAILED); + return; + } + memcpy(bt_mesh_prov_link.conf, data, 16); send_random(); @@ -662,7 +666,7 @@ static void prov_set_method(uint8_t method, uint8_t action, uint8_t size) int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size) { - if (!action || !size || size > 8) { + if (!action || !size || size > PROV_IO_OOB_SIZE_MAX) { return -EINVAL; } @@ -672,7 +676,7 @@ int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size) int bt_mesh_auth_method_set_output(bt_mesh_output_action_t action, uint8_t size) { - if (!action || !size || size > 8) { + if (!action || !size || size > PROV_IO_OOB_SIZE_MAX) { return -EINVAL; } @@ -702,7 +706,7 @@ int bt_mesh_auth_method_set_none(void) return 0; } -int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]) +int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[BT_PUB_KEY_LEN]) { if (public_key == NULL) { return -EINVAL; @@ -713,8 +717,7 @@ int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]) } /* Swap X and Y halves independently to big-endian */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], public_key, 32); - memcpy(&bt_mesh_prov_link.conf_inputs[81 + 32], &public_key[32], 32); + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, public_key, PDU_LEN_PUB_KEY); return 0; } diff --git a/nimble/host/mesh/src/provisioner.h b/nimble/host/mesh/src/provisioner.h index ccda47efed..315bde299f 100644 --- a/nimble/host/mesh/src/provisioner.h +++ b/nimble/host/mesh/src/provisioner.h @@ -7,4 +7,4 @@ */ int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr, - uint8_t attention_duration); \ No newline at end of file + uint8_t attention_duration); diff --git a/nimble/host/mesh/src/proxy.c b/nimble/host/mesh/src/proxy.c deleted file mode 100644 index 6d631b7211..0000000000 --- a/nimble/host/mesh/src/proxy.c +++ /dev/null @@ -1,1568 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_PROXY_LOG - -#if MYNEWT_VAL(BLE_MESH_PROXY) - -#include "mesh/mesh.h" -#include "host/ble_att.h" -#include "services/gatt/ble_svc_gatt.h" -#include "../../host/src/ble_hs_priv.h" - -#include "mesh_priv.h" -#include "adv.h" -#include "net.h" -#include "rpl.h" -#include "prov.h" -#include "beacon.h" -#include "foundation.h" -#include "access.h" -#include "proxy.h" - -#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) -#define PDU_SAR(data) (data[0] >> 6) - -#define BT_UUID_16_ENCODE(w16) \ - (((w16) >> 0) & 0xFF), \ - (((w16) >> 8) & 0xFF) -/* Mesh Profile 1.0 Section 6.6: - * "The timeout for the SAR transfer is 20 seconds. When the timeout - * expires, the Proxy Server shall disconnect." - */ -#define PROXY_SAR_TIMEOUT K_SECONDS(20) - -#define SAR_COMPLETE 0x00 -#define SAR_FIRST 0x01 -#define SAR_CONT 0x02 -#define SAR_LAST 0x03 - -#define CFG_FILTER_SET 0x00 -#define CFG_FILTER_ADD 0x01 -#define CFG_FILTER_REMOVE 0x02 -#define CFG_FILTER_STATUS 0x03 - -/** @def BT_UUID_MESH_PROV - * @brief Mesh Provisioning Service - */ -ble_uuid16_t BT_UUID_MESH_PROV = BLE_UUID16_INIT(0x1827); -#define BT_UUID_MESH_PROV_VAL 0x1827 -/** @def BT_UUID_MESH_PROXY - * @brief Mesh Proxy Service - */ -ble_uuid16_t BT_UUID_MESH_PROXY = BLE_UUID16_INIT(0x1828); -#define BT_UUID_MESH_PROXY_VAL 0x1828 -/** @def BT_UUID_GATT_CCC - * @brief GATT Client Characteristic Configuration - */ -ble_uuid16_t BT_UUID_GATT_CCC = BLE_UUID16_INIT(0x2902); -#define BT_UUID_GATT_CCC_VAL 0x2902 -/** @def BT_UUID_MESH_PROV_DATA_IN - * @brief Mesh Provisioning Data In - */ -ble_uuid16_t BT_UUID_MESH_PROV_DATA_IN = BLE_UUID16_INIT(0x2adb); -#define BT_UUID_MESH_PROV_DATA_IN_VAL 0x2adb -/** @def BT_UUID_MESH_PROV_DATA_OUT - * @brief Mesh Provisioning Data Out - */ -ble_uuid16_t BT_UUID_MESH_PROV_DATA_OUT = BLE_UUID16_INIT(0x2adc); -#define BT_UUID_MESH_PROV_DATA_OUT_VAL 0x2adc -/** @def BT_UUID_MESH_PROXY_DATA_IN - * @brief Mesh Proxy Data In - */ -ble_uuid16_t BT_UUID_MESH_PROXY_DATA_IN = BLE_UUID16_INIT(0x2add); -#define BT_UUID_MESH_PROXY_DATA_IN_VAL 0x2add -/** @def BT_UUID_MESH_PROXY_DATA_OUT - * @brief Mesh Proxy Data Out - */ -ble_uuid16_t BT_UUID_MESH_PROXY_DATA_OUT = BLE_UUID16_INIT(0x2ade); -#define BT_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade - -#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) - -#define CLIENT_BUF_SIZE 68 - -static const struct ble_gap_adv_params slow_adv_param = { - .conn_mode = (BLE_GAP_CONN_MODE_UND), - .disc_mode = (BLE_GAP_DISC_MODE_GEN), - .itvl_min = BT_GAP_ADV_SLOW_INT_MIN, - .itvl_max = BT_GAP_ADV_SLOW_INT_MAX, -}; - -static const struct ble_gap_adv_params fast_adv_param = { - .conn_mode = (BLE_GAP_CONN_MODE_UND), - .disc_mode = (BLE_GAP_DISC_MODE_GEN), - .itvl_min = BT_GAP_ADV_FAST_INT_MIN_2, - .itvl_max = BT_GAP_ADV_FAST_INT_MAX_2, -}; - -static bool proxy_adv_enabled; - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -static void proxy_send_beacons(struct ble_npl_event *work); -#endif - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static bool prov_fast_adv; -#endif - -static struct bt_mesh_proxy_client { - uint16_t conn_handle; - uint16_t filter[MYNEWT_VAL(BLE_MESH_PROXY_FILTER_SIZE)]; - enum __packed { - NONE, - WHITELIST, - BLACKLIST, - PROV, - } filter_type; - uint8_t msg_type; -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - struct ble_npl_callout send_beacons; -#endif - struct k_delayed_work sar_timer; - struct os_mbuf *buf; -} clients[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { - [0 ... (MYNEWT_VAL(BLE_MAX_CONNECTIONS) - 1)] = { 0 }, -}; - -static sys_slist_t idle_waiters; -static atomic_t pending_notifications; - -/* Track which service is enabled */ -static enum { - MESH_GATT_NONE, - MESH_GATT_PROV, - MESH_GATT_PROXY, -} gatt_svc = MESH_GATT_NONE; - -static struct { - uint16_t proxy_h; - uint16_t proxy_data_out_h; - uint16_t prov_h; - uint16_t prov_data_in_h; - uint16_t prov_data_out_h; -} svc_handles; - -static void resolve_svc_handles(void) -{ - int rc; - - /* Either all handles are already resolved, or none of them */ - if (svc_handles.prov_data_out_h) { - return; - } - - /* - * We assert if attribute is not found since at this stage all attributes - * shall be already registered and thus shall be found. - */ - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - &svc_handles.proxy_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), - NULL, &svc_handles.proxy_data_out_h); - assert(rc == 0); - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - &svc_handles.prov_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), - NULL, &svc_handles.prov_data_in_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), - NULL, &svc_handles.prov_data_out_h); - assert(rc == 0); -} - -static 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; -} - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -/* Next subnet in queue to be advertised */ -static struct bt_mesh_subnet *beacon_sub; - -static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg); - -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: - memset(client->filter, 0, sizeof(client->filter)); - client->filter_type = WHITELIST; - break; - case 0x01: - memset(client->filter, 0, sizeof(client->filter)); - client->filter_type = BLACKLIST; - 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 == WHITELIST) { - net_buf_simple_add_u8(buf, 0x00); - } else { - net_buf_simple_add_u8(buf, 0x01); - } - - for (filter_size = 0, 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 = proxy_segment_and_send(client->conn_handle, BT_MESH_PROXY_CONFIG, buf); - if (err) { - BT_ERR("Failed to send proxy cfg message (err %d)", err); - } -} - -static void proxy_cfg(struct bt_mesh_proxy_client *client) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(29); - struct bt_mesh_net_rx rx; - uint8_t opcode; - int err; - - err = bt_mesh_net_decode(client->buf, BT_MESH_NET_IF_PROXY_CFG, - &rx, buf); - if (err) { - BT_ERR("Failed to decode Proxy Configuration (err %d)", err); - goto done; - } - - 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); - goto done; - } - - /* Remove network headers */ - net_buf_simple_pull_mem(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"); - goto done; - } - - 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; - } - -done: - os_mbuf_free_chain(buf); -} - -static int beacon_send(uint16_t conn_handle, 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 = proxy_segment_and_send(conn_handle, 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->conn_handle, 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); -} - -static void proxy_sar_timeout(struct ble_npl_event *work) -{ - struct bt_mesh_proxy_client *client; - int rc; - - BT_WARN("Proxy SAR timeout"); - - client = ble_npl_event_get_arg(work); - assert(client != NULL); - - if ((client->conn_handle != BLE_HS_CONN_HANDLE_NONE)) { - rc = ble_gap_terminate(client->conn_handle, - BLE_ERR_REM_USER_CONN_TERM); - assert(rc == 0); - } -} - -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].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - beacon_send(clients[i].conn_handle, 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 = 0; -} - -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; -} - -#endif /* GATT_PROXY */ - -static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) -{ - switch (client->msg_type) { -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - case BT_MESH_PROXY_NET_PDU: - BT_INFO("Mesh Network PDU"); - bt_mesh_net_recv(client->buf, 0, BT_MESH_NET_IF_PROXY); - break; - case BT_MESH_PROXY_BEACON: - BT_INFO("Mesh Beacon PDU"); - bt_mesh_beacon_recv(client->buf); - break; - case BT_MESH_PROXY_CONFIG: - BT_INFO("Mesh Configuration PDU"); - proxy_cfg(client); - break; -#endif -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - case BT_MESH_PROXY_PROV: - BT_INFO("Mesh Provisioning PDU"); - bt_mesh_pb_gatt_recv(client->conn_handle, client->buf); - break; -#endif - default: - BT_WARN("Unhandled Message Type 0x%02x", client->msg_type); - break; - } - - net_buf_simple_init(client->buf, 0); -} - -static int proxy_recv(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - struct bt_mesh_proxy_client *client = find_client(conn_handle); - const uint8_t *data = ctxt->om->om_data; - uint16_t len = ctxt->om->om_len; - - client = find_client(conn_handle); - - if (!client) { - return -ENOTCONN; - } - - if (len < 1) { - BT_WARN("Too small Proxy PDU"); - return -EINVAL; - } - - if ((attr_handle == svc_handles.prov_data_in_h) != - (PDU_TYPE(data) == BT_MESH_PROXY_PROV)) { - BT_WARN("Proxy PDU type doesn't match GATT service"); - return -EINVAL; - } - - if (len - 1 > net_buf_simple_tailroom(client->buf)) { - BT_WARN("Too big proxy PDU"); - return -EINVAL; - } - - switch (PDU_SAR(data)) { - case SAR_COMPLETE: - if (client->buf->om_len) { - BT_WARN("Complete PDU while a pending incomplete one"); - return -EINVAL; - } - - client->msg_type = PDU_TYPE(data); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - proxy_complete_pdu(client); - break; - - case SAR_FIRST: - if (client->buf->om_len) { - BT_WARN("First PDU while a pending incomplete one"); - return -EINVAL; - } - - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); - client->msg_type = PDU_TYPE(data); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - break; - - case SAR_CONT: - if (!client->buf->om_len) { - BT_WARN("Continuation with no prior data"); - return -EINVAL; - } - - if (client->msg_type != PDU_TYPE(data)) { - BT_WARN("Unexpected message type in continuation"); - return -EINVAL; - } - - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - break; - - case SAR_LAST: - if (!client->buf->om_len) { - BT_WARN("Last SAR PDU with no prior data"); - return -EINVAL; - } - - if (client->msg_type != PDU_TYPE(data)) { - BT_WARN("Unexpected message type in last SAR PDU"); - return -EINVAL; - } - - k_delayed_work_cancel(&client->sar_timer); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - proxy_complete_pdu(client); - break; - } - - return len; -} - -static int conn_count; - -static void proxy_connected(uint16_t conn_handle) -{ - struct bt_mesh_proxy_client *client; - int i; - - BT_INFO("conn_handle %d", conn_handle); - - conn_count++; - - /* Since we use ADV_OPT_ONE_TIME */ - proxy_adv_enabled = false; - - /* Try to re-enable advertising in case it's possible */ - if (conn_count < CONFIG_BT_MAX_CONN) { - bt_mesh_adv_update(); - } - - for (client = NULL, i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle == BLE_HS_CONN_HANDLE_NONE) { - client = &clients[i]; - break; - } - } - - if (!client) { - BT_ERR("No free Proxy Client objects"); - return; - } - - client->conn_handle = conn_handle; - client->filter_type = NONE; - memset(client->filter, 0, sizeof(client->filter)); - net_buf_simple_init(client->buf, 0); -} - -static void proxy_disconnected(uint16_t conn_handle, int reason) -{ - int i; - - BT_DBG("conn handle %u reason 0x%02x", conn_handle, reason); - conn_count--; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if (client->conn_handle == conn_handle) { - if ((MYNEWT_VAL(BLE_MESH_PB_GATT)) && - client->filter_type == PROV) { - bt_mesh_pb_gatt_close(conn_handle); - } - - k_delayed_work_cancel(&client->sar_timer); - client->conn_handle = BLE_HS_CONN_HANDLE_NONE; - break; - } - } - - bt_mesh_adv_update(); -} - -struct os_mbuf *bt_mesh_proxy_get_buf(void) -{ - struct os_mbuf *buf = clients[0].buf; - - if (buf != NULL) { - net_buf_simple_init(buf, 0); - } - - return buf; -} - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static void prov_ccc_write(uint16_t conn_handle) -{ - struct bt_mesh_proxy_client *client; - - BT_DBG("conn_handle %d", conn_handle); - - /* If a connection exists there must be a client */ - client = find_client(conn_handle); - __ASSERT(client, "No client for connection"); - - if (client->filter_type == NONE) { - client->filter_type = PROV; - bt_mesh_pb_gatt_open(conn_handle); - } -} - -int bt_mesh_proxy_prov_enable(void) -{ - uint16_t handle; - int rc; - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_PROV) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_NONE) { - return -EBUSY; - } - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 1); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); - - gatt_svc = MESH_GATT_PROV; - prov_fast_adv = true; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - clients[i].filter_type = PROV; - } - } - - - return 0; -} - -int bt_mesh_proxy_prov_disable(bool disconnect) -{ - uint16_t handle; - int rc; - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_PROV) { - return -EBUSY; - } - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 0); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); - - gatt_svc = MESH_GATT_NONE; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if ((client->conn_handle == BLE_HS_CONN_HANDLE_NONE) - || (client->filter_type != PROV)) { - continue; - } - - if (disconnect) { - rc = ble_gap_terminate(client->conn_handle, - BLE_ERR_REM_USER_CONN_TERM); - assert(rc == 0); - } else { - bt_mesh_pb_gatt_close(client->conn_handle); - client->filter_type = NONE; - } - } - - bt_mesh_adv_update(); - - return 0; -} -#endif /* MYNEWT_VAL(BLE_MESH_PB_GATT) */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -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); - __ASSERT(client, "No client for connection"); - - if (client->filter_type == NONE) { - client->filter_type = WHITELIST; - 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 (gatt_svc == MESH_GATT_PROXY) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_NONE) { - 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); - - gatt_svc = MESH_GATT_PROXY; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - clients[i].filter_type = WHITELIST; - } - } - - 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->conn_handle != BLE_HS_CONN_HANDLE_NONE) && - (client->filter_type == WHITELIST || - client->filter_type == BLACKLIST)) { - client->filter_type = NONE; - rc = ble_gap_terminate(client->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 (gatt_svc == MESH_GATT_NONE) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_PROXY) { - return -EBUSY; - } - - 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); - - gatt_svc = MESH_GATT_NONE; - - return 0; -} - -void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr) -{ - struct bt_mesh_proxy_client *client = NULL; - int i; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - client = &clients[i]; - if (client->buf == buf) { - break; - } - } - - assert(client); - - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); - - if (client->filter_type == WHITELIST) { - filter_add(client, addr); - } else if (client->filter_type == BLACKLIST) { - 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 == BLACKLIST) { - 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 == WHITELIST) { - 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) -{ - bool relayed = false; - int i; - - 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->conn_handle == BLE_HS_CONN_HANDLE_NONE) { - 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); - - bt_mesh_proxy_send(client->conn_handle, BT_MESH_PROXY_NET_PDU, msg); - os_mbuf_free_chain(msg); - relayed = true; - } - - return relayed; -} - -#endif /* MYNEWT_VAL(BLE_MESH_GATT_PROXY) */ - -static 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)); - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - if (gatt_svc == MESH_GATT_PROXY) { - om = ble_hs_mbuf_from_flat(data, len); - assert(om); - err = ble_gattc_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om); - notify_complete(); - } -#endif - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - if (gatt_svc == MESH_GATT_PROV) { - om = ble_hs_mbuf_from_flat(data, len); - assert(om); - err = ble_gattc_notify_custom(conn_handle, svc_handles.prov_data_out_h, om); - notify_complete(); - } -#endif - - if (!err) { - atomic_inc(&pending_notifications); - } - - return err; -} - -static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg) -{ - uint16_t mtu; - - BT_DBG("conn_handle %d type 0x%02x len %u: %s", conn_handle, type, msg->om_len, - bt_hex(msg->om_data, msg->om_len)); - - /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ - mtu = ble_att_mtu(conn_handle) - 3; - if (mtu > msg->om_len) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); - return proxy_send(conn_handle, msg->om_data, msg->om_len); - } - - net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); - proxy_send(conn_handle, msg->om_data, mtu); - net_buf_simple_pull_mem(msg, mtu); - - while (msg->om_len) { - if (msg->om_len + 1 < mtu) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); - proxy_send(conn_handle, msg->om_data, msg->om_len); - break; - } - - net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); - proxy_send(conn_handle, msg->om_data, mtu); - net_buf_simple_pull_mem(msg, mtu); - } - - return 0; -} - -int bt_mesh_proxy_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg) -{ - struct bt_mesh_proxy_client *client = find_client(conn_handle); - - if (!client) { - BT_ERR("No Proxy Client found"); - return -ENOTCONN; - } - - if ((client->filter_type == PROV) != (type == BT_MESH_PROXY_PROV)) { - BT_ERR("Invalid PDU type for Proxy Client"); - return -EINVAL; - } - - return proxy_segment_and_send(conn_handle, type, msg); -} - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static uint8_t prov_svc_data[20] = { - BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL), -}; - -static const struct bt_data prov_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_PROV_VAL)), - BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), -}; -#endif /* PB_GATT */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - -#define ID_TYPE_NET 0x00 -#define ID_TYPE_NODE 0x01 - -#define NODE_ID_LEN 19 -#define NET_ID_LEN 11 - -#define NODE_ID_TIMEOUT K_SECONDS(CONFIG_BT_MESH_NODE_ID_TIMEOUT) - -static uint8_t proxy_svc_data[NODE_ID_LEN] = { - 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), -}; - -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), -}; - -static int node_id_adv(struct bt_mesh_subnet *sub) -{ - 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; - } - - 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_le_adv_start(&fast_adv_param, node_id_ad, - ARRAY_SIZE(node_id_ad), NULL, 0); - if (err) { - BT_WARN("Failed to advertise using Node ID (err %d)", err); - return err; - } - - proxy_adv_enabled = true; - - return 0; -} - -static int net_id_adv(struct bt_mesh_subnet *sub) -{ - 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_le_adv_start(&slow_adv_param, net_id_ad, - ARRAY_SIZE(net_id_ad), NULL, 0); - if (err) { - BT_WARN("Failed to advertise using Network ID (err %d)", err); - return err; - } - - proxy_adv_enabled = true; - - 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 int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) -{ - int32_t remaining = K_FOREVER; - int subnet_count; - - 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; - } - - 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", - (unsigned) active, (int) remaining); - node_id_adv(sub); - } else { - bt_mesh_proxy_identity_stop(sub); - BT_DBG("Node ID stopped"); - } - } - - if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) { - net_id_adv(sub); - } - - 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; - } - } - - BT_DBG("Advertising %d ms for net_idx 0x%04x", - (int) remaining, sub->net_idx); - - beacon_sub = bt_mesh_subnet_next(beacon_sub); - - return remaining; -} -#endif /* GATT_PROXY */ - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static size_t gatt_prov_adv_create(struct bt_data prov_sd[2]) -{ - const struct bt_mesh_prov *prov = bt_mesh_prov_get(); - const char *name = CONFIG_BT_DEVICE_NAME; - size_t name_len = strlen(name); - size_t prov_sd_len = 0; - 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 *)name; - prov_sd_len++; - } - - return prov_sd_len; -} -#endif /* PB_GATT */ - -int32_t bt_mesh_proxy_adv_start(void) -{ - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return K_FOREVER; - } - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - if (!bt_mesh_is_provisioned()) { - const struct ble_gap_adv_params *param; - struct bt_data prov_sd[2]; - size_t prov_sd_len; - - if (prov_fast_adv) { - param = &fast_adv_param; - } else { - param = &slow_adv_param; - } - - prov_sd_len = gatt_prov_adv_create(prov_sd); - - if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad), - prov_sd, prov_sd_len) == 0) { - proxy_adv_enabled = true; - - /* Advertise 60 seconds using fast interval */ - if (prov_fast_adv) { - prov_fast_adv = false; - return K_SECONDS(60); - } - } - } -#endif /* PB_GATT */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - if (bt_mesh_is_provisioned()) { - return gatt_proxy_advertise(next_sub()); - } -#endif /* GATT_PROXY */ - - return K_FOREVER; -} - -void bt_mesh_proxy_adv_stop(void) -{ - int err; - - BT_DBG("adv_enabled %u", proxy_adv_enabled); - - if (!proxy_adv_enabled) { - return; - } - - err = bt_le_adv_stop(true); - if (err) { - BT_ERR("Failed to stop advertising (err %d)", err); - } else { - proxy_adv_enabled = false; - } -} - -#if defined(CONFIG_BT_MESH_GATT_PROXY) -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); - } -} -#endif - -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; - } - - proxy_connected(event->adv_complete.conn_handle); - } -#else - if (event->type == BLE_GAP_EVENT_CONNECT) { - proxy_connected(event->connect.conn_handle); - } -#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) { - proxy_disconnected(event->disconnect.conn.conn_handle, - event->disconnect.reason); - } 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); -#endif - } 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); -#endif - } - } - - return 0; -} - -static int -dummy_access_cb(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - /* - * We should never never enter this callback - it's attached to notify-only - * characteristic which are notified directly from mbuf. And we can't pass - * NULL as access_cb because gatts will assert on init... - */ - BLE_HS_DBG_ASSERT(0); - return 0; -} - -static const struct ble_gatt_svc_def svc_defs [] = { - { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_IN_VAL), - .access_cb = proxy_recv, - .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, - }, { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), - .access_cb = dummy_access_cb, - .flags = BLE_GATT_CHR_F_NOTIFY, - }, { - 0, /* No more characteristics in this service. */ - } }, - }, { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), - .access_cb = proxy_recv, - .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, - }, { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), - .access_cb = dummy_access_cb, - .flags = BLE_GATT_CHR_F_NOTIFY, - }, { - 0, /* No more characteristics in this service. */ - } }, - }, { - 0, /* No more services. */ - }, -}; - -int bt_mesh_proxy_svcs_register(void) -{ - int rc; - - rc = ble_gatts_count_cfg(svc_defs); - assert(rc == 0); - - rc = ble_gatts_add_svcs(svc_defs); - assert(rc == 0); - - 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; - } -#endif - - 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); -#endif - clients[i].buf = NET_BUF_SIMPLE(CLIENT_BUF_SIZE); - clients[i].conn_handle = BLE_HS_CONN_HANDLE_NONE; - - k_delayed_work_init(&clients[i].sar_timer, proxy_sar_timeout); - k_delayed_work_add_arg(&clients[i].sar_timer, &clients[i]); - } - - 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; -} - -void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb) -{ - if (!atomic_get(&pending_notifications)) { - cb->cb(); - return; - } - - sys_slist_append(&idle_waiters, &cb->n); -} - -#endif /* MYNEWT_VAL(BLE_MESH_PROXY) */ diff --git a/nimble/host/mesh/src/proxy.h b/nimble/host/mesh/src/proxy.h index ebade45ab6..42530293e9 100644 --- a/nimble/host/mesh/src/proxy.h +++ b/nimble/host/mesh/src/proxy.h @@ -9,34 +9,35 @@ #ifndef __PROXY_H__ #define __PROXY_H__ -#define BT_MESH_PROXY_NET_PDU 0x00 -#define BT_MESH_PROXY_BEACON 0x01 -#define BT_MESH_PROXY_CONFIG 0x02 -#define BT_MESH_PROXY_PROV 0x03 - -#include "mesh/mesh.h" #include "mesh/slist.h" +#if CONFIG_BT_MESH_DEBUG_USE_ID_ADDR +#define ADV_OPT_USE_IDENTITY BT_LE_ADV_OPT_USE_IDENTITY +#else +#define ADV_OPT_USE_IDENTITY 0 +#endif + +#define ADV_SLOW_INT \ +.itvl_min = BT_GAP_ADV_SLOW_INT_MIN, \ +.itvl_max = BT_GAP_ADV_SLOW_INT_MAX, + +#define ADV_FAST_INT \ +.itvl_min = BT_GAP_ADV_FAST_INT_MIN_2, \ +.itvl_max = BT_GAP_ADV_FAST_INT_MAX_2, + struct bt_mesh_proxy_idle_cb { sys_snode_t n; void (*cb)(void); }; -int bt_mesh_proxy_send(uint16_t conn_handle, uint8_t type, struct os_mbuf *msg); - -int bt_mesh_proxy_prov_enable(void); -int bt_mesh_proxy_prov_disable(bool disconnect); - +void notify_complete(void); int bt_mesh_proxy_gatt_enable(void); int bt_mesh_proxy_gatt_disable(void); void bt_mesh_proxy_gatt_disconnect(void); void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub); -struct os_mbuf *bt_mesh_proxy_get_buf(void); - -int32_t bt_mesh_proxy_adv_start(void); -void bt_mesh_proxy_adv_stop(void); +int bt_mesh_proxy_adv_start(void); void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub); void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); @@ -44,9 +45,7 @@ void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst); void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr); -int bt_mesh_proxy_init(void); -void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb); - int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg); +int bt_mesh_proxy_init(void); -#endif +#endif /* __PROXY_H__ */ diff --git a/nimble/host/mesh/src/proxy_msg.c b/nimble/host/mesh/src/proxy_msg.c new file mode 100644 index 0000000000..44613af16d --- /dev/null +++ b/nimble/host/mesh/src/proxy_msg.c @@ -0,0 +1,235 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "syscfg/syscfg.h" +#define MESH_LOG_MODULE BLE_MESH_PROXY_LOG + +#if MYNEWT_VAL(BLE_MESH_PROXY) + +#include "mesh/mesh.h" +#include "host/ble_att.h" +#include "services/gatt/ble_svc_gatt.h" +#include "../../host/src/ble_hs_priv.h" + +#include "mesh_priv.h" +#include "adv.h" +#include "net.h" +#include "rpl.h" +#include "prov.h" +#include "beacon.h" +#include "foundation.h" +#include "access.h" +#include "proxy.h" +#include "proxy_msg.h" + +#define PDU_SAR(data) (data[0] >> 6) + +#define BT_UUID_16_ENCODE(w16) \ + (((w16) >> 0) & 0xFF), \ + (((w16) >> 8) & 0xFF) +/* Mesh Profile 1.0 Section 6.6: + * "The timeout for the SAR transfer is 20 seconds. When the timeout + * expires, the Proxy Server shall disconnect." + */ +#define PROXY_SAR_TIMEOUT K_SECONDS(20) + +#define SAR_COMPLETE 0x00 +#define SAR_FIRST 0x01 +#define SAR_CONT 0x02 +#define SAR_LAST 0x03 + +#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) + +static uint8_t bufs[CONFIG_BT_MAX_CONN * CONFIG_BT_MESH_PROXY_MSG_LEN]; + +static struct bt_mesh_proxy_role roles[CONFIG_BT_MAX_CONN]; + +static void proxy_sar_timeout(struct ble_npl_event *work) +{ + struct bt_mesh_proxy_role *role; + int rc; + role = ble_npl_event_get_arg(work); + + + BT_WARN("Proxy SAR timeout"); + + if (role->conn_handle) { + rc = ble_gap_terminate(role->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + assert(rc == 0); + } +} + +int bt_mesh_proxy_msg_recv(struct bt_mesh_proxy_role *role, + const void *buf, uint16_t len) +{ + const uint8_t *data = buf; + + switch (PDU_SAR(data)) { + case SAR_COMPLETE: + if (role->buf->om_len) { + BT_WARN("Complete PDU while a pending incomplete one"); + return -EINVAL; + } + + role->msg_type = PDU_TYPE(data); + net_buf_simple_add_mem(role->buf, data + 1, len - 1); + role->cb.recv(role); + net_buf_simple_reset(role->buf); + break; + + case SAR_FIRST: + if (role->buf->om_len) { + BT_WARN("First PDU while a pending incomplete one"); + return -EINVAL; + } + + k_work_reschedule(&role->sar_timer, PROXY_SAR_TIMEOUT); + role->msg_type = PDU_TYPE(data); + net_buf_simple_add_mem(role->buf, data + 1, len - 1); + break; + + case SAR_CONT: + if (!role->buf->om_len) { + BT_WARN("Continuation with no prior data"); + return -EINVAL; + } + + if (role->msg_type != PDU_TYPE(data)) { + BT_WARN("Unexpected message type in continuation"); + return -EINVAL; + } + + k_work_reschedule(&role->sar_timer, PROXY_SAR_TIMEOUT); + net_buf_simple_add_mem(role->buf, data + 1, len - 1); + break; + + case SAR_LAST: + if (!role->buf->om_len) { + BT_WARN("Last SAR PDU with no prior data"); + return -EINVAL; + } + + if (role->msg_type != PDU_TYPE(data)) { + BT_WARN("Unexpected message type in last SAR PDU"); + return -EINVAL; + } + + /* If this fails, the work handler exits early, as there's no + * active SAR buffer. + */ + (void)k_work_cancel_delayable(&role->sar_timer); + net_buf_simple_add_mem(role->buf, data + 1, len - 1); + role->cb.recv(role); + net_buf_simple_reset(role->buf); + break; + } + + return len; +} + +int bt_mesh_proxy_msg_send(struct bt_mesh_proxy_role *role, uint8_t type, + struct os_mbuf *msg) +{ + int err; + uint16_t mtu; + uint16_t conn_handle = role->conn_handle; + + BT_DBG("conn_handle %d type 0x%02x len %u: %s", conn_handle, type, msg->om_len, + bt_hex(msg->om_data, msg->om_len)); + + /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ + mtu = ble_att_mtu(conn_handle) - 3; + if (mtu > msg->om_len) { + net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); + return role->cb.send(conn_handle, msg->om_data, msg->om_len); + } + + net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); + err = role->cb.send(conn_handle, msg->om_data, mtu); + if (err) { + return err; + } + net_buf_simple_pull_mem(msg, mtu); + + while (msg->om_len) { + if (msg->om_len + 1 < mtu) { + net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); + err = role->cb.send(conn_handle, msg->om_data, msg->om_len); + if (err) { + return err; + } + break; + } + + net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); + err = role->cb.send(conn_handle, msg->om_data, mtu); + if (err) { + return err; + } + net_buf_simple_pull_mem(msg, mtu); + } + + return 0; +} + +static void proxy_msg_init(struct bt_mesh_proxy_role *role) +{ + + /* Check if buf has been allocated, in this way, we no longer need + * to repeat the operation. + */ + if (role->buf != NULL) { + net_buf_simple_reset(role->buf); + return; + } + + role->buf = NET_BUF_SIMPLE(CONFIG_BT_MESH_PROXY_MSG_LEN); + net_buf_simple_init_with_data(role->buf, + &bufs[role->conn_handle * + CONFIG_BT_MESH_PROXY_MSG_LEN], + CONFIG_BT_MESH_PROXY_MSG_LEN); + + net_buf_simple_reset(role->buf); + + k_work_init_delayable(&role->sar_timer, proxy_sar_timeout); + k_work_add_arg_delayable(&role->sar_timer, role); +} + +struct bt_mesh_proxy_role *bt_mesh_proxy_role_setup(uint16_t conn_handle, + proxy_send_cb_t send, + proxy_recv_cb_t recv) +{ + struct bt_mesh_proxy_role *role; + + role = &roles[conn_handle]; + + role->conn_handle = conn_handle; + proxy_msg_init(role); + + role->cb.recv = recv; + role->cb.send = send; + + return role; +} + +void bt_mesh_proxy_role_cleanup(struct bt_mesh_proxy_role *role) +{ + + /* If this fails, the work handler exits early, as + * there's no active connection. + */ + (void)k_work_cancel_delayable(&role->sar_timer); + + role->conn_handle = BLE_HS_CONN_HANDLE_NONE; + + bt_mesh_adv_update(); +} + +#endif /* MYNEWT_VAL(BLE_MESH_PROXY) */ diff --git a/nimble/host/mesh/src/proxy_msg.h b/nimble/host/mesh/src/proxy_msg.h new file mode 100644 index 0000000000..349ebcdf4a --- /dev/null +++ b/nimble/host/mesh/src/proxy_msg.h @@ -0,0 +1,66 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_MSG_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_MSG_H_ + +#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) +#define CFG_FILTER_SET 0x00 +#define CFG_FILTER_ADD 0x01 +#define CFG_FILTER_REMOVE 0x02 +#define CFG_FILTER_STATUS 0x03 + +#define BT_MESH_PROXY_NET_PDU 0x00 +#define BT_MESH_PROXY_BEACON 0x01 +#define BT_MESH_PROXY_CONFIG 0x02 +#define BT_MESH_PROXY_PROV 0x03 + +#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) + +struct bt_mesh_proxy_role; + +typedef int (*proxy_send_cb_t)(uint16_t conn_handle, + const void *data, uint16_t len); + +typedef void (*proxy_recv_cb_t)(struct bt_mesh_proxy_role *role); + +struct bt_mesh_proxy_role { + uint16_t conn_handle; + uint8_t msg_type; + + struct { + proxy_send_cb_t send; + proxy_recv_cb_t recv; + } cb; + + struct k_work_delayable sar_timer; + struct os_mbuf *buf; +}; + +struct bt_mesh_proxy_client { + struct bt_mesh_proxy_role *cli; + uint16_t filter[MYNEWT_VAL(BLE_MESH_PROXY_FILTER_SIZE)]; + enum __packed { + NONE, + ACCEPT, + REJECT, + } filter_type; + struct ble_npl_callout send_beacons; +}; + +int bt_mesh_proxy_msg_recv(struct bt_mesh_proxy_role *role, + const void *buf, uint16_t len); +int bt_mesh_proxy_msg_send(struct bt_mesh_proxy_role *role, uint8_t type, struct os_mbuf *msg); +void bt_mesh_proxy_msg_init(struct bt_mesh_proxy_role *role); +void bt_mesh_proxy_role_cleanup(struct bt_mesh_proxy_role *role); +struct bt_mesh_proxy_role *bt_mesh_proxy_role_setup(uint16_t conn_handle, + proxy_send_cb_t send, + proxy_recv_cb_t recv); +struct bt_mesh_proxy_client *find_client(uint16_t conn_handle); +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_MSG_H_ */ diff --git a/nimble/host/mesh/src/proxy_srv.c b/nimble/host/mesh/src/proxy_srv.c new file mode 100644 index 0000000000..dcbabfa296 --- /dev/null +++ b/nimble/host/mesh/src/proxy_srv.c @@ -0,0 +1,985 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define MESH_LOG_MODULE BLE_MESH_PROXY_LOG + +#include "mesh/slist.h" +#include "mesh/mesh.h" +#include "../../host/src/ble_hs_priv.h" +#include "services/gatt/ble_svc_gatt.h" + +#include "mesh_priv.h" +#include "adv.h" +#include "net.h" +#include "rpl.h" +#include "transport.h" +#include "prov.h" +#include "beacon.h" +#include "foundation.h" +#include "access.h" +#include "proxy.h" +#include "proxy_msg.h" +#include "pb_gatt_srv.h" + +#if defined(CONFIG_BT_MESH_PROXY_USE_DEVICE_NAME) +#define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME +#else +#define ADV_OPT_USE_NAME 0 +#endif + +#define ADV_OPT_PROXY \ +.conn_mode = (BLE_GAP_CONN_MODE_UND), \ +.disc_mode = (BLE_GAP_DISC_MODE_GEN), + + +#define BT_UUID_MESH_PROXY_VAL 0x1828 +#define CLIENT_BUF_SIZE 66 + +#define BT_UUID_16_ENCODE(w16) \ + (((w16) >> 0) & 0xFF), \ + (((w16) >> 8) & 0xFF) + +static sys_slist_t idle_waiters; +static atomic_t pending_notifications; + +static void proxy_send_beacons(struct ble_npl_event *work); + +static int proxy_send(uint16_t conn_handle, + const void *data, uint16_t len); + + +static struct bt_mesh_proxy_client clients[CONFIG_BT_MAX_CONN]; + +static bool service_registered; + +static int conn_count; + +struct bt_mesh_proxy_client *find_client(uint16_t conn_handle) +{ + return &clients[conn_handle]; +} + +/* 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; +} + +#define ID_TYPE_NET 0x00 +#define ID_TYPE_NODE 0x01 + +#define NODE_ID_LEN 19 +#define NET_ID_LEN 11 + +#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), +}; + +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), +}; + +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), +}; + +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 + }; +#else + 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 + }; +#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 + }; +#else + 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 = find_client(conn_handle); + + 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(uint16_t conn_handle, uint8_t reason) +{ + struct ble_gap_conn_desc info; + struct bt_mesh_proxy_client *client; + 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) { + return; + } + + if (!service_registered && bt_mesh_is_provisioned()) { + (void)bt_mesh_proxy_gatt_enable(); + return; + } + + conn_count--; + client = find_client(conn_handle); + if (client->cli) { + bt_mesh_proxy_role_cleanup(client->cli); + client->cli = NULL; + } +} + +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_gattc_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); +#if MYNEWT_VAL(BLE_MESH_PB_GATT) + 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 MYNEWT_VAL(BLE_MESH_PB_GATT) + 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.conn_handle, + event->disconnect.reason); +#if MYNEWT_VAL(BLE_MESH_PB_GATT) + gatt_disconnected_pb_gatt(event->disconnect.conn.conn_handle, + event->disconnect.reason); +#endif + } 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); +#endif + } 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); +#endif + } + } + + 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; + } +#endif + + 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); +#endif + } + + 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; +} diff --git a/nimble/host/mesh/src/rpl.c b/nimble/host/mesh/src/rpl.c index 93c2e1a885..3a54414cea 100644 --- a/nimble/host/mesh/src/rpl.c +++ b/nimble/host/mesh/src/rpl.c @@ -10,6 +10,7 @@ #define MESH_LOG_MODULE BLE_MESH_RPL_LOG #include "log/log.h" +#include #include "mesh_priv.h" #include "adv.h" @@ -17,17 +18,81 @@ #include "rpl.h" #include "settings.h" +/* Replay Protection List information for persistent storage. */ +struct rpl_val { + uint32_t seq:24, + old_iv:1; +}; + static struct bt_mesh_rpl replay_list[MYNEWT_VAL(BLE_MESH_CRPL)]; +static ATOMIC_DEFINE(store, MYNEWT_VAL(BLE_MESH_CRPL)); + +static inline int rpl_idx(const struct bt_mesh_rpl *rpl) +{ + return rpl - &replay_list[0]; +} + +static void clear_rpl(struct bt_mesh_rpl *rpl) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int err; + char path[18]; + + if (!rpl->src) { + return; + } + + snprintk(path, sizeof(path), "bt_mesh/RPL/%x", rpl->src); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear RPL"); + } else { + BT_DBG("Cleared RPL"); + } + + (void)memset(rpl, 0, sizeof(*rpl)); + atomic_clear_bit(store, rpl_idx(rpl)); +#endif +} + +static void schedule_rpl_store(struct bt_mesh_rpl *entry, bool force) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + atomic_set_bit(store, rpl_idx(entry)); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); + if (force +#ifdef CONFIG_BT_MESH_RPL_STORE_TIMEOUT + || CONFIG_BT_MESH_RPL_STORE_TIMEOUT >= 0 +#endif + ) { + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); + } +#endif +} + +static void schedule_rpl_clear(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); +#endif +} void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) { + /* If this is the first message on the new IV index, we should reset it + * to zero to avoid invalid combinations of IV index and seg. + */ + if (rpl->old_iv && !rx->old_iv) { + rpl->seg = 0; + } + rpl->src = rx->ctx.addr; rpl->seq = rx->seq; rpl->old_iv = rx->old_iv; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_rpl(rpl); + schedule_rpl_store(rpl, false); } } @@ -95,13 +160,14 @@ void bt_mesh_rpl_clear(void) BT_DBG(""); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_rpl(); + schedule_rpl_clear(); } else { (void)memset(replay_list, 0, sizeof(replay_list)); } } -struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src) +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src) { int i; @@ -114,7 +180,7 @@ struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src) return NULL; } -struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src) +static struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src) { int i; @@ -127,15 +193,7 @@ struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src) return NULL; } - -void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(replay_list); i++) { - func(&replay_list[i], user_data); - } -} +#endif void bt_mesh_rpl_reset(void) { @@ -149,14 +207,174 @@ void bt_mesh_rpl_reset(void) if (rpl->src) { if (rpl->old_iv) { - (void)memset(rpl, 0, sizeof(*rpl)); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + clear_rpl(rpl); + } else { + (void)memset(rpl, 0, sizeof(*rpl)); + } } else { rpl->old_iv = true; + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + schedule_rpl_store(rpl, true); + } } + } + } +} - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_rpl(rpl); - } +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int rpl_set(int argc, char **argv, char *val) +{ + struct bt_mesh_rpl *entry; + struct rpl_val rpl; + int len, err; + uint16_t src; + + if (argc < 1) { + BT_ERR("Invalid argc (%d)", argc); + return -ENOENT; + } + + BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); + + src = strtol(argv[0], NULL, 16); + entry = bt_mesh_rpl_find(src); + + if (!val) { + if (entry) { + memset(entry, 0, sizeof(*entry)); + } else { + BT_WARN("Unable to find RPL entry for 0x%04x", src); + } + + return 0; + } + + if (!entry) { + entry = bt_mesh_rpl_alloc(src); + if (!entry) { + BT_ERR("Unable to allocate RPL entry for 0x%04x", src); + return -ENOMEM; } } -} \ No newline at end of file + + len = sizeof(rpl); + err = settings_bytes_from_str(val, &rpl, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(rpl)) { + BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(rpl)); + return -EINVAL; + } + + entry->seq = rpl.seq; + entry->old_iv = rpl.old_iv; + + BT_DBG("RPL entry for 0x%04x: Seq 0x%06x old_iv %u", entry->src, + (unsigned) entry->seq, entry->old_iv); + return 0; +} +#endif + +static void store_rpl(struct bt_mesh_rpl *entry) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char buf[BT_SETTINGS_SIZE(sizeof(struct rpl_val))]; + struct rpl_val rpl; + char path[18]; + char *str; + int err; + + if (!entry->src) { + return; + } + + BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, + (unsigned) entry->seq, entry->old_iv); + + rpl.seq = entry->seq; + rpl.old_iv = entry->old_iv; + + str = settings_str_from_bytes(&rpl, sizeof(rpl), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode RPL as value"); + return; + } + + snprintk(path, sizeof(path), "bt_mesh/RPL/%x", entry->src); + + BT_DBG("Saving RPL %s as value %s", path, str); + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store RPL"); + } else { + BT_DBG("Stored RPL"); + } +#endif +} + +static void store_pending_rpl(struct bt_mesh_rpl *rpl) +{ + BT_DBG(""); + + if (atomic_test_and_clear_bit(store, rpl_idx(rpl))) { + store_rpl(rpl); + } +} + +void bt_mesh_rpl_pending_store(uint16_t addr) +{ + int i; + + if (!IS_ENABLED(CONFIG_BT_SETTINGS) || + (!BT_MESH_ADDR_IS_UNICAST(addr) && + addr != BT_MESH_ADDR_ALL_NODES)) { + return; + } + + if (addr == BT_MESH_ADDR_ALL_NODES) { + bt_mesh_settings_store_cancel(BT_MESH_SETTINGS_RPL_PENDING); + } + + for (i = 0; i < ARRAY_SIZE(replay_list); i++) { + if (addr != BT_MESH_ADDR_ALL_NODES && + addr != replay_list[i].src) { + continue; + } + + if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + store_pending_rpl(&replay_list[i]); + } else { + clear_rpl(&replay_list[i]); + } + + if (addr != BT_MESH_ADDR_ALL_NODES) { + break; + } + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_rpl_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = rpl_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_rpl_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_rpl_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_rpl conf"); +#endif +} diff --git a/nimble/host/mesh/src/rpl.h b/nimble/host/mesh/src/rpl.h index 0592712f87..9d110d9dab 100644 --- a/nimble/host/mesh/src/rpl.h +++ b/nimble/host/mesh/src/rpl.h @@ -8,12 +8,16 @@ */ struct bt_mesh_rpl { - uint16_t src; - bool old_iv; -#if defined(CONFIG_BT_SETTINGS) - bool store; -#endif - uint32_t seq; + uint64_t src:15, + old_iv:1, + seq:24, + /** Sequence authentication value for the previous segmented + * message received from this address. + * + * This value is used to manage the parallel RPL of the + * SeqAuth values in transport. + */ + seg:24; }; typedef void (*bt_mesh_rpl_func_t)(struct bt_mesh_rpl *rpl, @@ -23,8 +27,6 @@ void bt_mesh_rpl_reset(void); bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match); void bt_mesh_rpl_clear(void); -struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src); -struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src); -void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data); void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl, - struct bt_mesh_net_rx *rx); \ No newline at end of file + struct bt_mesh_net_rx *rx); +void bt_mesh_rpl_init(void); diff --git a/nimble/host/mesh/src/settings.c b/nimble/host/mesh/src/settings.c index 30fbf5a014..cddf025f92 100644 --- a/nimble/host/mesh/src/settings.c +++ b/nimble/host/mesh/src/settings.c @@ -10,144 +10,26 @@ #if MYNEWT_VAL(BLE_MESH_SETTINGS) #include "mesh_priv.h" -#include "mesh/mesh.h" #include "mesh/glue.h" #include "subnet.h" #include "app_keys.h" #include "net.h" +#include "cdb_priv.h" #include "rpl.h" #include "crypto.h" #include "transport.h" #include "heartbeat.h" #include "access.h" -#include "foundation.h" +#include "pb_gatt_srv.h" #include "proxy.h" #include "settings.h" -#include "lpn.h" #include "cfg.h" #include "config/config.h" -/* Tracking of what storage changes are pending for App and Net Keys. We - * track this in a separate array here instead of within the respective - * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key - * gets deleted its struct becomes invalid and may be reused for other keys. - */ -struct key_update { - uint16_t key_idx:12, /* AppKey or NetKey Index */ - valid:1, /* 1 if this entry is valid, 0 if not */ - app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */ - clear:1; /* 1 if key needs clearing, 0 if storing */ -}; - -static struct key_update key_updates[CONFIG_BT_MESH_APP_KEY_COUNT + - CONFIG_BT_MESH_SUBNET_COUNT]; - -static struct k_delayed_work pending_store; - -/* Mesh network storage information */ -struct net_val { - uint16_t primary_addr; - uint8_t dev_key[16]; -} __packed; - -/* Sequence number storage */ -struct seq_val { - uint8_t val[3]; -} __packed; - -/* Heartbeat Publication storage */ -struct hb_pub_val { - uint16_t dst; - uint8_t period; - uint8_t ttl; - uint16_t feat; - uint16_t net_idx:12, - indefinite:1; -}; - -/* Miscelaneous configuration server model states */ -struct cfg_val { - uint8_t net_transmit; - uint8_t relay; - uint8_t relay_retransmit; - uint8_t beacon; - uint8_t gatt_proxy; - uint8_t frnd; - uint8_t default_ttl; -}; - -/* IV Index & IV Update storage */ -struct iv_val { - uint32_t iv_index; - uint8_t iv_update:1, - iv_duration:7; -} __packed; - -/* Replay Protection List storage */ -struct rpl_val { - uint32_t seq:24, - old_iv:1; -}; - -/* NetKey storage information */ -struct net_key_val { - uint8_t kr_flag:1, - kr_phase:7; - uint8_t val[2][16]; -} __packed; - -/* AppKey storage information */ -struct app_key_val { - uint16_t net_idx; - bool updated; - uint8_t val[2][16]; -} __packed; - -struct mod_pub_val { - uint16_t addr; - uint16_t key; - uint8_t ttl; - uint8_t retransmit; - uint8_t period; - uint8_t period_div:4, - cred:1; -}; - -/* Virtual Address information */ -struct va_val { - uint16_t ref; - uint16_t addr; - uint8_t uuid[16]; -} __packed; - -struct cdb_net_val { - uint32_t iv_index; - bool iv_update; -} __packed; - -/* Node storage information */ -struct node_val { - uint16_t net_idx; - uint8_t num_elem; - uint8_t flags; -#define F_NODE_CONFIGURED 0x01 - uint8_t uuid[16]; - uint8_t dev_key[16]; -} __packed; - -struct node_update { - uint16_t addr; - bool clear; -}; - -#if MYNEWT_VAL(BLE_MESH_CDB) -static struct node_update cdb_node_updates[MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)]; -static struct key_update cdb_key_updates[ - MYNEWT_VAL(BLE_MESH_CDB_SUBNET_COUNT) + - MYNEWT_VAL(BLE_MESH_CDB_APP_KEY_COUNT)]; -#endif +static struct k_work_delayable pending_store; +static ATOMIC_DEFINE(pending_flags, BT_MESH_SETTINGS_FLAG_COUNT); int settings_name_next(char *name, char **next) { @@ -181,2270 +63,140 @@ int settings_name_next(char *name, char **next) return rc; } -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 rpl_set(int argc, char **argv, char *val) +static int mesh_commit(void) { - struct bt_mesh_rpl *entry; - struct rpl_val rpl; - int len, err; - uint16_t src; - - if (argc < 1) { - BT_ERR("Invalid argc (%d)", argc); - return -ENOENT; - } - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - src = strtol(argv[0], NULL, 16); - entry = bt_mesh_rpl_find(src); - - if (!val) { - if (entry) { - memset(entry, 0, sizeof(*entry)); - } else { - BT_WARN("Unable to find RPL entry for 0x%04x", src); - } - + if (!bt_mesh_subnet_next(NULL)) { + /* Nothing to do since we're not yet provisioned */ return 0; } - if (!entry) { - entry = bt_mesh_rpl_alloc(src); - if (!entry) { - BT_ERR("Unable to allocate RPL entry for 0x%04x", src); - return -ENOMEM; - } - } - - len = sizeof(rpl); - err = settings_bytes_from_str(val, &rpl, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(rpl)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(rpl)); - return -EINVAL; + if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + (void)bt_mesh_pb_gatt_disable(); } - entry->seq = rpl.seq; - entry->old_iv = rpl.old_iv; + bt_mesh_net_settings_commit(); + bt_mesh_model_settings_commit(); - BT_DBG("RPL entry for 0x%04x: Seq 0x%06x old_iv %u", entry->src, - (unsigned) entry->seq, entry->old_iv); + atomic_set_bit(bt_mesh.flags, BT_MESH_VALID); + bt_mesh_start(); return 0; } -static int net_key_set(int argc, char **argv, char *val) -{ - struct net_key_val key; - int len, err; - uint16_t net_idx; - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - net_idx = strtol(argv[0], NULL, 16); - - len = sizeof(key); - err = settings_bytes_from_str(val, &key, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(key)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(key)); - return -EINVAL; - } - - BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); - - return bt_mesh_subnet_set( - net_idx, key.kr_phase, key.val[0], - (key.kr_phase != BT_MESH_KR_NORMAL) ? key.val[1] : NULL); -} - -static int app_key_set(int argc, char **argv, char *val) -{ - struct app_key_val key; - uint16_t app_idx; - int len_rd, err; - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - app_idx = strtol(argv[0], NULL, 16); - len_rd = strtol(argv[1], NULL, 16); - - if (!len_rd) { - return 0; - } - - err = settings_bytes_from_str(val, &key, &len_rd); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - err = bt_mesh_app_key_set(app_idx, key.net_idx, key.val[0], - key.updated ? key.val[1] : NULL); - if (err) { - BT_ERR("Failed to set \'app-key\'"); - return err; - } - - BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); +/* Pending flags that use K_NO_WAIT as the storage timeout */ +#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_PENDING) | \ + BIT(BT_MESH_SETTINGS_IV_PENDING) | \ + BIT(BT_MESH_SETTINGS_SEQ_PENDING) | \ + BIT(BT_MESH_SETTINGS_CDB_PENDING)) - return 0; -} +/* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */ +#define GENERIC_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_KEYS_PENDING) | \ + BIT(BT_MESH_SETTINGS_APP_KEYS_PENDING) | \ + BIT(BT_MESH_SETTINGS_HB_PUB_PENDING) | \ + BIT(BT_MESH_SETTINGS_CFG_PENDING) | \ + BIT(BT_MESH_SETTINGS_MOD_PENDING) | \ + BIT(BT_MESH_SETTINGS_VA_PENDING)) -static int hb_pub_set(int argc, char **argv, char *val) +void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag) { - struct bt_mesh_hb_pub pub; - struct hb_pub_val hb_val; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - len = sizeof(hb_val); - err = settings_bytes_from_str(val, &hb_val, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(hb_val)) { - BT_ERR("Unexpected value length (%d != %zu)", len, - sizeof(hb_val)); - return -EINVAL; - } + int32_t timeout_ms, remaining_ms; - pub.dst = hb_val.dst; - pub.period = bt_mesh_hb_pwr2(hb_val.period); - pub.ttl = hb_val.ttl; - pub.feat = hb_val.feat; - pub.net_idx = hb_val.net_idx; + atomic_set_bit(pending_flags, flag); - if (hb_val.indefinite) { - pub.count = 0xffff; + if (atomic_get(pending_flags) & NO_WAIT_PENDING_BITS) { + timeout_ms = 0; + } else if (CONFIG_BT_MESH_RPL_STORE_TIMEOUT >= 0 && + atomic_test_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING) && + !(atomic_get(pending_flags) & GENERIC_PENDING_BITS)) { + timeout_ms = CONFIG_BT_MESH_RPL_STORE_TIMEOUT * MSEC_PER_SEC; } else { - pub.count = 0; - } - - (void)bt_mesh_hb_pub_set(&pub); - - BT_DBG("Restored heartbeat publication"); - - return 0; -} - -static int cfg_set(int argc, char **argv, char *val) -{ - struct cfg_val cfg; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - BT_DBG("Cleared configuration state"); - return 0; - } - - len = sizeof(cfg); - err = settings_bytes_from_str(val, &cfg, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(cfg)) { - BT_ERR("Unexpected value length (%d != %zu)", len, - sizeof(cfg)); - return -EINVAL; - } - - bt_mesh_net_transmit_set(cfg.net_transmit); - bt_mesh_relay_set(cfg.relay, cfg.relay_retransmit); - bt_mesh_beacon_set(cfg.beacon); - bt_mesh_gatt_proxy_set(cfg.gatt_proxy); - bt_mesh_friend_set(cfg.frnd); - bt_mesh_default_ttl_set(cfg.default_ttl); - - BT_DBG("Restored configuration state"); - - return 0; -} - -static int mod_set_bind(struct bt_mesh_model *mod, char *val) -{ - int len, err, i; - - /* Start with empty array regardless of cleared or set value */ - for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { - mod->keys[i] = BT_MESH_KEY_UNUSED; - } - - if (!val) { - BT_DBG("Cleared bindings for model"); - return 0; - } - - len = sizeof(mod->keys); - err = settings_bytes_from_str(val, mod->keys, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - BT_DBG("Decoded %u bound keys for model", len / sizeof(mod->keys[0])); - return 0; -} - -static int mod_set_sub(struct bt_mesh_model *mod, char *val) -{ - int len, err; - - /* Start with empty array regardless of cleared or set value */ - memset(mod->groups, 0, sizeof(mod->groups)); - - if (!val) { - BT_DBG("Cleared subscriptions for model"); - return 0; - } - - len = sizeof(mod->groups); - err = settings_bytes_from_str(val, mod->groups, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; + timeout_ms = CONFIG_BT_MESH_STORE_TIMEOUT * MSEC_PER_SEC; } - BT_DBG("Decoded %u subscribed group addresses for model", - len / sizeof(mod->groups[0])); - return 0; -} - -static int mod_set_pub(struct bt_mesh_model *mod, char *val) -{ - struct mod_pub_val pub; - int len, err; - - if (!mod->pub) { - BT_WARN("Model has no publication context!"); - return -EINVAL; - } - - if (!val) { - mod->pub->addr = BT_MESH_ADDR_UNASSIGNED; - mod->pub->key = 0; - mod->pub->cred = 0; - mod->pub->ttl = 0; - mod->pub->period = 0; - mod->pub->retransmit = 0; - mod->pub->count = 0; - - BT_DBG("Cleared publication for model"); - return 0; - } - - len = sizeof(pub); - err = settings_bytes_from_str(val, &pub, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - if (len != sizeof(pub)) { - BT_ERR("Invalid length for model publication"); - return -EINVAL; + remaining_ms = k_ticks_to_ms_floor32( + k_work_delayable_remaining_get(&pending_store)); + BT_DBG("Waiting %u ms vs rem %u ms", timeout_ms, remaining_ms); + /* If the new deadline is sooner, override any existing + * deadline; otherwise schedule without changing any existing + * deadline. + */ + if (timeout_ms < remaining_ms) { + k_work_reschedule(&pending_store, K_MSEC(timeout_ms)); + } else { + k_work_schedule(&pending_store, K_MSEC(timeout_ms)); } - - mod->pub->addr = pub.addr; - mod->pub->key = pub.key; - mod->pub->cred = pub.cred; - mod->pub->ttl = pub.ttl; - mod->pub->period = pub.period; - mod->pub->retransmit = pub.retransmit; - mod->pub->count = 0; - - BT_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", - pub.addr, pub.key); - - return 0; } -static int mod_data_set(struct bt_mesh_model *mod, - char *name, char *len_rd) +void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag) { - char *next; - - settings_name_next(name, &next); - - if (mod->cb && mod->cb->settings_set) { - return mod->cb->settings_set(mod, next, len_rd); - } - - return 0; + atomic_clear_bit(pending_flags, flag); } -static int mod_set(bool vnd, int argc, char **argv, char *val) +static void store_pending(struct ble_npl_event *work) { - struct bt_mesh_model *mod; - uint8_t elem_idx, mod_idx; - uint16_t mod_key; - - if (argc < 2) { - BT_ERR("Too small argc (%d)", argc); - return -ENOENT; - } - - mod_key = strtol(argv[0], NULL, 16); - elem_idx = mod_key >> 8; - mod_idx = mod_key; - - BT_DBG("Decoded mod_key 0x%04x as elem_idx %u mod_idx %u", - mod_key, elem_idx, mod_idx); - - mod = bt_mesh_model_get(vnd, elem_idx, mod_idx); - if (!mod) { - BT_ERR("Failed to get model for elem_idx %u mod_idx %u", - elem_idx, mod_idx); - return -ENOENT; + BT_DBG(""); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_RPL_PENDING)) { + bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES); } - if (!strcmp(argv[1], "bind")) { - return mod_set_bind(mod, val); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_NET_KEYS_PENDING)) { + bt_mesh_subnet_pending_store(); } - if (!strcmp(argv[1], "sub")) { - return mod_set_sub(mod, val); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_APP_KEYS_PENDING)) { + bt_mesh_app_key_pending_store(); } - if (!strcmp(argv[1], "pub")) { - return mod_set_pub(mod, val); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_NET_PENDING)) { + bt_mesh_net_pending_net_store(); } - if (!strcmp(argv[1], "data")) { - return mod_data_set(mod, argv[1], val); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_IV_PENDING)) { + bt_mesh_net_pending_iv_store(); } - BT_WARN("Unknown module key %s", argv[1]); - return -ENOENT; -} - -static int sig_mod_set(int argc, char **argv, char *val) -{ - return mod_set(false, argc, argv, val); -} - -static int vnd_mod_set(int argc, char **argv, char *val) -{ - return mod_set(true, argc, argv, val); -} - -#if CONFIG_BT_MESH_LABEL_COUNT > 0 -static int va_set(int argc, char **argv, char *val) -{ - struct va_val va; - struct bt_mesh_va *lab; - uint16_t index; - int len, err; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_SEQ_PENDING)) { + bt_mesh_net_pending_seq_store(); } - index = strtol(argv[0], NULL, 16); - - if (val == NULL) { - BT_WARN("Mesh Virtual Address length = 0"); - return 0; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_HB_PUB_PENDING)) { + bt_mesh_hb_pub_pending_store(); } - err = settings_bytes_from_str(val, &va, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_CFG_PENDING)) { + bt_mesh_cfg_pending_store(); } - if (len != sizeof(struct va_val)) { - BT_ERR("Invalid length for virtual address"); - return -EINVAL; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_MOD_PENDING)) { + bt_mesh_model_pending_store(); } - if (va.ref == 0) { - BT_WARN("Ignore Mesh Virtual Address ref = 0"); - return 0; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_VA_PENDING)) { + bt_mesh_va_pending_store(); } - lab = bt_mesh_va_get(index); - if (lab == NULL) { - BT_WARN("Out of labels buffers"); - return -ENOBUFS; +#if IS_ENABLED(CONFIG_BT_MESH_CDB) + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_CDB_PENDING)) { + bt_mesh_cdb_pending_store(); } - - memcpy(lab->uuid, va.uuid, 16); - lab->addr = va.addr; - lab->ref = va.ref; - - BT_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", - lab->addr, lab->ref); - - return 0; -} #endif - -#if MYNEWT_VAL(BLE_MESH_CDB) -static int cdb_net_set(int argc, char *val) -{ - struct cdb_net_val net; - int len, err; - - len = sizeof(net); - err = settings_bytes_from_str(val, &net, &len); - if (err) { - BT_ERR("Failed to set \'cdb_net\'"); - return err; - } - - bt_mesh_cdb.iv_index = net.iv_index; - - if (net.iv_update) { - atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS); - } - - atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID); - - return 0; -} - -static int cdb_node_set(int argc, char *str) -{ - struct bt_mesh_cdb_node *node; - struct node_val val; - uint16_t addr; - int len, err; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - addr = strtol(str, NULL, 16); - len = sizeof(str); - - if (argc < 1) { - BT_DBG("val (null)"); - BT_DBG("Deleting node 0x%04x", addr); - - node = bt_mesh_cdb_node_get(addr); - if (node) { - bt_mesh_cdb_node_del(node, false); - } - - return 0; - } - - err = settings_bytes_from_str(str, &val, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - if (len != sizeof(struct node_val)) { - BT_ERR("Invalid length for node_val"); - return -EINVAL; - } - - node = bt_mesh_cdb_node_get(addr); - if (!node) { - node = bt_mesh_cdb_node_alloc(val.uuid, addr, val.num_elem, - val.net_idx); - } - - if (!node) { - BT_ERR("No space for a new node"); - return -ENOMEM; - } - - if (val.flags & F_NODE_CONFIGURED) { - atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED); - } - - memcpy(node->uuid, val.uuid, 16); - memcpy(node->dev_key, val.dev_key, 16); - - BT_DBG("Node 0x%04x recovered from storage", addr); - - return 0; -} - -static int cdb_subnet_set(int argc, char *name) -{ - struct bt_mesh_cdb_subnet *sub; - struct net_key_val key; - uint16_t net_idx; - int len, len_rd, err; - - if (!name) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - len_rd = sizeof(sub); - net_idx = strtol(name, NULL, 16); - sub = bt_mesh_cdb_subnet_get(net_idx); - - if (len_rd == 0) { - BT_DBG("val (null)"); - if (!sub) { - BT_ERR("No subnet with NetKeyIndex 0x%03x", net_idx); - return -ENOENT; - } - - BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx); - bt_mesh_cdb_subnet_del(sub, false); - return 0; - } - - len = sizeof(key); - err = settings_bytes_from_str(name, &key, &len); - if (err) { - BT_ERR("Failed to set \'net-key\'"); - return err; - } - - if (sub) { - BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx); - - sub->kr_flag = key.kr_flag; - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); - - return 0; - } - - sub = bt_mesh_cdb_subnet_alloc(net_idx); - if (!sub) { - BT_ERR("No space to allocate a new subnet"); - return -ENOMEM; - } - - sub->kr_flag = key.kr_flag; - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); - - BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); - - return 0; -} - -static int cdb_app_key_set(int argc, char *name) -{ - struct bt_mesh_cdb_app_key *app; - struct app_key_val key; - uint16_t app_idx; - int len_rd, err; - - app_idx = strtol(name, NULL, 16); - len_rd = sizeof(key); - - if (len_rd == 0) { - BT_DBG("val (null)"); - BT_DBG("Deleting AppKeyIndex 0x%03x", app_idx); - - app = bt_mesh_cdb_app_key_get(app_idx); - if (app) { - bt_mesh_cdb_app_key_del(app, false); - } - - return 0; - } - - err = settings_bytes_from_str(name, &key, &len_rd); - if (err) { - BT_ERR("Failed to set \'app-key\'"); - return err; - } - - app = bt_mesh_cdb_app_key_get(app_idx); - if (!app) { - app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx); - } - - if (!app) { - BT_ERR("No space for a new app key"); - return -ENOMEM; - } - - memcpy(app->keys[0].app_key, key.val[0], 16); - memcpy(app->keys[1].app_key, key.val[1], 16); - - BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); - - return 0; -} - -static int cdb_set(int argc, char **argv, char *name) -{ - int len; - char *next; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - if (!strcmp(name, "Net")) { - return cdb_net_set(1, name); - } - - - len = settings_name_next(name, &next); - - if (!next) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - if (!strncmp(name, "Node", len)) { - return cdb_node_set(1, next); - } - - if (!strncmp(name, "Subnet", len)) { - return cdb_subnet_set(1, next); - } - - if (!strncmp(name, "AppKey", len)) { - return cdb_app_key_set(1, next); - } - - BT_WARN("Unknown module key %s", name); - return -ENOENT; -} -#endif - -const struct mesh_setting { - const char *name; - int (*func)(int argc, char **argv, char *val); -} settings[] = { - { "Net", net_set }, - { "IV", iv_set }, - { "Seq", seq_set }, - { "RPL", rpl_set }, - { "NetKey", net_key_set }, - { "AppKey", app_key_set }, - { "HBPub", hb_pub_set }, - { "Cfg", cfg_set }, - { "s", sig_mod_set }, - { "v", vnd_mod_set }, -#if CONFIG_BT_MESH_LABEL_COUNT > 0 - { "Va", va_set }, -#endif -#if MYNEWT_VAL(BLE_MESH_CDB) - { "cdb", cdb_set }, -#endif -}; - -static int mesh_set(int argc, char **argv, char *val) -{ - int i; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -EINVAL; - } - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - for (i = 0; i < ARRAY_SIZE(settings); i++) { - if (!strcmp(settings[i].name, argv[0])) { - argc--; - argv++; - - return settings[i].func(argc, argv, val); - } - } - - BT_WARN("No matching handler for key %s", argv[0]); - - return -ENOENT; -} - -static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - if (mod->pub && mod->pub->update && - mod->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int32_t ms = bt_mesh_model_pub_period_get(mod); - if (ms) { - BT_DBG("Starting publish timer (period %u ms)", - (unsigned) ms); - k_delayed_work_submit(&mod->pub->timer, ms); - } - } - - if (!IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - return; - } - - for (int i = 0; i < ARRAY_SIZE(mod->groups); i++) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - bt_mesh_lpn_group_add(mod->groups[i]); - } - } -} - -static int mesh_commit(void) -{ - if (!bt_mesh_subnet_next(NULL)) { - /* Nothing to do since we're not yet provisioned */ - return 0; - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { - bt_mesh_proxy_prov_disable(true); - } - - if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); - } - - bt_mesh_model_foreach(commit_mod, NULL); - - atomic_set_bit(bt_mesh.flags, BT_MESH_VALID); - - bt_mesh_start(); - - return 0; -} - -/* Pending flags that use K_NO_WAIT as the storage timeout */ -#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_NET_PENDING) | \ - BIT(BT_MESH_IV_PENDING) | \ - BIT(BT_MESH_SEQ_PENDING)) - -/* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */ -#define GENERIC_PENDING_BITS (BIT(BT_MESH_KEYS_PENDING) | \ - BIT(BT_MESH_HB_PUB_PENDING) | \ - BIT(BT_MESH_CFG_PENDING) | \ - BIT(BT_MESH_MOD_PENDING)) - -static void schedule_store(int flag) -{ - int32_t timeout, remaining; - - atomic_set_bit(bt_mesh.flags, flag); - - if (atomic_get(bt_mesh.flags) & NO_WAIT_PENDING_BITS) { - timeout = K_NO_WAIT; - } else if (atomic_test_bit(bt_mesh.flags, BT_MESH_RPL_PENDING) && - (!(atomic_get(bt_mesh.flags) & GENERIC_PENDING_BITS) || - (CONFIG_BT_MESH_RPL_STORE_TIMEOUT < - CONFIG_BT_MESH_STORE_TIMEOUT))) { - timeout = K_SECONDS(CONFIG_BT_MESH_RPL_STORE_TIMEOUT); - } else { - timeout = K_SECONDS(CONFIG_BT_MESH_STORE_TIMEOUT); - } - - remaining = k_delayed_work_remaining_get(&pending_store); - if (remaining && remaining < timeout) { - BT_DBG("Not rescheduling due to existing earlier deadline"); - return; - } - - BT_DBG("Waiting %d seconds", (int) (timeout / MSEC_PER_SEC)); - - k_delayed_work_submit(&pending_store, timeout); -} - -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 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_store_net(void) -{ - schedule_store(BT_MESH_NET_PENDING); -} - -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_store_iv(bool only_duration) -{ - schedule_store(BT_MESH_IV_PENDING); - - if (!only_duration) { - /* Always update Seq whenever IV changes */ - schedule_store(BT_MESH_SEQ_PENDING); - } -} - -static void store_pending_seq(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))]; - struct seq_val seq; - char *str; - int err; - - 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 Seq as value"); - return; - } - - BT_DBG("Saving Seq as value %s", str); - err = settings_save_one("bt_mesh/Seq", str); - if (err) { - BT_ERR("Failed to store Seq"); - } else { - BT_DBG("Stored Seq"); - } -} - -void bt_mesh_store_seq(void) -{ - if (CONFIG_BT_MESH_SEQ_STORE_RATE && - (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)) { - return; - } - - schedule_store(BT_MESH_SEQ_PENDING); -} - -static void store_rpl(struct bt_mesh_rpl *entry) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct rpl_val))]; - struct rpl_val rpl; - char path[18]; - char *str; - int err; - - BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, - (unsigned) entry->seq, entry->old_iv); - - rpl.seq = entry->seq; - rpl.old_iv = entry->old_iv; - - str = settings_str_from_bytes(&rpl, sizeof(rpl), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode RPL as value"); - return; - } - - snprintk(path, sizeof(path), "bt_mesh/RPL/%x", entry->src); - - BT_DBG("Saving RPL %s as value %s", path, str); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store RPL"); - } else { - BT_DBG("Stored RPL"); - } -} - -static void clear_rpl(struct bt_mesh_rpl *rpl, void *user_data) -{ - int err; - char path[18]; - - if (!rpl->src) { - return; - } - - snprintk(path, sizeof(path), "bt/mesh/RPL/%x", rpl->src); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear RPL"); - } else { - BT_DBG("Cleared RPL"); - } - - (void)memset(rpl, 0, sizeof(*rpl)); -} - -static void store_pending_rpl(struct bt_mesh_rpl *rpl, void *user_data) -{ - BT_DBG(""); - - if (rpl->store) { - rpl->store = false; - store_rpl(rpl); - } -} - -static void store_pending_hb_pub(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct hb_pub_val))]; - struct bt_mesh_hb_pub pub; - struct hb_pub_val val; - char *str; - int err; - - bt_mesh_hb_pub_get(&pub); - if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { - str = NULL; - } else { - val.indefinite = (pub.count == 0xffff); - val.dst = pub.dst; - val.period = bt_mesh_hb_log(pub.period); - val.ttl = pub.ttl; - val.feat = pub.feat; - val.net_idx = pub.net_idx; - - str = settings_str_from_bytes(&val, sizeof(val), - buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode hb pub as value"); - return; - } - } - - BT_DBG("Saving Heartbeat Publication as value %s", - str ? str : "(null)"); - err = settings_save_one("bt_mesh/HBPub", str); - if (err) { - BT_ERR("Failed to store Heartbeat Publication"); - } else { - BT_DBG("Stored Heartbeat Publication"); - } -} - -static void store_pending_cfg(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct cfg_val))]; - struct cfg_val val; - char *str; - int err; - - val.net_transmit = bt_mesh_net_transmit_get(); - val.relay = bt_mesh_relay_get(); - val.relay_retransmit = bt_mesh_relay_retransmit_get(); - val.beacon = bt_mesh_beacon_enabled(); - val.gatt_proxy = bt_mesh_gatt_proxy_get(); - val.frnd = bt_mesh_friend_get(); - val.default_ttl = bt_mesh_default_ttl_get(); - - str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode configuration as value"); - return; - } - - BT_DBG("Saving configuration as value %s", str); - err = settings_save_one("bt_mesh/Cfg", str); - if (err) { - BT_ERR("Failed to store configuration"); - } else { - BT_DBG("Stored configuration"); - } -} - -static void clear_cfg(void) -{ - int err; - - err = settings_save_one("bt_mesh/Cfg", NULL); - if (err) { - BT_ERR("Failed to clear configuration"); - } else { - BT_DBG("Cleared configuration"); - } -} - -static void clear_app_key(uint16_t app_idx) -{ - char path[20]; - int err; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); - } else { - BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); - } -} - -static void clear_net_key(uint16_t net_idx) -{ - char path[20]; - int err; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); - } else { - BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); - } -} - -static void store_subnet(uint16_t net_idx) -{ - const struct bt_mesh_subnet *sub; - struct net_key_val key; - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - char path[20]; - char *str; - int err; - - sub = bt_mesh_subnet_get(net_idx); - if (!sub) { - BT_WARN("NetKeyIndex 0x%03x not found", net_idx); - return; - } - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt/mesh/NetKey/%x", net_idx); - - memcpy(&key.val[0], sub->keys[0].net, 16); - memcpy(&key.val[1], sub->keys[1].net, 16); - key.kr_flag = 0U; /* Deprecated */ - key.kr_phase = sub->kr_phase; - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode AppKey as value"); - return; - } - - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store NetKey"); - } else { - BT_DBG("Stored NetKey"); - } -} - -static void store_app(uint16_t app_idx) -{ - const struct bt_mesh_app_key *app; - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - struct app_key_val key; - char path[20]; - char *str; - int err; - - snprintk(path, sizeof(path), "bt/mesh/AppKey/%x", app_idx); - - app = bt_mesh_app_key_get(app_idx); - if (!app) { - BT_WARN("ApKeyIndex 0x%03x not found", app_idx); - return; - } - - key.net_idx = app->net_idx, - key.updated = app->updated, - - memcpy(key.val[0], app->keys[0].val, 16); - memcpy(key.val[1], app->keys[1].val, 16); - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode AppKey as value"); - return; - } - - snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app->app_idx); - - BT_DBG("Saving AppKey %s as value %s", path, str); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store AppKey"); - } else { - BT_DBG("Stored AppKey"); - } -} - -static void store_pending_keys(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(key_updates); i++) { - struct key_update *update = &key_updates[i]; - - if (!update->valid) { - continue; - } - - if (update->clear) { - if (update->app_key) { - clear_app_key(update->key_idx); - } else { - clear_net_key(update->key_idx); - } - } else { - store_subnet(update->key_idx); - } - - update->valid = 0; - } -} - -#if MYNEWT_VAL(BLE_MESH_CDB) -static void clear_cdb(void) -{ - int err; - - err = settings_save_one("bt/mesh/cdb/Net", NULL); - if (err) { - BT_ERR("Failed to clear Network"); - } else { - BT_DBG("Cleared Network"); - } -} - -static void store_pending_cdb(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct cdb_net_val))]; - struct cdb_net_val net; - int err; - char *str; - - BT_DBG(""); - - net.iv_index = bt_mesh_cdb.iv_index; - net.iv_update = atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_IVU_IN_PROGRESS); - - str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Network as value"); - return; - } - err = settings_save_one("bt/mesh/cdb/Net", str); - if (err) { - BT_ERR("Failed to store Network value"); - } else { - BT_DBG("Stored Network value"); - } -} - -static void store_cdb_node(const struct bt_mesh_cdb_node *node) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct node_val))]; - struct node_val val; - char path[30]; - char *str; - int err; - - val.net_idx = node->net_idx; - val.num_elem = node->num_elem; - val.flags = 0; - - if (atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) { - val.flags |= F_NODE_CONFIGURED; - } - - memcpy(val.uuid, node->uuid, 16); - memcpy(val.dev_key, node->dev_key, 16); - - snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", node->addr); - - str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Node as value"); - return; - } - - - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store Node %s value", path); - } else { - BT_DBG("Stored Node %s value", path); - } -} - -static void clear_cdb_node(uint16_t addr) -{ - char path[30]; - int err; - - BT_DBG("Node 0x%04x", addr); - - snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", addr); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear Node 0x%04x", addr); - } else { - BT_DBG("Cleared Node 0x%04x", addr); - } -} - -static void store_pending_cdb_nodes(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cdb_node_updates); ++i) { - struct node_update *update = &cdb_node_updates[i]; - - if (update->addr == BT_MESH_ADDR_UNASSIGNED) { - continue; - } - - BT_DBG("addr: 0x%04x, clear: %d", update->addr, update->clear); - - if (update->clear) { - clear_cdb_node(update->addr); - } else { - struct bt_mesh_cdb_node *node; - - node = bt_mesh_cdb_node_get(update->addr); - if (node) { - store_cdb_node(node); - } else { - BT_WARN("Node 0x%04x not found", update->addr); - } - } - - update->addr = BT_MESH_ADDR_UNASSIGNED; - } -} - -static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))]; - struct net_key_val key; - char path[30]; - int err; - char *str; - - BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, - bt_hex(sub->keys[0].net_key, 16)); - - memcpy(&key.val[0], sub->keys[0].net_key, 16); - memcpy(&key.val[1], sub->keys[1].net_key, 16); - key.kr_flag = sub->kr_flag; - key.kr_phase = sub->kr_phase; - - snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", sub->net_idx); - - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Subnet as value"); - return; - } - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store Subnet value"); - } else { - BT_DBG("Stored Subnet value"); - } -} - -static void clear_cdb_subnet(uint16_t net_idx) -{ - char path[30]; - int err; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", net_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); - } else { - BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); - } -} - -static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - struct app_key_val key; - char path[30]; - int err; - char *str; - - key.net_idx = app->net_idx; - key.updated = false; - memcpy(key.val[0], app->keys[0].app_key, 16); - memcpy(key.val[1], app->keys[1].app_key, 16); - - snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app->app_idx); - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store AppKey"); - } else { - BT_DBG("Stored AppKey"); - } -} - -static void clear_cdb_app_key(uint16_t app_idx) -{ - char path[30]; - int err; - - snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); - } else { - BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); - } -} - -static void store_pending_cdb_keys(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { - struct key_update *update = &cdb_key_updates[i]; - - if (!update->valid) { - continue; - } - - if (update->clear) { - if (update->app_key) { - clear_cdb_app_key(update->key_idx); - } else { - clear_cdb_subnet(update->key_idx); - } - } else { - if (update->app_key) { - struct bt_mesh_cdb_app_key *key; - - key = bt_mesh_cdb_app_key_get(update->key_idx); - if (key) { - store_cdb_app_key(key); - } else { - BT_WARN("AppKeyIndex 0x%03x not found", - update->key_idx); - } - } else { - struct bt_mesh_cdb_subnet *sub; - - sub = bt_mesh_cdb_subnet_get(update->key_idx); - if (sub) { - store_cdb_subnet(sub); - } else { - BT_WARN("NetKeyIndex 0x%03x not found", - update->key_idx); - } - } - } - - update->valid = 0U; - } -} - -static struct node_update *cdb_node_update_find(uint16_t addr, - struct node_update **free_slot) -{ - struct node_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(cdb_node_updates); i++) { - struct node_update *update = &cdb_node_updates[i]; - - if (update->addr == BT_MESH_ADDR_UNASSIGNED) { - *free_slot = update; - continue; - } - - if (update->addr == addr) { - match = update; - } - } - - return match; -} -#endif - -static void encode_mod_path(struct bt_mesh_model *mod, bool vnd, - const char *key, char *path, size_t path_len) -{ - uint16_t mod_key = (((uint16_t)mod->elem_idx << 8) | mod->mod_idx); - - if (vnd) { - snprintk(path, path_len, "bt_mesh/v/%x/%s", mod_key, key); - } else { - snprintk(path, path_len, "bt_mesh/s/%x/%s", mod_key, key); - } -} - -static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd) -{ - uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT]; - char buf[BT_SETTINGS_SIZE(sizeof(keys))]; - char path[20]; - int i, count, err; - char *val; - - for (i = 0, count = 0; i < ARRAY_SIZE(mod->keys); i++) { - if (mod->keys[i] != BT_MESH_KEY_UNUSED) { - keys[count++] = mod->keys[i]; - } - } - - if (count) { - val = settings_str_from_bytes(keys, count * sizeof(keys[0]), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model bindings as value"); - return; - } - } else { - val = NULL; - } - - encode_mod_path(mod, vnd, "bind", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store bind"); - } else { - BT_DBG("Stored bind"); - } -} - -static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) -{ - uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT]; - char buf[BT_SETTINGS_SIZE(sizeof(groups))]; - char path[20]; - int i, count, err; - char *val; - - for (i = 0, count = 0; i < CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - groups[count++] = mod->groups[i]; - } - } - - if (count) { - val = settings_str_from_bytes(groups, count * sizeof(groups[0]), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model subscription as value"); - return; - } - } else { - val = NULL; - } - - encode_mod_path(mod, vnd, "sub", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store sub"); - } else { - BT_DBG("Stored sub"); - } -} - -static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; - struct mod_pub_val pub; - char path[20]; - char *val; - int err; - - if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - val = NULL; - } else { - pub.addr = mod->pub->addr; - pub.key = mod->pub->key; - pub.ttl = mod->pub->ttl; - pub.retransmit = mod->pub->retransmit; - pub.period = mod->pub->period; - pub.period_div = mod->pub->period_div; - pub.cred = mod->pub->cred; - - val = settings_str_from_bytes(&pub, sizeof(pub), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return; - } - } - - encode_mod_path(mod, vnd, "pub", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store pub"); - } else { - BT_DBG("Stored pub"); - } -} - -static void store_pending_mod(struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, bool vnd, - bool primary, void *user_data) -{ - if (!mod->flags) { - return; - } - - if (mod->flags & BT_MESH_MOD_BIND_PENDING) { - mod->flags &= ~BT_MESH_MOD_BIND_PENDING; - store_pending_mod_bind(mod, vnd); - } - - if (mod->flags & BT_MESH_MOD_SUB_PENDING) { - mod->flags &= ~BT_MESH_MOD_SUB_PENDING; - store_pending_mod_sub(mod, vnd); - } - - if (mod->flags & BT_MESH_MOD_PUB_PENDING) { - mod->flags &= ~BT_MESH_MOD_PUB_PENDING; - store_pending_mod_pub(mod, vnd); - } -} - -#define IS_VA_DEL(_label) ((_label)->ref == 0) -static void store_pending_va(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct va_val))]; - struct bt_mesh_va *lab; - struct va_val va; - char path[18]; - char *val; - uint16_t i; - int err = 0; - - for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { - if (!lab->changed) { - continue; - } - - lab->changed = 0U; - - snprintk(path, sizeof(path), "bt_mesh/Va/%x", i); - - if (IS_VA_DEL(lab)) { - val = NULL; - } else { - va.ref = lab->ref; - va.addr = lab->addr; - memcpy(va.uuid, lab->uuid, 16); - - val = settings_str_from_bytes(&va, sizeof(va), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return; - } - - err = settings_save_one(path, val); - } - - if (err) { - BT_ERR("Failed to %s %s value (err %d)", - IS_VA_DEL(lab) ? "delete" : "store", path, err); - } else { - BT_DBG("%s %s value", - IS_VA_DEL(lab) ? "Deleted" : "Stored", path); - } - } -} - -static void store_pending(struct ble_npl_event *work) -{ - BT_DBG(""); - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_RPL_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_rpl_foreach(store_pending_rpl, NULL); - } else { - bt_mesh_rpl_foreach(clear_rpl, NULL); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_KEYS_PENDING)) { - store_pending_keys(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_NET_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_net(); - } else { - clear_net(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_IV_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_iv(); - } else { - clear_iv(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_SEQ_PENDING)) { - store_pending_seq(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_HB_PUB_PENDING)) { - store_pending_hb_pub(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_CFG_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_cfg(); - } else { - clear_cfg(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) { - bt_mesh_model_foreach(store_pending_mod, NULL); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_VA_PENDING)) { - store_pending_va(); - } - -#if MYNEWT_VAL(BLE_MESH_CDB) - if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_SUBNET_PENDING)) { - if (atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_VALID)) { - store_pending_cdb(); - } else { - clear_cdb(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_NODES_PENDING)) { - store_pending_cdb_nodes(); - } - - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_KEYS_PENDING)) { - store_pending_cdb_keys(); - } - } -#endif -} - -void bt_mesh_store_rpl(struct bt_mesh_rpl *entry) -{ - entry->store = true; - schedule_store(BT_MESH_RPL_PENDING); -} - -static struct key_update *key_update_find(bool app_key, uint16_t key_idx, - struct key_update **free_slot) -{ - struct key_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(key_updates); i++) { - struct key_update *update = &key_updates[i]; - - if (!update->valid) { - *free_slot = update; - continue; - } - - if (update->app_key != app_key) { - continue; - } - - if (update->key_idx == key_idx) { - match = update; - } - } - - return match; -} - -void bt_mesh_store_subnet(uint16_t net_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - update = key_update_find(false, net_idx, &free_slot); - if (update) { - update->clear = 0; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_subnet(net_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = net_idx; - free_slot->app_key = 0; - free_slot->clear = 0; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_store_app_key(uint16_t app_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - update = key_update_find(true, app_idx, &free_slot); - if (update) { - update->clear = 0; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_app(app_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = app_idx; - free_slot->app_key = 1; - free_slot->clear = 0; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_store_hb_pub(void) -{ - schedule_store(BT_MESH_HB_PUB_PENDING); -} - -void bt_mesh_store_cfg(void) -{ - schedule_store(BT_MESH_CFG_PENDING); -} - -void bt_mesh_clear_net(void) -{ - schedule_store(BT_MESH_NET_PENDING); - schedule_store(BT_MESH_IV_PENDING); - schedule_store(BT_MESH_CFG_PENDING); -} - -void bt_mesh_clear_subnet(uint16_t net_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - update = key_update_find(false, net_idx, &free_slot); - if (update) { - update->clear = 1; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_net_key(net_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = net_idx; - free_slot->app_key = 0; - free_slot->clear = 1; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_clear_app_key(uint16_t app_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - update = key_update_find(true, app_idx, &free_slot); - if (update) { - update->clear = 1; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_app_key(app_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = app_idx; - free_slot->app_key = 1; - free_slot->clear = 1; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_clear_rpl(void) -{ - schedule_store(BT_MESH_RPL_PENDING); -} - -void bt_mesh_store_mod_bind(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_BIND_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - -void bt_mesh_store_mod_sub(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_SUB_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - -void bt_mesh_store_mod_pub(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_PUB_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - - -void bt_mesh_store_label(void) -{ - schedule_store(BT_MESH_VA_PENDING); -} - -#if MYNEWT_VAL(BLE_MESH_CDB) -static void schedule_cdb_store(int flag) -{ - atomic_set_bit(bt_mesh_cdb.flags, flag); - k_delayed_work_submit(&pending_store, K_NO_WAIT); -} - -void bt_mesh_store_cdb(void) -{ - schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING); -} - -void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node) -{ - struct node_update *update, *free_slot; - - BT_DBG("Node 0x%04x", node->addr); - - update = cdb_node_update_find(node->addr, &free_slot); - if (update) { - update->clear = false; - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); - return; - } - - if (!free_slot) { - store_cdb_node(node); - return; - } - - free_slot->addr = node->addr; - free_slot->clear = false; - - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); -} - -void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node) -{ - struct node_update *update, *free_slot; - - BT_DBG("Node 0x%04x", node->addr); - - update = cdb_node_update_find(node->addr, &free_slot); - if (update) { - update->clear = true; - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_node(node->addr); - return; - } - - free_slot->addr = node->addr; - free_slot->clear = true; - - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); -} - -/* TODO: Could be shared with key_update_find? */ -static struct key_update *cdb_key_update_find(bool app_key, uint16_t key_idx, - struct key_update **free_slot) -{ - struct key_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { - struct key_update *update = &cdb_key_updates[i]; - - if (!update->valid) { - *free_slot = update; - continue; - } - - if (update->app_key != app_key) { - continue; - } - - if (update->key_idx == key_idx) { - match = update; - } - } - - return match; -} - -void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); - - update = cdb_key_update_find(false, sub->net_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_cdb_subnet(sub); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; - free_slot->app_key = 0U; - free_slot->clear = 0U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); - - update = cdb_key_update_find(false, sub->net_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_subnet(sub->net_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; - free_slot->app_key = 0U; - free_slot->clear = 1U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *key) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); - - update = cdb_key_update_find(true, key->app_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_cdb_app_key(key); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; - free_slot->app_key = 1U; - free_slot->clear = 0U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *key) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); - - update = cdb_key_update_find(true, key->app_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_app_key(key->app_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; - free_slot->app_key = 1U; - free_slot->clear = 1U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} -#endif - -int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, - const char *name, const void *data, - size_t data_len) -{ - char path[30]; - char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; - char *val; - int err; - - encode_mod_path(mod, vnd, "data", path, sizeof(path)); - if (name) { - strcat(path, "/"); - strncat(path, name, 8); - } - - if (data_len) { - val = settings_str_from_bytes(data, data_len, - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return -EINVAL; - } - err = settings_save_one(path, val); - } else { - err = settings_save_one(path, NULL); - } - - if (err) { - BT_ERR("Failed to store %s value", path); - } else { - BT_DBG("Stored %s value", path); - } - return err; } static struct conf_handler bt_mesh_settings_conf_handler = { .ch_name = "bt_mesh", .ch_get = NULL, - .ch_set = mesh_set, + .ch_set = NULL, .ch_commit = mesh_commit, .ch_export = NULL, }; @@ -2458,7 +210,7 @@ void bt_mesh_settings_init(void) SYSINIT_PANIC_ASSERT_MSG(rc == 0, "Failed to register bt_mesh_settings conf"); - k_delayed_work_init(&pending_store, store_pending); + k_work_init_delayable(&pending_store, store_pending); } #endif /* MYNEWT_VAL(BLE_MESH_SETTINGS) */ diff --git a/nimble/host/mesh/src/settings.h b/nimble/host/mesh/src/settings.h index 9060a14a72..73105fb345 100644 --- a/nimble/host/mesh/src/settings.h +++ b/nimble/host/mesh/src/settings.h @@ -3,30 +3,24 @@ * * SPDX-License-Identifier: Apache-2.0 */ +/* Pending storage actions. */ +enum bt_mesh_settings_flag { + BT_MESH_SETTINGS_RPL_PENDING, + BT_MESH_SETTINGS_NET_KEYS_PENDING, + BT_MESH_SETTINGS_APP_KEYS_PENDING, + BT_MESH_SETTINGS_NET_PENDING, + BT_MESH_SETTINGS_IV_PENDING, + BT_MESH_SETTINGS_SEQ_PENDING, + BT_MESH_SETTINGS_HB_PUB_PENDING, + BT_MESH_SETTINGS_CFG_PENDING, + BT_MESH_SETTINGS_MOD_PENDING, + BT_MESH_SETTINGS_VA_PENDING, + BT_MESH_SETTINGS_CDB_PENDING, -void bt_mesh_store_net(void); -void bt_mesh_store_iv(bool only_duration); -void bt_mesh_store_seq(void); -void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl); -void bt_mesh_store_subnet(uint16_t net_idx); -void bt_mesh_store_app_key(uint16_t app_idx); -void bt_mesh_store_hb_pub(void); -void bt_mesh_store_cfg(void); -void bt_mesh_store_mod_bind(struct bt_mesh_model *mod); -void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); -void bt_mesh_store_mod_pub(struct bt_mesh_model *mod); -void bt_mesh_store_label(void); -void bt_mesh_store_cdb(void); -void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node); -void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub); -void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *app); - -void bt_mesh_clear_net(void); -void bt_mesh_clear_subnet(uint16_t net_idx); -void bt_mesh_clear_app_key(uint16_t app_idx); -void bt_mesh_clear_rpl(void); -void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node); -void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub); -void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *app); + BT_MESH_SETTINGS_FLAG_COUNT, +}; void bt_mesh_settings_init(void); +int settings_name_next(char *name, char **next); +void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag); +void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag); diff --git a/nimble/host/mesh/src/shell.c b/nimble/host/mesh/src/shell.c index 1ac4cafe68..e905231081 100644 --- a/nimble/host/mesh/src/shell.c +++ b/nimble/host/mesh/src/shell.c @@ -169,7 +169,7 @@ static struct bt_mesh_cfg_cli cfg_cli = { #endif /* MYNEWT_VAL(BLE_MESH_CFG_CLI) */ #if MYNEWT_VAL(BLE_MESH_HEALTH_CLI) -void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) +static void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) { size_t i; @@ -707,10 +707,9 @@ static int check_pub_addr_unassigned(void) #ifdef ARCH_sim return 0; #else - uint8_t zero_addr[BLE_DEV_ADDR_LEN] = { 0 }; + uint8_t addr[BLE_DEV_ADDR_LEN]; - return memcmp(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), - zero_addr, BLE_DEV_ADDR_LEN) == 0; + return ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr, NULL) != 0; #endif } @@ -738,7 +737,7 @@ int cmd_mesh_init(int argc, char *argv[]) printk("Mesh initialized\n"); - if (IS_ENABLED(CONFIG_SETTINGS)) { + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { settings_load(); } @@ -997,78 +996,79 @@ struct shell_cmd_help cmd_timeout_help = { static int cmd_get_comp(int argc, char *argv[]) { - struct os_mbuf *comp = NET_BUF_SIMPLE(32); - uint8_t status, page = 0x00; + struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); + struct bt_mesh_comp_p0_elem elem; + struct bt_mesh_comp_p0 comp; + uint8_t page = 0x00; int err = 0; if (argc > 1) { page = strtol(argv[1], NULL, 0); } - net_buf_simple_init(comp, 0); - err = bt_mesh_cfg_comp_data_get(net.net_idx, net.dst, page, - &status, comp); + net_buf_simple_init(buf, 0); + err = bt_mesh_cfg_comp_data_get(net.net_idx, net.dst, page, &page, + buf); if (err) { printk("Getting composition failed (err %d)\n", err); goto done; } - if (status != 0x00) { - printk("Got non-success status 0x%02x\n", status); + if (page != 0x00) { + printk("Got page 0x%02x. No parser available.", + page); goto done; } - printk("Got Composition Data for 0x%04x:\n", net.dst); - printk("\tCID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tPID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tVID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tCRPL 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tFeatures 0x%04x\n", net_buf_simple_pull_le16(comp)); - - while (comp->om_len > 4) { - uint8_t sig, vnd; - uint16_t loc; - int i; - - loc = net_buf_simple_pull_le16(comp); - sig = net_buf_simple_pull_u8(comp); - vnd = net_buf_simple_pull_u8(comp); + err = bt_mesh_comp_p0_get(&comp, buf); + if (err) { + printk("Getting composition failed (err %d)\n", err); + goto done; + } - printk("\n\tElement @ 0x%04x:\n", loc); + printk("Got Composition Data for 0x%04x:", net.dst); + printk("\tCID 0x%04x", comp.cid); + printk("\tPID 0x%04x", comp.pid); + printk("\tVID 0x%04x", comp.vid); + printk("\tCRPL 0x%04x", comp.crpl); + printk("\tFeatures 0x%04x", comp.feat); - if (comp->om_len < ((sig * 2) + (vnd * 4))) { - printk("\t\t...truncated data!\n"); - break; - } + while (bt_mesh_comp_p0_elem_pull(&comp, &elem)) { + int i; - if (sig) { + printk("\tElement @ 0x%04x:", elem.loc); + if (elem.nsig) { printk("\t\tSIG Models:\n"); } else { printk("\t\tNo SIG Models\n"); } - for (i = 0; i < sig; i++) { - uint16_t mod_id = net_buf_simple_pull_le16(comp); + for (i = 0; i < elem.nsig; i++) { + uint16_t mod_id = bt_mesh_comp_p0_elem_mod(&elem, i); printk("\t\t\t0x%04x\n", mod_id); } - if (vnd) { + if (elem.nvnd) { printk("\t\tVendor Models:\n"); } else { printk("\t\tNo Vendor Models\n"); } - for (i = 0; i < vnd; i++) { - uint16_t cid = net_buf_simple_pull_le16(comp); - uint16_t mod_id = net_buf_simple_pull_le16(comp); + for (i = 0; i < elem.nvnd; i++) { + struct bt_mesh_mod_id_vnd mod = + bt_mesh_comp_p0_elem_mod_vnd(&elem, i); - printk("\t\t\tCompany 0x%04x: 0x%04x\n", cid, mod_id); + printk("\t\t\tCompany 0x%04x: 0x%04x", + mod.company, mod.id); } } + if (buf->om_len) { + printk("\t\t...truncated data!"); + } done: - os_mbuf_free_chain(comp); + os_mbuf_free_chain(buf); return err; } @@ -2001,6 +2001,7 @@ static int mod_pub_set(uint16_t addr, uint16_t mod_id, uint16_t cid, char *argv[ int err; pub.addr = strtoul(argv[0], NULL, 0); + pub.uuid = NULL; pub.app_idx = strtoul(argv[1], NULL, 0); pub.cred_flag = str2bool(argv[2]); pub.ttl = strtoul(argv[3], NULL, 0); @@ -2345,7 +2346,7 @@ static int cmd_provision(int argc, char *argv[]) return 0; } - net_key = sub->keys[sub->kr_flag].net_key; + net_key = sub->keys[SUBNET_KEY_TX_IDX(sub)].net_key; } err = bt_mesh_provision(net_key, net_idx, 0, iv_index, addr, @@ -2905,8 +2906,8 @@ static int cmd_cdb_node_add(int argc, char *argv[]) memcpy(node->dev_key, dev_key, 16); - if (IS_ENABLED(CONFIG_SETTINGS)) { - bt_mesh_store_cdb_node(node); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_cdb_node_store(node); } printk("Added node 0x%04x", addr); @@ -2959,8 +2960,8 @@ static int cmd_cdb_subnet_add(int argc, memcpy(sub->keys[0].net_key, net_key, 16); - if (IS_ENABLED(CONFIG_SETTINGS)) { - bt_mesh_store_cdb_subnet(sub); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_cdb_subnet_store(sub); } printk("Added Subnet 0x%03x", net_idx); @@ -3015,8 +3016,8 @@ static int cmd_cdb_app_key_add(int argc, memcpy(key->keys[0].app_key, app_key, 16); - if (IS_ENABLED(CONFIG_SETTINGS)) { - bt_mesh_store_cdb_app_key(key); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_cdb_app_key_store(key); } printk("Added AppKey 0x%03x", app_idx); diff --git a/nimble/host/mesh/src/subnet.c b/nimble/host/mesh/src/subnet.c index d6fcfbeee7..9108cc471f 100644 --- a/nimble/host/mesh/src/subnet.c +++ b/nimble/host/mesh/src/subnet.c @@ -4,7 +4,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ - +#include #include "syscfg/syscfg.h" #define MESH_LOG_MODULE BLE_MESH_NET_KEYS_LOG @@ -26,6 +26,26 @@ #include "settings.h" #include "prov.h" +/* Tracking of what storage changes are pending for Net Keys. We track this in + * a separate array here instead of within the respective bt_mesh_subnet + * struct itselve, since once a key gets deleted its struct becomes invalid + * and may be reused for other keys. + */ +struct net_key_update { + uint16_t key_idx:12, /* NetKey Index */ + valid:1, /* 1 if this entry is valid, 0 if not */ + clear:1; /* 1 if key needs clearing, 0 if storing */ +}; + +/* NetKey storage information */ +struct net_key_val { + uint8_t kr_flag:1, + kr_phase:7; + uint8_t val[2][16]; +} __packed; + +static struct net_key_update net_key_updates[CONFIG_BT_MESH_SUBNET_COUNT]; + #ifdef CONFIG_BT_MESH_GATT_PROXY void (*bt_mesh_subnet_cb_list[5]) (struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt); @@ -51,6 +71,91 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) } } +static void clear_net_key(uint16_t net_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[20]; + int err; + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); + } else { + BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); + } +#endif +} + +static void store_subnet(uint16_t net_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + const struct bt_mesh_subnet *sub; + struct net_key_val key; + char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))]; + char path[20]; + char *str; + int err; + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + BT_WARN("NetKeyIndex 0x%03x not found", net_idx); + return; + } + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx); + + memcpy(&key.val[0], sub->keys[0].net, 16); + memcpy(&key.val[1], sub->keys[1].net, 16); + key.kr_flag = 0U; /* Deprecated */ + key.kr_phase = sub->kr_phase; + + str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode AppKey as value"); + return; + } + + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store NetKey"); + } else { + BT_DBG("Stored NetKey"); + } +#endif +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct net_key_update *net_key_update_find(uint16_t key_idx, + struct net_key_update **free_slot) +{ + struct net_key_update *match; + int i; + + match = NULL; + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(net_key_updates); i++) { + struct net_key_update *update = &net_key_updates[i]; + + if (!update->valid) { + *free_slot = update; + continue; + } + + if (update->key_idx == key_idx) { + match = update; + } + } + + return match; +} +#endif + uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) { uint8_t flags = 0x00; @@ -66,6 +171,46 @@ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) return flags; } +static void update_subnet_settings(uint16_t net_idx, bool store) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + struct net_key_update *update, *free_slot; + uint8_t clear = store ? 0U : 1U; + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + update = net_key_update_find(net_idx, &free_slot); + if (update) { + update->clear = clear; + bt_mesh_settings_store_schedule( + BT_MESH_SETTINGS_NET_KEYS_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_subnet(net_idx); + } else { + clear_net_key(net_idx); + } + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = net_idx; + free_slot->clear = clear; + + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_KEYS_PENDING); +#endif +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +void bt_mesh_subnet_store(uint16_t net_idx) +{ + update_subnet_settings(net_idx, true); +} +#endif + static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase) { BT_DBG("Phase 0x%02x -> 0x%02x", sub->kr_phase, new_phase); @@ -97,7 +242,7 @@ static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase) if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing Updated NetKey persistently"); - bt_mesh_store_subnet(sub->net_idx); + bt_mesh_subnet_store(sub->net_idx); } } @@ -139,7 +284,7 @@ static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx) static void subnet_del(struct bt_mesh_subnet *sub) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_subnet(sub->net_idx); + update_subnet_settings(sub->net_idx, false); } bt_mesh_net_loopback_clear(sub->net_idx); @@ -242,7 +387,7 @@ uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16]) if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing NetKey persistently"); - bt_mesh_store_subnet(sub->net_idx); + bt_mesh_subnet_store(sub->net_idx); } return STATUS_SUCCESS; @@ -664,3 +809,77 @@ bool bt_mesh_net_cred_find(struct bt_mesh_net_rx *rx, struct os_mbuf *in, return false; } + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int net_key_set(int argc, char **argv, char *val) +{ + struct net_key_val key; + int len, err; + uint16_t net_idx; + + BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); + + net_idx = strtol(argv[0], NULL, 16); + + len = sizeof(key); + err = settings_bytes_from_str(val, &key, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(key)) { + BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(key)); + return -EINVAL; + } + + BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); + + return bt_mesh_subnet_set( + net_idx, key.kr_phase, key.val[0], + (key.kr_phase != BT_MESH_KR_NORMAL) ? key.val[1] : NULL); +} +#endif + +void bt_mesh_subnet_pending_store(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(net_key_updates); i++) { + struct net_key_update *update = &net_key_updates[i]; + + if (!update->valid) { + continue; + } + + if (update->clear) { + clear_net_key(update->key_idx); + } else { + store_subnet(update->key_idx); + } + + update->valid = 0U; + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_net_key_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = net_key_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_net_key_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_net_key_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_net_key conf"); +#endif +} diff --git a/nimble/host/mesh/src/subnet.h b/nimble/host/mesh/src/subnet.h index 154b5d4e31..b64177d364 100644 --- a/nimble/host/mesh/src/subnet.h +++ b/nimble/host/mesh/src/subnet.h @@ -37,7 +37,7 @@ struct bt_mesh_subnet { uint8_t beacons_last; /* Number of beacons during last * observation window */ - uint8_t beacons_cur; /* Number of beaconds observed during + uint8_t beacons_cur; /* Number of beacons observed during * currently ongoing window. */ @@ -194,4 +194,13 @@ bt_mesh_subnet_has_new_key(const struct bt_mesh_subnet *sub) return sub->kr_phase != BT_MESH_KR_NORMAL; } -#endif /* _BLUETOOTH_MESH_SUBNET_H_ */ \ No newline at end of file +/** @brief Store the Subnet information in persistent storage. + * + * @param net_idx Network index to store. + */ +void bt_mesh_subnet_store(uint16_t net_idx); + +/** @brief Store the pending Subnets in persistent storage. */ +void bt_mesh_subnet_pending_store(void); +void bt_mesh_net_key_init(void); +#endif /* _BLUETOOTH_MESH_SUBNET_H_ */ diff --git a/nimble/host/mesh/src/testing.c b/nimble/host/mesh/src/testing.c index dfe8d18e3d..7ee11a1373 100644 --- a/nimble/host/mesh/src/testing.c +++ b/nimble/host/mesh/src/testing.c @@ -135,8 +135,6 @@ void bt_test_print_credentials(void) console_printf("Subnet: %d\n", i); console_printf("\tNetKeyIdx: %04x\n", sub->net_idx); - console_printf("\tNetKey: %s\n", - bt_hex(sub->keys[sub->kr_flag].net_key, 16)); } for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) @@ -154,8 +152,6 @@ void bt_test_print_credentials(void) app_key->net_idx); console_printf("\tAppKeyIdx: %04x\n", app_key->app_idx); - console_printf("\tAppKey: %s\n", - bt_hex(app_key->keys[sub->kr_flag].app_key, 16)); } for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) diff --git a/nimble/host/mesh/src/transport.c b/nimble/host/mesh/src/transport.c index f3a7c2d601..d563c9fa05 100644 --- a/nimble/host/mesh/src/transport.c +++ b/nimble/host/mesh/src/transport.c @@ -11,6 +11,7 @@ #include #include +#include #include "mesh/mesh.h" #include "mesh/glue.h" @@ -69,6 +70,20 @@ /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT +struct virtual_addr { + uint16_t ref:15, + changed:1; + uint16_t addr; + uint8_t uuid[16]; +}; + +/* Virtual Address information for persistent storage. */ +struct va_val { + uint16_t ref; + uint16_t addr; + uint8_t uuid[16]; +} __packed; + static struct seg_tx { struct bt_mesh_subnet *sub; void *seg[CONFIG_BT_MESH_TX_SEG_MAX]; @@ -92,7 +107,7 @@ static struct seg_tx { friend_cred:1; /* Using Friend credentials */ const struct bt_mesh_send_cb *cb; void *cb_data; - struct k_delayed_work retransmit; /* Retransmit timer */ + struct k_work_delayable retransmit; /* Retransmit timer */ } seg_tx[MYNEWT_VAL(BLE_MESH_TX_SEG_MSG_COUNT)]; static struct seg_rx { @@ -110,20 +125,21 @@ static struct seg_rx { uint8_t ttl; uint32_t block; uint32_t last; - struct k_delayed_work ack; + struct k_work_delayable ack; } seg_rx[CONFIG_BT_MESH_RX_SEG_MSG_COUNT]; -char _k_mem_slab_buffer_[(BT_MESH_APP_SEG_SDU_MAX*CONFIG_BT_MESH_SEG_BUFS)]; + +char _k_mem_slab_buffer_[OS_ALIGN((BT_MESH_APP_SEG_SDU_MAX)*(CONFIG_BT_MESH_SEG_BUFS), OS_ALIGNMENT)]; struct k_mem_slab segs = { .num_blocks = CONFIG_BT_MESH_SEG_BUFS, - .block_size = BT_MESH_APP_SEG_SDU_MAX, + .block_size = OS_ALIGN(BT_MESH_APP_SEG_SDU_MAX, OS_ALIGNMENT), .buffer = _k_mem_slab_buffer_, .free_list = NULL, .num_used = 0 }; -static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; +static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; static int send_unseg(struct bt_mesh_net_tx *tx, struct os_mbuf *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, @@ -232,7 +248,7 @@ static void seg_tx_unblock_check(struct seg_tx *tx) BT_DBG("Unblocked 0x%04x", (uint16_t)(blocked->seq_auth & TRANS_SEQ_ZERO_MASK)); blocked->blocked = false; - k_delayed_work_submit(&blocked->retransmit, 0); + k_work_reschedule(&blocked->retransmit, 0); } } @@ -240,7 +256,8 @@ static void seg_tx_reset(struct seg_tx *tx) { int i; - k_delayed_work_cancel(&tx->retransmit); + /* If this call fails, the handler will exit early, as nack_count is 0. */ + (void)k_work_cancel_delayable(&tx->retransmit); tx->cb = NULL; tx->cb_data = NULL; @@ -301,8 +318,9 @@ static void schedule_retransmit(struct seg_tx *tx) * called this from inside bt_mesh_net_send), we should continue the * retransmit immediately, as we just freed up a tx buffer. */ - k_delayed_work_submit(&tx->retransmit, - tx->seg_o ? 0 : K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); + k_work_reschedule(&tx->retransmit, + tx->seg_o ? K_NO_WAIT : + K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); } static void seg_send_start(uint16_t duration, int err, void *user_data) @@ -423,8 +441,8 @@ static void seg_tx_send_unacked(struct seg_tx *tx) tx->attempts--; end: if (!tx->seg_pending) { - k_delayed_work_submit(&tx->retransmit, - SEG_RETRANSMIT_TIMEOUT(tx)); + k_work_reschedule(&tx->retransmit, + K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); } tx->sending = 0U; @@ -614,12 +632,12 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct os_mbuf *msg, return -EINVAL; } - if (msg->om_len > BT_MESH_TX_SDU_MAX) { - BT_ERR("Not enough segment buffers for length %u", msg->om_len); + if (msg->om_len > BT_MESH_TX_SDU_MAX - BT_MESH_MIC_SHORT) { + BT_ERR("Message too big: %u", msg->om_len); return -EMSGSIZE; } - if (net_buf_simple_tailroom(msg) < 4) { + if (net_buf_simple_tailroom(msg) < BT_MESH_MIC_SHORT) { BT_ERR("Insufficient tailroom for Transport MIC"); return -EINVAL; } @@ -642,15 +660,15 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct os_mbuf *msg, return -EINVAL; } - BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, - tx->ctx->app_idx, tx->ctx->addr); - BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_len)); - err = bt_mesh_keys_resolve(tx->ctx, &tx->sub, &key, &aid); if (err) { return err; } + BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, + tx->ctx->app_idx, tx->ctx->addr); + BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_len)); + tx->xmit = bt_mesh_net_transmit_get(); tx->aid = aid; @@ -844,8 +862,6 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, return -EINVAL; } - k_delayed_work_cancel(&tx->retransmit); - while ((bit = find_lsb_set(ack))) { if (tx->seg[bit - 1]) { BT_DBG("seg %u/%u acked", bit - 1, tx->seg_n); @@ -856,7 +872,11 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, } if (tx->nack_count) { - seg_tx_send_unacked(tx); + /* According to the Bluetooth Mesh Profile specification, + * section 3.5.3.3, we should reset the retransmit timer and + * retransmit immediately when receiving a valid ack message: + */ + k_work_reschedule(&tx->retransmit, K_NO_WAIT); } else { BT_DBG("SDU TX complete"); seg_tx_complete(tx, 0); @@ -1078,7 +1098,10 @@ static void seg_rx_reset(struct seg_rx *rx, bool full_reset) BT_DBG("rx %p", rx); - k_delayed_work_cancel(&rx->ack); + /* If this fails, the handler will exit early on the next execution, as + * it checks rx->in_use. + */ + (void)k_work_cancel_delayable(&rx->ack); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->obo && rx->block != BLOCK_COMPLETE(rx->seg_n)) { @@ -1115,6 +1138,16 @@ static void seg_ack(struct ble_npl_event *work) struct seg_rx *rx = ble_npl_event_get_arg(work); int32_t timeout; + if (!rx->in_use || rx->block == BLOCK_COMPLETE(rx->seg_n)) { + /* Cancellation of this timer may have failed. If it fails as + * part of seg_reset, in_use will be false. + * If it fails as part of the processing of a fully received + * SDU, the ack is already being sent from the receive handler, + * and the timer based ack sending can be ignored. + */ + return; + } + BT_DBG("rx %p", rx); if (k_uptime_get_32() - rx->last > K_SECONDS(60)) { @@ -1132,7 +1165,7 @@ static void seg_ack(struct ble_npl_event *work) rx->block, rx->obo); timeout = ack_timeout(rx); - k_delayed_work_submit(&rx->ack, K_MSEC(timeout)); + k_work_schedule(&rx->ack, K_MSEC(timeout)); } static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) @@ -1247,6 +1280,7 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, struct seg_rx *rx; uint8_t *hdr = buf->om_data; uint16_t seq_zero; + uint32_t auth_seqnum; uint8_t seg_n; uint8_t seg_o; int err; @@ -1298,6 +1332,7 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, ((((net_rx->seq & BIT_MASK(14)) - seq_zero)) & BIT_MASK(13)))); + auth_seqnum = *seq_auth & BIT_MASK(24); *seg_count = seg_n + 1; /* Look for old RX sessions */ @@ -1366,6 +1401,28 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, return -ENOBUFS; } + /* Keep track of the received SeqAuth values received from this address + * and discard segmented messages that are not newer, as described in + * the Bluetooth Mesh specification section 3.5.3.4. + * + * The logic on the first segmented receive is a bit special, since the + * initial value of rpl->seg is 0, which would normally fail the + * comparison check with auth_seqnum: + * - If this is the first time we receive from this source, rpl->src + * will be 0, and we can skip this check. + * - If this is the first time we receive from this source on the new IV + * index, rpl->old_iv will be set, and the check is also skipped. + * - If this is the first segmented message on the new IV index, but we + * have received an unsegmented message already, the unsegmented + * message will have reset rpl->seg to 0, and this message's SeqAuth + * cannot be zero. + */ + if (rpl && rpl->src && auth_seqnum <= rpl->seg && + (!rpl->old_iv || net_rx->old_iv)) { + BT_WARN("Ignoring old SeqAuth 0x%06x", auth_seqnum); + return -EALREADY; + } + /* Look for free slot for a new RX session */ rx = seg_rx_alloc(net_rx, hdr, seq_auth, seg_n); if (!rx) { @@ -1413,11 +1470,10 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, /* Reset the Incomplete Timer */ rx->last = k_uptime_get_32(); - if (!k_delayed_work_remaining_get(&rx->ack) && - !bt_mesh_lpn_established()) { + if (!bt_mesh_lpn_established()) { int32_t timeout = ack_timeout(rx); - - k_delayed_work_submit(&rx->ack, K_MSEC(timeout)); + /* Should only start ack timer if it isn't running already: */ + k_work_schedule(&rx->ack, K_MSEC(timeout)); } /* Allocated segment here */ @@ -1444,11 +1500,20 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, if (rpl) { bt_mesh_rpl_update(rpl, net_rx); + /* Update the seg, unless it has already been surpassed: + * This needs to happen after rpl_update to ensure that the IV + * update reset logic inside rpl_update doesn't overwrite the + * change. + */ + rpl->seg = MAX(rpl->seg, auth_seqnum); } *pdu_type = BT_MESH_FRIEND_PDU_COMPLETE; - k_delayed_work_cancel(&rx->ack); + /* If this fails, the work handler will either exit early because the + * block is fully received, or rx->in_use is false. + */ + (void)k_work_cancel_delayable(&rx->ack); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); @@ -1540,20 +1605,8 @@ int bt_mesh_trans_recv(struct os_mbuf *buf, struct bt_mesh_net_rx *rx) err = trans_unseg(buf, rx, &seq_auth); } - /* Notify LPN state machine so a Friend Poll will be sent. If the - * message was a Friend Update it's possible that a Poll was already - * queued for sending, however that's fine since then the - * bt_mesh_lpn_waiting_update() function will return false: - * we still need to go through the actual sending to the bearer and - * wait for ReceiveDelay before transitioning to WAIT_UPDATE state. - * Another situation where we want to notify the LPN state machine - * is if it's configured to use an automatic Friendship establishment - * timer, in which case we want to reset the timer at this point. - * - */ - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && - (bt_mesh_lpn_timer() || - (bt_mesh_lpn_established() && bt_mesh_lpn_waiting_update()))) { + /* Notify LPN state machine so a Friend Poll will be sent. */ + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { bt_mesh_lpn_msg_received(rx); } @@ -1583,6 +1636,13 @@ void bt_mesh_rx_reset(void) } } +static void store_va_label(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); +#endif +} + void bt_mesh_trans_reset(void) { int i; @@ -1605,7 +1665,7 @@ void bt_mesh_trans_reset(void) bt_mesh_rpl_clear(); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_label(); + store_va_label(); } } @@ -1616,43 +1676,34 @@ void bt_mesh_trans_init(void) /* We need to initialize memslab free list here */ rc = create_free_list(&segs); if (rc) { - BT_ERR("Failed to create free memslab list") + BT_ERR("Failed to create free memslab list (error: %d)", rc); } for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - k_delayed_work_init(&seg_tx[i].retransmit, seg_retransmit); - k_delayed_work_add_arg(&seg_tx[i].retransmit, &seg_tx[i]); + k_work_init_delayable(&seg_tx[i].retransmit, seg_retransmit); + k_work_add_arg_delayable(&seg_tx[i].retransmit, &seg_tx[i]); } /* XXX Probably we need mempool for that. * For now we increase MSYS_1_BLOCK_COUNT */ for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - k_delayed_work_init(&seg_rx[i].ack, seg_ack); - k_delayed_work_add_arg(&seg_rx[i].ack, &seg_rx[i]); - } -} - -struct bt_mesh_va *bt_mesh_va_get(uint16_t index) -{ - if (index >= ARRAY_SIZE(virtual_addrs)) { - return NULL; + k_work_init_delayable(&seg_rx[i].ack, seg_ack); + k_work_add_arg_delayable(&seg_rx[i].ack, &seg_rx[i]); } - - return &virtual_addrs[index]; } -static inline void va_store(struct bt_mesh_va *store) +static inline void va_store(struct virtual_addr *store) { store->changed = 1U; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_label(); + store_va_label(); } } -uint8_t bt_mesh_va_add(uint8_t uuid[16], uint16_t *addr) +uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr) { - struct bt_mesh_va *va = NULL; + struct virtual_addr *va = NULL; int err; for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { @@ -1692,9 +1743,9 @@ uint8_t bt_mesh_va_add(uint8_t uuid[16], uint16_t *addr) return STATUS_SUCCESS; } -uint8_t bt_mesh_va_del(uint8_t uuid[16], uint16_t *addr) +uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr) { - struct bt_mesh_va *va = NULL; + struct virtual_addr *va = NULL; for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { if (virtual_addrs[i].ref && @@ -1718,19 +1769,6 @@ uint8_t bt_mesh_va_del(uint8_t uuid[16], uint16_t *addr) return STATUS_SUCCESS; } -struct bt_mesh_va *bt_mesh_va_find(uint8_t uuid[16]) -{ - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && - !memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - return &virtual_addrs[i]; - } - } - - return NULL; -} - uint8_t *bt_mesh_va_label_get(uint16_t addr) { int i; @@ -1749,3 +1787,140 @@ uint8_t *bt_mesh_va_label_get(uint16_t addr) return NULL; } + +#if CONFIG_BT_MESH_LABEL_COUNT > 0 +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct virtual_addr *bt_mesh_va_get(uint16_t index) +{ + if (index >= ARRAY_SIZE(virtual_addrs)) { + return NULL; + } + + return &virtual_addrs[index]; +} + +static int va_set(int argc, char **argv, char *val) +{ + struct va_val va; + struct virtual_addr *lab; + uint16_t index; + int len, err; + + if (argc < 1) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + index = strtol(argv[0], NULL, 16); + + if (val == NULL) { + BT_WARN("Mesh Virtual Address length = 0"); + return 0; + } + + err = settings_bytes_from_str(val, &va, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + if (len != sizeof(struct va_val)) { + BT_ERR("Invalid length for virtual address"); + return -EINVAL; + } + + if (va.ref == 0) { + BT_WARN("Ignore Mesh Virtual Address ref = 0"); + return 0; + } + + lab = bt_mesh_va_get(index); + if (lab == NULL) { + BT_WARN("Out of labels buffers"); + return -ENOBUFS; + } + + memcpy(lab->uuid, va.uuid, 16); + lab->addr = va.addr; + lab->ref = va.ref; + + BT_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", + lab->addr, lab->ref); + + return 0; +} + +#define IS_VA_DEL(_label) ((_label)->ref == 0) +void bt_mesh_va_pending_store(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct va_val))]; + struct virtual_addr *lab; + struct va_val va; + char path[18]; + char *val; + uint16_t i; + int err = 0; + + for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { + if (!lab->changed) { + continue; + } + + lab->changed = 0U; + + snprintk(path, sizeof(path), "bt_mesh/Va/%x", i); + + if (IS_VA_DEL(lab)) { + val = NULL; + } else { + va.ref = lab->ref; + va.addr = lab->addr; + memcpy(va.uuid, lab->uuid, 16); + + val = settings_str_from_bytes(&va, sizeof(va), + buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model publication as value"); + return; + } + + err = settings_save_one(path, val); + } + + if (err) { + BT_ERR("Failed to %s %s value (err %d)", + IS_VA_DEL(lab) ? "delete" : "store", path, err); + } else { + BT_DBG("%s %s value", + IS_VA_DEL(lab) ? "Deleted" : "Stored", path); + } + } +} + +static struct conf_handler bt_mesh_va_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = va_set, + .ch_commit = NULL, + .ch_export = NULL, + }; +#endif + +void bt_mesh_va_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_va_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_hb_pub conf"); +#endif +} + +#else +void bt_mesh_va_pending_store(void) +{ + /* Do nothing. */ +} +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ diff --git a/nimble/host/mesh/src/transport.h b/nimble/host/mesh/src/transport.h index 23be7139d6..ad7a59f236 100644 --- a/nimble/host/mesh/src/transport.h +++ b/nimble/host/mesh/src/transport.h @@ -79,13 +79,6 @@ struct bt_mesh_ctl_friend_sub_confirm { uint8_t xact; }__attribute__((__packed__)); -struct bt_mesh_va { - uint16_t ref:15, - changed:1; - uint16_t addr; - uint8_t uuid[16]; -}; - bool bt_mesh_tx_in_progress(void); void bt_mesh_rx_reset(void); @@ -102,12 +95,12 @@ void bt_mesh_trans_init(void); void bt_mesh_trans_reset(void); -struct bt_mesh_va *bt_mesh_va_get(uint16_t index); +uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr); -struct bt_mesh_va *bt_mesh_va_find(uint8_t uuid[16]); +uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr); -uint8_t bt_mesh_va_add(uint8_t uuid[16], uint16_t *addr); +uint8_t *bt_mesh_va_label_get(uint16_t addr); -uint8_t bt_mesh_va_del(uint8_t uuid[16], uint16_t *addr); +void bt_mesh_va_pending_store(void); -uint8_t *bt_mesh_va_label_get(uint16_t addr); \ No newline at end of file +void bt_mesh_va_init(void); diff --git a/nimble/host/mesh/syscfg.yml b/nimble/host/mesh/syscfg.yml index cf0c7f7505..c75828d243 100644 --- a/nimble/host/mesh/syscfg.yml +++ b/nimble/host/mesh/syscfg.yml @@ -23,6 +23,11 @@ syscfg.defs: BLE_MESH_PB_ADV or BLE_MESH_PB_GATT is set. value: 1 + BLE_MESH_PROV_OOB_PUBLIC_KEY: + description: > + Enable this option if public key is to be exchanged via Out of Band (OOB) technology. + value: 0 + BLE_MESH_PB_ADV: description: > Enable this option to allow the device to be provisioned over @@ -63,7 +68,7 @@ syscfg.defs: description: > This option specifies how many nodes each network can at most save in the configuration database. - value: 1 + value: 8 BLE_MESH_CDB_SUBNET_COUNT: description: > @@ -82,17 +87,44 @@ syscfg.defs: Use this option to enable configuration database debug logs. value: 1 + BLE_MESH_DEBUG_CFG: + description: + Use this option to enable node configuration debug logs for the + Bluetooth Mesh functionality. + value: 1 + BLE_MESH_PROXY: description: > Enable proxy. This is automatically set whenever BLE_MESH_PB_GATT or BLE_MESH_GATT_PROXY is set. value: 0 + BLE_MESH_GATT: + value: 1 + + BLE_MESH_PROXY_MSG_LEN: + description: > + Integer value + value: + restrictions: BLE_MESH_GATT + + BLE_MESH_GATT_SERVER: + value: 1 + restrictions: BLE_MESH_GATT + BLE_MESH_PB_GATT: description: > Enable this option to allow the device to be provisioned over the GATT bearer. value: 1 + restrictions: + - '(BLE_MESH_GATT_SERVER && BLE_MESH_PROV)' + + BLE_MESH_PB_GATT_USE_DEVICE_NAME: + description: > + This option includes GAP device name in scan response when + the PB-GATT is enabled. + value: 1 BLE_MESH_GATT_PROXY: description: > @@ -100,6 +132,8 @@ syscfg.defs: i.e. the ability to act as a proxy between a Mesh GATT Client and a Mesh network. value: 1 + restrictions: + - '(BLE_MESH_GATT_SERVER && BLE_MESH_PROXY)' BLE_MESH_GATT_PROXY_ENABLED: description: > @@ -127,8 +161,22 @@ syscfg.defs: descryption: > This option specifies how many Proxy Filter entries the local node supports. + value: 3 + restrictions: BLE_MESH_GATT_PROXY + + BLE_MESH_ACCESS_LAYER_MSG: + descryption: > + This option allows the applicaiton to directly access + Bluetooth access layer messages without the need to + instantiate Bluetooth mesh models. value: 1 + BLE_MESH_PROXY_USE_DEVICE_NAME: + description: > + Include Bluetooth device name in scan response + value: 0 + restrictions: BLE_MESH_GATT_PROXY + BLE_MESH_SUBNET_COUNT: description: > This option specifies how many subnets a Mesh network can @@ -153,6 +201,12 @@ syscfg.defs: at most be subscribed to. value: 1 + BLE_MESH_MODEL_VND_MSG_CID_FORCE: + description: > + This option forces vendor model to use messages for the + corresponding CID field. + value: 1 + BLE_MESH_LABEL_COUNT: description: > This option specifies how many Label UUIDs can be stored. @@ -179,6 +233,11 @@ syscfg.defs: but has a different purpose. value: 10 + BLE_MESH_NET_BUF_USER_DATA_SIZE: + description: > + Number of octets that are used as user_data at the end of os_mbufs + value: 4 + BLE_MESH_ADV_BUF_COUNT: description: > Number of advertising buffers available. This should be chosen @@ -189,6 +248,37 @@ syscfg.defs: supported outgoing segment count (BT_MESH_TX_SEG_MAX). value: 6 + BLE_MESH_ADV: + description: > + Advertiser mode + value: 1 + + BLE_MESH_ADV_LEGACY: + description: > + Use legacy advertising commands for mesh sending. Legacy + advertising is significantly slower than the extended advertising, but + is supported by all controllers. + value: 1 + restrictions: + - "BLE_MESH_ADV if 0" + - "!BLE_MESH_ADV_EXT" + + BLE_MESH_ADV_EXT: + description: > + Use extended advertising commands for operating the advertiser. + Extended advertising is faster and uses less memory than legacy + advertising, but isn't supported by all controllers. + value: 0 + restrictions: + - "BLE_MESH_ADV if 0" + - "!BLE_MESH_ADV_LEGACY" + - "BLE_EXT_ADV" + + BLE_MESH_DEBUG_USE_ID_ADDR: + description: > + Use ID address for mesh advertisements, use random address otherwise. + value: 0 + BLE_MESH_ADV_STACK_SIZE: description: > Mesh advertiser thread stack size. @@ -196,6 +286,11 @@ syscfg.defs: absolutely necessary value: 768 + BLE_MESH_IV_UPDATE_SEQ_LIMIT: + description: > + This option specifies the sequence number value to start iv update. + value: 0x800000 + BLE_MESH_IVU_DIVIDER: description: > When the IV Update state enters Normal operation or IV Update @@ -311,13 +406,6 @@ syscfg.defs: value: 4 retrictions: 'BLE_MESH_SEG_RETRANSMIT_ATTEMPTS > 1' - BLE_MESH_RELAY: - description: > - Controls the initial number of retransmissions of original messages, - in addition to the first transmission. Can be changed through runtime - configuration. - value: 2 - BLE_MESH_NETWORK_TRANSMIT_COUNT: description: > Controls the initial number of retransmissions of original messages, @@ -332,7 +420,7 @@ syscfg.defs: configuration. value: 20 - BT_MESH_RELAY: + BLE_MESH_RELAY: description: > Support for acting as a Mesh Relay Node. value: 1 @@ -341,14 +429,13 @@ syscfg.defs: description: > Controls whether the Mesh Relay feature is enabled by default. Can be changed through runtime configuration. - value: 1 + value: MYNEWT_VAL(BLE_MESH_RELAY) BLE_MESH_RELAY_RETRANSMIT_COUNT: description: > Controls the initial number of retransmissions of relayed messages, in addition to the first transmission. Can be changed through runtime configuration. - value: 2 BLE_MESH_RELAY_RETRANSMIT_INTERVAL: @@ -436,16 +523,6 @@ syscfg.defs: a value of 300 means 30 seconds. value: 300 - BLE_MESH_LPN_POLL_TIMEOUT: - description: > - PollTimeout timer is used to measure time between two - consecutive requests sent by the Low Power node. If no - requests are received by the Friend node before the - PollTimeout timer expires, then the friendship is considered - terminated. The value is in units of 100 milliseconds, so e.g. - a value of 300 means 30 seconds. - value: 300 - BLE_MESH_LPN_INIT_POLL_TIMEOUT: description: > The initial value of the PollTimeout timer when Friendship @@ -471,7 +548,7 @@ syscfg.defs: description: > Automatically subscribe all nodes address when friendship established. - value: 1 + value: 0 BLE_MESH_FRIEND: description: > @@ -619,16 +696,22 @@ syscfg.defs: BLE_MESH_RPL_STORE_TIMEOUT: description: > - This value defines in seconds how soon the RPL gets written to - persistent storage after a change occurs. If the node receives - messages frequently it may make sense to have this set to a - large value, whereas if the RPL gets updated infrequently a - value as low as 0 (write immediately) may make sense. Note that - if the node operates a security sensitive use case, and there's - a risk of sudden power loss, it may be a security vulnerability - to set this value to anything else than 0 (a power loss before - writing to storage exposes the node to potential message - replay attacks). + Minimum interval after which unsaved RPL entries are updated in storage + + This value defines in seconds how soon unsaved RPL entries + gets written to the persistent storage. Setting this value + to a large number may lead to security vulnerabilities if a node + gets powered off before the timer is fired. When flash is used + as the persistent storage setting this value to a low number + may wear out flash sooner or later. However, if the RPL gets + updated infrequently a value as low as 0 (write immediately) + may make sense. Setting this value to -1 will disable this timer. + In this case, a user is responsible to store pending RPL entries + using @ref bt_mesh_rpl_pending_store. In the mean time, when + IV Index is updated, the outdated RPL entries will still be + stored by @ref BT_MESH_STORE_TIMEOUT. Finding the right balance + between this timeout and calling @ref bt_mesh_rpl_pending_store + may reduce a risk of security vulnerability and flash wear out. value: 5 BLE_MESH_DEVICE_NAME: @@ -897,3 +980,8 @@ syscfg.vals.BLE_MESH_PB_GATT: syscfg.vals.BLE_MESH_PB_ADV: BLE_MESH_PROV: 1 + +syscfg.vals.'BLE_MESH_PB_GATT': + BLE_MESH_PROXY_MSG_LEN: 66 +syscfg.vals.'BLE_MESH_GATT_PROXY': + BLE_MESH_PROXY_MSG_LEN: 33 diff --git a/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h b/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h index 06c44784af..344bc8520b 100644 --- a/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h +++ b/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h @@ -29,8 +29,10 @@ extern "C" { struct ble_hs_cfg; #define BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05 +#define BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16 0x2B2A void ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle); +void ble_svc_conn_gatt_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle); void ble_svc_gatt_init(void); #ifdef __cplusplus diff --git a/nimble/host/services/gatt/src/ble_svc_gatt.c b/nimble/host/services/gatt/src/ble_svc_gatt.c index 78b4a0683c..c8cae8a620 100644 --- a/nimble/host/services/gatt/src/ble_svc_gatt.c +++ b/nimble/host/services/gatt/src/ble_svc_gatt.c @@ -22,8 +22,10 @@ #include "sysinit/sysinit.h" #include "host/ble_hs.h" #include "services/gatt/ble_svc_gatt.h" +#include "host/ble_gatt.h" static uint16_t ble_svc_gatt_changed_val_handle; +static uint16_t ble_svc_gatt_hash_val_handle; static uint16_t ble_svc_gatt_start_handle; static uint16_t ble_svc_gatt_end_handle; @@ -31,6 +33,10 @@ static int ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +static int +ble_svc_gatt_db_hash_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = { { /*** Service: GATT */ @@ -41,7 +47,14 @@ static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = { .access_cb = ble_svc_gatt_access, .val_handle = &ble_svc_gatt_changed_val_handle, .flags = BLE_GATT_CHR_F_INDICATE, - }, { + }, + { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16), + .access_cb = ble_svc_gatt_db_hash_access, + .val_handle = &ble_svc_gatt_hash_val_handle, + .flags = BLE_GATT_CHR_F_READ, + }, + { 0, /* No more characteristics in this service. */ } }, }, @@ -51,6 +64,28 @@ static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = { }, }; +static int +ble_svc_gatt_db_hash_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + int rc; + assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + assert(ctxt->chr == &ble_svc_gatt_defs[0].characteristics[1]); + uint8_t db_hash[16]; + uint16_t len_data = sizeof(db_hash); + int res = ble_compute_db_hash(db_hash); + if(res != 0){ + return BLE_ATT_ERR_UNLIKELY; + } + + rc = os_mbuf_append(ctxt->om, db_hash, len_data); + if(rc !=0){ + return BLE_ATT_ERR_UNLIKELY; + } + + return 0; +} + static int ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) @@ -73,7 +108,7 @@ ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle, put_le16(u8p + 0, ble_svc_gatt_start_handle); put_le16(u8p + 2, ble_svc_gatt_end_handle); - + return 0; } @@ -89,7 +124,22 @@ ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle) { ble_svc_gatt_start_handle = start_handle; ble_svc_gatt_end_handle = end_handle; - ble_gatts_chr_updated(ble_svc_gatt_changed_val_handle); + ble_gatts_chr_updated(ble_svc_gatt_changed_val_handle); +} + +/** + * Indicates a change in attribute assignment to specified peer. + * + * @param conn_handle The connection to indicate. + * @param start_handle The start of the affected handle range. + * @param end_handle The end of the affected handle range. + */ +void +ble_svc_conn_gatt_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle) +{ + ble_svc_gatt_start_handle = start_handle; + ble_svc_gatt_end_handle = end_handle; + ble_gattc_indicate(conn_handle, ble_svc_gatt_changed_val_handle); } void diff --git a/nimble/host/src/ble_att_svr.c b/nimble/host/src/ble_att_svr.c index 0cfbc7d96b..468768ac02 100644 --- a/nimble/host/src/ble_att_svr.c +++ b/nimble/host/src/ble_att_svr.c @@ -30,7 +30,7 @@ * ATT server - Attribute Protocol * * Notes on buffer reuse: - * Most request handlers reuse the request buffer for the reponse. This is + * Most request handlers reuse the request buffer for the response. This is * done to prevent out-of-memory conditions. However, there are two handlers * which do not reuse the request buffer: * 1. Write request. @@ -284,6 +284,16 @@ ble_att_svr_check_perms(uint16_t conn_handle, int is_read, } ble_att_svr_get_sec_state(conn_handle, &sec_state); + /* In SC Only mode all characteristics requiring security + * require it on level 4 + */ + if (MYNEWT_VAL(BLE_SM_SC_ONLY)) { + if (sec_state.key_size != 16 || + !sec_state.authenticated || + !sec_state.encrypted) { + return BLE_ATT_ERR_INSUFFICIENT_KEY_SZ; + } + } if ((enc || authen) && !sec_state.encrypted) { ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); @@ -2661,6 +2671,8 @@ ble_att_svr_reset(void) ble_att_svr_entry_free(entry); } + ble_att_svr_id = 0; + /* Note: prep entries do not get freed here because it is assumed there are * no established connections. */ diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 8e56df13fb..3d8f3038ae 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -1303,6 +1303,16 @@ ble_gap_adv_active_instance(uint8_t instance) } #endif +#if MYNEWT_VAL(BLE_EXT_ADV) +int ble_gap_ext_adv_active(uint8_t instance) +{ + if (instance >= BLE_ADV_INSTANCES) { + return 0; + } + return ble_gap_adv_active_instance(instance); +} +#endif + /** * Clears advertisement and discovery state. This function is necessary * when the controller loses its active state (e.g. on stack reset). @@ -2169,11 +2179,6 @@ ble_gap_wl_set(const ble_addr_t *addrs, uint8_t white_list_count) ble_hs_lock(); - if (white_list_count == 0) { - rc = BLE_HS_EINVAL; - goto done; - } - for (i = 0; i < white_list_count; i++) { if (addrs[i].type != BLE_ADDR_PUBLIC && addrs[i].type != BLE_ADDR_RANDOM) { @@ -2687,15 +2692,28 @@ ble_gap_ext_adv_params_tx(uint8_t instance, if (params->high_duty_directed) { cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED; } - if (params->legacy_pdu) { - cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; - } if (params->anonymous) { cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV; } if (params->include_tx_power) { cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR; } + if (params->legacy_pdu) { + cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; + + /* check right away if the applied configuration is valid before handing + * the command to the controller to improve error reporting */ + switch (cmd.props) { + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN: + break; + default: + return BLE_HS_EINVAL; + } + } /* Fill optional fields if application did not specify them. */ if (params->itvl_min == 0 && params->itvl_max == 0) { @@ -5779,7 +5797,7 @@ ble_gap_enc_event(uint16_t conn_handle, int status, return; } - /* If encryption succeded and encryption has been restored for bonded device, + /* If encryption succeeded and encryption has been restored for bonded device, * notify gatt server so it has chance to send notification/indication if needed. */ if (security_restored) { diff --git a/nimble/host/src/ble_gattc.c b/nimble/host/src/ble_gattc.c index 74a2837ad7..b43a0af03c 100644 --- a/nimble/host/src/ble_gattc.c +++ b/nimble/host/src/ble_gattc.c @@ -3765,17 +3765,20 @@ ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc, proc->write_long.length) != 0) { rc = BLE_HS_EBADDATA; - goto err; - } - /* Send follow-up request. */ - proc->write_long.attr.offset += OS_MBUF_PKTLEN(om); - rc = ble_gattc_write_long_resume(proc); - if (rc != 0) { + /* if data doesn't match up send cancel write */ + ble_att_clt_tx_exec_write(proc->conn_handle, BLE_ATT_EXEC_WRITE_F_CANCEL); goto err; - } + } else { + /* Send follow-up request. */ + proc->write_long.attr.offset += OS_MBUF_PKTLEN(om); + rc = ble_gattc_write_long_resume(proc); + if (rc != 0) { + goto err; + } - return 0; + return 0; + } err: /* XXX: Might need to cancel pending writes. */ diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c index a635f2d7f4..61a7189f8a 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -28,6 +28,17 @@ #define BLE_GATTS_INCLUDE_SZ 6 #define BLE_GATTS_CHR_MAX_SZ 19 +#if NIMBLE_BLE_SM +#include "tinycrypt/aes.h" +#include "tinycrypt/constants.h" +#include "tinycrypt/utils.h" + +#if MYNEWT_VAL(BLE_SM_SC) +#include "tinycrypt/cmac_mode.h" +#include "tinycrypt/ecc_dh.h" +#endif +#endif + static const ble_uuid_t *uuid_pri = BLE_UUID16_DECLARE(BLE_ATT_UUID_PRIMARY_SERVICE); static const ble_uuid_t *uuid_sec = @@ -364,7 +375,7 @@ ble_gatts_val_access(uint16_t conn_handle, uint16_t attr_handle, gatt_ctxt->om = *om; } else { new_om = 1; - gatt_ctxt->om = os_msys_get_pkthdr(0, 0); + gatt_ctxt->om = ble_hs_mbuf_att_pkt(); if (gatt_ctxt->om == NULL) { return BLE_ATT_ERR_INSUFFICIENT_RES; } @@ -1719,6 +1730,8 @@ ble_gatts_bonding_restored(uint16_t conn_handle) { struct ble_store_value_cccd cccd_value; struct ble_store_key_cccd cccd_key; + struct ble_store_value_hash hash_value; + struct ble_store_key_hash hash_key; struct ble_gatts_clt_cfg *clt_cfg; struct ble_hs_conn *conn; uint8_t att_op; @@ -1799,6 +1812,13 @@ ble_gatts_bonding_restored(uint16_t conn_handle) cccd_key.idx++; } + + hash_key.peer_addr = conn->bhc_peer_addr; + hash_key.peer_addr.type = + ble_hs_misc_peer_addr_type_to_id(conn->bhc_peer_addr.type); + hash_key.idx = 0; + + rc = ble_store_read_hash(conn_handle, &hash_key, &hash_value); // read peer hash, read the database hash characteristic and compare, if rc != 0 => ble_svc_conn_gatt_changed(0, 0xffff) } static struct ble_gatts_svc_entry * @@ -2182,3 +2202,107 @@ ble_gatts_init(void) return 0; } + +static void ble_db_hash_message_append_u16(uint16_t val, uint8_t *buf, uint8_t *len) { + val = htole16(val); + memcpy(buf + *len, &val, sizeof(uint16_t)); + *len += sizeof(uint16_t); +} + +static void ble_db_hash_message_append_u32(uint32_t val, uint8_t *buf, uint8_t *len) { + val = htole32(val); + memcpy(buf + *len, &val, sizeof(uint32_t)); + *len += sizeof(uint32_t); +} + +static void ble_db_hash_message_append_uuid(const ble_uuid_t *uuid, uint8_t *buf, uint8_t *len) { + switch (uuid->type) { + case BLE_UUID_TYPE_16: { + ble_db_hash_message_append_u16( BLE_UUID16(uuid)->value, buf, len); + break; + } + case BLE_UUID_TYPE_32: { + ble_db_hash_message_append_u32(BLE_UUID32(uuid)->value, buf, len); + break; + } + case BLE_UUID_TYPE_128: { + memcpy(buf + *len, BLE_UUID128(uuid)->value, 16); + *len += 16; + break; + } + default: + break; + } +} + +/** + * Called when the database cmac hash needs to be computed using the information + * from registered services, characteristics and descriptors. This + * function: + * o Sets up the cmac generator with a key of 0s + * o Parse services, characteristics and descriptors and adds information + * to the message to code. + * o Computes the cmac coded message. + */ +int ble_compute_db_hash(uint8_t db_hash[16]) +{ + uint8_t buf[24]; + uint8_t buf_len; + + struct tc_aes_key_sched_struct sched; + struct tc_cmac_struct state; + const uint8_t key[16] = {0}; + + if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { + return BLE_HS_EUNKNOWN; + } + + for (int i = 0; i < ble_gatts_num_svc_entries; i++) { + struct ble_gatts_svc_entry *entry = &ble_gatts_svc_entries[i]; + buf_len = 0; + ble_db_hash_message_append_u16(entry->handle, buf, &buf_len); + ble_db_hash_message_append_u16(BLE_ATT_UUID_PRIMARY_SERVICE, buf, &buf_len); + ble_db_hash_message_append_uuid(entry->svc->uuid, buf, &buf_len); + + if (tc_cmac_update(&state, buf, buf_len) == TC_CRYPTO_FAIL) { + return BLE_HS_EUNKNOWN; + } + buf_len = 0; + + if (entry->svc->characteristics != NULL) { + for (const struct ble_gatt_chr_def *chr = entry->svc->characteristics; chr && chr->uuid; chr++) { + if (chr->val_handle == NULL) { + continue; + } + ble_db_hash_message_append_u16(*chr->val_handle - 1, buf, &buf_len); + ble_db_hash_message_append_u16(BLE_ATT_UUID_CHARACTERISTIC, buf, &buf_len); + ble_db_hash_message_append_u16(chr->flags, buf, &buf_len); + ble_db_hash_message_append_u16(*chr->val_handle, buf, &buf_len); + ble_db_hash_message_append_uuid(chr->uuid, buf, &buf_len); + + if (tc_cmac_update(&state, buf, buf_len) == TC_CRYPTO_FAIL) { + return BLE_HS_EUNKNOWN; + } + buf_len = 0; + + if (chr->descriptors != NULL) { + for (struct ble_gatt_dsc_def *dsc = chr->descriptors; dsc && dsc->uuid; dsc++) { + ble_db_hash_message_append_u16(*chr->val_handle + 1, buf, &buf_len); + ble_db_hash_message_append_u16(BLE_ATT_UUID_DESCRIPTOR, buf, &buf_len); + + if (tc_cmac_update(&state, buf, buf_len) == TC_CRYPTO_FAIL) { + return BLE_HS_EUNKNOWN; + } + buf_len = 0; + } + } + } + } + } + + if (tc_cmac_final(db_hash, &state) == TC_CRYPTO_FAIL) { + return BLE_HS_EUNKNOWN; + } + + return 0; +} diff --git a/nimble/host/src/ble_hs_flow.c b/nimble/host/src/ble_hs_flow.c index 2520c85415..1eabba9e0c 100644 --- a/nimble/host/src/ble_hs_flow.c +++ b/nimble/host/src/ble_hs_flow.c @@ -92,7 +92,7 @@ ble_hs_flow_tx_num_comp_pkts(void) * response from the controller, so don't use the normal blocking * HCI API when sending it. */ - rc = ble_hs_hci_cmd_send_buf( + rc = ble_hs_hci_cmd_tx_no_rsp( BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS), buf, sizeof(buf)); diff --git a/nimble/host/src/ble_hs_hci.c b/nimble/host/src/ble_hs_hci.c index ac472a9ea5..53d36473b6 100644 --- a/nimble/host/src/ble_hs_hci.c +++ b/nimble/host/src/ble_hs_hci.c @@ -41,11 +41,20 @@ static uint32_t ble_hs_hci_sup_feat; static uint8_t ble_hs_hci_version; +#if MYNEWT_VAL(BLE_CONTROLLER) #define BLE_HS_HCI_FRAG_DATABUF_SIZE \ (BLE_ACL_MAX_PKT_SIZE + \ BLE_HCI_DATA_HDR_SZ + \ sizeof (struct os_mbuf_pkthdr) + \ + sizeof (struct ble_mbuf_hdr) + \ sizeof (struct os_mbuf)) +#else +#define BLE_HS_HCI_FRAG_DATABUF_SIZE \ + (BLE_ACL_MAX_PKT_SIZE + \ + BLE_HCI_DATA_HDR_SZ + \ + sizeof (struct os_mbuf_pkthdr) + \ + sizeof (struct os_mbuf)) +#endif #define BLE_HS_HCI_FRAG_MEMBLOCK_SIZE \ (OS_ALIGN(BLE_HS_HCI_FRAG_DATABUF_SIZE, 4)) @@ -291,6 +300,20 @@ ble_hs_hci_wait_for_ack(void) return rc; } +int +ble_hs_hci_cmd_tx_no_rsp(uint16_t opcode, const void *cmd, uint8_t cmd_len) +{ + int rc; + + ble_hs_hci_lock(); + + rc = ble_hs_hci_cmd_send_buf(opcode, cmd, cmd_len); + + ble_hs_hci_unlock(); + + return rc; +} + int ble_hs_hci_cmd_tx(uint16_t opcode, const void *cmd, uint8_t cmd_len, void *rsp, uint8_t rsp_len) @@ -407,7 +430,11 @@ ble_hs_hci_frag_alloc(uint16_t frag_size, void *arg) struct os_mbuf *om; /* Prefer the dedicated one-element fragment pool. */ +#if MYNEWT_VAL(BLE_CONTROLLER) + om = os_mbuf_get_pkthdr(&ble_hs_hci_frag_mbuf_pool, sizeof(struct ble_mbuf_hdr)); +#else om = os_mbuf_get_pkthdr(&ble_hs_hci_frag_mbuf_pool, 0); +#endif if (om != NULL) { om->om_data += BLE_HCI_DATA_HDR_SZ; return om; diff --git a/nimble/host/src/ble_hs_hci_priv.h b/nimble/host/src/ble_hs_hci_priv.h index b02d4ab2e8..11e544f18f 100644 --- a/nimble/host/src/ble_hs_hci_priv.h +++ b/nimble/host/src/ble_hs_hci_priv.h @@ -81,6 +81,8 @@ struct hci_periodic_adv_params extern uint16_t ble_hs_hci_avail_pkts; +/* This function is not waiting for command status/complete HCI events */ +int ble_hs_hci_cmd_tx_no_rsp(uint16_t opcode, const void *cmd, uint8_t cmd_len); int ble_hs_hci_cmd_tx(uint16_t opcode, const void *cmd, uint8_t cmd_len, void *rsp, uint8_t rsp_len); void ble_hs_hci_init(void); diff --git a/nimble/host/src/ble_hs_mbuf.c b/nimble/host/src/ble_hs_mbuf.c index d938d34806..6e920f94fe 100644 --- a/nimble/host/src/ble_hs_mbuf.c +++ b/nimble/host/src/ble_hs_mbuf.c @@ -29,7 +29,11 @@ ble_hs_mbuf_gen_pkt(uint16_t leading_space) struct os_mbuf *om; int rc; +#if MYNEWT_VAL(BLE_CONTROLLER) + om = os_msys_get_pkthdr(0, sizeof(struct ble_mbuf_hdr)); +#else om = os_msys_get_pkthdr(0, 0); +#endif if (om == NULL) { return NULL; } diff --git a/nimble/host/src/ble_l2cap.c b/nimble/host/src/ble_l2cap.c index 2bc50e0e93..bfbdadfcd6 100644 --- a/nimble/host/src/ble_l2cap.c +++ b/nimble/host/src/ble_l2cap.c @@ -393,8 +393,11 @@ ble_l2cap_rx(struct ble_hs_conn *conn, } if (l2cap_hdr.len > ble_l2cap_get_mtu(chan)) { - /* More data then we expected on the channel */ + /* More data than we expected on the channel. + * Disconnect peer with invalid behaviour + */ rc = BLE_HS_EBADDATA; + ble_l2cap_disconnect(chan); goto err; } diff --git a/nimble/host/src/ble_l2cap_coc.c b/nimble/host/src/ble_l2cap_coc.c index aa953d79c5..f74cea2800 100644 --- a/nimble/host/src/ble_l2cap_coc.c +++ b/nimble/host/src/ble_l2cap_coc.c @@ -198,6 +198,17 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) } sdu_len = get_le16((*om)->om_data); + + /* We should receive payload of size sdu_len + 2 bytes of sdu_len field */ + if (om_total > sdu_len + 2) { + BLE_HS_LOG(ERROR, "Payload larger than expected (%d>%d)\n", + om_total, sdu_len + 2); + /* Disconnect peer with invalid behaviour */ + rx->sdu = NULL; + rx->data_offset = 0; + ble_l2cap_disconnect(chan); + return BLE_HS_EBADDATA; + } if (sdu_len > rx->mtu) { BLE_HS_LOG(INFO, "error: sdu_len > rx->mtu (%d>%d)\n", sdu_len, rx->mtu); @@ -227,6 +238,15 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) } else { BLE_HS_LOG(DEBUG, "Continuation...received %d\n", (*om)->om_len); + if (OS_MBUF_PKTLEN(rx->sdu) + (*om)->om_len > rx->data_offset) { + /* Disconnect peer with invalid behaviour */ + BLE_HS_LOG(ERROR, "Payload larger than expected (%d>%d)\n", + OS_MBUF_PKTLEN(rx->sdu) + (*om)->om_len, rx->data_offset); + rx->sdu = NULL; + rx->data_offset = 0; + ble_l2cap_disconnect(chan); + return BLE_HS_EBADDATA; + } rc = os_mbuf_appendfrom(rx->sdu, *om, 0, om_total); if (rc != 0) { /* FIXME: need to handle it better */ diff --git a/nimble/host/src/ble_l2cap_sig.c b/nimble/host/src/ble_l2cap_sig.c index aaf9c642a4..3033e05dd5 100644 --- a/nimble/host/src/ble_l2cap_sig.c +++ b/nimble/host/src/ble_l2cap_sig.c @@ -784,10 +784,6 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t conn_handle, if (chan[i]->peer_coc_mps > req->mps) { reduction_mps++; - if (reduction_mps > 1) { - rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED); - goto failed; - } } if (chan[i]->coc_tx.mtu > req->mtu) { @@ -796,6 +792,11 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t conn_handle, } } + if (reduction_mps > 0 && cid_cnt > 1) { + rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED); + goto failed; + } + ble_hs_unlock(); for (i = 0; i < cid_cnt; i++) { @@ -1047,6 +1048,7 @@ ble_l2cap_sig_credit_base_con_rsp_rx(uint16_t conn_handle, struct ble_hs_conn *conn; int rc; int i; + uint16_t duplicated_cids[5] = {}; #if !BLE_MONITOR BLE_HS_LOG(DEBUG, "L2CAP LE COC connection response received\n"); @@ -1092,6 +1094,12 @@ ble_l2cap_sig_credit_base_con_rsp_rx(uint16_t conn_handle, chan->dcid = 0; continue; } + if (ble_hs_conn_chan_find_by_dcid(conn, rsp->dcids[i])) { + duplicated_cids[i] = rsp->dcids[i]; + chan->dcid = 0; + continue; + } + chan->peer_coc_mps = le16toh(rsp->mps); chan->dcid = le16toh(rsp->dcids[i]); chan->coc_tx.mtu = le16toh(rsp->mtu); @@ -1103,6 +1111,16 @@ ble_l2cap_sig_credit_base_con_rsp_rx(uint16_t conn_handle, ble_hs_unlock(); done: + for (i = 0; i < 5; i++){ + if (duplicated_cids[i] != 0){ + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + chan = ble_hs_conn_chan_find_by_dcid(conn, duplicated_cids[i]); + ble_hs_unlock(); + rc = ble_l2cap_sig_disconnect(chan); + } + } + ble_l2cap_sig_coc_connect_cb(proc, rc); ble_l2cap_sig_proc_free(proc); @@ -1540,7 +1558,13 @@ ble_l2cap_sig_disc_req_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, * is from peer perspective. It is source CID from nimble perspective */ chan = ble_hs_conn_chan_find_by_scid(conn, le16toh(req->dcid)); - if (!chan || (le16toh(req->scid) != chan->dcid)) { + if (!chan) { + os_mbuf_free_chain(txom); + ble_hs_unlock(); + ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, hdr->identifier, req->dcid, req->scid); + return 0; + } + if (le16toh(req->scid) != chan->dcid) { os_mbuf_free_chain(txom); ble_hs_unlock(); return 0; diff --git a/nimble/host/src/ble_l2cap_sig_cmd.c b/nimble/host/src/ble_l2cap_sig_cmd.c index d9e507e258..48b35249ec 100644 --- a/nimble/host/src/ble_l2cap_sig_cmd.c +++ b/nimble/host/src/ble_l2cap_sig_cmd.c @@ -21,6 +21,7 @@ #include "ble_hs_priv.h" #if NIMBLE_BLE_CONNECT +/* this function consumes tx os_mbuf */ int ble_l2cap_sig_tx(uint16_t conn_handle, struct os_mbuf *txom) { @@ -33,6 +34,8 @@ ble_l2cap_sig_tx(uint16_t conn_handle, struct os_mbuf *txom) &conn, &chan); if (rc == 0) { rc = ble_l2cap_tx(conn, chan, txom); + } else { + os_mbuf_free_chain(txom); } ble_hs_unlock(); diff --git a/nimble/host/src/ble_sm.c b/nimble/host/src/ble_sm.c index b4e8096a57..8f2bc5f517 100644 --- a/nimble/host/src/ble_sm.c +++ b/nimble/host/src/ble_sm.c @@ -516,11 +516,13 @@ static void ble_sm_persist_keys(struct ble_sm_proc *proc) { struct ble_store_value_sec value_sec; + struct ble_store_value_hash value_hash; struct ble_hs_conn *conn; ble_addr_t peer_addr; int authenticated; int identity_ev = 0; int sc; + int rc; ble_hs_lock(); @@ -577,6 +579,14 @@ ble_sm_persist_keys(struct ble_sm_proc *proc) ble_sm_fill_store_value(&peer_addr, authenticated, sc, &proc->peer_keys, &value_sec); ble_store_write_peer_sec(&value_sec); + + + // Compute current database hash and store it + value_hash.peer_addr = peer_addr; + rc = ble_compute_db_hash(value_hash.db_hash); + if (rc == 0) { + rc = ble_store_write_hash(&value_hash); + } } static int @@ -1726,17 +1736,23 @@ ble_sm_pair_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, } static bool -ble_sm_verify_auth_requirements(uint8_t authreq) +ble_sm_verify_auth_requirements(uint8_t cmd) { /* For now we check only SC only mode. I.e.: when remote indicates * to not support SC pairing, let us make sure legacy pairing is supported * on our side. If not, we can fail right away. */ - if (!(authreq & BLE_SM_PAIR_AUTHREQ_SC)) { + if (!(cmd & BLE_SM_PAIR_AUTHREQ_SC)) { if (MYNEWT_VAL(BLE_SM_LEGACY) == 0) { return false; } } + /* Fail if Secure Connections level forces MITM protection and remote does not + * support it + */ + if (MYNEWT_VAL(BLE_SM_SC_LVL) >= 3 && !(cmd & BLE_SM_PAIR_AUTHREQ_MITM)) { + return false; + } return true; } @@ -1817,12 +1833,21 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om, if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); + } else if (MYNEWT_VAL(BLE_SM_SC_LVL) == 1) { + res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; + res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); } else if (req->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) { res->sm_err = BLE_SM_ERR_ENC_KEY_SZ; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ); } else if (req->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) { res->sm_err = BLE_SM_ERR_INVAL; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL); + } else if (MYNEWT_VAL(BLE_SM_SC_ONLY) && (req->max_enc_key_size != BLE_SM_PAIR_KEY_SZ_MAX)) { + /* Fail if Secure Connections Only mode is on and remote does not meet + * key size requirements - MITM was checked in last step + */ + res->sm_err = BLE_SM_ERR_ENC_KEY_SZ; + res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ); } else if (!ble_sm_verify_auth_requirements(req->authreq)) { res->sm_err = BLE_SM_ERR_AUTHREQ; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ); @@ -1886,6 +1911,12 @@ ble_sm_pair_rsp_rx(uint16_t conn_handle, struct os_mbuf **om, } else if (rsp->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) { res->sm_err = BLE_SM_ERR_INVAL; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL); + } else if (MYNEWT_VAL(BLE_SM_SC_ONLY) && (rsp->max_enc_key_size != BLE_SM_PAIR_KEY_SZ_MAX)) { + /* Fail if Secure Connections Only mode is on and remote does not meet + * key size requirements - MITM was checked in last step + */ + res->sm_err = BLE_SM_ERR_ENC_KEY_SZ; + res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ); } else if (!ble_sm_verify_auth_requirements(rsp->authreq)) { res->sm_err = BLE_SM_ERR_AUTHREQ; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ); diff --git a/nimble/host/src/ble_sm_cmd.c b/nimble/host/src/ble_sm_cmd.c index 2983102cd1..b84df1ec75 100644 --- a/nimble/host/src/ble_sm_cmd.c +++ b/nimble/host/src/ble_sm_cmd.c @@ -63,6 +63,8 @@ ble_sm_tx(uint16_t conn_handle, struct os_mbuf *txom) &conn, &chan); if (rc == 0) { rc = ble_l2cap_tx(conn, chan, txom); + } else { + os_mbuf_free_chain(txom); } return rc; diff --git a/nimble/host/src/ble_sm_lgcy.c b/nimble/host/src/ble_sm_lgcy.c index 0259ff4682..1a500fb746 100644 --- a/nimble/host/src/ble_sm_lgcy.c +++ b/nimble/host/src/ble_sm_lgcy.c @@ -36,7 +36,7 @@ #define IOACT_INPUT BLE_SM_IOACT_INPUT #define IOACT_DISP BLE_SM_IOACT_DISP -/* This is the initiator passkey action action dpeneding on the io +/* This is the initiator passkey action action depending on the io * capabilties of both parties */ static const uint8_t ble_sm_lgcy_init_ioa[5 /*resp*/ ][5 /*init*/ ] = diff --git a/nimble/host/src/ble_sm_sc.c b/nimble/host/src/ble_sm_sc.c index 7fae5b1c94..162a4a2ba1 100644 --- a/nimble/host/src/ble_sm_sc.c +++ b/nimble/host/src/ble_sm_sc.c @@ -612,6 +612,13 @@ ble_sm_sc_public_key_rx(uint16_t conn_handle, struct os_mbuf **om, } cmd = (struct ble_sm_public_key *)(*om)->om_data; + /* Check if the peer public key is same as our generated public key. + * Return fail if the public keys match. */ + if (memcmp(cmd, ble_sm_sc_pub_key, 64) == 0) { + res->enc_cb = 1; + res->sm_err = BLE_SM_ERR_AUTHREQ; + return; + } ble_hs_lock(); proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PUBLIC_KEY, -1, diff --git a/nimble/host/src/ble_store.c b/nimble/host/src/ble_store.c index 22e6089471..574973904a 100644 --- a/nimble/host/src/ble_store.c +++ b/nimble/host/src/ble_store.c @@ -21,6 +21,8 @@ #include "host/ble_store.h" #include "ble_hs_priv.h" +#include "host/ble_gatt.h" +#include "services/gatt/ble_svc_gatt.h" int ble_store_read(int obj_type, const union ble_store_key *key, @@ -249,6 +251,64 @@ ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec) return 0; } +int +ble_store_read_hash(uint16_t conn_handle, const struct ble_store_key_hash *key_hash, + struct ble_store_value_hash *value_hash) +{ + union ble_store_value *store_value; + union ble_store_key *store_key; + int rc; + int rc_calc; + + store_key = (void *)key_hash; + store_value = (void *)value_hash; + rc = ble_store_read(BLE_STORE_OBJ_TYPE_HASH, store_key, store_value); + + struct ble_store_value_hash new_value_hash; + new_value_hash.peer_addr = key_hash->peer_addr; + rc_calc = ble_compute_db_hash(new_value_hash.db_hash); + if (rc_calc != 0) { + return rc_calc; + } + if (rc == 0) { + for(int i=0; i<16; i++){ + if(memcmp(new_value_hash.db_hash, value_hash->db_hash, 16) != 0){ + rc = 1; + break; + } + } + } + + if (rc != 0) { + ble_store_write_hash(&new_value_hash); + ble_svc_conn_gatt_changed(conn_handle, 0x0001, 0xffff); + } + + return rc; +} + +int +ble_store_write_hash(const struct ble_store_value_hash *value_hash) +{ + int rc; + union ble_store_value *store_value; + + store_value = (void *)value_hash; + rc = ble_store_write(BLE_STORE_OBJ_TYPE_HASH, store_value); + return rc; +} + +int +ble_store_delete_hash(const struct ble_store_key_hash *key) +{ + union ble_store_key *store_key; + int rc; + + store_key = (void *)key; + rc = ble_store_delete(BLE_STORE_OBJ_TYPE_HASH, store_key); + return rc; +} + int ble_store_read_cccd(const struct ble_store_key_cccd *key, struct ble_store_value_cccd *out_value) @@ -306,6 +366,14 @@ ble_store_key_from_value_sec(struct ble_store_key_sec *out_key, out_key->idx = 0; } +void +ble_store_key_from_value_hash(struct ble_store_key_hash *out_key, + const struct ble_store_value_hash *value) +{ + out_key->peer_addr = value->peer_addr; + out_key->idx = 0; +} + void ble_store_key_from_value(int obj_type, union ble_store_key *out_key, @@ -321,6 +389,10 @@ ble_store_key_from_value(int obj_type, ble_store_key_from_value_cccd(&out_key->cccd, &value->cccd); break; + case BLE_STORE_OBJ_TYPE_HASH: + ble_store_key_from_value_hash(&out_key->hash, &value->hash); + break; + default: BLE_HS_DBG_ASSERT(0); break; @@ -350,6 +422,10 @@ ble_store_iterate(int obj_type, key.cccd.peer_addr = *BLE_ADDR_ANY; pidx = &key.cccd.idx; break; + case BLE_STORE_OBJ_TYPE_HASH: + key.hash.peer_addr = *BLE_ADDR_ANY; + pidx = &key.hash.idx; + break; default: BLE_HS_DBG_ASSERT(0); return BLE_HS_EINVAL; @@ -394,6 +470,7 @@ ble_store_clear(void) BLE_STORE_OBJ_TYPE_OUR_SEC, BLE_STORE_OBJ_TYPE_PEER_SEC, BLE_STORE_OBJ_TYPE_CCCD, + BLE_STORE_OBJ_TYPE_HASH }; union ble_store_key key; int obj_type; diff --git a/nimble/host/src/ble_store_util.c b/nimble/host/src/ble_store_util.c index 7de482721b..39247f945a 100644 --- a/nimble/host/src/ble_store_util.c +++ b/nimble/host/src/ble_store_util.c @@ -101,7 +101,8 @@ ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int *out_num_peers, /** * Deletes all entries from the store that are attached to the specified peer - * address. This function deletes security entries and CCCD records. + * address. This function deletes security entries, CCCD records and stored + * database hashes. * * @param peer_id_addr Entries with this peer address get deleted. * @@ -127,6 +128,11 @@ ble_store_util_delete_peer(const ble_addr_t *peer_id_addr) return rc; } + rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_HASH, &key); + if (rc != 0) { + return rc; + } + memset(&key, 0, sizeof key); key.cccd.peer_addr = *peer_id_addr; diff --git a/nimble/host/syscfg.yml b/nimble/host/syscfg.yml index e72e8d529e..c814ba5695 100644 --- a/nimble/host/syscfg.yml +++ b/nimble/host/syscfg.yml @@ -133,6 +133,34 @@ syscfg.defs: description: 'Security manager secure connections (4.2).' value: 0 + BLE_SM_SC_ONLY: + description: > + Force global Secure Connections Pairing Only mode. This means + that only SC pairing mode 1 level 4 shall be used, and all + characteristics will require it to access, except these + requiring mode 1 level 1. + value: 0 + restrictions: + - 'BLE_SM_SC_LVL == 4 if 1' + + BLE_SM_SC_LVL: + description: > + Force global Secure Connections mode 1 level. This level + describes requirements for pairing response/request received + to accept pairing: + - 1 - do not pair; only access to characteristics with no + authentication requirements is granted + - 2 - allow to pair despite MITM being on or off + - 3 - allow to pair only when MITM protection is on + - 4 - allow to pair only when 128 bit key is used and MITM is on + When set to 0 level is no forced and pairing is allowed for all + requests/responses with valid values (for example pairing will be + rejected with key longer than 128 bits). Successful pairing with + insufficient security will still cause denying access to protected + GATT characteristics. + value: 0 + range: 0..4 + BLE_SM_MAX_PROCS: description: > The maximum number of concurrent security manager procedures. diff --git a/nimble/host/test/pkg.yml b/nimble/host/test/pkg.yml index dd1ad18bf3..cb5d97cfb3 100644 --- a/nimble/host/test/pkg.yml +++ b/nimble/host/test/pkg.yml @@ -31,4 +31,4 @@ pkg.deps.SELFTEST: - "@apache-mynewt-core/sys/console/stub" - "@apache-mynewt-core/sys/log/full" - "@apache-mynewt-core/sys/stats/stub" - - nimble/transport/ram + - nimble/transport diff --git a/nimble/host/test/src/ble_gap_test.c b/nimble/host/test/src/ble_gap_test.c index 7496e31681..876ef8f257 100644 --- a/nimble/host/test/src/ble_gap_test.c +++ b/nimble/host/test/src/ble_gap_test.c @@ -449,9 +449,10 @@ TEST_CASE_SELF(ble_gap_test_case_wl_bad_args) ble_gap_test_util_init(); - /*** 0 white list entries. */ + /*** 0 white list entries. This is acceptable now with the wl_set API + * change. */ rc = ble_hs_test_util_wl_set(NULL, 0, 0, 0); - TEST_ASSERT(rc == BLE_HS_EINVAL); + TEST_ASSERT(rc == 0); /*** Invalid address type. */ rc = ble_hs_test_util_wl_set( diff --git a/nimble/host/test/src/ble_hs_test_util.h b/nimble/host/test/src/ble_hs_test_util.h index 411443cfdd..7a0aa3eb19 100644 --- a/nimble/host/test/src/ble_hs_test_util.h +++ b/nimble/host/test/src/ble_hs_test_util.h @@ -162,6 +162,8 @@ int ble_hs_test_util_l2cap_rx_payload_flat(uint16_t conn_handle, uint16_t cid, const void *data, int len); uint8_t ble_hs_test_util_verify_tx_l2cap_sig(uint16_t opcode, void *cmd, uint16_t cmd_size); +uint8_t ble_hs_test_util_verify_tx_l2cap_discon_rej(uint16_t opcode, void *cmd, + uint16_t cmd_size); int ble_hs_test_util_inject_rx_l2cap_sig(uint16_t conn_handle, uint8_t opcode, uint8_t id, void *cmd, uint16_t cmd_size); void ble_hs_test_util_verify_tx_l2cap(struct os_mbuf *txom); diff --git a/nimble/host/test/src/ble_l2cap_test.c b/nimble/host/test/src/ble_l2cap_test.c index 2b17da06a7..0f55bc006b 100644 --- a/nimble/host/test/src/ble_l2cap_test.c +++ b/nimble/host/test/src/ble_l2cap_test.c @@ -999,6 +999,46 @@ ble_l2cap_test_coc_disc_by_peer(struct test_data *t) &req, sizeof(req)) == id); } +static void +ble_l2cap_test_coc_disc_by_peer_invalid_dcid(struct test_data *t) +{ + struct ble_l2cap_sig_disc_req req; + struct event *ev = &t->event[t->event_iter++]; + uint8_t id = 10; + int rc; + struct os_mbuf *cmd; + uint16_t rej_err = htole16(BLE_L2CAP_SIG_ERR_INVALID_CID); + req.dcid = htole16(t->chan[0]->dcid + 1); + req.scid = htole16(t->chan[0]->dcid); + + rc = ble_hs_test_util_inject_rx_l2cap_sig(2, BLE_L2CAP_SIG_OP_DISCONN_REQ, + id, &req, sizeof(req)); + TEST_ASSERT(rc == 0); + + /* Ensure callback got NOT called. */ + TEST_ASSERT(!ev->handled); + + struct { + uint16_t local_cid; + uint16_t remote_cid; + } data = { + .local_cid = req.scid, + .remote_cid = req.dcid, + }; + + /* Ensure an we sent back Command Reject response + * Recect command should contain reason and CIDs pair + */ + cmd = os_mbuf_get(&sdu_os_mbuf_pool, 0); + os_mbuf_append(cmd, &rej_err, sizeof(uint16_t)); + os_mbuf_append(cmd, &data, sizeof(data)); + + ble_hs_test_util_verify_tx_l2cap_sig( + BLE_L2CAP_SIG_OP_REJECT, + cmd->om_data, cmd->om_len); + os_mbuf_free_chain(cmd); +} + static void ble_l2cap_test_coc_invalid_disc_by_peer(struct test_data *t) { @@ -1361,6 +1401,29 @@ TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_incoming_disconnect_failed) ble_hs_test_util_assert_mbufs_freed(NULL); } +TEST_CASE_SELF(ble_l2cap_test_case_invalid_cid_in_disconnect_req) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = 0; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS; + t.event[1].type = BLE_L2CAP_EVENT_COC_DISCONNECTED; + + ble_l2cap_test_coc_connect(&t); + ble_l2cap_test_coc_disc_by_peer_invalid_dcid(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + TEST_CASE_SELF(ble_l2cap_test_case_coc_send_data_succeed) { struct test_data t; @@ -1493,6 +1556,7 @@ TEST_SUITE(ble_l2cap_test_suite) ble_l2cap_test_case_sig_coc_disconnect_succeed(); ble_l2cap_test_case_sig_coc_incoming_disconnect_succeed(); ble_l2cap_test_case_sig_coc_incoming_disconnect_failed(); + ble_l2cap_test_case_invalid_cid_in_disconnect_req(); ble_l2cap_test_case_coc_send_data_succeed(); ble_l2cap_test_case_coc_send_data_failed_too_big_sdu(); ble_l2cap_test_case_coc_recv_data_succeed(); diff --git a/nimble/host/test/src/ble_sm_sc_test.c b/nimble/host/test/src/ble_sm_sc_test.c index c3d195503c..cd453e023c 100644 --- a/nimble/host/test/src/ble_sm_sc_test.c +++ b/nimble/host/test/src/ble_sm_sc_test.c @@ -2285,6 +2285,612 @@ TEST_CASE_SELF(ble_sm_sc_us_pk_iio2_rio4_b1_iat0_rat0_ik7_rk5) ble_hs_test_util_assert_mbufs_freed(NULL); } +/** + * Secure connections pairing + * Master: us + * Pair algorithm: passkey entry + * Initiator IO capabilities: 2 + * Responder IO capabilities: 4 + * Bonding: true + * Initiator address type: 0 + * Responder address type: 0 + * Initiator key distribution: 7 + * Responder key distribution: 5 + * Peer responds with same public key + */ +TEST_CASE_SELF(ble_sm_sc_us_pk_iio2_rio4_b1_iat0_rat0_ik7_rk5_peer_same_pk) { + struct ble_sm_test_params params; + + params = (struct ble_sm_test_params) { + .init_id_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + .resp_id_addr = { + 0xca, 0x61, 0xa0, 0x67, 0x94, 0xe0, + }, + .pair_req = { + .io_cap = 0x02, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x07, + }, + .pair_rsp = { + .io_cap = 0x04, + .oob_data_flag = 0x00, + .authreq = 0x0d, + .max_enc_key_size = 0x10, + .init_key_dist = 0x07, + .resp_key_dist = 0x05, + }, + .our_priv_key = { + 0xb1, 0x6b, 0x4f, 0x81, 0xbc, 0xe3, 0x60, 0x9e, + 0x00, 0x20, 0xf1, 0x73, 0x3e, 0xfb, 0xcc, 0x6e, + 0x8c, 0xb6, 0xd2, 0x51, 0xd9, 0x36, 0x8a, 0x6d, + 0xca, 0x8c, 0xd7, 0xbe, 0x96, 0x03, 0xdf, 0xd6, + }, + .public_key_req = { + .x = { + 0xe5, 0x0f, 0x02, 0x0a, 0x37, 0x90, 0x94, 0x5a, + 0x06, 0x21, 0xf7, 0xbc, 0xd5, 0xbe, 0xb9, 0x24, + 0x8a, 0x35, 0xfd, 0xf8, 0x5e, 0xe2, 0x70, 0xd5, + 0x5a, 0xe8, 0xe7, 0xdd, 0x13, 0x90, 0xeb, 0xd4, + }, + .y = { + 0x41, 0xc8, 0x51, 0x1a, 0x25, 0x44, 0x01, 0x53, + 0x42, 0x74, 0x07, 0x9c, 0x18, 0xe6, 0x3b, 0x8a, + 0xce, 0x7a, 0x37, 0x1f, 0x18, 0x5c, 0x02, 0x7c, + 0x67, 0x16, 0xf5, 0x30, 0x2b, 0x31, 0xa9, 0xc7, + }, + }, + .public_key_rsp = { + .x = { + 0xe5, 0x0f, 0x02, 0x0a, 0x37, 0x90, 0x94, 0x5a, + 0x06, 0x21, 0xf7, 0xbc, 0xd5, 0xbe, 0xb9, 0x24, + 0x8a, 0x35, 0xfd, 0xf8, 0x5e, 0xe2, 0x70, 0xd5, + 0x5a, 0xe8, 0xe7, 0xdd, 0x13, 0x90, 0xeb, 0xd4, + }, + .y = { + 0x41, 0xc8, 0x51, 0x1a, 0x25, 0x44, 0x01, 0x53, + 0x42, 0x74, 0x07, 0x9c, 0x18, 0xe6, 0x3b, 0x8a, + 0xce, 0x7a, 0x37, 0x1f, 0x18, 0x5c, 0x02, 0x7c, + 0x67, 0x16, 0xf5, 0x30, 0x2b, 0x31, 0xa9, 0xc7, + }, + }, + .confirm_req[0] = { + .value = { + 0x55, 0x2c, 0xaa, 0x41, 0x59, 0x42, 0x4d, 0xfe, + 0x47, 0x74, 0xcd, 0x2b, 0x11, 0xab, 0x21, 0xe6, + }, + }, + .confirm_rsp[0] = { + .value = { + 0x6a, 0x3c, 0x45, 0xf5, 0xb2, 0xe2, 0x04, 0x30, + 0xde, 0xd6, 0x3c, 0x6d, 0x85, 0x00, 0x00, 0x2c, + }, + }, + .random_req[0] = { + .value = { + 0x78, 0x06, 0x04, 0x60, 0x76, 0xe9, 0xc4, 0x5a, + 0xfb, 0x34, 0x44, 0xae, 0x45, 0xa0, 0x84, 0xde, + }, + }, + .random_rsp[0] = { + .value = { + 0x91, 0xc8, 0xfd, 0x1b, 0xb2, 0x85, 0x08, 0x76, + 0xd3, 0xf1, 0xc4, 0xa0, 0xfa, 0x92, 0x8c, 0x94, + }, + }, + .confirm_req[1] = { + .value = { + 0xb1, 0x2f, 0x68, 0x35, 0xa1, 0xa5, 0x84, 0xb1, + 0x4f, 0x1a, 0xb1, 0xb5, 0xf0, 0xb2, 0xbe, 0x61, + }, + }, + .confirm_rsp[1] = { + .value = { + 0x07, 0xd8, 0x43, 0x74, 0xe8, 0x42, 0xf3, 0xf1, + 0x87, 0x3d, 0x9e, 0x92, 0xea, 0x33, 0xe8, 0x54, + }, + }, + .random_req[1] = { + .value = { + 0x4c, 0xb7, 0xcc, 0x6d, 0x90, 0x9f, 0x1e, 0x2d, + 0x9d, 0x1e, 0x52, 0xa7, 0xe0, 0x0c, 0x7b, 0xf7, + }, + }, + .random_rsp[1] = { + .value = { + 0x5c, 0x32, 0x82, 0xc8, 0x76, 0x17, 0x3b, 0x18, + 0x66, 0xda, 0xbf, 0xc3, 0x13, 0x49, 0x05, 0xfb, + }, + }, + .confirm_req[2] = { + .value = { + 0x27, 0x61, 0x4d, 0x04, 0x64, 0xa9, 0x58, 0xf1, + 0xe0, 0xf9, 0xe5, 0x78, 0x0b, 0x54, 0x89, 0x0a, + }, + }, + .confirm_rsp[2] = { + .value = { + 0xe4, 0x8f, 0xdb, 0xc8, 0x35, 0xed, 0x4e, 0x7d, + 0xbc, 0x92, 0x7f, 0x58, 0x02, 0xaa, 0xbf, 0x6b, + }, + }, + .random_req[2] = { + .value = { + 0xfe, 0x85, 0x08, 0xe0, 0x35, 0x90, 0x13, 0xa9, + 0xd3, 0xcf, 0xb6, 0x6d, 0x36, 0xaf, 0xbd, 0x59, + }, + }, + .random_rsp[2] = { + .value = { + 0x47, 0x40, 0x8e, 0x97, 0xe3, 0xfe, 0x8f, 0x52, + 0x29, 0x5e, 0x6b, 0x44, 0xdf, 0x0d, 0x60, 0xf4, + }, + }, + .confirm_req[3] = { + .value = { + 0xac, 0xab, 0x13, 0x7c, 0x1a, 0x6e, 0x7a, 0xdb, + 0xf6, 0xe8, 0x72, 0x9f, 0xc5, 0xc3, 0x99, 0x1b, + }, + }, + .confirm_rsp[3] = { + .value = { + 0x79, 0xf2, 0xd1, 0x89, 0x5e, 0xa5, 0xa2, 0x90, + 0xee, 0x25, 0x36, 0x81, 0x5a, 0x87, 0x20, 0x82, + }, + }, + .random_req[3] = { + .value = { + 0xd4, 0x46, 0xa0, 0xc4, 0x3d, 0xae, 0x22, 0x06, + 0xaf, 0x5d, 0x93, 0x96, 0xb7, 0x06, 0xc3, 0x61, + }, + }, + .random_rsp[3] = { + .value = { + 0x5f, 0x81, 0x97, 0x8b, 0x52, 0x87, 0x1c, 0x67, + 0xe0, 0x04, 0xcc, 0x50, 0xd9, 0x2b, 0x16, 0xb5, + }, + }, + .confirm_req[4] = { + .value = { + 0x6c, 0x51, 0xc3, 0x61, 0x77, 0x7f, 0xf1, 0x05, + 0x9e, 0x0f, 0xba, 0xfd, 0x32, 0x02, 0x09, 0x45, + }, + }, + .confirm_rsp[4] = { + .value = { + 0x54, 0xe5, 0x24, 0x81, 0x62, 0x68, 0xe2, 0x45, + 0x86, 0x2c, 0x11, 0x28, 0x15, 0xa8, 0x8e, 0x5b, + }, + }, + .random_req[4] = { + .value = { + 0xbb, 0x29, 0x3a, 0xba, 0xe6, 0x4f, 0x06, 0xcf, + 0xa3, 0x13, 0x27, 0xf2, 0xcb, 0xe4, 0xd2, 0xe6, + }, + }, + .random_rsp[4] = { + .value = { + 0x50, 0xba, 0xd0, 0x0e, 0x26, 0xab, 0x04, 0xf8, + 0xa2, 0x03, 0x1e, 0x63, 0x9a, 0xf7, 0x15, 0xdc, + }, + }, + .confirm_req[5] = { + .value = { + 0x12, 0x3e, 0xfe, 0x5a, 0xb1, 0x09, 0x6f, 0x17, + 0xb7, 0x77, 0x7e, 0x65, 0x88, 0xd4, 0x95, 0x56, + }, + }, + .confirm_rsp[5] = { + .value = { + 0xc6, 0x9b, 0xac, 0xde, 0x7e, 0x03, 0x7a, 0xd3, + 0xf1, 0xff, 0x3c, 0x4f, 0x4a, 0x85, 0xba, 0x73, + }, + }, + .random_req[5] = { + .value = { + 0x17, 0xd5, 0x5e, 0x69, 0x30, 0x2c, 0x1f, 0x01, + 0x87, 0x9c, 0xd6, 0xd2, 0xe4, 0x48, 0x8c, 0x84, + }, + }, + .random_rsp[5] = { + .value = { + 0x9d, 0x54, 0x83, 0x4a, 0xcd, 0x93, 0x7c, 0x1e, + 0x5b, 0xaf, 0xd2, 0x66, 0x8c, 0x2d, 0xaa, 0xc3, + }, + }, + .confirm_req[6] = { + .value = { + 0xdc, 0x24, 0x69, 0xa8, 0xd3, 0xa9, 0x17, 0x11, + 0x08, 0x37, 0x1a, 0x1e, 0x92, 0x03, 0xee, 0x36, + }, + }, + .confirm_rsp[6] = { + .value = { + 0x98, 0xf8, 0x72, 0x71, 0x99, 0xa0, 0xbd, 0xcd, + 0xb1, 0x97, 0x4c, 0x8a, 0xb8, 0xa8, 0x1a, 0x52, + }, + }, + .random_req[6] = { + .value = { + 0xbf, 0xb1, 0x8e, 0xa5, 0x14, 0xe3, 0xeb, 0x9e, + 0x29, 0x27, 0xe0, 0x19, 0xb1, 0xb2, 0x5c, 0xfe, + }, + }, + .random_rsp[6] = { + .value = { + 0xae, 0x8a, 0x92, 0x78, 0x53, 0x7b, 0xdb, 0x8c, + 0xec, 0x3a, 0x99, 0x2b, 0x94, 0xf1, 0x17, 0xfe, + }, + }, + .confirm_req[7] = { + .value = { + 0xcf, 0xaf, 0x70, 0x73, 0x53, 0x65, 0x89, 0x57, + 0x36, 0x98, 0xd2, 0x28, 0x86, 0x79, 0xfe, 0x85, + }, + }, + .confirm_rsp[7] = { + .value = { + 0x0d, 0x2d, 0x77, 0x8a, 0x21, 0x11, 0xd9, 0x61, + 0x9f, 0x80, 0x32, 0x8a, 0x32, 0x09, 0x42, 0x42, + }, + }, + .random_req[7] = { + .value = { + 0x8b, 0xd2, 0x53, 0xcd, 0x96, 0xd1, 0x14, 0xb5, + 0xea, 0x17, 0xb1, 0xa3, 0xa8, 0xfc, 0x3c, 0x2b, + }, + }, + .random_rsp[7] = { + .value = { + 0xc2, 0x4f, 0x84, 0x60, 0x54, 0x79, 0x16, 0xed, + 0x1a, 0x6e, 0x78, 0xa0, 0x99, 0x58, 0xf2, 0x94, + }, + }, + .confirm_req[8] = { + .value = { + 0x9a, 0x4c, 0xbc, 0x9c, 0x55, 0x15, 0xa2, 0x4f, + 0xa2, 0x5d, 0x3b, 0xa7, 0x43, 0xb3, 0x9c, 0x63, + }, + }, + .confirm_rsp[8] = { + .value = { + 0xa3, 0xb1, 0x88, 0xa5, 0x70, 0xca, 0xa3, 0xa9, + 0x67, 0x2a, 0xac, 0x99, 0x5e, 0x61, 0x68, 0xa0, + }, + }, + .random_req[8] = { + .value = { + 0xcf, 0xcf, 0x5b, 0x94, 0xe0, 0xb2, 0x9d, 0x5a, + 0x86, 0x71, 0x45, 0xce, 0xd9, 0xce, 0x13, 0xba, + }, + }, + .random_rsp[8] = { + .value = { + 0x10, 0x96, 0x8a, 0x50, 0xa4, 0xd0, 0xaa, 0x5f, + 0xd6, 0x32, 0xdb, 0x09, 0x7e, 0x22, 0x96, 0x42, + }, + }, + .confirm_req[9] = { + .value = { + 0xf0, 0x90, 0x61, 0x25, 0x04, 0x29, 0x4f, 0xb6, + 0x8b, 0xd5, 0x73, 0x49, 0xbd, 0xf7, 0x9b, 0xe7, + }, + }, + .confirm_rsp[9] = { + .value = { + 0x5b, 0xe6, 0xb4, 0x3f, 0x1b, 0x77, 0x12, 0x75, + 0x84, 0x94, 0xc6, 0x07, 0xfa, 0xa1, 0x41, 0x94, + }, + }, + .random_req[9] = { + .value = { + 0x3d, 0x1a, 0xa3, 0x95, 0xec, 0x72, 0x84, 0xf4, + 0xc5, 0xcd, 0xaa, 0x48, 0xe9, 0x0c, 0x0f, 0xe3, + }, + }, + .random_rsp[9] = { + .value = { + 0x8a, 0x5a, 0x53, 0xfc, 0x07, 0x52, 0x01, 0xb9, + 0xe9, 0x2d, 0xe7, 0x9d, 0x8c, 0x7c, 0xc7, 0xb3, + }, + }, + .confirm_req[10] = { + .value = { + 0xe7, 0x8e, 0xc5, 0x08, 0x7f, 0x7e, 0xb8, 0xdc, + 0x05, 0x88, 0x3a, 0x92, 0x5a, 0xf5, 0x9b, 0xa9, + }, + }, + .confirm_rsp[10] = { + .value = { + 0xf7, 0xa2, 0xb6, 0xec, 0xcd, 0xef, 0xcb, 0xb7, + 0x6f, 0xc3, 0xac, 0x17, 0xe2, 0xfd, 0xfa, 0x42, + }, + }, + .random_req[10] = { + .value = { + 0x0d, 0xd1, 0xa2, 0x1d, 0xff, 0x74, 0xc5, 0x99, + 0xe0, 0x67, 0x07, 0x99, 0x95, 0x75, 0x39, 0x76, + }, + }, + .random_rsp[10] = { + .value = { + 0x2f, 0x13, 0xd1, 0x59, 0xfe, 0x20, 0x60, 0xf0, + 0x02, 0x0c, 0xea, 0x79, 0xd7, 0x40, 0x86, 0x85, + }, + }, + .confirm_req[11] = { + .value = { + 0x8b, 0x57, 0x87, 0xdd, 0xb1, 0xcc, 0x2d, 0x65, + 0xc1, 0xba, 0xac, 0x88, 0x48, 0x23, 0xda, 0xe7, + }, + }, + .confirm_rsp[11] = { + .value = { + 0xb3, 0xc4, 0x2e, 0xea, 0x33, 0xaf, 0x12, 0x9c, + 0xb5, 0xab, 0xa1, 0x95, 0x30, 0xca, 0x46, 0x48, + }, + }, + .random_req[11] = { + .value = { + 0x35, 0x57, 0xcd, 0xd5, 0xd2, 0xf8, 0xd7, 0xf2, + 0x7b, 0xe3, 0xd7, 0xba, 0x31, 0xa5, 0xca, 0xfd, + }, + }, + .random_rsp[11] = { + .value = { + 0xe2, 0x3b, 0x20, 0xbe, 0xec, 0xa5, 0x34, 0x3b, + 0x76, 0x23, 0x53, 0x28, 0x36, 0xc4, 0x60, 0x13, + }, + }, + .confirm_req[12] = { + .value = { + 0xc9, 0xfe, 0x03, 0x49, 0xe4, 0xff, 0x7e, 0xf7, + 0x00, 0xd1, 0x2b, 0x13, 0xb1, 0x15, 0x6e, 0x92, + }, + }, + .confirm_rsp[12] = { + .value = { + 0xbc, 0xa2, 0xf2, 0x03, 0x5c, 0xfd, 0x20, 0x7b, + 0xd0, 0x1f, 0xd6, 0x50, 0xec, 0xc6, 0x7b, 0x31, + }, + }, + .random_req[12] = { + .value = { + 0x04, 0x50, 0xea, 0xb8, 0xca, 0x36, 0x1a, 0x61, + 0x92, 0xed, 0xa0, 0x67, 0x78, 0x15, 0x10, 0xb5, + }, + }, + .random_rsp[12] = { + .value = { + 0x0c, 0x8e, 0x9d, 0x7b, 0x9d, 0x7e, 0xda, 0x23, + 0xbb, 0x61, 0xd9, 0xff, 0x46, 0x77, 0x33, 0x1b, + }, + }, + .confirm_req[13] = { + .value = { + 0x9a, 0xff, 0xd6, 0xe5, 0x1a, 0xc3, 0xd3, 0x37, + 0x34, 0xeb, 0x3e, 0x3a, 0x8e, 0x0b, 0x86, 0xb4, + }, + }, + .confirm_rsp[13] = { + .value = { + 0xf6, 0x32, 0x19, 0xb4, 0x08, 0x6b, 0x8a, 0x0f, + 0xc9, 0x9c, 0x1b, 0x68, 0xb8, 0xa0, 0xd0, 0xc9, + }, + }, + .random_req[13] = { + .value = { + 0x86, 0xeb, 0x5c, 0xf9, 0x33, 0x54, 0x7d, 0xe4, + 0xa4, 0xe2, 0xe1, 0xf6, 0x6b, 0xea, 0x34, 0xed, + }, + }, + .random_rsp[13] = { + .value = { + 0xad, 0x53, 0xa0, 0x6e, 0xde, 0x1d, 0xda, 0x99, + 0x31, 0x45, 0xe5, 0x3a, 0x73, 0xa1, 0x5e, 0xe1, + }, + }, + .confirm_req[14] = { + .value = { + 0x93, 0xd4, 0xe0, 0xaa, 0x0c, 0x91, 0xba, 0xde, + 0xc9, 0x5c, 0x68, 0xb0, 0xce, 0xb6, 0x84, 0xcd, + }, + }, + .confirm_rsp[14] = { + .value = { + 0x85, 0xc7, 0x05, 0x02, 0x21, 0x9d, 0x4c, 0x4c, + 0x16, 0xf7, 0x8f, 0x7b, 0xaa, 0xb4, 0x8f, 0x37, + }, + }, + .random_req[14] = { + .value = { + 0x84, 0xfd, 0xf1, 0x39, 0x1a, 0x9a, 0xa5, 0xb8, + 0x49, 0xc0, 0x66, 0xdc, 0x33, 0x71, 0x32, 0x87, + }, + }, + .random_rsp[14] = { + .value = { + 0x5d, 0xaf, 0x38, 0xcd, 0xb5, 0x83, 0xaa, 0xa0, + 0xab, 0x30, 0x82, 0xed, 0x6f, 0xd2, 0x75, 0xe7, + }, + }, + .confirm_req[15] = { + .value = { + 0x88, 0x12, 0xe8, 0x89, 0xd4, 0x52, 0x6d, 0xac, + 0x61, 0x2a, 0x85, 0x85, 0x1e, 0x9c, 0x82, 0x21, + }, + }, + .confirm_rsp[15] = { + .value = { + 0xc1, 0xe9, 0xcd, 0x21, 0x29, 0x6a, 0x78, 0xe4, + 0x7b, 0x7d, 0x73, 0x25, 0x9e, 0x9b, 0x95, 0x8b, + }, + }, + .random_req[15] = { + .value = { + 0x95, 0x87, 0x9d, 0x5a, 0x10, 0x14, 0xa0, 0xdf, + 0x5e, 0x02, 0x22, 0x39, 0x23, 0xc9, 0xbc, 0xba, + }, + }, + .random_rsp[15] = { + .value = { + 0x1b, 0x91, 0xe2, 0xdf, 0xca, 0xfe, 0x2b, 0x61, + 0x33, 0x8c, 0x83, 0xbf, 0xcf, 0xc3, 0x72, 0xcc, + }, + }, + .confirm_req[16] = { + .value = { + 0xce, 0xc9, 0x68, 0xf7, 0xea, 0x41, 0x18, 0x5c, + 0x16, 0x6a, 0x98, 0x13, 0x0c, 0x10, 0xc2, 0xa3, + }, + }, + .confirm_rsp[16] = { + .value = { + 0x97, 0x73, 0xc9, 0x72, 0x68, 0x99, 0x63, 0xed, + 0x81, 0x3b, 0x5c, 0xee, 0x37, 0xfc, 0xca, 0xae, + }, + }, + .random_req[16] = { + .value = { + 0x5b, 0x85, 0xb0, 0x1b, 0xc3, 0xde, 0x18, 0xba, + 0xc1, 0xc7, 0x89, 0x99, 0xfe, 0xcd, 0xdb, 0x6a, + }, + }, + .random_rsp[16] = { + .value = { + 0x5e, 0x1a, 0xcb, 0xbc, 0xda, 0x41, 0x06, 0x5a, + 0x14, 0x34, 0x3a, 0xb1, 0xa1, 0x6f, 0xb2, 0xd8, + }, + }, + .confirm_req[17] = { + .value = { + 0x1d, 0x59, 0x8a, 0xb0, 0x19, 0xe5, 0xff, 0x45, + 0xb6, 0xc3, 0x33, 0x64, 0xd1, 0x6e, 0xee, 0xdd, + }, + }, + .confirm_rsp[17] = { + .value = { + 0x4c, 0x9b, 0xe8, 0x68, 0x52, 0x34, 0xef, 0xe1, + 0x84, 0xbd, 0x37, 0x85, 0x53, 0x0d, 0xd5, 0xc1, + }, + }, + .random_req[17] = { + .value = { + 0xa6, 0xf7, 0x97, 0x18, 0x9a, 0x3e, 0x9d, 0xcf, + 0x91, 0xa3, 0xa3, 0x8e, 0xda, 0x8f, 0x8f, 0x90, + }, + }, + .random_rsp[17] = { + .value = { + 0x94, 0x10, 0x19, 0x17, 0x8d, 0x0a, 0x72, 0xfd, + 0x24, 0x9d, 0xfd, 0x37, 0x4e, 0xdf, 0x4c, 0x30, + }, + }, + .confirm_req[18] = { + .value = { + 0xfc, 0x64, 0x8a, 0x8b, 0x37, 0x17, 0x90, 0x6d, + 0x25, 0x0e, 0xc6, 0x18, 0xc9, 0xc9, 0xc2, 0x2a, + }, + }, + .confirm_rsp[18] = { + .value = { + 0x50, 0x98, 0x86, 0xf5, 0xc0, 0xda, 0x45, 0x2d, + 0xea, 0xc8, 0x9d, 0x28, 0x04, 0xd8, 0x73, 0x6f, + }, + }, + .random_req[18] = { + .value = { + 0x13, 0x10, 0x38, 0xe8, 0x17, 0x6d, 0x72, 0xd5, + 0x94, 0xaf, 0xed, 0x4f, 0x23, 0xa0, 0x41, 0xfc, + }, + }, + .random_rsp[18] = { + .value = { + 0xdf, 0xed, 0xf7, 0x08, 0xce, 0x64, 0xbc, 0x11, + 0x41, 0x7a, 0xd9, 0xf7, 0x4a, 0xd9, 0x4a, 0x15, + }, + }, + .confirm_req[19] = { + .value = { + 0xae, 0x24, 0x8f, 0xdf, 0xb0, 0x57, 0xc4, 0x9c, + 0xe6, 0xae, 0x9b, 0xc2, 0x4d, 0x3d, 0x1c, 0xcb, + }, + }, + .confirm_rsp[19] = { + .value = { + 0xcc, 0x5c, 0xa3, 0xbe, 0xd7, 0x83, 0xee, 0x60, + 0x80, 0xff, 0x5f, 0x1a, 0x07, 0xbf, 0x4c, 0x33, + }, + }, + .random_req[19] = { + .value = { + 0x93, 0xc3, 0x62, 0x06, 0xcb, 0xe5, 0xb0, 0x01, + 0x02, 0x18, 0xa2, 0x50, 0x4c, 0x73, 0xa2, 0x27, + }, + }, + .random_rsp[19] = { + .value = { + 0x11, 0x2a, 0xd3, 0x06, 0x28, 0x9c, 0xdf, 0x73, + 0xa5, 0xa4, 0xe5, 0x1e, 0x07, 0xcf, 0xee, 0x71, + }, + }, + .dhkey_check_req = { + .value = { + 0x73, 0xa0, 0x40, 0x58, 0x78, 0x20, 0x5f, 0x2c, + 0xf4, 0x19, 0x23, 0xa8, 0x74, 0xbd, 0xc2, 0x3e, + }, + }, + .dhkey_check_rsp = { + .value = { + 0x5a, 0x30, 0xbc, 0xce, 0xec, 0xdf, 0xf0, 0x32, + 0x3c, 0x18, 0xa3, 0xd3, 0x3f, 0x20, 0x87, 0x10, + }, + }, + .sign_info_req = { + .sig_key = { + 0x2e, 0x81, 0x09, 0xde, 0x32, 0xc5, 0x28, 0x34, + 0xe1, 0x45, 0x4a, 0x35, 0x49, 0xef, 0xa2, 0xed, + }, + }, + .id_info_rsp = { + .irk = { + 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d, + 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8, + }, + }, + .id_addr_info_rsp = { + .addr_type = 0, + .bd_addr = { + 0x01, 0x01, 0x01, 0x07, 0x08, 0x01, + }, + }, + .sign_info_rsp = { + .sig_key = { + 0x90, 0x3d, 0x26, 0x65, 0xc1, 0xd1, 0x5a, 0x9d, + 0xda, 0xab, 0x0d, 0x00, 0x05, 0x0e, 0x6c, 0x5d, + }, + }, + .ltk = { + 0xf1, 0x41, 0x1a, 0x5b, 0x60, 0xc1, 0x43, 0xc6, + 0x80, 0x34, 0x5e, 0x7f, 0xd8, 0x0c, 0x75, 0xdc, + }, + .pair_alg = BLE_SM_PAIR_ALG_PASSKEY, + .authenticated = 1, + .passkey_info = { + .passkey = { + .action = BLE_SM_IOACT_INPUT, + .passkey = 516645, + }, + }, + }; + ble_sm_test_util_us_sc_bad(¶ms); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} /** * Secure connections pairing * Master: us diff --git a/nimble/host/test/src/ble_sm_test_util.c b/nimble/host/test/src/ble_sm_test_util.c index 6170371f51..bad473f178 100644 --- a/nimble/host/test/src/ble_sm_test_util.c +++ b/nimble/host/test/src/ble_sm_test_util.c @@ -844,6 +844,35 @@ ble_sm_test_util_rx_public_key(uint16_t conn_handle, TEST_ASSERT_FATAL(rc == 0); } +static void +ble_sm_test_util_rx_public_key_bad(uint16_t conn_handle, + struct ble_sm_public_key *cmd) +{ + struct hci_data_hdr hci_hdr; + struct os_mbuf *om; + void *v; + int payload_len; + int rc; + + hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR( + 2, BLE_HCI_PB_FIRST_FLUSH, + BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key)); + + om = ble_hs_mbuf_l2cap_pkt(); + TEST_ASSERT_FATAL(om != NULL); + + payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key); + + v = os_mbuf_extend(om, payload_len); + TEST_ASSERT_FATAL(v != NULL); + + ble_sm_public_key_write(v, payload_len, cmd); + + rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM, + &hci_hdr, om); + TEST_ASSERT_FATAL(rc != 0); +} + static void ble_sm_test_util_rx_dhkey_check(uint16_t conn_handle, struct ble_sm_dhkey_check *cmd, @@ -2567,6 +2596,52 @@ ble_sm_test_util_us_sc_good_once_no_init( ble_hs_test_util_conn_disconnect(2); } +static void +ble_sm_test_util_us_sc_bad_once_no_init(struct ble_sm_test_params *params, + struct ble_hs_conn *conn, + struct ble_sm_test_util_entity *our_entity, + struct ble_sm_test_util_entity *peer_entity) +{ + int rc; + + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 0); + + ble_hs_test_util_hci_ack_set( + ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_START_ENCRYPT), 0); + if (params->sec_req.authreq != 0) { + ble_sm_test_util_rx_sec_req(2, ¶ms->sec_req, 0); + } else { + /* Initiate the pairing procedure. */ + rc = ble_gap_security_initiate(2); + TEST_ASSERT_FATAL(rc == 0); + } + + /* Ensure we sent the expected pair request. */ + ble_sm_test_util_verify_tx_pair_req(our_entity->pair_cmd); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a pair response from the peer. */ + ble_sm_test_util_rx_pair_rsp(2, peer_entity->pair_cmd, 0); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Ensure we sent the expected public key. */ + ble_sm_test_util_verify_tx_public_key(our_entity->public_key); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); + ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action); + + /* Receive a wrong public key from the peer. */ + ble_sm_test_util_rx_public_key_bad(2, peer_entity->public_key); + TEST_ASSERT(!conn->bhc_sec_state.encrypted); + TEST_ASSERT(ble_sm_num_procs() == 1); +} + static void ble_sm_test_util_us_sc_good_once(struct ble_sm_test_params *params) { @@ -2579,6 +2654,17 @@ ble_sm_test_util_us_sc_good_once(struct ble_sm_test_params *params) params, conn, &our_entity, &peer_entity); } +static void +ble_sm_test_util_us_sc_bad_once(struct ble_sm_test_params *params) +{ + struct ble_sm_test_util_entity peer_entity; + struct ble_sm_test_util_entity our_entity; + struct ble_hs_conn *conn; + + ble_sm_test_util_init_good(params, 1, &conn, &our_entity, &peer_entity); + ble_sm_test_util_us_sc_bad_once_no_init( + params, conn, &our_entity, &peer_entity); +} void ble_sm_test_util_us_sc_good(struct ble_sm_test_params *params) { @@ -2610,12 +2696,22 @@ ble_sm_test_util_us_sc_good(struct ble_sm_test_params *params) TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0); } +void +ble_sm_test_util_us_sc_bad(struct ble_sm_test_params *params) +{ + /*** We are master. */ + + /* We initiate pairing. */ + params->passkey_info.io_before_rx = 0; + params->sec_req.authreq = 0; + ble_sm_test_util_us_sc_bad_once(params); +} + static void -ble_sm_test_util_peer_sc_good_once_no_init( - struct ble_sm_test_params *params, - struct ble_hs_conn *conn, - struct ble_sm_test_util_entity *our_entity, - struct ble_sm_test_util_entity *peer_entity) +ble_sm_test_util_peer_sc_good_once_no_init(struct ble_sm_test_params *params, + struct ble_hs_conn *conn, + struct ble_sm_test_util_entity *our_entity, + struct ble_sm_test_util_entity *peer_entity) { int num_iters; int rc; diff --git a/nimble/host/test/src/ble_sm_test_util.h b/nimble/host/test/src/ble_sm_test_util.h index d8629b60c0..d9aa3805c7 100644 --- a/nimble/host/test/src/ble_sm_test_util.h +++ b/nimble/host/test/src/ble_sm_test_util.h @@ -119,6 +119,7 @@ void ble_sm_test_util_peer_lgcy_good(struct ble_sm_test_params *params); void ble_sm_test_util_peer_bonding_bad(uint16_t ediv, uint64_t rand_num); void ble_sm_test_util_peer_sc_good(struct ble_sm_test_params *params); void ble_sm_test_util_us_sc_good(struct ble_sm_test_params *params); +void ble_sm_test_util_us_sc_bad(struct ble_sm_test_params *params); void ble_sm_test_util_us_fail_inval(struct ble_sm_test_params *params); #ifdef __cplusplus diff --git a/nimble/host/test/syscfg.yml b/nimble/host/test/syscfg.yml index 6307398e4c..45bc638b62 100644 --- a/nimble/host/test/syscfg.yml +++ b/nimble/host/test/syscfg.yml @@ -29,3 +29,4 @@ syscfg.vals: CONFIG_FCB: 1 BLE_VERSION: 52 BLE_L2CAP_ENHANCED_COC: 1 + BLE_HCI_TRANSPORT: ram diff --git a/nimble/include/nimble/ble.h b/nimble/include/nimble/ble.h index 248e8ae834..d349afebb0 100644 --- a/nimble/include/nimble/ble.h +++ b/nimble/include/nimble/ble.h @@ -88,6 +88,9 @@ struct ble_mbuf_hdr_rxinfo * set for the same PDU (e.g. one use by scanner, other one used by * connection) */ +#define BLE_MBUF_HDR_F_CONNECT_IND_TXD (0x4000) +#define BLE_MBUF_HDR_F_CONNECT_REQ_TXD (0x4000) +#define BLE_MBUF_HDR_F_CONNECT_RSP_RXD (0x0008) #define BLE_MBUF_HDR_F_CONN_CREDIT (0x8000) #define BLE_MBUF_HDR_F_IGNORED (0x8000) #define BLE_MBUF_HDR_F_SCAN_REQ_TXD (0x4000) @@ -109,9 +112,9 @@ struct ble_mbuf_hdr_rxinfo struct ble_mbuf_hdr_txinfo { uint8_t flags; - uint8_t offset; - uint8_t pyld_len; uint8_t hdr_byte; + uint16_t offset; + uint16_t pyld_len; }; struct ble_mbuf_hdr diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 92031c3c16..e4830833b3 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -1061,12 +1061,24 @@ struct ble_hci_le_set_host_feat_cp { uint8_t val; } __attribute__((packed)); -/* --- Vendor specific commands (OGF 0x00FF) */ -#define BLE_HCI_OCF_VS_RD_STATIC_ADDR (0x0001) +/* --- Vendor specific commands (OGF 0x003F) */ +/* Read Random Static Address */ +#define BLE_HCI_OCF_VS_RD_STATIC_ADDR (0x0001) struct ble_hci_vs_rd_static_addr_rp { uint8_t addr[6]; } __attribute__((packed)); +/* Set default transmit power. Actual selected TX power is returned + * in reply. Setting 0xff restores controller reset default. + */ +#define BLE_HCI_OCF_VS_SET_TX_PWR (0x0002) +struct ble_hci_vs_set_tx_pwr_cp { + int8_t tx_power; +} __attribute__((packed)); +struct ble_hci_vs_set_tx_pwr_rp { + int8_t tx_power; +} __attribute__((packed)); + /* Command Specific Definitions */ /* --- Set controller to host flow control (OGF 0x03, OCF 0x0031) --- */ #define BLE_HCI_CTLR_TO_HOST_FC_OFF (0) @@ -1152,11 +1164,13 @@ struct ble_hci_vs_rd_static_addr_rp { /* Scan interval and scan window timing */ #define BLE_HCI_SCAN_ITVL (625) /* usecs */ -#define BLE_HCI_SCAN_ITVL_MIN (4) /* units */ -#define BLE_HCI_SCAN_ITVL_MAX (16384) /* units */ +#define BLE_HCI_SCAN_ITVL_MIN (0x0004) /* units */ +#define BLE_HCI_SCAN_ITVL_MAX (0x4000) /* units */ +#define BLE_HCI_SCAN_ITVL_MAX_EXT (0xffff) /* units */ #define BLE_HCI_SCAN_ITVL_DEF (16) /* units */ -#define BLE_HCI_SCAN_WINDOW_MIN (4) /* units */ -#define BLE_HCI_SCAN_WINDOW_MAX (16384) /* units */ +#define BLE_HCI_SCAN_WINDOW_MIN (0x0004) /* units */ +#define BLE_HCI_SCAN_WINDOW_MAX (0x4000) /* units */ +#define BLE_HCI_SCAN_WINDOW_MAX_EXT (0xffff) /* units */ #define BLE_HCI_SCAN_WINDOW_DEF (16) /* units */ /* @@ -1444,8 +1458,8 @@ struct ble_hci_ev_auth_pyld_tmo { #define BLE_HCI_EVCODE_SAM_STATUS_CHG (0x58) -#define BLE_HCI_EVCODE_VENDOR_DEBUG (0xFF) -struct ble_hci_ev_vendor_debug { +#define BLE_HCI_EVCODE_VS_DEBUG (0xFF) +struct ble_hci_ev_vs_debug { uint8_t id; uint8_t data[0]; } __attribute__((packed)); @@ -1826,6 +1840,7 @@ struct ble_hci_ev_le_subev_biginfo_adv_report { #define BLE_HCI_VER_BCS_5_0 (9) #define BLE_HCI_VER_BCS_5_1 (10) #define BLE_HCI_VER_BCS_5_2 (11) +#define BLE_HCI_VER_BCS_5_3 (12) #define BLE_LMP_VER_BCS_1_0b (0) #define BLE_LMP_VER_BCS_1_1 (1) @@ -1839,6 +1854,7 @@ struct ble_hci_ev_le_subev_biginfo_adv_report { #define BLE_LMP_VER_BCS_5_0 (9) #define BLE_LMP_VER_BCS_5_1 (10) #define BLE_LMP_VER_BCS_5_2 (11) +#define BLE_LMP_VER_BCS_5_3 (12) /* selected HCI and LMP version */ #if MYNEWT_VAL(BLE_VERSION) == 50 @@ -1850,7 +1866,9 @@ struct ble_hci_ev_le_subev_biginfo_adv_report { #elif MYNEWT_VAL(BLE_VERSION) == 52 #define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_5_2 #define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_5_2 - +#elif MYNEWT_VAL(BLE_VERSION) == 53 +#define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_5_3 +#define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_5_3 #endif #define BLE_HCI_DATA_HDR_SZ 4 diff --git a/nimble/syscfg.yml b/nimble/syscfg.yml index b5cfc585d6..0e87c0647d 100644 --- a/nimble/syscfg.yml +++ b/nimble/syscfg.yml @@ -67,6 +67,7 @@ syscfg.defs: value: 0 restrictions: - 'BLE_PERIODIC_ADV if 1' + - '(BLE_ROLE_CENTRAL || BLE_ROLE_PERIPHERAL) if 1' BLE_EXT_ADV_MAX_SIZE: description: > @@ -79,7 +80,7 @@ syscfg.defs: This allows to configure supported Bluetooth Core version. Some features may not be available if version is too low. Version is integer for easy comparison. - range: 50, 51, 52 + range: 50, 51, 52, 53 value: 50 BLE_ISO: description: > diff --git a/nimble/transport/da1469x/syscfg.yml b/nimble/transport/da1469x/syscfg.yml index 4ea9da9b36..2ce8cd3cf2 100644 --- a/nimble/transport/da1469x/syscfg.yml +++ b/nimble/transport/da1469x/syscfg.yml @@ -16,28 +16,12 @@ # under the License. # -syscfg.defs: - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 +syscfg.vals.'!BLE_HCI_BRIDGE && !BLE_EXT_ADV': + BLE_HCI_EVT_HI_BUF_COUNT: 2 + BLE_HCI_EVT_LO_BUF_COUNT: 8 + BLE_HCI_EVT_BUF_SIZE: 70 + BLE_ACL_BUF_COUNT: 4 + BLE_ACL_BUF_SIZE: 255 - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - -syscfg.vals.BLE_EXT_ADV: +syscfg.vals.'!BLE_HCI_BRIDGE && BLE_EXT_ADV': BLE_HCI_EVT_BUF_SIZE: 274 diff --git a/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c b/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c index 4f75470654..0a4e27e6d5 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c +++ b/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c @@ -20,7 +20,7 @@ #include "syscfg/syscfg.h" #include "mcu/mcu.h" -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) void cmac_diag_setup_host(void) { diff --git a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h b/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h index 90b5827dd4..4e37bb8b82 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h +++ b/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h @@ -131,7 +131,7 @@ struct cmac_shared_data { uint8_t mbox_c2s_buf[ MYNEWT_VAL(CMAC_MBOX_SIZE_C2S) ]; }; -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) extern volatile struct cmac_shared_data *g_cmac_shared_data; #elif MYNEWT_VAL(BLE_CONTROLLER) extern volatile struct cmac_shared_data g_cmac_shared_data; @@ -161,7 +161,7 @@ void cmac_rand_set_isr_cb(cmac_rand_isr_cb_t cb); void cmac_shared_init(void); void cmac_shared_sync(void); -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) #define CMAC_SHARED_LOCK_VAL 0x40000000 #elif MYNEWT_VAL(BLE_CONTROLLER) #define CMAC_SHARED_LOCK_VAL 0xc0000000 diff --git a/nimble/transport/dialog_cmac/cmac_driver/pkg.yml b/nimble/transport/dialog_cmac/cmac_driver/pkg.yml index 5b4a212914..00200b65a7 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/pkg.yml +++ b/nimble/transport/dialog_cmac/cmac_driver/pkg.yml @@ -37,3 +37,6 @@ pkg.post_link_cmds.BLE_CONTROLLER: pkg.pre_link_cmds.BLE_HOST: scripts/build_libcmac.sh: 100 + +pkg.pre_link_cmds.BLE_HCI_BRIDGE: + scripts/build_libcmac.sh: 100 diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c index 9594dbe900..88764c4dfc 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c +++ b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c @@ -49,7 +49,7 @@ cmac_mbox_set_write_notif_cb(cmac_mbox_write_notif_cb *cb) int cmac_mbox_read(void) { -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) volatile struct cmac_mbox *mbox = &g_cmac_shared_data->mbox_c2s; uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data->mbox_c2s_buf; const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_C2S); @@ -96,7 +96,7 @@ cmac_mbox_read(void) int cmac_mbox_write(const void *data, uint16_t len) { -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) volatile struct cmac_mbox *mbox = &g_cmac_shared_data->mbox_s2c; uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data->mbox_s2c_buf; const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_S2C); diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c index 67a315f96e..10810972ca 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c +++ b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c @@ -26,7 +26,7 @@ #include "os/os_arch.h" #include "os/os.h" -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) int cmac_rand_is_active(void) { diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c index 24640ca475..a4f2e37f56 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c +++ b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c @@ -34,7 +34,7 @@ #define min(_a, _b) ((_a) < (_b) ? (_a) : (_b)) #endif -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) volatile struct cmac_shared_data *g_cmac_shared_data; #include "mcu/da1469x_clock.h" #define MCU_DIAG_SER(_x) @@ -45,7 +45,7 @@ volatile struct cmac_shared_data g_cmac_shared_data __attribute__((section(" void cmac_shared_init(void) { -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) g_cmac_shared_data = (void *)(MCU_MEM_SYSRAM_START_ADDRESS + MEMCTRL->CMI_SHARED_BASE_REG); @@ -77,7 +77,7 @@ cmac_shared_sync(void) * to wait until CMAC finished initialization as otherwise host may start * sending HCI packets which will timeout as there is no one to read them. */ -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) assert(g_cmac_shared_data->magic_sys == 0); while (g_cmac_shared_data->magic_cmac != CMAC_SHARED_MAGIC_CMAC); diff --git a/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c b/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c index 665b62166b..5a41ee6313 100644 --- a/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c +++ b/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c @@ -41,6 +41,7 @@ BLE_MBUF_MEMBLOCK_OVERHEAD + \ BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) static uint8_t ble_hci_pool_cmd_mempool_buf[ OS_MEMPOOL_BYTES(HCI_CMD_COUNT, BLE_HCI_TRANS_CMD_SZ)]; static struct os_mempool ble_hci_pool_cmd_mempool; @@ -54,6 +55,7 @@ static uint8_t ble_hci_pool_evt_lo_mempool_buf[ OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; static struct os_mempool ble_hci_pool_evt_lo_mempool; +#endif static uint8_t ble_hci_pool_acl_mempool_buf[ OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_ACL_BUF_COUNT), @@ -66,6 +68,7 @@ __attribute__((weak)) void ble_hci_trans_notify_free(void); static os_mempool_put_fn *g_ble_hci_pool_acl_mempool_put_cb; static void *g_ble_hci_pool_acl_mempool_put_arg; +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) int ble_hci_trans_reset(void) { @@ -117,6 +120,7 @@ ble_hci_trans_buf_free(uint8_t *buf) ble_hci_trans_notify_free(); } +#endif struct os_mbuf * ble_hci_cmac_alloc_acl_mbuf(void) @@ -147,6 +151,7 @@ ble_hci_cmac_free_acl_cb(struct os_mempool_ext *mpe, void *data, void *arg) } +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) { @@ -155,6 +160,7 @@ ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) return 0; } +#endif void ble_hci_cmac_init(void) @@ -163,6 +169,7 @@ ble_hci_cmac_init(void) SYSINIT_ASSERT_ACTIVE(); +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) rc = os_mempool_init(&ble_hci_pool_cmd_mempool, HCI_CMD_COUNT, BLE_HCI_TRANS_CMD_SZ, ble_hci_pool_cmd_mempool_buf, "ble_hci_cmd"); @@ -179,6 +186,7 @@ ble_hci_cmac_init(void) MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), ble_hci_pool_evt_lo_mempool_buf, "ble_hci_evt_lo"); SYSINIT_PANIC_ASSERT(rc == 0); +#endif rc = os_mempool_ext_init(&ble_hci_pool_acl_mempool, MYNEWT_VAL(BLE_ACL_BUF_COUNT), POOL_ACL_BLOCK_SIZE, diff --git a/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c b/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c index 1164fe7186..266637f78e 100644 --- a/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c +++ b/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c @@ -21,7 +21,7 @@ #include #include "syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) #include "cmac_driver/cmac_shared.h" #include "cmac_driver/cmac_host.h" @@ -41,6 +41,27 @@ static struct ble_hci_cmac_hs_api g_ble_hci_cmac_hs_api; static struct ble_hci_trans_h4_rx_state g_ble_hci_cmac_hs_rx_state; static bool g_ble_hci_cmac_hs_read_err; +#if MYNEWT_VAL(BLE_HCI_BRIDGE) +/* + * TODO: Remove/fix functions ble_ll_data_buffer_overflow() ble_ll_hw_error() + * Following two functions are added to allowed build of HCI bridge configurations. + * Those functions are only used by UART transport, in RAM transport configuration + * they can be called directly in bridge mode controller code is on other core + * and those can't be called. + */ +void +ble_ll_data_buffer_overflow(void) +{ + +} + +void +ble_ll_hw_error(uint8_t err) +{ + (void)err; +} +#endif + static int ble_hci_cmac_hs_frame_cb(uint8_t pkt_type, void *data) { diff --git a/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c b/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c index 3531529c71..6b49158ad9 100644 --- a/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c +++ b/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c @@ -92,12 +92,17 @@ int ble_hci_trans_ll_evt_tx(uint8_t *evt) { uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_EVT; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); cmac_mbox_write(&pkt_type, sizeof(pkt_type)); cmac_mbox_write(evt, evt[1] + 2); ble_hci_trans_buf_free(evt); + OS_EXIT_CRITICAL(sr); + return 0; } diff --git a/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c b/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c index 74da391239..628ae75d96 100644 --- a/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c +++ b/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c @@ -64,7 +64,7 @@ ble_hci_trans_h4_rxs_start(struct ble_hci_trans_h4_rx_state *rxs, uint8_t pkt_ty case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: rxs->min_len = 4; break; -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: rxs->min_len = 2; break; @@ -95,7 +95,7 @@ static int ble_hci_trans_h4_rx_state_w4_header(struct ble_hci_trans_h4_rx_state *rxs, struct input_buffer *ib) { -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) int pool; #endif int rc; @@ -127,7 +127,7 @@ ble_hci_trans_h4_rx_state_w4_header(struct ble_hci_trans_h4_rx_state *rxs, os_mbuf_append(rxs->om, rxs->hdr, rxs->len); rxs->expected_len = get_le16(&rxs->hdr[2]) + 4; break; -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: pool = BLE_HCI_TRANS_BUF_EVT_HI; if (rxs->hdr[0] == BLE_HCI_EVCODE_LE_META) { @@ -194,7 +194,7 @@ ble_hci_trans_h4_rx_state_w4_payload(struct ble_hci_trans_h4_rx_state *rxs, #if MYNEWT_VAL(BLE_CONTROLLER) case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: #endif -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: #endif if (rxs->buf) { @@ -240,7 +240,7 @@ ble_hci_trans_h4_rx_state_completed(struct ble_hci_trans_h4_rx_state *rxs, #if MYNEWT_VAL(BLE_CONTROLLER) case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: #endif -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: #endif if (rxs->buf) { diff --git a/nimble/transport/dialog_cmac/syscfg.yml b/nimble/transport/dialog_cmac/syscfg.yml index c44773efcd..54607fd814 100644 --- a/nimble/transport/dialog_cmac/syscfg.yml +++ b/nimble/transport/dialog_cmac/syscfg.yml @@ -16,28 +16,12 @@ # under the License. # -syscfg.defs: - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 +syscfg.vals.'!BLE_HCI_BRIDGE && !(BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV)': + BLE_HCI_EVT_HI_BUF_COUNT: 2 + BLE_HCI_EVT_LO_BUF_COUNT: 8 + BLE_HCI_EVT_BUF_SIZE: 70 + BLE_ACL_BUF_COUNT: 4 + BLE_ACL_BUF_SIZE: 255 - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - -syscfg.vals.'BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV': +syscfg.vals.'!BLE_HCI_BRIDGE && (BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV)': BLE_HCI_EVT_BUF_SIZE: 257 diff --git a/nimble/transport/emspi/syscfg.yml b/nimble/transport/emspi/syscfg.yml index 4751271b0d..501175467a 100644 --- a/nimble/transport/emspi/syscfg.yml +++ b/nimble/transport/emspi/syscfg.yml @@ -28,28 +28,6 @@ syscfg.defs: # This is a host-only transport. - BLE_HOST - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 - - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - BLE_HCI_ACL_OUT_COUNT: description: > This count is used in creating a pool of elements used by the @@ -95,5 +73,12 @@ syscfg.defs: Sysinit stage for the EMSPI BLE transport. value: 100 -syscfg.vals.BLE_EXT_ADV: +syscfg.vals.'!BLE_HCI_BRIDGE && BLE_EXT_ADV': BLE_HCI_EVT_BUF_SIZE: 257 + +syscfg.vals.'!BLE_HCI_BRIDGE && !BLE_EXT_ADV': + BLE_HCI_EVT_HI_BUF_COUNT: 2 + BLE_HCI_EVT_LO_BUF_COUNT: 8 + BLE_HCI_EVT_BUF_SIZE: 70 + BLE_ACL_BUF_COUNT: 4 + BLE_ACL_BUF_SIZE: 255 diff --git a/nimble/transport/nrf5340/src/nrf5340_ble_hci.c b/nimble/transport/nrf5340/src/nrf5340_ble_hci.c index 3f113e1175..41f164edb2 100644 --- a/nimble/transport/nrf5340/src/nrf5340_ble_hci.c +++ b/nimble/transport/nrf5340/src/nrf5340_ble_hci.c @@ -39,7 +39,7 @@ #define IPC_RX_CHANNEL 1 #endif -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) #define IPC_TX_CHANNEL 1 #define IPC_RX_CHANNEL 0 #endif @@ -49,7 +49,7 @@ struct nrf5340_ble_hci_api { ble_hci_trans_rx_cmd_fn *cmd_cb; void *cmd_arg; #endif -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) ble_hci_trans_rx_cmd_fn *evt_cb; void *evt_arg; #endif @@ -73,8 +73,21 @@ struct nrf5340_ble_hci_pool_cmd { bool allocated; }; -/* (Pseudo)pool for HCI commands */ -static struct nrf5340_ble_hci_pool_cmd nrf5340_ble_hci_pool_cmd; +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) +/* + * If controller-to-host flow control is enabled we need to hold an extra command + * buffer for HCI_Host_Number_Of_Completed_Packets which can be sent at any time. + */ +#if MYNEWT_VAL(BLE_HS_FLOW_CTRL) || MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) +#define HCI_CMD_COUNT 2 +#else +#define HCI_CMD_COUNT 1 +#endif + +static uint8_t nrf5340_ble_hci_pool_cmd_mempool_buf[OS_MEMPOOL_BYTES( + HCI_CMD_COUNT, + BLE_HCI_TRANS_CMD_SZ)]; +static struct os_mempool nrf5340_ble_hci_pool_cmd_mempool; /* Pools for HCI events (high and low priority) */ static uint8_t nrf5340_ble_hci_pool_evt_hi_buf[OS_MEMPOOL_BYTES( @@ -86,11 +99,13 @@ static uint8_t nrf5340_ble_hci_pool_evt_lo_buf[OS_MEMPOOL_BYTES( MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; static struct os_mempool nrf5340_ble_hci_pool_evt_lo; +#endif + /* Pool for ACL data */ static uint8_t nrf5340_ble_hci_pool_acl_buf[OS_MEMPOOL_BYTES( MYNEWT_VAL(BLE_ACL_BUF_COUNT), POOL_ACL_BLOCK_SIZE)]; -static struct os_mempool nrf5340_ble_hci_pool_acl; +static struct os_mempool_ext nrf5340_ble_hci_pool_acl; static struct os_mbuf_pool nrf5340_ble_hci_pool_acl_mbuf; /* Interface to host/ll */ @@ -99,12 +114,35 @@ static struct nrf5340_ble_hci_api nrf5340_ble_hci_api; /* State of RX currently in progress (needs to reassemble frame) */ static struct nrf5340_ble_hci_rx_data nrf5340_ble_hci_rx_data; +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) int ble_hci_trans_reset(void) { /* XXX Should we do something with RF and/or BLE core? */ return 0; } +#endif + +#if MYNEWT_VAL(BLE_HCI_BRIDGE) +/* + * TODO: Remove/fix functions ble_ll_data_buffer_overflow() ble_ll_hw_error() + * Following two functions are added to allowed build of HCI bridge configurations. + * Those functions are only used by UART transport, in RAM transport configuration + * they can be called directly in bridge mode controller code is on other core + * and those can't be called. + */ +void +ble_ll_data_buffer_overflow(void) +{ + +} + +void +ble_ll_hw_error(uint8_t err) +{ + (void)err; +} +#endif static int ble_hci_trans_acl_tx(struct os_mbuf *om) @@ -165,7 +203,7 @@ ble_hci_trans_ll_acl_tx(struct os_mbuf *om) } #endif -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, void *evt_arg, ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) @@ -200,6 +238,7 @@ ble_hci_trans_hs_acl_tx(struct os_mbuf *om) } #endif +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) uint8_t * ble_hci_trans_buf_alloc(int type) { @@ -207,9 +246,7 @@ ble_hci_trans_buf_alloc(int type) switch (type) { case BLE_HCI_TRANS_BUF_CMD: - assert(!nrf5340_ble_hci_pool_cmd.allocated); - nrf5340_ble_hci_pool_cmd.allocated = 1; - buf = nrf5340_ble_hci_pool_cmd.cmd; + buf = os_memblock_get(&nrf5340_ble_hci_pool_cmd_mempool); break; case BLE_HCI_TRANS_BUF_EVT_HI: buf = os_memblock_get(&nrf5340_ble_hci_pool_evt_hi); @@ -233,9 +270,9 @@ ble_hci_trans_buf_free(uint8_t *buf) { int rc; - if (buf == nrf5340_ble_hci_pool_cmd.cmd) { - assert(nrf5340_ble_hci_pool_cmd.allocated); - nrf5340_ble_hci_pool_cmd.allocated = 0; + if (os_memblock_from(&nrf5340_ble_hci_pool_cmd_mempool, buf)) { + rc = os_memblock_put(&nrf5340_ble_hci_pool_cmd_mempool, buf); + assert(rc == 0); } else if (os_memblock_from(&nrf5340_ble_hci_pool_evt_hi, buf)) { rc = os_memblock_put(&nrf5340_ble_hci_pool_evt_hi, buf); assert(rc == 0); @@ -245,12 +282,13 @@ ble_hci_trans_buf_free(uint8_t *buf) assert(rc == 0); } } +#endif static void nrf5340_ble_hci_trans_rx_process(int channel) { struct nrf5340_ble_hci_rx_data *rxd = &nrf5340_ble_hci_rx_data; -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) int pool = BLE_HCI_TRANS_BUF_EVT_HI; #endif int rc; @@ -262,23 +300,37 @@ nrf5340_ble_hci_trans_rx_process(int channel) rxd->expected_len = 0; #if MYNEWT_VAL(BLE_CONTROLLER) - assert((rxd->type == HCI_PKT_ACL) || (rxd->type = HCI_PKT_CMD)); + assert((rxd->type == HCI_PKT_ACL) || (rxd->type == HCI_PKT_CMD)); #endif -#if MYNEWT_VAL(BLE_HOST) - assert((rxd->type == HCI_PKT_ACL) || (rxd->type = HCI_PKT_EVT)); +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) + assert((rxd->type == HCI_PKT_ACL) || (rxd->type == HCI_PKT_EVT)); #endif break; #if MYNEWT_VAL(BLE_CONTROLLER) case HCI_PKT_CMD: - /* commands are sent complete over IPC */ - rxd->len = ipc_nrf5340_read(channel, rxd->hdr, 3); - assert(rxd->len == 3); + /* header */ + if (rxd->len < 3) { + rxd->len += ipc_nrf5340_read(channel, &rxd->hdr[rxd->len], + 3 - rxd->len); + if (rxd->len < 3) { + break; + } + } - rxd->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - memcpy(rxd->buf, rxd->hdr, rxd->len); + if (rxd->expected_len == 0) { + rxd->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + memcpy(rxd->buf, rxd->hdr, rxd->len); - rxd->len += ipc_nrf5340_read(channel, &rxd->buf[rxd->len], rxd->hdr[2]); - assert(rxd->len == 3 + rxd->hdr[2]); + rxd->expected_len = 3 + rxd->hdr[2]; + } + + if (rxd->len < rxd->expected_len) { + rxd->len += ipc_nrf5340_read(channel, &rxd->buf[rxd->len], + rxd->expected_len - rxd->len); + if (rxd->len < rxd->expected_len) { + break; + } + } rc = nrf5340_ble_hci_api.cmd_cb(rxd->buf, nrf5340_ble_hci_api.cmd_arg); if (rc != 0) { @@ -288,16 +340,25 @@ nrf5340_ble_hci_trans_rx_process(int channel) rxd->type = HCI_PKT_NONE; break; #endif -#if MYNEWT_VAL(BLE_HOST) +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) case HCI_PKT_EVT: - /* events are sent complete over IPC */ - rxd->len = ipc_nrf5340_read(channel, rxd->hdr, 2); - assert(rxd->len == 2); + /* header */ + if (rxd->len < 2) { + rxd->len += ipc_nrf5340_read(channel, &rxd->hdr[rxd->len], + 2 - rxd->len); + if (rxd->len < 2) { + break; + } + } if (rxd->hdr[0] == BLE_HCI_EVCODE_LE_META) { - /* For LE Meta event we need 3 bytes to parse header */ - rxd->len += ipc_nrf5340_read(channel, rxd->hdr + 2, 1); - assert(rxd->len == 3); + if (rxd->len < 3) { + /* For LE Meta event we need 3 bytes to parse header */ + rxd->len += ipc_nrf5340_read(channel, &rxd->hdr[rxd->len], 1); + if (rxd->len < 3) { + break; + } + } /* Advertising reports shall be allocated from low-prio pool */ if ((rxd->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) || @@ -306,26 +367,33 @@ nrf5340_ble_hci_trans_rx_process(int channel) } } - rxd->buf = ble_hci_trans_buf_alloc(pool); - if (!rxd->buf) { - /* - * Only care about valid buffer when shall be allocated from - * high-prio pool, otherwise NULL is fine and we'll just skip - * this event. - */ - if (pool != BLE_HCI_TRANS_BUF_EVT_LO) { - rxd->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + if (rxd->expected_len == 0) { + rxd->buf = ble_hci_trans_buf_alloc(pool); + if (!rxd->buf) { + /* + * Only care about valid buffer when shall be allocated from + * high-prio pool, otherwise NULL is fine and we'll just skip + * this event. + */ + if (pool != BLE_HCI_TRANS_BUF_EVT_LO) { + rxd->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + } } - } - rxd->expected_len = 2 + rxd->hdr[1]; + rxd->expected_len = 2 + rxd->hdr[1]; - if (rxd->buf) { - memcpy(rxd->buf, rxd->hdr, rxd->len); + /* copy header */ + if (rxd->buf) { + memcpy(rxd->buf, rxd->hdr, rxd->len); + } + } + if (rxd->buf) { rxd->len += ipc_nrf5340_read(channel, &rxd->buf[rxd->len], rxd->expected_len - rxd->len); - assert(rxd->expected_len == rxd->len); + if (rxd->len < rxd->expected_len) { + break; + } rc = nrf5340_ble_hci_api.evt_cb(rxd->buf, nrf5340_ble_hci_api.evt_arg); @@ -335,7 +403,9 @@ nrf5340_ble_hci_trans_rx_process(int channel) } else { rxd->len += ipc_nrf5340_consume(channel, rxd->expected_len - rxd->len); - assert(rxd->expected_len == rxd->len); + if (rxd->len < rxd->expected_len) { + break; + } } rxd->type = HCI_PKT_NONE; @@ -343,8 +413,8 @@ nrf5340_ble_hci_trans_rx_process(int channel) #endif case HCI_PKT_ACL: if (rxd->len < 4) { - rxd->len += ipc_nrf5340_read(channel, rxd->hdr, 4 - rxd->len); - + rxd->len += ipc_nrf5340_read(channel, &rxd->hdr[rxd->len], + 4 - rxd->len); if (rxd->len < 4) { break; } @@ -355,7 +425,7 @@ nrf5340_ble_hci_trans_rx_process(int channel) rxd->om = os_mbuf_get_pkthdr(&nrf5340_ble_hci_pool_acl_mbuf, sizeof(struct ble_mbuf_hdr)); if (!rxd->om) { - /* not much we can do here... */ + /* TODO not much we can do here... */ assert(0); } @@ -391,6 +461,17 @@ nrf5340_ble_hci_trans_rx(int channel, void *user_data) } } +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) +int +ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) +{ + nrf5340_ble_hci_pool_acl.mpe_put_cb = cb; + nrf5340_ble_hci_pool_acl.mpe_put_arg = arg; + + return 0; +} +#endif + void nrf5340_ble_hci_init(void) { @@ -398,16 +479,18 @@ nrf5340_ble_hci_init(void) SYSINIT_ASSERT_ACTIVE(); - rc = os_mempool_init(&nrf5340_ble_hci_pool_acl, MYNEWT_VAL(BLE_ACL_BUF_COUNT), - POOL_ACL_BLOCK_SIZE, nrf5340_ble_hci_pool_acl_buf, - "nrf5340_ble_hci_pool_acl"); + rc = os_mempool_ext_init(&nrf5340_ble_hci_pool_acl, + MYNEWT_VAL(BLE_ACL_BUF_COUNT), POOL_ACL_BLOCK_SIZE, + nrf5340_ble_hci_pool_acl_buf, + "nrf5340_ble_hci_pool_acl"); SYSINIT_PANIC_ASSERT(rc == 0); rc = os_mbuf_pool_init(&nrf5340_ble_hci_pool_acl_mbuf, - &nrf5340_ble_hci_pool_acl, POOL_ACL_BLOCK_SIZE, + &nrf5340_ble_hci_pool_acl.mpe_mp, POOL_ACL_BLOCK_SIZE, MYNEWT_VAL(BLE_ACL_BUF_COUNT)); SYSINIT_PANIC_ASSERT(rc == 0); +#if !MYNEWT_VAL(BLE_HCI_BRIDGE) rc = os_mempool_init(&nrf5340_ble_hci_pool_evt_hi, MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), @@ -422,5 +505,12 @@ nrf5340_ble_hci_init(void) "nrf5340_ble_hci_pool_evt_lo"); SYSINIT_PANIC_ASSERT(rc == 0); + rc = os_mempool_init(&nrf5340_ble_hci_pool_cmd_mempool, + HCI_CMD_COUNT, BLE_HCI_TRANS_CMD_SZ, + nrf5340_ble_hci_pool_cmd_mempool_buf, + "nrf5340_ble_hci_pool_cmd_mempool"); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif + ipc_nrf5340_recv(IPC_RX_CHANNEL, nrf5340_ble_hci_trans_rx, NULL); } diff --git a/nimble/transport/nrf5340/syscfg.yml b/nimble/transport/nrf5340/syscfg.yml index 1417bbc03d..a12e0c3736 100644 --- a/nimble/transport/nrf5340/syscfg.yml +++ b/nimble/transport/nrf5340/syscfg.yml @@ -17,34 +17,21 @@ # syscfg.defs: - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 - - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - BLE_TRANS_NRF5340_SYSINIT_STAGE: description: > Sysinit stage for the RAM BLE transport. value: 100 -syscfg.vals.BLE_EXT_ADV: +syscfg.vals.'!BLE_HCI_BRIDGE: + BLE_HCI_EVT_HI_BUF_COUNT: 2 + BLE_HCI_EVT_LO_BUF_COUNT: 8 + BLE_ACL_BUF_COUNT: 4 + BLE_ACL_BUF_SIZE: 255 + +syscfg.vals.'!BLE_HCI_BRIDGE && !BLE_EXT_ADV': + BLE_HCI_EVT_BUF_SIZE: 70 + +syscfg.vals.'!BLE_HCI_BRIDGE && BLE_EXT_ADV': BLE_HCI_EVT_BUF_SIZE: 257 syscfg.restrictions: diff --git a/nimble/transport/pkg.yml b/nimble/transport/pkg.yml index 8174286d06..5484002ebc 100644 --- a/nimble/transport/pkg.yml +++ b/nimble/transport/pkg.yml @@ -52,3 +52,9 @@ pkg.deps.'BLE_HCI_TRANSPORT == "usb"': pkg.deps.'BLE_HCI_TRANSPORT == "nrf5340"': - nimble/transport/nrf5340 + +pkg.deps.'BLE_HCI_BRIDGE_TRANSPORT == "nrf5340"': + - nimble/transport/nrf5340 + +pkg.deps.'BLE_HCI_BRIDGE_TRANSPORT == "dialog_cmac"': + - nimble/transport/dialog_cmac diff --git a/nimble/transport/ram/syscfg.yml b/nimble/transport/ram/syscfg.yml index 3b822fcc60..6286dfe722 100644 --- a/nimble/transport/ram/syscfg.yml +++ b/nimble/transport/ram/syscfg.yml @@ -17,32 +17,17 @@ # syscfg.defs: - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 - - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - BLE_TRANS_RAM_SYSINIT_STAGE: description: > Sysinit stage for the RAM BLE transport. value: 100 +syscfg.vals: + BLE_HCI_EVT_HI_BUF_COUNT: 2 + BLE_HCI_EVT_LO_BUF_COUNT: 8 + BLE_HCI_EVT_BUF_SIZE: 70 + BLE_ACL_BUF_COUNT: 4 + BLE_ACL_BUF_SIZE: 65535 + syscfg.vals.BLE_EXT_ADV: BLE_HCI_EVT_BUF_SIZE: 257 diff --git a/nimble/transport/socket/src/ble_hci_socket.c b/nimble/transport/socket/src/ble_hci_socket.c index 44de8fed53..b444a24032 100644 --- a/nimble/transport/socket/src/ble_hci_socket.c +++ b/nimble/transport/socket/src/ble_hci_socket.c @@ -333,7 +333,6 @@ ble_hci_sock_acl_tx(struct os_mbuf *om) static int ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) { - uint8_t btaddr[6]; struct msghdr msg; struct iovec iov[8]; int len; diff --git a/nimble/transport/socket/syscfg.yml b/nimble/transport/socket/syscfg.yml index 2050f64692..9c8fa583d6 100644 --- a/nimble/transport/socket/syscfg.yml +++ b/nimble/transport/socket/syscfg.yml @@ -17,24 +17,6 @@ # syscfg.defs: - BLE_HCI_EVT_BUF_SIZE: - description: 'The size of the allocated event buffers' - value: 70 - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'The number of high priority event buffers' - value: 8 - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'The number of low priority event buffers' - value: 8 - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 24 - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - BLE_HCI_ACL_OUT_COUNT: description: > This count is used in creating a pool of elements used by the @@ -75,5 +57,12 @@ syscfg.defs: Sysinit stage for the socket BLE transport. value: 500 -syscfg.vals.BLE_EXT_ADV: +syscfg.vals.'!BLE_HCI_BRIDGE && BLE_EXT_ADV': BLE_HCI_EVT_BUF_SIZE: 257 + +syscfg.vals.'!BLE_HCI_BRIDGE && !BLE_EXT_ADV': + BLE_HCI_EVT_BUF_SIZE: 70 + BLE_HCI_EVT_HI_BUF_COUNT: 8 + BLE_HCI_EVT_LO_BUF_COUNT: 8 + BLE_ACL_BUF_COUNT: 24 + BLE_ACL_BUF_SIZE: 255 diff --git a/nimble/transport/syscfg.yml b/nimble/transport/syscfg.yml index 5bec6adf4d..7eed69ba4e 100644 --- a/nimble/transport/syscfg.yml +++ b/nimble/transport/syscfg.yml @@ -37,6 +37,47 @@ syscfg.defs: - usb # USB - nrf5340 # nRF5340 + BLE_HCI_BRIDGE_TRANSPORT: + description: > + Selects HCI transport to be included in bridge configuration build. + This applies to multi core configurations where controller runs + on separate core and main core forwards HCI traffic to external host. + This has virtually the same effect as including package dependency + manually, but it allows to easily override HCI transport package in + application or target settings. + This is the transport + value: + choices: + - dialog_cmac # Dialog CMAC via shared memory + - nrf5340 # nRF5340 + + BLE_HCI_BRIDGE: + description: > + External interface (UART/USB/Socket) bridged to second core controller. + value: 0 + + BLE_HCI_EVT_HI_BUF_COUNT: + description: 'Number of high-priority event buffers.' + value: + + BLE_HCI_EVT_LO_BUF_COUNT: + description: 'Number of low-priority event buffers.' + value: + + BLE_HCI_EVT_BUF_SIZE: + description: 'Size of each event buffer, in bytes.' + value: + + BLE_ACL_BUF_COUNT: + description: 'The number of ACL data buffers' + value: + + BLE_ACL_BUF_SIZE: + description: > + This is the maximum size of the data portion of HCI ACL data + packets. + value: + # Deprecated settings BLE_HCI_TRANSPORT_NIMBLE_BUILTIN: description: Use BLE_HCI_TRANSPORT instead. @@ -69,3 +110,10 @@ syscfg.vals.BLE_HCI_TRANSPORT_SOCKET: BLE_HCI_TRANSPORT: socket syscfg.vals.BLE_HCI_TRANSPORT_EMSPI: BLE_HCI_TRANSPORT: emspi + +syscfg.vals.'(MCU_TARGET == "DA14691" || MCU_TARGET == "DA14695" || MCU_TARGET == "DA14697" || MCU_TARGET == "DA14699")': + BLE_HCI_BRIDGE_TRANSPORT: dialog_cmac + +syscfg.vals.'(MCU_TARGET == "nRF5340_APP")': + BLE_HCI_BRIDGE_TRANSPORT: nrf5340 + diff --git a/nimble/transport/uart/src/ble_hci_uart.c b/nimble/transport/uart/src/ble_hci_uart.c index cbb6dd4259..cc796c0005 100644 --- a/nimble/transport/uart/src/ble_hci_uart.c +++ b/nimble/transport/uart/src/ble_hci_uart.c @@ -53,9 +53,9 @@ */ /* XXX: for now, define this here */ -#if MYNEWT_VAL(BLE_CONTROLLER) +#if MYNEWT_VAL(BLE_CONTROLLER) || MYNEWT_VAL(BLE_HCI_BRIDGE) extern void ble_ll_data_buffer_overflow(void); -extern void ble_ll_hw_error(uint8_t err); +extern void ble_ll_hw_error(void); static const uint8_t ble_hci_uart_reset_cmd[4] = { 0x01, 0x03, 0x0C, 0x00 }; #endif @@ -385,7 +385,7 @@ ble_hci_uart_tx_char(void *arg) return rc; } -#if MYNEWT_VAL(BLE_CONTROLLER) +#if MYNEWT_VAL(BLE_CONTROLLER) || MYNEWT_VAL(BLE_HCI_BRIDGE) /** * HCI uart sync lost. * @@ -400,7 +400,7 @@ ble_hci_uart_sync_lost(void) ble_hci_uart_state.rx_cmd.cur = 0; ble_hci_uart_state.rx_cmd.data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - ble_ll_hw_error(BLE_HW_ERR_HCI_SYNC_LOSS); + ble_ll_hw_error(); ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SYNC_LOSS; } #endif @@ -418,7 +418,7 @@ ble_hci_uart_rx_pkt_type(uint8_t data) switch (ble_hci_uart_state.rx_type) { /* Host should never receive a command! */ -#if MYNEWT_VAL(BLE_CONTROLLER) +#if MYNEWT_VAL(BLE_CONTROLLER) || MYNEWT_VAL(BLE_HCI_BRIDGE) case BLE_HCI_UART_H4_CMD: ble_hci_uart_state.rx_cmd.len = 0; ble_hci_uart_state.rx_cmd.cur = 0; @@ -458,7 +458,7 @@ ble_hci_uart_rx_pkt_type(uint8_t data) break; default: -#if MYNEWT_VAL(BLE_CONTROLLER) +#if MYNEWT_VAL(BLE_CONTROLLER) || MYNEWT_VAL(BLE_HCI_BRIDGE) /* * If we receive an unknown HCI packet type this is considered a loss * of sync. @@ -477,7 +477,7 @@ ble_hci_uart_rx_pkt_type(uint8_t data) return 0; } -#if MYNEWT_VAL(BLE_CONTROLLER) +#if MYNEWT_VAL(BLE_CONTROLLER) || MYNEWT_VAL(BLE_HCI_BRIDGE) /** * HCI uart sync loss. * @@ -708,7 +708,7 @@ ble_hci_uart_rx_acl(uint8_t data) */ if (pktlen > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) { os_mbuf_free_chain(ble_hci_uart_state.rx_acl.buf); -#if MYNEWT_VAL(BLE_CONTROLLER) +#if MYNEWT_VAL(BLE_CONTROLLER) || MYNEWT_VAL(BLE_HCI_BRIDGE) ble_hci_uart_sync_lost(); #else /* @@ -755,7 +755,9 @@ ble_hci_uart_rx_skip_acl(uint8_t data) if (rxd_bytes == ble_hci_uart_state.rx_acl.len) { /* XXX: I dont like this but for now this denotes controller only */ #if MYNEWT_VAL(BLE_CONTROLLER) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) ble_ll_data_buffer_overflow(); +#endif #endif ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; } @@ -767,7 +769,7 @@ ble_hci_uart_rx_char(void *arg, uint8_t data) switch (ble_hci_uart_state.rx_type) { case BLE_HCI_UART_H4_NONE: return ble_hci_uart_rx_pkt_type(data); -#if MYNEWT_VAL(BLE_CONTROLLER) +#if MYNEWT_VAL(BLE_CONTROLLER) || MYNEWT_VAL(BLE_HCI_BRIDGE) case BLE_HCI_UART_H4_CMD: ble_hci_uart_rx_cmd(data); return 0; @@ -896,6 +898,7 @@ ble_hci_trans_ll_acl_tx(struct os_mbuf *om) return rc; } +#if MYNEWT_VAL(BLE_HOST) /** * Sends an HCI command from the host to the controller. * @@ -953,6 +956,7 @@ ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, { ble_hci_uart_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg); } +#endif /** * Configures the HCI transport to operate with a host. The transport will diff --git a/nimble/transport/uart/syscfg.yml b/nimble/transport/uart/syscfg.yml index 43486a8bfe..7eff9517c1 100644 --- a/nimble/transport/uart/syscfg.yml +++ b/nimble/transport/uart/syscfg.yml @@ -17,24 +17,6 @@ # syscfg.defs: - BLE_HCI_EVT_BUF_SIZE: - description: 'The size of the allocated event buffers' - value: 70 - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'The number of high priority event buffers' - value: 8 - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'The number of low priority event buffers' - value: 8 - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 12 - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - BLE_HCI_ACL_OUT_COUNT: description: > This count is used in creating a pool of elements used by the @@ -70,3 +52,10 @@ syscfg.defs: syscfg.vals.BLE_EXT_ADV: BLE_HCI_EVT_BUF_SIZE: 257 + +syscfg.vals: + BLE_HCI_EVT_BUF_SIZE: 70 + BLE_HCI_EVT_HI_BUF_COUNT: 8 + BLE_HCI_EVT_LO_BUF_COUNT: 8 + BLE_ACL_BUF_COUNT: 12 + BLE_ACL_BUF_SIZE: 255 diff --git a/nimble/transport/usb/pkg.yml b/nimble/transport/usb/pkg.yml index 49317c97d5..c4c314c867 100644 --- a/nimble/transport/usb/pkg.yml +++ b/nimble/transport/usb/pkg.yml @@ -31,6 +31,7 @@ pkg.deps: - "@apache-mynewt-core/kernel/os" - "@apache-mynewt-core/util/mem" - nimble + - "@apache-mynewt-core/hw/usb/tinyusb" pkg.apis: - ble_transport diff --git a/nimble/transport/usb/src/ble_hci_usb.c b/nimble/transport/usb/src/ble_hci_usb.c index d09421bb20..8160536b95 100644 --- a/nimble/transport/usb/src/ble_hci_usb.c +++ b/nimble/transport/usb/src/ble_hci_usb.c @@ -229,7 +229,7 @@ tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len) if (ble_hci_usb_rx_cmd_ll_cb) { buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); assert(buf != NULL); - memcpy(buf, hci_cmd, cmd_len); + memcpy(buf, hci_cmd, min(cmd_len, BLE_HCI_TRANS_CMD_SZ)); rc = ble_hci_usb_rx_cmd_ll_cb(buf, ble_hci_usb_rx_cmd_ll_arg); } @@ -285,6 +285,11 @@ ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) assert(hci_ev != NULL); + if (!tud_ready()) { + ble_hci_trans_buf_free(hci_ev); + return 0; + } + pkt = os_memblock_get(&ble_hci_pkt_pool); if (pkt == NULL) { ble_hci_trans_buf_free(hci_ev); diff --git a/nimble/transport/usb/syscfg.yml b/nimble/transport/usb/syscfg.yml index ebc261a23d..38effde60c 100644 --- a/nimble/transport/usb/syscfg.yml +++ b/nimble/transport/usb/syscfg.yml @@ -17,24 +17,6 @@ # syscfg.defs: - BLE_HCI_EVT_BUF_SIZE: - description: 'The size of the allocated event buffers' - value: 70 - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'The number of high priority event buffers' - value: 8 - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'The number of low priority event buffers' - value: 8 - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 12 - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - BLE_HCI_ACL_OUT_COUNT: description: > This count is used in creating a pool of elements used by the @@ -53,5 +35,12 @@ syscfg.defs: syscfg.vals.BLE_EXT_ADV: BLE_HCI_EVT_BUF_SIZE: 257 +syscfg.vals: + BLE_HCI_EVT_BUF_SIZE: 70 + BLE_HCI_EVT_HI_BUF_COUNT: 8 + BLE_HCI_EVT_LO_BUF_COUNT: 8 + BLE_ACL_BUF_COUNT: 12 + BLE_ACL_BUF_SIZE: 255 + syscfg.restrictions: - '!BLE_HOST' diff --git a/porting/examples/dummy/Makefile b/porting/examples/dummy/Makefile index 861934f7f0..1c38ac4a3c 100644 --- a/porting/examples/dummy/Makefile +++ b/porting/examples/dummy/Makefile @@ -60,6 +60,7 @@ OBJ := $(SRC:.c=.o) TINYCRYPT_OBJ := $(TINYCRYPT_SRC:.c=.o) CFLAGS := $(NIMBLE_CFLAGS) +LDFLAGS := $(NIMBLE_LDFLAGS) .PHONY: all clean .DEFAULT: all @@ -76,4 +77,4 @@ $(TINYCRYPT_OBJ): CFLAGS+=$(TINYCRYPT_CFLAGS) $(CC) -c $(addprefix -I, $(INC)) $(CFLAGS) -o $@ $< dummy: $(OBJ) $(TINYCRYPT_OBJ) - $(CC) -o $@ $^ + $(CC) -o $@ $^ $(LDFLAGS) diff --git a/porting/examples/linux/Makefile b/porting/examples/linux/Makefile index 11f4ebc308..c3eee16cb5 100644 --- a/porting/examples/linux/Makefile +++ b/porting/examples/linux/Makefile @@ -81,7 +81,7 @@ CFLAGS = \ -D_GNU_SOURCE \ $(NULL) -LIBS := -lrt -lpthread -lstdc++ +LIBS := $(NIMBLE_LDFLAGS) -lrt -lpthread -lstdc++ .PHONY: all clean .DEFAULT: all diff --git a/porting/examples/linux/include/logcfg/logcfg.h b/porting/examples/linux/include/logcfg/logcfg.h index 837cdeac1f..fab4d812fc 100644 --- a/porting/examples/linux/include/logcfg/logcfg.h +++ b/porting/examples/linux/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_LOGCFG_ @@ -22,11 +22,4 @@ #define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) #define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - #endif diff --git a/porting/examples/linux/include/syscfg/syscfg.h b/porting/examples/linux/include/syscfg/syscfg.h index 99939f2b41..fc9ef468fc 100644 --- a/porting/examples/linux/include/syscfg/syscfg.h +++ b/porting/examples/linux/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -28,11 +28,20 @@ #define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif +/*** @apache-mynewt-core/hw/bsp/native */ +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) +#endif + /*** @apache-mynewt-core/hw/hal */ #ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS #define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + #ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ #define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif @@ -45,10 +54,47 @@ #define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + #ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB #define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) #endif +/*** @apache-mynewt-core/hw/mcu/native */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) +#endif + +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) +#endif + /*** @apache-mynewt-core/kernel/os */ #ifndef MYNEWT_VAL_FLOAT_USER #define MYNEWT_VAL_FLOAT_USER (0) @@ -94,6 +140,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #endif @@ -102,8 +152,9 @@ #define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE -#define MYNEWT_VAL_OS_CRASH_FILE_LINE (0) +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_OS_CRASH_LOG @@ -142,8 +193,9 @@ #define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MAX (600000) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN -#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (100) +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) #endif #ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE @@ -210,6 +262,11 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +/* Overridden by @apache-mynewt-core/hw/mcu/native (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -226,6 +283,33 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif +/*** @apache-mynewt-core/net/ip/native_sockets */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + /*** @apache-mynewt-core/sys/console/stub */ #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) @@ -244,8 +328,12 @@ #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif /*** @apache-mynewt-core/sys/log/common */ @@ -300,23 +388,6 @@ #define MYNEWT_VAL_LOG_LEVEL (0) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - /*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) @@ -344,12 +415,14 @@ #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ #ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE -#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ #ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE -#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) #endif /*** @apache-mynewt-core/util/rwlock */ @@ -366,6 +439,10 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif @@ -739,6 +816,14 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_LVL +#define MYNEWT_VAL_BLE_SM_SC_LVL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -985,19 +1070,19 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("dummy") +#define MYNEWT_VAL_ARCH_NAME ("sim") #endif -#ifndef MYNEWT_VAL_ARCH_dummy -#define MYNEWT_VAL_ARCH_dummy (1) +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("dummy_bsp") +#define MYNEWT_VAL_BSP_NAME ("native") #endif -#ifndef MYNEWT_VAL_BSP_dummy_bsp -#define MYNEWT_VAL_BSP_dummy_bsp (1) +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) #endif #ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG diff --git a/porting/examples/linux/include/sysflash/sysflash.h b/porting/examples/linux/include/sysflash/sysflash.h index ab1341b25d..28391ca66a 100644 --- a/porting/examples/linux/include/sysflash/sysflash.h +++ b/porting/examples/linux/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ diff --git a/porting/examples/linux/main.c b/porting/examples/linux/main.c index 86b6fb9559..a2e255d083 100644 --- a/porting/examples/linux/main.c +++ b/porting/examples/linux/main.c @@ -65,8 +65,8 @@ int main(int argc, char *argv[]) ble_hci_sock_set_device(atoi(argv[1])); } - ble_hci_sock_init(); nimble_port_init(); + ble_hci_sock_init(); /* This example provides GATT Alert service */ ble_svc_gap_init(); diff --git a/porting/examples/linux_blemesh/Makefile b/porting/examples/linux_blemesh/Makefile index 556fc8ca6c..67783f2766 100644 --- a/porting/examples/linux_blemesh/Makefile +++ b/porting/examples/linux_blemesh/Makefile @@ -17,7 +17,7 @@ # Toolchain commands CROSS_COMPILE ?= -CC := ccache $(CROSS_COMPILIE)gcc +CC := ccache $(CROSS_COMPILE)gcc CXX := ccache $(CROSS_COMPILE)g++ LD := $(CROSS_COMPILE)gcc AR := $(CROSS_COMPILE)ar @@ -83,7 +83,7 @@ CFLAGS = \ -D_GNU_SOURCE \ $(NULL) -LIBS := -lrt -lpthread -lstdc++ +LIBS := $(NIMBLE_LDFLAGS) -lrt -lpthread -lstdc++ .PHONY: all clean .DEFAULT: all diff --git a/porting/examples/linux_blemesh/ble.c b/porting/examples/linux_blemesh/ble.c index deaef5a462..7a64eac9ea 100644 --- a/porting/examples/linux_blemesh/ble.c +++ b/porting/examples/linux_blemesh/ble.c @@ -142,11 +142,12 @@ static struct bt_mesh_model_pub gen_onoff_pub; static uint8_t gen_on_off_state; static int16_t gen_level_state; -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = NET_BUF_SIMPLE(3); uint8_t *status; + int rc; console_printf("#mesh-onoff STATUS\n"); @@ -154,23 +155,25 @@ static void gen_onoff_status(struct bt_mesh_model *model, status = net_buf_simple_add(msg, 1); *status = gen_on_off_state; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { console_printf("#mesh-onoff STATUS: send status failed\n"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-onoff GET\n"); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -178,16 +181,17 @@ static void gen_onoff_set(struct bt_mesh_model *model, gen_on_off_state = buf->om_data[0]; - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-onoff SET-UNACK\n"); gen_on_off_state = buf->om_data[0]; + return 0; } static const struct bt_mesh_model_op gen_onoff_op[] = { @@ -214,16 +218,17 @@ static void gen_level_status(struct bt_mesh_model *model, os_mbuf_free_chain(msg); } -static void gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-level GET\n"); gen_level_status(model, ctx); + return 0; } -static void gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -236,9 +241,10 @@ static void gen_level_set(struct bt_mesh_model *model, gen_level_state = level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -249,9 +255,10 @@ static void gen_level_set_unack(struct bt_mesh_model *model, gen_level_state = level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_delta_set(struct bt_mesh_model *model, +static int gen_delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -264,9 +271,10 @@ static void gen_delta_set(struct bt_mesh_model *model, gen_level_state += delta_level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_delta_set_unack(struct bt_mesh_model *model, +static int gen_delta_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -277,18 +285,21 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, gen_level_state += delta_level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_move_set(struct bt_mesh_model *model, +static int gen_move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + return 0; } -static void gen_move_set_unack(struct bt_mesh_model *model, +static int gen_move_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + return 0; } static const struct bt_mesh_model_op gen_level_op[] = { @@ -313,11 +324,12 @@ static struct bt_mesh_model root_models[] = { static struct bt_mesh_model_pub vnd_model_pub; -static void vnd_model_recv(struct bt_mesh_model *model, +static int vnd_model_recv(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(3); + int rc; console_printf("#vendor-model-recv\n"); @@ -327,11 +339,13 @@ static void vnd_model_recv(struct bt_mesh_model *model, bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR)); os_mbuf_append(msg, buf->om_data, buf->om_len); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { console_printf("#vendor-model-recv: send rsp failed\n"); } os_mbuf_free_chain(msg); + return rc; } static const struct bt_mesh_model_op vnd_model_op[] = { diff --git a/porting/examples/linux_blemesh/include/logcfg/logcfg.h b/porting/examples/linux_blemesh/include/logcfg/logcfg.h index 798418dabb..c3b5cdf400 100644 --- a/porting/examples/linux_blemesh/include/logcfg/logcfg.h +++ b/porting/examples/linux_blemesh/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_LOGCFG_ @@ -50,6 +50,13 @@ #define BLE_MESH_FRIEND_LOG_CRITICAL(...) MODLOG_CRITICAL(14, __VA_ARGS__) #define BLE_MESH_FRIEND_LOG_DISABLED(...) MODLOG_DISABLED(14, __VA_ARGS__) +#define BLE_MESH_HEARTBEAT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) +#define BLE_MESH_HEARTBEAT_LOG_INFO(...) MODLOG_INFO(26, __VA_ARGS__) +#define BLE_MESH_HEARTBEAT_LOG_WARN(...) MODLOG_WARN(26, __VA_ARGS__) +#define BLE_MESH_HEARTBEAT_LOG_ERROR(...) MODLOG_ERROR(26, __VA_ARGS__) +#define BLE_MESH_HEARTBEAT_LOG_CRITICAL(...) MODLOG_CRITICAL(26, __VA_ARGS__) +#define BLE_MESH_HEARTBEAT_LOG_DISABLED(...) MODLOG_DISABLED(26, __VA_ARGS__) + #define BLE_MESH_LOG_DEBUG(...) IGNORE(__VA_ARGS__) #define BLE_MESH_LOG_INFO(...) MODLOG_INFO(9, __VA_ARGS__) #define BLE_MESH_LOG_WARN(...) MODLOG_WARN(9, __VA_ARGS__) @@ -71,6 +78,13 @@ #define BLE_MESH_MODEL_LOG_CRITICAL(...) MODLOG_CRITICAL(16, __VA_ARGS__) #define BLE_MESH_MODEL_LOG_DISABLED(...) MODLOG_DISABLED(16, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_INFO(...) MODLOG_INFO(23, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_WARN(...) MODLOG_WARN(23, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_ERROR(...) MODLOG_ERROR(23, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_CRITICAL(...) MODLOG_CRITICAL(23, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_DISABLED(...) MODLOG_DISABLED(23, __VA_ARGS__) + #define BLE_MESH_NET_LOG_DEBUG(...) IGNORE(__VA_ARGS__) #define BLE_MESH_NET_LOG_INFO(...) MODLOG_INFO(17, __VA_ARGS__) #define BLE_MESH_NET_LOG_WARN(...) MODLOG_WARN(17, __VA_ARGS__) @@ -78,6 +92,20 @@ #define BLE_MESH_NET_LOG_CRITICAL(...) MODLOG_CRITICAL(17, __VA_ARGS__) #define BLE_MESH_NET_LOG_DISABLED(...) MODLOG_DISABLED(17, __VA_ARGS__) +#define BLE_MESH_PROVISIONER_LOG_DEBUG(...) IGNORE(__VA_ARGS__) +#define BLE_MESH_PROVISIONER_LOG_INFO(...) MODLOG_INFO(25, __VA_ARGS__) +#define BLE_MESH_PROVISIONER_LOG_WARN(...) MODLOG_WARN(25, __VA_ARGS__) +#define BLE_MESH_PROVISIONER_LOG_ERROR(...) MODLOG_ERROR(25, __VA_ARGS__) +#define BLE_MESH_PROVISIONER_LOG_CRITICAL(...) MODLOG_CRITICAL(25, __VA_ARGS__) +#define BLE_MESH_PROVISIONER_LOG_DISABLED(...) MODLOG_DISABLED(25, __VA_ARGS__) + +#define BLE_MESH_PROV_DEVICE_LOG_DEBUG(...) IGNORE(__VA_ARGS__) +#define BLE_MESH_PROV_DEVICE_LOG_INFO(...) MODLOG_INFO(24, __VA_ARGS__) +#define BLE_MESH_PROV_DEVICE_LOG_WARN(...) MODLOG_WARN(24, __VA_ARGS__) +#define BLE_MESH_PROV_DEVICE_LOG_ERROR(...) MODLOG_ERROR(24, __VA_ARGS__) +#define BLE_MESH_PROV_DEVICE_LOG_CRITICAL(...) MODLOG_CRITICAL(24, __VA_ARGS__) +#define BLE_MESH_PROV_DEVICE_LOG_DISABLED(...) MODLOG_DISABLED(24, __VA_ARGS__) + #define BLE_MESH_PROV_LOG_DEBUG(...) IGNORE(__VA_ARGS__) #define BLE_MESH_PROV_LOG_INFO(...) MODLOG_INFO(18, __VA_ARGS__) #define BLE_MESH_PROV_LOG_WARN(...) MODLOG_WARN(18, __VA_ARGS__) @@ -92,6 +120,13 @@ #define BLE_MESH_PROXY_LOG_CRITICAL(...) MODLOG_CRITICAL(19, __VA_ARGS__) #define BLE_MESH_PROXY_LOG_DISABLED(...) MODLOG_DISABLED(19, __VA_ARGS__) +#define BLE_MESH_RPL_LOG_DEBUG(...) IGNORE(__VA_ARGS__) +#define BLE_MESH_RPL_LOG_INFO(...) MODLOG_INFO(22, __VA_ARGS__) +#define BLE_MESH_RPL_LOG_WARN(...) MODLOG_WARN(22, __VA_ARGS__) +#define BLE_MESH_RPL_LOG_ERROR(...) MODLOG_ERROR(22, __VA_ARGS__) +#define BLE_MESH_RPL_LOG_CRITICAL(...) MODLOG_CRITICAL(22, __VA_ARGS__) +#define BLE_MESH_RPL_LOG_DISABLED(...) MODLOG_DISABLED(22, __VA_ARGS__) + #define BLE_MESH_SETTINGS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) #define BLE_MESH_SETTINGS_LOG_INFO(...) MODLOG_INFO(20, __VA_ARGS__) #define BLE_MESH_SETTINGS_LOG_WARN(...) MODLOG_WARN(20, __VA_ARGS__) @@ -106,34 +141,6 @@ #define BLE_MESH_TRANS_LOG_CRITICAL(...) MODLOG_CRITICAL(21, __VA_ARGS__) #define BLE_MESH_TRANS_LOG_DISABLED(...) MODLOG_DISABLED(21, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_RPL_LOG_INFO(...) MODLOG_INFO(22, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_WARN(...) MODLOG_WARN(22, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_ERROR(...) MODLOG_ERROR(22, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_CRITICAL(...) MODLOG_CRITICAL(22, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_DISABLED(...) MODLOG_DISABLED(22, __VA_ARGS__) - -#define BLE_MESH_NET_KEYS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_INFO(...) MODLOG_INFO(23, __VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_WARN(...) MODLOG_WARN(23, __VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_ERROR(...) MODLOG_ERROR(23, __VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_CRITICAL(...) MODLOG_CRITICAL(23, __VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_DISABLED(...) MODLOG_DISABLED(23, __VA_ARGS__) - -#define BLE_MESH_PROV_DEVICE_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_INFO(...) MODLOG_INFO(24, __VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_WARN(...) MODLOG_WARN(24, __VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_ERROR(...) MODLOG_ERROR(24, __VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_CRITICAL(...) MODLOG_CRITICAL(24, __VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_DISABLED(...) MODLOG_DISABLED(24, __VA_ARGS__) - -#define BLE_MESH_HEARTBEAT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_INFO(...) MODLOG_INFO(25, __VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_WARN(...) MODLOG_WARN(25, __VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_ERROR(...) MODLOG_ERROR(25, __VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_CRITICAL(...) MODLOG_CRITICAL(25, __VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_DISABLED(...) MODLOG_DISABLED(25, __VA_ARGS__) - #define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) #define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__) #define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__) @@ -141,11 +148,4 @@ #define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) #define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - #endif diff --git a/porting/examples/linux_blemesh/include/syscfg/syscfg.h b/porting/examples/linux_blemesh/include/syscfg/syscfg.h index 9aac1068ab..3f9258d896 100644 --- a/porting/examples/linux_blemesh/include/syscfg/syscfg.h +++ b/porting/examples/linux_blemesh/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -28,11 +28,20 @@ #define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif +/*** @apache-mynewt-core/hw/bsp/native */ +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) +#endif + /*** @apache-mynewt-core/hw/hal */ #ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS #define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + #ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ #define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif @@ -45,10 +54,47 @@ #define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + #ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB #define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) #endif +/*** @apache-mynewt-core/hw/mcu/native */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) +#endif + +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) +#endif + /*** @apache-mynewt-core/kernel/os */ #ifndef MYNEWT_VAL_FLOAT_USER #define MYNEWT_VAL_FLOAT_USER (0) @@ -95,6 +141,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #endif @@ -103,8 +153,9 @@ #define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE -#define MYNEWT_VAL_OS_CRASH_FILE_LINE (0) +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_OS_CRASH_LOG @@ -143,8 +194,9 @@ #define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MAX (600000) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN -#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (100) +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) #endif #ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE @@ -211,6 +263,11 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +/* Overridden by @apache-mynewt-core/hw/mcu/native (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -227,6 +284,33 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif +/*** @apache-mynewt-core/net/ip/native_sockets */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + /*** @apache-mynewt-core/sys/console/stub */ #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) @@ -245,8 +329,12 @@ #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif /*** @apache-mynewt-core/sys/log/common */ @@ -301,23 +389,6 @@ #define MYNEWT_VAL_LOG_LEVEL (0) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - /*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) @@ -345,12 +416,14 @@ #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ #ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE -#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ #ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE -#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) #endif /*** @apache-mynewt-core/util/rwlock */ @@ -367,6 +440,10 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif @@ -742,6 +819,14 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_LVL +#define MYNEWT_VAL_BLE_SM_SC_LVL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -755,6 +840,10 @@ #endif /*** @apache-mynewt-nimble/nimble/host/mesh */ +#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LAYER_MSG +#define MYNEWT_VAL_BLE_MESH_ACCESS_LAYER_MSG (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL #define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL (1) #endif @@ -763,11 +852,23 @@ #define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_MOD (10) #endif +#ifndef MYNEWT_VAL_BLE_MESH_ADV +#define MYNEWT_VAL_BLE_MESH_ADV (1) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT #define MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT (20) #endif +#ifndef MYNEWT_VAL_BLE_MESH_ADV_EXT +#define MYNEWT_VAL_BLE_MESH_ADV_EXT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_LEGACY +#define MYNEWT_VAL_BLE_MESH_ADV_LEGACY (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL #define MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL (1) #endif @@ -776,6 +877,10 @@ #define MYNEWT_VAL_BLE_MESH_ADV_LOG_MOD (11) #endif +#ifndef MYNEWT_VAL_BLE_MESH_ADV_STACK_SIZE +#define MYNEWT_VAL_BLE_MESH_ADV_STACK_SIZE (768) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO #define MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO (9) #endif @@ -785,6 +890,10 @@ #define MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT (4) #endif +#ifndef MYNEWT_VAL_BLE_MESH_BEACON_ENABLED +#define MYNEWT_VAL_BLE_MESH_BEACON_ENABLED (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_BEACON_LOG_LVL #define MYNEWT_VAL_BLE_MESH_BEACON_LOG_LVL (1) #endif @@ -793,6 +902,22 @@ #define MYNEWT_VAL_BLE_MESH_BEACON_LOG_MOD (12) #endif +#ifndef MYNEWT_VAL_BLE_MESH_CDB +#define MYNEWT_VAL_BLE_MESH_CDB (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT (8) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT (1) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_CFG_CLI #define MYNEWT_VAL_BLE_MESH_CFG_CLI (1) @@ -810,6 +935,22 @@ #define MYNEWT_VAL_BLE_MESH_CRYPTO_LOG_MOD (13) #endif +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CDB +#define MYNEWT_VAL_BLE_MESH_DEBUG_CDB (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CFG +#define MYNEWT_VAL_BLE_MESH_DEBUG_CFG (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_USE_ID_ADDR +#define MYNEWT_VAL_BLE_MESH_DEBUG_USE_ID_ADDR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEFAULT_TTL +#define MYNEWT_VAL_BLE_MESH_DEFAULT_TTL (7) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_DEVICE_NAME #define MYNEWT_VAL_BLE_MESH_DEVICE_NAME ("nimble-mesh-node") #endif @@ -823,6 +964,10 @@ #define MYNEWT_VAL_BLE_MESH_FRIEND (1) #endif +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED +#define MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL #define MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL (1) #endif @@ -851,19 +996,43 @@ #define MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE (3) #endif +#ifndef MYNEWT_VAL_BLE_MESH_GATT +#define MYNEWT_VAL_BLE_MESH_GATT (1) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY #define MYNEWT_VAL_BLE_MESH_GATT_PROXY (1) #endif +#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED +#define MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_GATT_SERVER +#define MYNEWT_VAL_BLE_MESH_GATT_SERVER (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_HEALTH_CLI #define MYNEWT_VAL_BLE_MESH_HEALTH_CLI (0) #endif +#ifndef MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_MOD (26) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_IVU_DIVIDER #define MYNEWT_VAL_BLE_MESH_IVU_DIVIDER (4) #endif +#ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_SEQ_LIMIT +#define MYNEWT_VAL_BLE_MESH_IV_UPDATE_SEQ_LIMIT (0x800000) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST #define MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST (1) @@ -882,6 +1051,10 @@ #define MYNEWT_VAL_BLE_MESH_LOG_MOD (9) #endif +#ifndef MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS +#define MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS (3) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER #define MYNEWT_VAL_BLE_MESH_LOW_POWER (1) @@ -912,10 +1085,6 @@ #define MYNEWT_VAL_BLE_MESH_LPN_GROUPS (10) #endif -#ifndef MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR -#define MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR (1) -#endif - #ifndef MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT #define MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT (MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT) #endif @@ -948,6 +1117,10 @@ #define MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY (10) #endif +#ifndef MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR +#define MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR (0) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS #define MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS (0) #endif @@ -969,10 +1142,35 @@ #define MYNEWT_VAL_BLE_MESH_MODEL_LOG_MOD (16) #endif +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_VND_MSG_CID_FORCE +#define MYNEWT_VAL_BLE_MESH_MODEL_VND_MSG_CID_FORCE (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE #define MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE (10) #endif +#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT +#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL +#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_BUF_USER_DATA_SIZE +#define MYNEWT_VAL_BLE_MESH_NET_BUF_USER_DATA_SIZE (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_MOD (23) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_NET_LOG_LVL #define MYNEWT_VAL_BLE_MESH_NET_LOG_LVL (1) #endif @@ -981,10 +1179,6 @@ #define MYNEWT_VAL_BLE_MESH_NET_LOG_MOD (17) #endif -#ifndef MYNEWT_VAL_BLE_MESH_NODE_COUNT -#define MYNEWT_VAL_BLE_MESH_NODE_COUNT (1) -#endif - #ifndef MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT #define MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT (60) #endif @@ -1010,34 +1204,46 @@ #define MYNEWT_VAL_BLE_MESH_PB_ADV (1) #endif +#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT (500) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_PB_GATT #define MYNEWT_VAL_BLE_MESH_PB_GATT (1) #endif +#ifndef MYNEWT_VAL_BLE_MESH_PB_GATT_USE_DEVICE_NAME +#define MYNEWT_VAL_BLE_MESH_PB_GATT_USE_DEVICE_NAME (1) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_PROV #define MYNEWT_VAL_BLE_MESH_PROV (1) #endif #ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER -#define MYNEWT_VAL_BLE_MESH_PROVISIONER (0) +#define MYNEWT_VAL_BLE_MESH_PROVISIONER (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_CDB -#define MYNEWT_VAL_BLE_MESH_CDB (0) +#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_LVL (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT -#define MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT (1) +#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_MOD (25) #endif -#ifndef MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT -#define MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT (1) +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT -#define MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT (1) +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_MOD (24) #endif #ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL @@ -1048,13 +1254,17 @@ #define MYNEWT_VAL_BLE_MESH_PROV_LOG_MOD (18) #endif +#ifndef MYNEWT_VAL_BLE_MESH_PROV_OOB_PUBLIC_KEY +#define MYNEWT_VAL_BLE_MESH_PROV_OOB_PUBLIC_KEY (0) +#endif + /* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_PROXY #define MYNEWT_VAL_BLE_MESH_PROXY (1) #endif #ifndef MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE -#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (1) +#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (3) #endif #ifndef MYNEWT_VAL_BLE_MESH_PROXY_LOG_LVL @@ -1065,17 +1275,43 @@ #define MYNEWT_VAL_BLE_MESH_PROXY_LOG_MOD (19) #endif +/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_MSG_LEN +#define MYNEWT_VAL_BLE_MESH_PROXY_MSG_LEN (66) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_USE_DEVICE_NAME +#define MYNEWT_VAL_BLE_MESH_PROXY_USE_DEVICE_NAME (0) +#endif + /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_RELAY #define MYNEWT_VAL_BLE_MESH_RELAY (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT (5) +/* Value copied from BLE_MESH_RELAY */ +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_ENABLED +#define MYNEWT_VAL_BLE_MESH_RELAY_ENABLED (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_SEG_BUFS -#define MYNEWT_VAL_BLE_MESH_SEG_BUFS (72) +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT +#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL +#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD (22) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT (5) #endif #ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MAX @@ -1086,6 +1322,10 @@ #define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (2) #endif +#ifndef MYNEWT_VAL_BLE_MESH_SEG_BUFS +#define MYNEWT_VAL_BLE_MESH_SEG_BUFS (64) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS #define MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS (4) #endif @@ -1146,86 +1386,29 @@ #define MYNEWT_VAL_BLE_MESH_TRANS_LOG_MOD (21) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD (22) -#endif - /* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MAX #define MYNEWT_VAL_BLE_MESH_TX_SEG_MAX (6) #endif -#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT -#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (3) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT -#define MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT (5) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT (500) -#endif - #ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT -#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (4) +#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (1) #endif #ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT #define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT (4) #endif -#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST -#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST (400) -#endif - #ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP #define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP (50) #endif -#ifndef MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS -#define MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS (3) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_DEFAULT_TTL -#define MYNEWT_VAL_BLE_MESH_DEFAULT_TTL (7) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT -#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL -#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL (20) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT -#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_BEACON_ENABLED -#define MYNEWT_VAL_BLE_MESH_BEACON_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED -#define MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED -#define MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_ENABLED -#define MYNEWT_VAL_BLE_MESH_RELAY_ENABLED (1) +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST +#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST (400) #endif -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL -#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL (20) +#ifndef MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT +#define MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT (5) #endif /*** @apache-mynewt-nimble/nimble/host/services/ans */ @@ -1462,19 +1645,19 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("dummy") +#define MYNEWT_VAL_ARCH_NAME ("sim") #endif -#ifndef MYNEWT_VAL_ARCH_dummy -#define MYNEWT_VAL_ARCH_dummy (1) +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("dummy_bsp") +#define MYNEWT_VAL_BSP_NAME ("native") #endif -#ifndef MYNEWT_VAL_BSP_dummy_bsp -#define MYNEWT_VAL_BSP_dummy_bsp (1) +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) #endif #ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG diff --git a/porting/examples/linux_blemesh/include/sysflash/sysflash.h b/porting/examples/linux_blemesh/include/sysflash/sysflash.h index ab1341b25d..28391ca66a 100644 --- a/porting/examples/linux_blemesh/include/sysflash/sysflash.h +++ b/porting/examples/linux_blemesh/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ diff --git a/porting/examples/linux_blemesh/main.c b/porting/examples/linux_blemesh/main.c index 0913551e8c..f5c5e4f04f 100644 --- a/porting/examples/linux_blemesh/main.c +++ b/porting/examples/linux_blemesh/main.c @@ -77,8 +77,8 @@ int main(int argc, char *argv[]) ble_hci_sock_set_device(atoi(argv[1])); } - ble_hci_sock_init(); nimble_port_init(); + ble_hci_sock_init(); ble_svc_gap_init(); ble_svc_gatt_init(); diff --git a/porting/examples/nuttx/include/logcfg/logcfg.h b/porting/examples/nuttx/include/logcfg/logcfg.h index 837cdeac1f..fab4d812fc 100644 --- a/porting/examples/nuttx/include/logcfg/logcfg.h +++ b/porting/examples/nuttx/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_LOGCFG_ @@ -22,11 +22,4 @@ #define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) #define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - #endif diff --git a/porting/examples/nuttx/include/syscfg/syscfg.h b/porting/examples/nuttx/include/syscfg/syscfg.h index ff73312e13..1f5be13597 100644 --- a/porting/examples/nuttx/include/syscfg/syscfg.h +++ b/porting/examples/nuttx/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -15,86 +15,84 @@ #define MYNEWT_VAL(_name) MYNEWT_VAL_ ## _name #define MYNEWT_VAL_CHOICE(_name, _val) MYNEWT_VAL_ ## _name ## __ ## _val - -/*** Repository @apache-mynewt-core info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_CORE -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_CORE ("4d75fc41bd7ead84638ebbfad4841d5effb296dd") +/*** @apache-mynewt-core/crypto/tinycrypt */ +#ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE +#define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_CORE -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_CORE ("0.0.1") +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") #endif -/*** Repository @apache-mynewt-mcumgr info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_MCUMGR -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_MCUMGR ("8d087a7e0e5485394419d10051606c92d68d2111") +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_MCUMGR -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_MCUMGR ("0.0.0") +/*** @apache-mynewt-core/hw/bsp/native */ +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) #endif -/*** Repository @apache-mynewt-nimble info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_NIMBLE -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_NIMBLE ("37dceb35df57ff41a6c31f79290512df2fde7064") +/*** @apache-mynewt-core/hw/hal */ +#ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS +#define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_NIMBLE -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_NIMBLE ("0.0.0") +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) #endif -/*** Repository @mcuboot info */ -#ifndef MYNEWT_VAL_REPO_HASH_MCUBOOT -#define MYNEWT_VAL_REPO_HASH_MCUBOOT ("03d96ad1f6dd77d47ffca72ade9377acb8559115-dirty") +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ +#define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_MCUBOOT -#define MYNEWT_VAL_REPO_VERSION_MCUBOOT ("0.0.0") +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES +#define MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES (0) #endif -/*** Repository @my_project info */ -#ifndef MYNEWT_VAL_REPO_HASH_MY_PROJECT -#define MYNEWT_VAL_REPO_HASH_MY_PROJECT ("37dceb35df57ff41a6c31f79290512df2fde7064") +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES +#define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_MY_PROJECT -#define MYNEWT_VAL_REPO_VERSION_MY_PROJECT ("0.0.0") +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) #endif +#ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB +#define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) +#endif - -/*** @apache-mynewt-core/crypto/tinycrypt */ -#ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE -#define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) +/*** @apache-mynewt-core/hw/mcu/native */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) #endif -#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) #endif -#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) #endif -/*** @apache-mynewt-core/hw/hal */ -#ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS -#define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) #endif -#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ -#define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) #endif -#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES -#define MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES (0) +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) #endif -#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES -#define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) #endif -#ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB -#define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) #endif /*** @apache-mynewt-core/kernel/os */ @@ -142,6 +140,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #endif @@ -150,8 +152,9 @@ #define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE -#define MYNEWT_VAL_OS_CRASH_FILE_LINE (0) +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_OS_CRASH_LOG @@ -190,8 +193,9 @@ #define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MAX (600000) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN -#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (100) +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) #endif #ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE @@ -258,6 +262,11 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +/* Overridden by @apache-mynewt-core/hw/mcu/native (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -274,6 +283,33 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif +/*** @apache-mynewt-core/net/ip/native_sockets */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + /*** @apache-mynewt-core/sys/console/stub */ #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) @@ -292,8 +328,12 @@ #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif /*** @apache-mynewt-core/sys/log/common */ @@ -348,23 +388,6 @@ #define MYNEWT_VAL_LOG_LEVEL (2) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - /*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) @@ -392,12 +415,14 @@ #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ #ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE -#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ #ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE -#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) #endif /*** @apache-mynewt-core/util/rwlock */ @@ -414,6 +439,10 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif @@ -789,6 +818,14 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_LVL +#define MYNEWT_VAL_BLE_SM_SC_LVL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -1015,16 +1052,10 @@ #define MYNEWT_VAL_BLE_SOCK_TCP_PORT (14433) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE #define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport/socket) */ -#ifndef MYNEWT_VAL_BLE_SOCK_USE_NUTTX -#define MYNEWT_VAL_BLE_SOCK_USE_NUTTX (1) -#endif - /* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_TCP #define MYNEWT_VAL_BLE_SOCK_USE_TCP (0) @@ -1040,19 +1071,19 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("dummy") +#define MYNEWT_VAL_ARCH_NAME ("sim") #endif -#ifndef MYNEWT_VAL_ARCH_dummy -#define MYNEWT_VAL_ARCH_dummy (1) +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("dummy_bsp") +#define MYNEWT_VAL_BSP_NAME ("native") #endif -#ifndef MYNEWT_VAL_BSP_dummy_bsp -#define MYNEWT_VAL_BSP_dummy_bsp (1) +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) #endif #ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG diff --git a/porting/examples/nuttx/include/sysflash/sysflash.h b/porting/examples/nuttx/include/sysflash/sysflash.h index ab1341b25d..28391ca66a 100644 --- a/porting/examples/nuttx/include/sysflash/sysflash.h +++ b/porting/examples/nuttx/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ diff --git a/porting/examples/nuttx/main.c b/porting/examples/nuttx/main.c index acfc9fcd18..82582573ad 100644 --- a/porting/examples/nuttx/main.c +++ b/porting/examples/nuttx/main.c @@ -71,11 +71,12 @@ int main(int argc, char *argv[]) ble_hci_sock_set_device(atoi(argv[1])); } - printf("hci init\n"); - ble_hci_sock_init(); printf("port init\n"); nimble_port_init(); + printf("hci init\n"); + ble_hci_sock_init(); + /* This example provides GATT Alert service */ printf("gap init\n"); ble_svc_gap_init(); diff --git a/porting/nimble/Makefile.defs b/porting/nimble/Makefile.defs index 5bab893fde..78f73fbc9b 100644 --- a/porting/nimble/Makefile.defs +++ b/porting/nimble/Makefile.defs @@ -19,7 +19,10 @@ ifeq (,$(NIMBLE_ROOT)) $(error NIMBLE_ROOT shall be defined) endif -NIMBLE_CFLAGS := +# For now this is required as there are places in NimBLE +# assumingthat pointer is 4 bytes long. +NIMBLE_CFLAGS := -m32 +NIMBLE_LDFLAGS := -m32 NIMBLE_INCLUDE := \ $(NIMBLE_ROOT)/nimble/include \ diff --git a/porting/nimble/include/logcfg/logcfg.h b/porting/nimble/include/logcfg/logcfg.h index 837cdeac1f..fab4d812fc 100644 --- a/porting/nimble/include/logcfg/logcfg.h +++ b/porting/nimble/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_LOGCFG_ @@ -22,11 +22,4 @@ #define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) #define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - #endif diff --git a/porting/nimble/include/os/os_mbuf.h b/porting/nimble/include/os/os_mbuf.h index 771ea76159..bee47d0bbf 100644 --- a/porting/nimble/include/os/os_mbuf.h +++ b/porting/nimble/include/os/os_mbuf.h @@ -133,11 +133,11 @@ struct os_mqueue { /** Get a packet header pointer given an mbuf pointer */ #define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *) \ - ((uint8_t *)&(__om)->om_data + sizeof(struct os_mbuf))) + (void *)((uint8_t *)&(__om)->om_data + sizeof(struct os_mbuf))) /** Given a mbuf packet header pointer, return a pointer to the mbuf */ #define OS_MBUF_PKTHDR_TO_MBUF(__hdr) \ - (struct os_mbuf *)((uint8_t *)(__hdr) - sizeof(struct os_mbuf)) + (struct os_mbuf *)(void *)((uint8_t *)(__hdr) - sizeof(struct os_mbuf)) /** * Gets the length of an entire mbuf chain. The specified mbuf must have a diff --git a/porting/nimble/include/syscfg/syscfg.h b/porting/nimble/include/syscfg/syscfg.h index c4b70db4bc..a16c528191 100644 --- a/porting/nimble/include/syscfg/syscfg.h +++ b/porting/nimble/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -28,11 +28,20 @@ #define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif +/*** @apache-mynewt-core/hw/bsp/native */ +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) +#endif + /*** @apache-mynewt-core/hw/hal */ #ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS #define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + #ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ #define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif @@ -45,10 +54,47 @@ #define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + #ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB #define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) #endif +/*** @apache-mynewt-core/hw/mcu/native */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) +#endif + +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) +#endif + /*** @apache-mynewt-core/kernel/os */ #ifndef MYNEWT_VAL_FLOAT_USER #define MYNEWT_VAL_FLOAT_USER (0) @@ -94,6 +140,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #endif @@ -102,8 +152,9 @@ #define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE -#define MYNEWT_VAL_OS_CRASH_FILE_LINE (0) +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_OS_CRASH_LOG @@ -142,8 +193,9 @@ #define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MAX (600000) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN -#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (100) +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) #endif #ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE @@ -210,6 +262,11 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +/* Overridden by @apache-mynewt-core/hw/mcu/native (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -226,6 +283,33 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif +/*** @apache-mynewt-core/net/ip/native_sockets */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + /*** @apache-mynewt-core/sys/console/stub */ #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) @@ -244,8 +328,12 @@ #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif /*** @apache-mynewt-core/sys/log/common */ @@ -299,23 +387,6 @@ #define MYNEWT_VAL_LOG_LEVEL (255) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - /*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) @@ -343,12 +414,14 @@ #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ #ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE -#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) #endif +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ #ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE -#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) #endif /*** @apache-mynewt-core/util/rwlock */ @@ -365,6 +438,10 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif @@ -738,6 +815,14 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_LVL +#define MYNEWT_VAL_BLE_SM_SC_LVL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -962,12 +1047,14 @@ #define MYNEWT_VAL_BLE_SOCK_TCP_PORT (14433) #endif +/* Overridden by @apache-mynewt-nimble/porting/targets/porting_default (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE -#define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (0) +#define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (1) #endif +/* Overridden by @apache-mynewt-nimble/porting/targets/porting_default (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_TCP -#define MYNEWT_VAL_BLE_SOCK_USE_TCP (1) +#define MYNEWT_VAL_BLE_SOCK_USE_TCP (0) #endif /*** newt */ @@ -980,19 +1067,19 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("dummy") +#define MYNEWT_VAL_ARCH_NAME ("sim") #endif -#ifndef MYNEWT_VAL_ARCH_dummy -#define MYNEWT_VAL_ARCH_dummy (1) +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("dummy_bsp") +#define MYNEWT_VAL_BSP_NAME ("native") #endif -#ifndef MYNEWT_VAL_BSP_dummy_bsp -#define MYNEWT_VAL_BSP_dummy_bsp (1) +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) #endif #ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG diff --git a/porting/nimble/include/sysflash/sysflash.h b/porting/nimble/include/sysflash/sysflash.h index ab1341b25d..28391ca66a 100644 --- a/porting/nimble/include/sysflash/sysflash.h +++ b/porting/nimble/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ diff --git a/porting/nimble/src/nimble_port.c b/porting/nimble/src/nimble_port.c index 06b5f6df91..d4824d0b37 100644 --- a/porting/nimble/src/nimble_port.c +++ b/porting/nimble/src/nimble_port.c @@ -30,6 +30,7 @@ static struct ble_npl_eventq g_eventq_dflt; extern void os_msys_init(void); +extern void os_mempool_module_init(void); void nimble_port_init(void) @@ -37,14 +38,17 @@ nimble_port_init(void) /* Initialize default event queue */ ble_npl_eventq_init(&g_eventq_dflt); /* Initialize the global memory pool */ + os_mempool_module_init(); os_msys_init(); /* Initialize the host */ ble_hs_init(); #if NIMBLE_CFG_CONTROLLER ble_hci_ram_init(); +#ifndef RIOT_VERSION hal_timer_init(5, NULL); os_cputime_init(32768); +#endif ble_ll_init(); #endif } diff --git a/porting/npl/freertos/src/npl_os_freertos.c b/porting/npl/freertos/src/npl_os_freertos.c index 87936bd8de..ecc5cd7b1e 100644 --- a/porting/npl/freertos/src/npl_os_freertos.c +++ b/porting/npl/freertos/src/npl_os_freertos.c @@ -279,10 +279,6 @@ npl_freertos_callout_reset(struct ble_npl_callout *co, ble_npl_time_t ticks) { BaseType_t woken1, woken2, woken3; - if (ticks < 0) { - return BLE_NPL_INVALID_PARAM; - } - if (ticks == 0) { ticks = 1; } diff --git a/porting/npl/linux/include/nimble/nimble_npl_os.h b/porting/npl/linux/include/nimble/nimble_npl_os.h index bdd3988699..585d378525 100644 --- a/porting/npl/linux/include/nimble/nimble_npl_os.h +++ b/porting/npl/linux/include/nimble/nimble_npl_os.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "os_types.h" @@ -30,7 +31,7 @@ extern "C" { #endif -#define BLE_NPL_OS_ALIGNMENT 4 +#define BLE_NPL_OS_ALIGNMENT (__WORDSIZE / 8) #define BLE_NPL_TIME_FOREVER INT32_MAX diff --git a/porting/npl/nuttx/src/os_task.c b/porting/npl/nuttx/src/os_task.c index ab535a36c5..40f8c8c7ba 100644 --- a/porting/npl/nuttx/src/os_task.c +++ b/porting/npl/nuttx/src/os_task.c @@ -18,6 +18,8 @@ */ #include +#include + #include "os/os.h" #include "nimble/nimble_npl.h" diff --git a/porting/npl/riot/include/logcfg/logcfg.h b/porting/npl/riot/include/logcfg/logcfg.h index 837cdeac1f..fab4d812fc 100644 --- a/porting/npl/riot/include/logcfg/logcfg.h +++ b/porting/npl/riot/include/logcfg/logcfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_LOGCFG_ @@ -22,11 +22,4 @@ #define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) #define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - #endif diff --git a/porting/npl/riot/include/nimble/nimble_npl_os.h b/porting/npl/riot/include/nimble/nimble_npl_os.h index 854fd06c13..4633cbd1a7 100644 --- a/porting/npl/riot/include/nimble/nimble_npl_os.h +++ b/porting/npl/riot/include/nimble/nimble_npl_os.h @@ -24,8 +24,12 @@ #include #include "event/callback.h" #include "mutex.h" -#include "semaphore.h" -#include "xtimer.h" +#include "sema.h" +#include "ztimer.h" + +#if defined(CPU_FAM_NRF51) || defined(CPU_FAM_NRF52) +#include "nrf_clock.h" +#endif #ifdef __cplusplus extern "C" { @@ -38,8 +42,6 @@ extern "C" { typedef uint32_t ble_npl_time_t; typedef int32_t ble_npl_stime_t; -extern volatile int ble_npl_in_critical; - struct ble_npl_event { event_callback_t e; void *arg; @@ -50,8 +52,8 @@ struct ble_npl_eventq { }; struct ble_npl_callout { - xtimer_t timer; - uint64_t target_us; + ztimer_t timer; + ble_npl_time_t ticks; struct ble_npl_event e; event_queue_t *q; }; @@ -61,7 +63,7 @@ struct ble_npl_mutex { }; struct ble_npl_sem { - sem_t sem; + sema_t sem; }; static inline bool @@ -100,8 +102,9 @@ ble_npl_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo) } else if (tmo == BLE_NPL_TIME_FOREVER) { return (struct ble_npl_event *)event_wait(&evq->q); } else { - return (struct ble_npl_event *)event_wait_timeout64(&evq->q, - tmo * US_PER_MS); + return (struct ble_npl_event *)event_wait_timeout_ztimer(&evq->q, + ZTIMER_MSEC, + (uint32_t)tmo); } } @@ -174,49 +177,39 @@ ble_npl_mutex_release(struct ble_npl_mutex *mu) static inline ble_npl_error_t ble_npl_sem_init(struct ble_npl_sem *sem, uint16_t tokens) { - int rc; - - rc = sem_init(&sem->sem, 0, tokens); - - return rc == 0 ? BLE_NPL_OK : BLE_NPL_ERROR; + sema_create(&sem->sem, (unsigned)tokens); + return BLE_NPL_OK; } static inline ble_npl_error_t ble_npl_sem_release(struct ble_npl_sem *sem) { - int rc; - - rc = sem_post(&sem->sem); - - return rc == 0 ? BLE_NPL_OK : BLE_NPL_ERROR; + int rc = sema_post(&sem->sem); + return (rc == 0) ? BLE_NPL_OK : BLE_NPL_ERROR; } static inline uint16_t ble_npl_sem_get_count(struct ble_npl_sem *sem) { - int val = 0; - - sem_getvalue(&sem->sem, &val); - - return (uint16_t)val; + return (uint16_t)sema_get_value(&sem->sem); } static inline void ble_npl_callout_stop(struct ble_npl_callout *co) { - xtimer_remove(&co->timer); + ztimer_remove(ZTIMER_MSEC, &co->timer); } static inline bool ble_npl_callout_is_active(struct ble_npl_callout *c) { - return (c->timer.offset || c->timer.long_offset); + return ztimer_is_set(ZTIMER_MSEC, &c->timer); } static inline ble_npl_time_t ble_npl_callout_get_ticks(struct ble_npl_callout *co) { - return (ble_npl_time_t)(co->target_us / US_PER_MS); + return co->ticks; } static inline void @@ -228,7 +221,7 @@ ble_npl_callout_set_arg(struct ble_npl_callout *co, void *arg) static inline ble_npl_time_t ble_npl_time_get(void) { - return (ble_npl_time_t)(xtimer_now_usec64() / US_PER_MS); + return (ble_npl_time_t)ztimer_now(ZTIMER_MSEC); } static inline ble_npl_error_t @@ -260,35 +253,43 @@ ble_npl_time_ticks_to_ms32(ble_npl_time_t ticks) static inline void ble_npl_time_delay(ble_npl_time_t ticks) { - xtimer_usleep64(ticks * US_PER_MS); + ztimer_sleep(ZTIMER_MSEC, (uint32_t)ticks); } static inline uint32_t ble_npl_hw_enter_critical(void) { - uint32_t ctx = irq_disable(); - ++ble_npl_in_critical; - return ctx; + return (uint32_t)irq_disable(); } static inline void ble_npl_hw_exit_critical(uint32_t ctx) { - --ble_npl_in_critical; irq_restore((unsigned)ctx); } static inline bool ble_npl_hw_is_in_critical(void) { - /* - * XXX Currently RIOT does not support an API for finding out if interrupts - * are currently disabled, hence in a critical section in this context. - * So for now, we use this global variable to keep this state for us. - -*/ - return (ble_npl_in_critical > 0); + return (bool)!irq_is_enabled(); +} + +/* XXX: these functions are required to build hal_timer.c, however with the +* default configuration they are never used... */ +#if defined(CPU_FAM_NRF51) || defined(CPU_FAM_NRF52) +static inline void +nrf52_clock_hfxo_request(void) +{ + clock_hfxo_request(); } +static inline void +nrf52_clock_hfxo_release(void) +{ + clock_hfxo_release(); +} +#endif + #ifdef __cplusplus } #endif diff --git a/porting/npl/riot/include/npl_syscfg/npl_sycfg.h b/porting/npl/riot/include/npl_syscfg/npl_sycfg.h new file mode 120000 index 0000000000..53c55a90b9 --- /dev/null +++ b/porting/npl/riot/include/npl_syscfg/npl_sycfg.h @@ -0,0 +1 @@ +../syscfg/syscfg.h \ No newline at end of file diff --git a/porting/npl/riot/include/syscfg/syscfg.h b/porting/npl/riot/include/syscfg/syscfg.h index 816f410ac5..538c8213b4 100644 --- a/porting/npl/riot/include/syscfg/syscfg.h +++ b/porting/npl/riot/include/syscfg/syscfg.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSCFG_ @@ -34,6 +34,10 @@ #define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + #ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ #define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif @@ -46,6 +50,10 @@ #define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + #ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB #define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) #endif @@ -118,10 +126,24 @@ #define MYNEWT_VAL_MCU_GPIO_USE_PORT_EVENT (0) #endif +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE__HFINT +#define MYNEWT_VAL_MCU_HFCLK_SOURCE__HFINT (0) +#endif +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE__HFXO +#define MYNEWT_VAL_MCU_HFCLK_SOURCE__HFXO (1) +#endif +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE +#define MYNEWT_VAL_MCU_HFCLK_SOURCE (1) +#endif + #ifndef MYNEWT_VAL_MCU_I2C_RECOVERY_DELAY_USEC #define MYNEWT_VAL_MCU_I2C_RECOVERY_DELAY_USEC (100) #endif +#ifndef MYNEWT_VAL_MCU_ICACHE_ENABLED +#define MYNEWT_VAL_MCU_ICACHE_ENABLED (0) +#endif + /* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_MCU_LFCLK_SOURCE__LFRC #define MYNEWT_VAL_MCU_LFCLK_SOURCE__LFRC (0) @@ -165,10 +187,6 @@ #define MYNEWT_VAL_NFC_PINS_AS_GPIO (1) #endif -#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC -#define MYNEWT_VAL_OS_TICKS_PER_SEC (128) -#endif - #ifndef MYNEWT_VAL_PWM_0 #define MYNEWT_VAL_PWM_0 (0) #endif @@ -493,6 +511,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + /* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (32768) @@ -611,6 +633,11 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +/* Overridden by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (128) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -632,6 +659,10 @@ #define MYNEWT_VAL_BASELIBC_ASSERT_FILE_LINE (0) #endif +#ifndef MYNEWT_VAL_BASELIBC_EXECUTE_GLOBAL_CONSTRUCTORS +#define MYNEWT_VAL_BASELIBC_EXECUTE_GLOBAL_CONSTRUCTORS (1) +#endif + #ifndef MYNEWT_VAL_BASELIBC_PRESENT #define MYNEWT_VAL_BASELIBC_PRESENT (1) #endif @@ -654,8 +685,12 @@ #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif /*** @apache-mynewt-core/sys/log/common */ @@ -709,23 +744,6 @@ #define MYNEWT_VAL_LOG_LEVEL (255) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - /*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) @@ -775,6 +793,11 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble) */ +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (1) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif @@ -847,7 +870,7 @@ #endif #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ (MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL) #endif #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL @@ -926,7 +949,7 @@ #endif #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL) #endif /* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ @@ -950,8 +973,12 @@ #define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_HCI_EV (-1) #endif -#ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB -#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB (-1) +#ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_RFMGMT +#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_RFMGMT (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM +#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM (-1) #endif #ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_RUN @@ -975,6 +1002,19 @@ #define MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_HCI_LLCP_TRACE +#define MYNEWT_VAL_BLE_LL_HCI_LLCP_TRACE (0) +#endif + +/* Value copied from BLE_HCI_VS */ +#ifndef MYNEWT_VAL_BLE_LL_HCI_VS +#define MYNEWT_VAL_BLE_LL_HCI_VS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_HCI_VS_EVENT_ON_ASSERT +#define MYNEWT_VAL_BLE_LL_HCI_VS_EVENT_ON_ASSERT (0) +#endif + #ifndef MYNEWT_VAL_BLE_LL_MASTER_SCA #define MYNEWT_VAL_BLE_LL_MASTER_SCA (4) #endif @@ -1007,6 +1047,10 @@ #define MYNEWT_VAL_BLE_LL_PRIO (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_PUBLIC_DEV_ADDR +#define MYNEWT_VAL_BLE_LL_PUBLIC_DEV_ADDR (0x000000000000) +#endif + #ifndef MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE #define MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE (4) #endif @@ -1020,11 +1064,35 @@ #define MYNEWT_VAL_BLE_LL_RNG_BUFSIZE (32) #endif +/* Value copied from BLE_ROLE_BROADCASTER */ +#ifndef MYNEWT_VAL_BLE_LL_ROLE_BROADCASTER +#define MYNEWT_VAL_BLE_LL_ROLE_BROADCASTER (1) +#endif + +/* Value copied from BLE_ROLE_CENTRAL */ +#ifndef MYNEWT_VAL_BLE_LL_ROLE_CENTRAL +#define MYNEWT_VAL_BLE_LL_ROLE_CENTRAL (1) +#endif + +/* Value copied from BLE_ROLE_OBSERVER */ +#ifndef MYNEWT_VAL_BLE_LL_ROLE_OBSERVER +#define MYNEWT_VAL_BLE_LL_ROLE_OBSERVER (1) +#endif + +/* Value copied from BLE_ROLE_PERIPHERAL */ +#ifndef MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL +#define MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL (1) +#endif + /* Value copied from BLE_LL_OUR_SCA */ #ifndef MYNEWT_VAL_BLE_LL_SCA #define MYNEWT_VAL_BLE_LL_SCA (60) #endif +#ifndef MYNEWT_VAL_BLE_LL_SCAN_AUX_SEGMENT_CNT +#define MYNEWT_VAL_BLE_LL_SCAN_AUX_SEGMENT_CNT (8) +#endif + #ifndef MYNEWT_VAL_BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY #define MYNEWT_VAL_BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY (0) #endif @@ -1096,10 +1164,6 @@ #endif /*** @apache-mynewt-nimble/nimble/drivers/nrf52 */ -#ifndef MYNEWT_VAL_BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN -#define MYNEWT_VAL_BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN (0) -#endif - #ifndef MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN #define MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN (-1) #endif @@ -1447,6 +1511,14 @@ #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_LVL +#define MYNEWT_VAL_BLE_SM_SC_LVL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -1516,7 +1588,7 @@ #endif #ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE -#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (65535) #endif #ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE diff --git a/porting/npl/riot/include/sysflash/sysflash.h b/porting/npl/riot/include/sysflash/sysflash.h index ab1341b25d..28391ca66a 100644 --- a/porting/npl/riot/include/sysflash/sysflash.h +++ b/porting/npl/riot/include/sysflash/sysflash.h @@ -1,5 +1,5 @@ /** - * This file was generated by Apache newt version: 1.9.0-dev + * This file was generated by Apache newt version: 1.10.0-dev */ #ifndef H_MYNEWT_SYSFLASH_ diff --git a/porting/npl/riot/src/npl_os_riot.c b/porting/npl/riot/src/npl_os_riot.c index 2f4efd8ba5..71c130f198 100644 --- a/porting/npl/riot/src/npl_os_riot.c +++ b/porting/npl/riot/src/npl_os_riot.c @@ -35,18 +35,8 @@ _callout_fire(void *arg) ble_npl_error_t ble_npl_sem_pend(struct ble_npl_sem *sem, ble_npl_time_t timeout) { - int rc; - struct timespec abs; - uint64_t time; - - time = xtimer_now_usec64() + - (ble_npl_time_ticks_to_ms32(timeout) * US_PER_MS); - abs.tv_sec = (time_t)(time / US_PER_SEC); - abs.tv_nsec = (long)((time % US_PER_SEC) * NS_PER_US); - - rc = sem_timedwait(&sem->sem, &abs); - - return rc == 0 ? BLE_NPL_OK : BLE_NPL_ENOENT; + int rc = sema_wait_timed_ztimer(&sem->sem, ZTIMER_MSEC, timeout); + return (rc == 0) ? BLE_NPL_OK : BLE_NPL_ENOENT; } void @@ -62,19 +52,18 @@ ble_npl_callout_init(struct ble_npl_callout *c, struct ble_npl_eventq *evq, ble_npl_error_t ble_npl_callout_reset(struct ble_npl_callout *c, ble_npl_time_t ticks) { - /* Use critical section to ensure matching target_us and xtimer value. */ + /* Use critical section to ensure matching target_us and ztimer value. */ uint32_t crit_state = ble_npl_hw_enter_critical(); - uint64_t now = xtimer_now_usec64(); - c->target_us = now + ticks * US_PER_MS; - xtimer_set64(&c->timer, ticks * US_PER_MS); + c->ticks = ztimer_now(ZTIMER_MSEC) + ticks; + ztimer_set(ZTIMER_MSEC, &c->timer, ticks); ble_npl_hw_exit_critical(crit_state); return BLE_NPL_OK; } -uint32_t +ble_npl_time_t ble_npl_callout_remaining_ticks(struct ble_npl_callout *co, ble_npl_time_t time) { - uint64_t now = xtimer_now_usec64(); - return (uint32_t)((co->target_us - now) / US_PER_MS); + ztimer_now_t now = ztimer_now(ZTIMER_MSEC); + return (ble_npl_time_t)(co->ticks - now); } diff --git a/porting/targets/dummy_bsp/bsp.yml b/porting/targets/dummy_bsp/bsp.yml deleted file mode 100644 index ecd1d42041..0000000000 --- a/porting/targets/dummy_bsp/bsp.yml +++ /dev/null @@ -1,56 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -bsp.name: "dummy" -bsp.url: -bsp.maker: -bsp.arch: dummy -bsp.compiler: "@apache-mynewt-core/compiler/sim" - -bsp.flash_map: - areas: - # System areas. - FLASH_AREA_BOOTLOADER: - device: 0 - offset: 0x00000000 - size: 32kB - FLASH_AREA_IMAGE_0: - device: 0 - offset: 0x0000c000 - size: 472kB - FLASH_AREA_IMAGE_1: - device: 0 - offset: 0x00082000 - size: 472kB - FLASH_AREA_IMAGE_SCRATCH: - device: 0 - offset: 0x000f8000 - size: 16kB - - # User areas. - FLASH_AREA_REBOOT_LOG: - user_id: 0 - device: 0 - offset: 0x00008000 - size: 16kB - FLASH_AREA_NFFS: - user_id: 1 - device: 0 - offset: 0x000fc000 - size: 16kB diff --git a/porting/targets/linux/target.yml b/porting/targets/linux/target.yml index 9ab4152c9d..7145d70386 100644 --- a/porting/targets/linux/target.yml +++ b/porting/targets/linux/target.yml @@ -16,5 +16,5 @@ # under the License. # target.app: "porting/targets/dummy_app" -target.bsp: "porting/targets/dummy_bsp" +target.bsp: "@apache-mynewt-core/hw/bsp/native" target.build_profile: "debug" diff --git a/porting/targets/linux_blemesh/syscfg.yml b/porting/targets/linux_blemesh/syscfg.yml index efc4150b4c..8ef7972184 100644 --- a/porting/targets/linux_blemesh/syscfg.yml +++ b/porting/targets/linux_blemesh/syscfg.yml @@ -34,6 +34,7 @@ syscfg.vals: BLE_MESH_LABEL_COUNT: 2 BLE_MESH_SUBNET_COUNT: 2 BLE_MESH_MODEL_GROUP_COUNT: 2 + BLE_MESH_MODEL_VND_MSG_CID_FORCE: 1 BLE_MESH_APP_KEY_COUNT: 4 BLE_MESH_IV_UPDATE_TEST: 1 BLE_MESH_TESTING: 1 diff --git a/porting/targets/linux_blemesh/target.yml b/porting/targets/linux_blemesh/target.yml index 83eb415886..4b9a4dab8b 100644 --- a/porting/targets/linux_blemesh/target.yml +++ b/porting/targets/linux_blemesh/target.yml @@ -17,5 +17,5 @@ # target.app: "porting/targets/dummy_app" -target.bsp: "porting/targets/dummy_bsp" +target.bsp: "@apache-mynewt-core/hw/bsp/native" target.build_profile: "debug" diff --git a/porting/targets/nuttx/target.yml b/porting/targets/nuttx/target.yml index 9ab4152c9d..7145d70386 100644 --- a/porting/targets/nuttx/target.yml +++ b/porting/targets/nuttx/target.yml @@ -16,5 +16,5 @@ # under the License. # target.app: "porting/targets/dummy_app" -target.bsp: "porting/targets/dummy_bsp" +target.bsp: "@apache-mynewt-core/hw/bsp/native" target.build_profile: "debug" diff --git a/porting/targets/porting_default/syscfg.yml b/porting/targets/porting_default/syscfg.yml new file mode 100644 index 0000000000..d0aff807f2 --- /dev/null +++ b/porting/targets/porting_default/syscfg.yml @@ -0,0 +1,3 @@ +syscfg.vals: + BLE_SOCK_USE_TCP: 0 + BLE_SOCK_USE_LINUX_BLUE: 1 diff --git a/porting/targets/porting_default/target.yml b/porting/targets/porting_default/target.yml index 83eb415886..4b9a4dab8b 100644 --- a/porting/targets/porting_default/target.yml +++ b/porting/targets/porting_default/target.yml @@ -17,5 +17,5 @@ # target.app: "porting/targets/dummy_app" -target.bsp: "porting/targets/dummy_bsp" +target.bsp: "@apache-mynewt-core/hw/bsp/native" target.build_profile: "debug" diff --git a/porting/targets/riot/syscfg.yml b/porting/targets/riot/syscfg.yml index d6ee102bf9..8359eaa7c9 100644 --- a/porting/targets/riot/syscfg.yml +++ b/porting/targets/riot/syscfg.yml @@ -18,6 +18,7 @@ syscfg.vals: BLE_ACL_BUF_COUNT: 24 + BLE_HCI_VS: 1 BLE_HCI_EVT_HI_BUF_COUNT: 2 BLE_HW_WHITELIST_ENABLE: 0 BLE_LL_CFG_FEAT_DATA_LEN_EXT: 0 diff --git a/repository.yml b/repository.yml index 4a097d39a5..9f112a825e 100644 --- a/repository.yml +++ b/repository.yml @@ -22,18 +22,20 @@ repo.versions: "0.0.0": "master" "0-dev": "0.0.0" - "0-latest": "1.3.0" - "1-latest": "1.3.0" + "0-latest": "1.4.0" + "1-latest": "1.4.0" "1.0.0": "nimble_1_0_0_tag" "1.1.0": "nimble_1_1_0_tag" "1.2.0": "nimble_1_2_0_tag" "1.3.0": "nimble_1_3_0_tag" + "1.4.0": "nimble_1_4_0_tag" "1.0-latest": "1.0.0" "1.1-latest": "1.1.0" "1.2-latest": "1.2.0" "1.3-latest": "1.3.0" + "1.4-latest": "1.4.0" repo.newt_compatibility: 0.0.0: @@ -46,3 +48,5 @@ repo.newt_compatibility: 1.7.0: good 1.3.0: 1.8.0: good + 1.4.0: + 1.9.0: good diff --git a/targets/dialog_cmac/syscfg.yml b/targets/dialog_cmac/syscfg.yml index b94427ac22..3a8895d7db 100644 --- a/targets/dialog_cmac/syscfg.yml +++ b/targets/dialog_cmac/syscfg.yml @@ -32,4 +32,4 @@ syscfg.vals: BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY: 150 # NOTE: set public address in target settings - # BLE_PUBLIC_DEV_ADDR: "(uint8_t[6]){0xff, 0xff, 0xff, 0xff, 0xff, 0xff}" + # BLE_LL_PUBLIC_DEV_ADDR: 0xffffffffffff diff --git a/targets/nordic_pca10056-blehci-usb/pkg.yml b/targets/nordic_pca10056-blehci-usb/pkg.yml new file mode 100644 index 0000000000..772dd75ebe --- /dev/null +++ b/targets/nordic_pca10056-blehci-usb/pkg.yml @@ -0,0 +1,9 @@ +pkg.name: "targets/nordic_pca10056-blehci-usb" +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + +pkg.deps: + - "@apache-mynewt-core/hw/usb/tinyusb" + - "@apache-mynewt-core/hw/usb/tinyusb/std_descriptors" diff --git a/targets/nordic_pca10056-blehci-usb/syscfg.yml b/targets/nordic_pca10056-blehci-usb/syscfg.yml new file mode 100644 index 0000000000..e664792eaa --- /dev/null +++ b/targets/nordic_pca10056-blehci-usb/syscfg.yml @@ -0,0 +1,6 @@ +syscfg.vals: + BLE_HCI_TRANSPORT: usb + USBD_BTH: 1 + + USBD_PID: 0xC01A + USBD_VID: 0xC0CA diff --git a/targets/nordic_pca10056-blehci-usb/target.yml b/targets/nordic_pca10056-blehci-usb/target.yml new file mode 100644 index 0000000000..39f4c8c447 --- /dev/null +++ b/targets/nordic_pca10056-blehci-usb/target.yml @@ -0,0 +1,3 @@ +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" +target.build_profile: debug diff --git a/porting/targets/dummy_bsp/pkg.yml b/targets/nordic_pca10095_net-blehci/pkg.yml similarity index 87% rename from porting/targets/dummy_bsp/pkg.yml rename to targets/nordic_pca10095_net-blehci/pkg.yml index 8b8484960a..af24376a83 100644 --- a/porting/targets/dummy_bsp/pkg.yml +++ b/targets/nordic_pca10095_net-blehci/pkg.yml @@ -17,11 +17,8 @@ # under the License. # -pkg.name: porting/targets/dummy_bsp -pkg.type: bsp -pkg.description: A dummy BSP definition +pkg.name: targets/nordic_pca10095_net-blehci +pkg.type: target +pkg.description: Sample target for BLE controller on NRF5340 pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: -pkg.cflags: -pkg.deps: diff --git a/targets/nordic_pca10095_net-blehci/syscfg.yml b/targets/nordic_pca10095_net-blehci/syscfg.yml new file mode 100644 index 0000000000..4a4a1ba069 --- /dev/null +++ b/targets/nordic_pca10095_net-blehci/syscfg.yml @@ -0,0 +1,42 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_HCI_TRANSPORT: nrf5340 + + MSYS_1_BLOCK_COUNT: 12 + MSYS_1_BLOCK_SIZE: 292 + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_LL_CFG_FEAT_LE_CODED_PHY: 1 + BLE_LL_CFG_FEAT_LL_PRIVACY: 1 + BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL: 1 + BLE_LL_CONN_INIT_MAX_TX_BYTES: 251 + BLE_LL_CONN_INIT_SLOTS: 4 + BLE_LL_DTM: 1 + BLE_LL_DTM_EXTENSIONS: 1 + BLE_LL_VND_EVENT_ON_ASSERT: 1 + BLE_MAX_CONNECTIONS: 5 + BLE_EXT_ADV: 1 + BLE_EXT_ADV_MAX_SIZE: 1650 + BLE_MAX_PERIODIC_SYNCS: 5 + BLE_MULTI_ADV_INSTANCES: 5 + BLE_PERIODIC_ADV: 1 + BLE_PERIODIC_ADV_SYNC_TRANSFER: 1 + BLE_VERSION: 51 diff --git a/targets/nordic_pca10095_net-blehci/target.yml b/targets/nordic_pca10095_net-blehci/target.yml new file mode 100644 index 0000000000..4d2641b77c --- /dev/null +++ b/targets/nordic_pca10095_net-blehci/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095_net" +target.build_profile: debug