소스 검색

ble_mesh: stack: Add node local netkey/appkey func

lly 5 년 전
부모
커밋
42bdf7ecc2

+ 85 - 0
components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c

@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include <stdint.h>
+#include <string.h>
 
 #include "esp_err.h"
 
@@ -128,3 +129,87 @@ esp_err_t esp_ble_mesh_model_unsubscribe_group_addr(uint16_t element_addr, uint1
     return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL)
             == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
 }
+
+#if CONFIG_BLE_MESH_NODE
+
+const uint8_t *esp_ble_mesh_node_get_local_net_key(uint16_t net_idx)
+{
+    return btc_ble_mesh_node_get_local_net_key(net_idx);
+}
+
+const uint8_t *esp_ble_mesh_node_get_local_app_key(uint16_t app_idx)
+{
+    return btc_ble_mesh_node_get_local_app_key(app_idx);
+}
+
+esp_err_t esp_ble_mesh_node_add_local_net_key(const uint8_t net_key[16], uint16_t net_idx)
+{
+    btc_ble_mesh_prov_args_t arg = {0};
+    btc_msg_t msg = {0};
+
+    if (net_key == NULL || net_idx > 0xFFF) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_PROV;
+    msg.act = BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_NET_KEY;
+
+    arg.node_add_local_net_key.net_idx = net_idx;
+    memcpy(arg.node_add_local_net_key.net_key, net_key, 16);
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL)
+            == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+esp_err_t esp_ble_mesh_node_add_local_app_key(const uint8_t app_key[16], uint16_t net_idx, uint16_t app_idx)
+{
+    btc_ble_mesh_prov_args_t arg = {0};
+    btc_msg_t msg = {0};
+
+    if (app_key == NULL || net_idx > 0xFFF || app_idx > 0xFFF) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_PROV;
+    msg.act = BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_APP_KEY;
+
+    arg.node_add_local_app_key.net_idx = net_idx;
+    arg.node_add_local_app_key.app_idx = app_idx;
+    memcpy(arg.node_add_local_app_key.app_key, app_key, 16);
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL)
+            == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+esp_err_t esp_ble_mesh_node_bind_app_key_to_local_model(uint16_t element_addr, uint16_t model_id,
+                                                        uint16_t company_id, uint16_t app_idx)
+{
+    btc_ble_mesh_prov_args_t arg = {0};
+    btc_msg_t msg = {0};
+
+    if (!ESP_BLE_MESH_ADDR_IS_UNICAST(element_addr) || app_idx > 0xFFF) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_PROV;
+    msg.act = BTC_BLE_MESH_ACT_NODE_BIND_APP_KEY_TO_MODEL;
+
+    arg.node_local_mod_app_bind.element_addr = element_addr;
+    arg.node_local_mod_app_bind.model_id = model_id;
+    arg.node_local_mod_app_bind.company_id = company_id;
+    arg.node_local_mod_app_bind.app_idx = app_idx;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL)
+            == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+#endif /* CONFIG_BLE_MESH_NODE */

+ 66 - 0
components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h

@@ -142,6 +142,72 @@ esp_err_t esp_ble_mesh_model_subscribe_group_addr(uint16_t element_addr, uint16_
 esp_err_t esp_ble_mesh_model_unsubscribe_group_addr(uint16_t element_addr, uint16_t company_id,
                                                     uint16_t model_id, uint16_t group_addr);
 
+/**
+ * @brief         This function is called by Node to get the local NetKey.
+ *
+ * @param[in]     net_idx: NetKey index.
+ *
+ * @return        NetKey on success, or NULL on failure.
+ *
+ */
+const uint8_t *esp_ble_mesh_node_get_local_net_key(uint16_t net_idx);
+
+/**
+ * @brief         This function is called by Node to get the local AppKey.
+ *
+ * @param[in]     app_idx: AppKey index.
+ *
+ * @return        AppKey on success, or NULL on failure.
+ *
+ */
+const uint8_t *esp_ble_mesh_node_get_local_app_key(uint16_t app_idx);
+
+/**
+ * @brief         This function is called by Node to add a local NetKey.
+ *
+ * @param[in]     net_key: NetKey to be added.
+ * @param[in]     net_idx: NetKey Index.
+ *
+ * @note          This function can only be called after the device is provisioned.
+ *
+ * @return        ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_node_add_local_net_key(const uint8_t net_key[16], uint16_t net_idx);
+
+/**
+ * @brief         This function is called by Node to add a local AppKey.
+ *
+ * @param[in]     app_key: AppKey to be added.
+ * @param[in]     net_idx: NetKey Index.
+ * @param[in]     app_idx: AppKey Index.
+ *
+ * @note          The net_idx must be an existing one.
+ *                This function can only be called after the device is provisioned.
+ *
+ * @return        ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_node_add_local_app_key(const uint8_t app_key[16], uint16_t net_idx, uint16_t app_idx);
+
+/**
+ * @brief         This function is called by Node to bind AppKey to model locally.
+ *
+ * @param[in]     element_addr: Node local element address
+ * @param[in]     app_idx: Node local appkey index
+ * @param[in]     model_id: Node local model id
+ * @param[in]     company_id: Node local company id
+ *
+ * @note          If going to bind app_key with local vendor model, the company_id
+ *                shall be set to 0xFFFF.
+ *                This function can only be called after the device is provisioned.
+ *
+ * @return        ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_node_bind_app_key_to_local_model(uint16_t element_addr, uint16_t app_idx,
+                                                        uint16_t model_id, uint16_t company_id);
+
 #ifdef __cplusplus
 }
 #endif

+ 28 - 0
components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h

@@ -821,6 +821,9 @@ typedef enum {
     ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT,           /*!< Enable BLE Mesh Proxy Identity advertising completion event */
     ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT,               /*!< Enable BLE Mesh GATT Proxy Service completion event */
     ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT,              /*!< Disable BLE Mesh GATT Proxy Service completion event */
+    ESP_BLE_MESH_NODE_ADD_LOCAL_NET_KEY_COMP_EVT,               /*!< Node add NetKey locally completion event */
+    ESP_BLE_MESH_NODE_ADD_LOCAL_APP_KEY_COMP_EVT,               /*!< Node add AppKey locally completion event */
+    ESP_BLE_MESH_NODE_BIND_APP_KEY_TO_MODEL_COMP_EVT,           /*!< Node bind AppKey to model locally completion event */
     ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT,              /*!< Provisioner enable provisioning functionality completion event */
     ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT,             /*!< Provisioner disable provisioning functionality completion event */
     ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT,           /*!< Provisioner receives unprovisioned device beacon event */
@@ -988,6 +991,31 @@ typedef union {
     struct ble_mesh_proxy_gatt_disable_comp_param {
         int err_code;                           /*!< Indicate the result of disabling Mesh Proxy Service */
     } node_proxy_gatt_disable_comp;             /*!< Event parameter of ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT */
+    /**
+     * @brief ESP_BLE_MESH_NODE_ADD_LOCAL_NET_KEY_COMP_EVT
+     */
+    struct ble_mesh_node_add_local_net_key_comp_param {
+        int err_code;                           /*!< Indicate the result of adding local NetKey by the node */
+        uint16_t net_idx;                       /*!< NetKey Index */
+    } node_add_net_key_comp;                    /*!< Event parameter of ESP_BLE_MESH_NODE_ADD_LOCAL_NET_KEY_COMP_EVT */
+    /**
+     * @brief ESP_BLE_MESH_NODE_ADD_LOCAL_APP_KEY_COMP_EVT
+     */
+    struct ble_mesh_node_add_local_app_key_comp_param {
+        int err_code;                           /*!< Indicate the result of adding local AppKey by the node */
+        uint16_t net_idx;                       /*!< NetKey Index */
+        uint16_t app_idx;                       /*!< AppKey Index */
+    } node_add_app_key_comp;                    /*!< Event parameter of ESP_BLE_MESH_NODE_ADD_LOCAL_APP_KEY_COMP_EVT */
+    /**
+     * @brief ESP_BLE_MESH_NODE_BIND_APP_KEY_TO_MODEL_COMP_EVT
+     */
+    struct ble_mesh_node_bind_local_mod_app_comp_param {
+        int err_code;                           /*!< Indicate the result of binding AppKey with model by the node */
+        uint16_t element_addr;                  /*!< Element address */
+        uint16_t app_idx;                       /*!< AppKey Index */
+        uint16_t company_id;                    /*!< Company ID */
+        uint16_t model_id;                      /*!< Model ID */
+    } node_bind_app_key_to_model_comp;          /*!< Event parameter of ESP_BLE_MESH_NODE_BIND_APP_KEY_TO_MODEL_COMP_EVT */
     /**
      * @brief ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT
      */

+ 38 - 0
components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c

@@ -641,6 +641,16 @@ static void btc_ble_mesh_reset_cb(void)
     btc_ble_mesh_prov_callback(NULL, ESP_BLE_MESH_NODE_PROV_RESET_EVT);
     return;
 }
+
+const uint8_t *btc_ble_mesh_node_get_local_net_key(uint16_t net_idx)
+{
+    return bt_mesh_node_get_local_net_key(net_idx);
+}
+
+const uint8_t *btc_ble_mesh_node_get_local_app_key(uint16_t app_idx)
+{
+    return bt_mesh_node_get_local_app_key(app_idx);
+}
 #endif /* CONFIG_BLE_MESH_NODE */
 
 static void btc_ble_mesh_prov_register_complete_cb(int err_code)
@@ -1763,6 +1773,34 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg)
         act = ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT;
         param.node_prov_input_str_comp.err_code = bt_mesh_input_string(arg->input_string.string);
         break;
+    case BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_NET_KEY:
+        act = ESP_BLE_MESH_NODE_ADD_LOCAL_NET_KEY_COMP_EVT;
+        param.node_add_net_key_comp.net_idx = arg->node_add_local_net_key.net_idx;
+        param.node_add_net_key_comp.err_code =
+            bt_mesh_node_local_net_key_add(arg->node_add_local_net_key.net_idx,
+                                           arg->node_add_local_net_key.net_key);
+        break;
+    case BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_APP_KEY:
+        act = ESP_BLE_MESH_NODE_ADD_LOCAL_APP_KEY_COMP_EVT;
+        param.node_add_app_key_comp.net_idx = arg->node_add_local_app_key.net_idx;
+        param.node_add_app_key_comp.app_idx = arg->node_add_local_app_key.app_idx;
+        param.node_add_app_key_comp.err_code =
+            bt_mesh_node_local_app_key_add(arg->node_add_local_app_key.net_idx,
+                                           arg->node_add_local_app_key.app_idx,
+                                           arg->node_add_local_app_key.app_key);
+        break;
+    case BTC_BLE_MESH_ACT_NODE_BIND_APP_KEY_TO_MODEL:
+        act = ESP_BLE_MESH_NODE_BIND_APP_KEY_TO_MODEL_COMP_EVT;
+        param.node_bind_app_key_to_model_comp.element_addr = arg->node_local_mod_app_bind.element_addr;
+        param.node_bind_app_key_to_model_comp.model_id = arg->node_local_mod_app_bind.model_id;
+        param.node_bind_app_key_to_model_comp.company_id = arg->node_local_mod_app_bind.company_id;
+        param.node_bind_app_key_to_model_comp.app_idx = arg->node_local_mod_app_bind.app_idx;
+        param.node_bind_app_key_to_model_comp.err_code =
+            bt_mesh_node_bind_app_key_to_model(arg->node_local_mod_app_bind.element_addr,
+                                               arg->node_local_mod_app_bind.model_id,
+                                               arg->node_local_mod_app_bind.company_id,
+                                               arg->node_local_mod_app_bind.app_idx);
+        break;
 #endif /* CONFIG_BLE_MESH_NODE */
 #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \
     CONFIG_BLE_MESH_GATT_PROXY_SERVER

+ 22 - 0
components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h

@@ -39,6 +39,9 @@ typedef enum {
     BTC_BLE_MESH_ACT_PROXY_IDENTITY_ENABLE,
     BTC_BLE_MESH_ACT_PROXY_GATT_ENABLE,
     BTC_BLE_MESH_ACT_PROXY_GATT_DISABLE,
+    BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_NET_KEY,
+    BTC_BLE_MESH_ACT_NODE_ADD_LOCAL_APP_KEY,
+    BTC_BLE_MESH_ACT_NODE_BIND_APP_KEY_TO_MODEL,
     BTC_BLE_MESH_ACT_PROVISIONER_READ_OOB_PUB_KEY,
     BTC_BLE_MESH_ACT_PROVISIONER_INPUT_STR,
     BTC_BLE_MESH_ACT_PROVISIONER_INPUT_NUM,
@@ -110,6 +113,21 @@ typedef union {
     struct ble_mesh_set_device_name_args {
         char name[ESP_BLE_MESH_DEVICE_NAME_MAX_LEN + 1];
     } set_device_name;
+    struct ble_mesh_node_add_local_net_key_args {
+        uint8_t  net_key[16];
+        uint16_t net_idx;
+    } node_add_local_net_key;
+    struct ble_mesh_node_add_local_app_key_args {
+        uint8_t  app_key[16];
+        uint16_t net_idx;
+        uint16_t app_idx;
+    } node_add_local_app_key;
+    struct ble_mesh_node_bind_local_mod_app_args {
+        uint16_t element_addr;
+        uint16_t company_id;
+        uint16_t model_id;
+        uint16_t app_idx;
+    } node_local_mod_app_bind;
     struct ble_mesh_provisioner_read_oob_pub_key_args {
         uint8_t link_idx;
         uint8_t pub_key_x[32];
@@ -296,6 +314,10 @@ void btc_ble_mesh_prov_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
 
 void btc_ble_mesh_model_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
 
+const uint8_t *btc_ble_mesh_node_get_local_net_key(uint16_t net_idx);
+
+const uint8_t *btc_ble_mesh_node_get_local_app_key(uint16_t app_idx);
+
 esp_ble_mesh_node_t *btc_ble_mesh_provisioner_get_node_with_uuid(const uint8_t uuid[16]);
 
 esp_ble_mesh_node_t *btc_ble_mesh_provisioner_get_node_with_addr(uint16_t unicast_addr);

+ 222 - 0
components/bt/esp_ble_mesh/mesh_core/local_operation.c

@@ -119,3 +119,225 @@ int bt_mesh_model_unsubscribe_group_addr(u16_t elem_addr, u16_t cid,
     BT_INFO("Unsubscribe group address 0x%04x", group_addr);
     return 0;
 }
+
+#if CONFIG_BLE_MESH_NODE
+
+const u8_t *bt_mesh_node_get_local_net_key(u16_t net_idx)
+{
+    struct bt_mesh_subnet *sub = NULL;
+
+    if (net_idx > 0xFFF) {
+        BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx);
+        return NULL;
+    }
+
+    sub = bt_mesh_subnet_get(net_idx);
+    if (!sub) {
+        BT_ERR("NetKey 0x%04x not exists", net_idx);
+        return NULL;
+    }
+
+    return sub->kr_flag ? sub->keys[1].net : sub->keys[0].net;
+}
+
+const u8_t *bt_mesh_node_get_local_app_key(u16_t app_idx)
+{
+    struct bt_mesh_app_key *key = NULL;
+
+    if (app_idx > 0xFFF) {
+        BT_ERR("Invalid AppKeyIndex 0x%04x", app_idx);
+        return NULL;
+    }
+
+    key = bt_mesh_app_key_find(app_idx);
+    if (!key) {
+        BT_ERR("AppKey 0x%04x not exists", app_idx);
+        return NULL;
+    }
+
+    return key->updated ? key->keys[1].val : key->keys[0].val;
+}
+
+int bt_mesh_node_local_net_key_add(u16_t net_idx, const u8_t net_key[16])
+{
+    struct bt_mesh_subnet *sub = NULL;
+    int err = 0;
+    int i;
+
+    if (net_idx > 0xFFF || net_key == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return -EINVAL;
+    }
+
+    if (!bt_mesh_is_provisioned()) {
+        BT_ERR("Not provisioned, failed to add NetKey");
+        return -EIO;
+    }
+
+    sub = bt_mesh_subnet_get(net_idx);
+    if (sub) {
+        BT_WARN("NetKey 0x%04x already exists", net_idx);
+        return -EEXIST;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
+        if (bt_mesh.sub[i].net_idx != BLE_MESH_KEY_UNUSED) {
+            if ((bt_mesh.sub[i].kr_flag == false &&
+                memcmp(bt_mesh.sub[i].keys[0].net, net_key, 16) == 0) ||
+                (bt_mesh.sub[i].kr_flag == true &&
+                memcmp(bt_mesh.sub[i].keys[1].net, net_key, 16) == 0)) {
+                BT_WARN("Key value %s already exists", bt_hex(net_key, 16));
+                return -EEXIST;
+            }
+        }
+    }
+
+    for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
+        if (bt_mesh.sub[i].net_idx == BLE_MESH_KEY_UNUSED) {
+            sub = &bt_mesh.sub[i];
+            break;
+        }
+    }
+
+    if (sub == NULL) {
+        BT_ERR("NetKey is full!");
+        return -ENOMEM;
+    }
+
+    err = bt_mesh_net_keys_create(&sub->keys[0], net_key);
+    if (err) {
+        BT_ERR("Failed to create keys for NetKey 0x%04x", net_idx);
+        return -EIO;
+    }
+
+    sub->net_idx = net_idx;
+    sub->kr_flag = false;
+    sub->kr_phase = BLE_MESH_KR_NORMAL;
+    if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) {
+        sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED;
+    } else {
+        sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED;
+    }
+
+    if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) {
+        BT_DBG("Storing NetKey persistently");
+        bt_mesh_store_subnet(sub);
+    }
+
+    /* Make sure we have valid beacon data to be sent */
+    bt_mesh_net_beacon_update(sub);
+
+    return 0;
+}
+
+int bt_mesh_node_local_app_key_add(u16_t net_idx, u16_t app_idx,
+                                   const u8_t app_key[16])
+{
+    struct bt_mesh_app_key *key = NULL;
+
+    if (net_idx > 0xFFF || app_idx > 0xFFF || app_key == NULL) {
+        BT_ERR("%s, Invalid parameter", __func__);
+        return -EINVAL;
+    }
+
+    if (!bt_mesh_is_provisioned()) {
+        BT_ERR("Not provisioned, failed to add AppKey");
+        return -EIO;
+    }
+
+    if (bt_mesh_subnet_get(net_idx) == NULL) {
+        BT_ERR("Subnet 0x%04x not exists", net_idx);
+        return -EIO;
+    }
+
+    key = bt_mesh_app_key_find(app_idx);
+    if (key) {
+        BT_WARN("AppKey 0x%04x already exists", app_idx);
+        return -EEXIST;
+    }
+
+    for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) {
+        if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED) {
+            if ((bt_mesh.app_keys[i].updated == false &&
+                memcmp(bt_mesh.app_keys[i].keys[0].val, app_key, 16) == 0) ||
+                (bt_mesh.app_keys[i].updated == true &&
+                memcmp(bt_mesh.app_keys[i].keys[1].val, app_key, 16) == 0)) {
+                BT_WARN("Key value %s already exists", bt_hex(app_key, 16));
+                return -EEXIST;
+            }
+        }
+    }
+
+    key = bt_mesh_app_key_alloc(app_idx);
+    if (key) {
+        struct bt_mesh_app_keys *keys = &key->keys[0];
+
+        if (bt_mesh_app_id(app_key, &keys->id)) {
+            BT_ERR("Failed to generate AID");
+            return -EIO;
+        }
+
+        key->net_idx = net_idx;
+        key->app_idx = app_idx;
+        key->updated = false;
+        memcpy(keys->val, app_key, 16);
+
+        if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) {
+            BT_DBG("Storing AppKey persistently");
+            bt_mesh_store_app_key(key);
+        }
+
+        BT_INFO("Add AppKey 0x%04x, NetKeyIndex 0x%04x", app_idx, net_idx);
+        return 0;
+    }
+
+    BT_ERR("AppKey is full!");
+    return -ENOMEM;
+}
+
+int bt_mesh_node_bind_app_key_to_model(u16_t elem_addr, u16_t mod_id,
+                                       u16_t cid, u16_t app_idx)
+{
+    struct bt_mesh_model *model = NULL;
+    int i;
+
+    if (!bt_mesh_is_provisioned()) {
+        BT_ERR("Not provisioned, failed to bind AppKey");
+        return -EIO;
+    }
+
+    model = find_model(elem_addr, cid, mod_id);
+    if (model == NULL) {
+        BT_ERR("Bind, model(id 0x%04x, cid 0x%04x) not found", mod_id, cid);
+        return -ENODEV;
+    }
+
+    if (bt_mesh_app_key_find(app_idx) == NULL) {
+        BT_ERR("Bind, AppKey 0x%03x not exists", app_idx);
+        return -ENODEV;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(model->keys); i++) {
+        if (model->keys[i] == app_idx) {
+            BT_WARN("Already bound to AppKey 0x%04x", app_idx);
+            return -EALREADY;
+        }
+    }
+
+    for (i = 0; i < ARRAY_SIZE(model->keys); i++) {
+        if (model->keys[i] == BLE_MESH_KEY_UNUSED) {
+            model->keys[i] = app_idx;
+            if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) {
+                bt_mesh_store_mod_bind(model);
+            }
+
+            BT_INFO("Model(id 0x%04x, cid 0x%04x) bound to AppKey 0x%04x", mod_id, cid, app_idx);
+            return 0;
+        }
+    }
+
+    BT_ERR("Model bound is full!");
+    return -ENOMEM;
+}
+
+#endif /* CONFIG_BLE_MESH_NODE */

+ 12 - 0
components/bt/esp_ble_mesh/mesh_core/local_operation.h

@@ -22,6 +22,18 @@ int bt_mesh_model_subscribe_group_addr(u16_t elem_addr, u16_t mod_id,
 int bt_mesh_model_unsubscribe_group_addr(u16_t elem_addr, u16_t cid,
                                          u16_t mod_id, u16_t group_addr);
 
+const u8_t *bt_mesh_node_get_local_net_key(u16_t net_idx);
+
+const u8_t *bt_mesh_node_get_local_app_key(u16_t app_idx);
+
+int bt_mesh_node_local_net_key_add(u16_t net_idx, const u8_t net_key[16]);
+
+int bt_mesh_node_local_app_key_add(u16_t net_idx, u16_t app_idx,
+                                   const u8_t app_key[16]);
+
+int bt_mesh_node_bind_app_key_to_model(u16_t elem_addr, u16_t mod_id,
+                                       u16_t cid, u16_t app_idx);
+
 #ifdef __cplusplus
 }
 #endif