diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c')
-rw-r--r-- | thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c new file mode 100644 index 0000000..241ec48 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/medium/ble_ncfgs/ble_ncfgs.c @@ -0,0 +1,516 @@ +/** + * Copyright (c) 2015-2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifdef COMMISSIONING_ENABLED + +#include <string.h> +#include "ble_ncfgs.h" +#include "app_error.h" +#include "ble.h" +#include "nordic_common.h" + +/**@brief NCFGS database encapsulation. */ +typedef struct +{ + uint16_t service_handle; + ble_gatts_char_handles_t ssid_handles; + ble_gatts_char_handles_t keys_store_handles; + ble_gatts_char_handles_t ctrlp_handles; +} ble_database_t; + +static ble_ncfgs_state_t m_service_state = NCFGS_STATE_IDLE; /**< Module state value. */ +static ble_ncfgs_evt_handler_t m_app_evt_handler; /**< Parent module callback function. */ +static ble_database_t m_database; /**< GATT handles database. */ +static uint8_t m_ctrlp_value_buffer[NCFGS_CTRLP_VALUE_LEN]; /**< Stores received Control Point value before parsing. */ +static ble_ncfgs_data_t m_ncfgs_data; /**< Stores all values written by the peer device. */ + +#if NCFGS_CONFIG_LOG_ENABLED + +#define NRF_LOG_MODULE_NAME ble_ncfgs + +#define NRF_LOG_LEVEL NCFGS_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR NCFGS_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR NCFGS_CONFIG_DEBUG_COLOR + +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define NCFGS_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */ +#define NCFGS_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */ +#define NCFGS_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */ + +#define NCFGS_ENTRY() NCFGS_TRC(">> %s", __func__) +#define NCFGS_EXIT() NCFGS_TRC("<< %s", __func__) + +#else // NCFGS_CONFIG_LOG_ENABLED + +#define NCFGS_TRC(...) /**< Disables traces. */ +#define NCFGS_DUMP(...) /**< Disables dumping of octet streams. */ +#define NCFGS_ERR(...) /**< Disables error logs. */ + +#define NCFGS_ENTRY(...) +#define NCFGS_EXIT(...) + +#endif // NCFGS_CONFIG_LOG_ENABLED + +/**@brief Function for adding the SSID Store characteristic. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static uint32_t add_ssid_characteristic(ble_uuid_t * p_srv_uuid) +{ + ble_gatts_char_md_t char_md; + ble_gatts_attr_t attr_char_value; + ble_uuid_t char_uuid; + ble_gatts_attr_md_t attr_md; + + memset(&char_md, 0x00, sizeof(char_md)); + + char_md.char_props.read = 1; + char_md.char_props.write = 1; + + memset(&attr_md, 0x00, sizeof(attr_md)); + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + attr_md.wr_auth = 1; + attr_md.vloc = BLE_GATTS_VLOC_USER; + + memset(&attr_char_value, 0x00, sizeof(attr_char_value)); + + char_uuid.type = p_srv_uuid->type; + char_uuid.uuid = BLE_UUID_NCFGS_SSID_CHAR; + + attr_char_value.p_uuid = &char_uuid; + attr_char_value.p_attr_md = &attr_md; + attr_char_value.init_len = NCFGS_SSID_MAX_LEN; + attr_char_value.init_offs = 0; + attr_char_value.max_len = NCFGS_SSID_MAX_LEN; + attr_char_value.p_value = &m_ncfgs_data.ssid_from_router.ssid[0]; + + return sd_ble_gatts_characteristic_add(m_database.service_handle, + &char_md, + &attr_char_value, + &m_database.ssid_handles); +} + + +/**@brief Function for adding the Keys Store characteristic. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static uint32_t add_keys_store_characteristic(ble_uuid_t * p_srv_uuid) +{ + ble_gatts_char_md_t char_md; + ble_gatts_attr_t attr_char_value; + ble_uuid_t char_uuid; + ble_gatts_attr_md_t attr_md; + + memset(&char_md, 0x00, sizeof(char_md)); + + char_md.char_props.read = 1; + char_md.char_props.write = 1; + + memset(&attr_md, 0x00, sizeof(attr_md)); + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + attr_md.wr_auth = 1; + attr_md.vloc = BLE_GATTS_VLOC_USER; + + memset(&attr_char_value, 0x00, sizeof(attr_char_value)); + + char_uuid.type = p_srv_uuid->type; + char_uuid.uuid = BLE_UUID_NCFGS_KEYS_STORE_CHAR; + + attr_char_value.p_uuid = &char_uuid; + attr_char_value.p_attr_md = &attr_md; + attr_char_value.init_len = NCFGS_KEYS_MAX_LEN; + attr_char_value.init_offs = 0; + attr_char_value.max_len = NCFGS_KEYS_MAX_LEN; + attr_char_value.p_value = &m_ncfgs_data.keys_from_router.keys[0]; + + return sd_ble_gatts_characteristic_add(m_database.service_handle, + &char_md, + &attr_char_value, + &m_database.keys_store_handles); +} + + +/**@brief Function for adding the Control Point characteristic. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static uint32_t add_ip_cfg_cp_characteristic(ble_uuid_t * p_srv_uuid) +{ + ble_gatts_char_md_t char_md; + ble_gatts_attr_t attr_char_value; + ble_uuid_t char_uuid; + ble_gatts_attr_md_t attr_md; + + memset(&char_md, 0x00, sizeof(char_md)); + + char_md.char_props.read = 1; + char_md.char_props.write = 1; + + memset(&attr_md, 0x00, sizeof(attr_md)); + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + attr_md.wr_auth = 1; + attr_md.vloc = BLE_GATTS_VLOC_USER; + + memset(&attr_char_value, 0x00, sizeof(attr_char_value)); + + char_uuid.type = p_srv_uuid->type; + char_uuid.uuid = BLE_UUID_NCFGS_CTRLPT_CHAR; + + attr_char_value.p_uuid = &char_uuid; + attr_char_value.p_attr_md = &attr_md; + attr_char_value.init_len = NCFGS_CTRLP_VALUE_LEN; + attr_char_value.init_offs = 0; + attr_char_value.max_len = NCFGS_CTRLP_VALUE_LEN; + attr_char_value.p_value = &m_ctrlp_value_buffer[0]; + + return sd_ble_gatts_characteristic_add(m_database.service_handle, + &char_md, + &attr_char_value, + &m_database.ctrlp_handles); +} + + +/**@brief Function for creating the GATT database. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static uint32_t ble_ncfgs_create_database(void) +{ + uint32_t err_code = NRF_SUCCESS; + + // Add service. + ble_uuid_t service_uuid; + + const ble_uuid128_t base_uuid128 = + { + { + 0x73, 0x3E, 0x2D, 0x02, 0xB7, 0x6B, 0xBE, 0xBE, \ + 0xE5, 0x4F, 0x40, 0x8F, 0x00, 0x00, 0x20, 0x54 + } + }; + + service_uuid.uuid = BLE_UUID_NODE_CFG_SERVICE; + + err_code = sd_ble_uuid_vs_add(&base_uuid128, &(service_uuid.type)); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, \ + &service_uuid, \ + &m_database.service_handle); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + err_code = add_ssid_characteristic(&service_uuid); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + err_code = add_keys_store_characteristic(&service_uuid); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + err_code = add_ip_cfg_cp_characteristic(&service_uuid); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + return err_code; +} + + +uint32_t ble_ncfgs_init(ble_ncfgs_evt_handler_t ble_ncfgs_cb) +{ + NCFGS_ENTRY(); + uint32_t err_code; + memset(&m_ncfgs_data, 0x00, sizeof(m_ncfgs_data)); + + m_app_evt_handler = ble_ncfgs_cb; + + err_code = ble_ncfgs_create_database(); + NCFGS_EXIT(); + return err_code; +} + + +/**@brief Function for decoding the Control Point characteristic value. + * + * @return NRF_SUCCESS on success, otherwise an error code. + */ +static uint32_t ctrlp_value_decode(const ble_evt_t * p_ble_evt) +{ + uint16_t wr_req_value_len = \ + p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.len; + + memcpy(m_ctrlp_value_buffer, \ + p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.data, \ + wr_req_value_len); + + m_ncfgs_data.ctrlp_value.opcode = \ + (ble_ncfgs_opcode_t)m_ctrlp_value_buffer[0]; + memcpy((void *)&m_ncfgs_data.ctrlp_value.delay_sec, \ + &m_ctrlp_value_buffer[NCFGS_CTRLP_OPCODE_LEN], \ + sizeof(uint32_t)); + m_ncfgs_data.ctrlp_value.delay_sec = \ + HTONL(m_ncfgs_data.ctrlp_value.delay_sec); + memcpy((void *)&m_ncfgs_data.ctrlp_value.duration_sec, \ + &m_ctrlp_value_buffer[NCFGS_CTRLP_OPCODE_LEN+NCFGS_CTRLP_DELAY_LEN], \ + sizeof(uint32_t)); + m_ncfgs_data.ctrlp_value.duration_sec = \ + HTONL(m_ncfgs_data.ctrlp_value.duration_sec); + m_ncfgs_data.ctrlp_value.state_on_failure = \ + (state_on_failure_t)m_ctrlp_value_buffer[NCFGS_CTRLP_OPCODE_LEN+ \ + NCFGS_CTRLP_DELAY_LEN+ \ + NCFGS_CTRLP_DURATION_LEN]; + + if ((m_ncfgs_data.ctrlp_value.state_on_failure != NCFGS_SOF_NO_CHANGE) && \ + (m_ncfgs_data.ctrlp_value.state_on_failure != NCFGS_SOF_PWR_OFF) && \ + (m_ncfgs_data.ctrlp_value.state_on_failure != NCFGS_SOF_CONFIG_MODE)) + { + return NRF_ERROR_INVALID_DATA; + } + + uint16_t id_data_len = wr_req_value_len - NCFGS_CTRLP_ALL_BUT_ID_DATA_LEN; + if (id_data_len != 0) + { + m_ncfgs_data.id_data.identity_data_len = id_data_len; + + memcpy(m_ncfgs_data.id_data.identity_data, \ + &m_ctrlp_value_buffer[NCFGS_CTRLP_ALL_BUT_ID_DATA_LEN], \ + id_data_len); + } + + return NRF_SUCCESS; +} + + +void ble_ncfgs_ble_evt_handler(const ble_evt_t * p_ble_evt) +{ + switch (p_ble_evt->header.evt_id) + { + case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: + { + if (p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op == \ + BLE_GATTS_OP_WRITE_REQ) + { + uint16_t wr_req_handle = \ + p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.handle; + uint16_t wr_req_value_len = \ + p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.len; + + ble_gatts_rw_authorize_reply_params_t reply_params; + memset(&reply_params, 0x00, sizeof(reply_params)); + + reply_params.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; + reply_params.params.write.update = 1; + reply_params.params.write.offset = p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.offset; + reply_params.params.write.len = p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.len; + reply_params.params.write.p_data = p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.data; + + if (wr_req_handle == m_database.ssid_handles.value_handle) + { + NCFGS_TRC("> wr_req: ssid_handle"); + + if ((wr_req_value_len > NCFGS_SSID_MAX_LEN) || \ + (wr_req_value_len < NCFGS_SSID_MIN_LEN)) + { + reply_params.params.write.gatt_status = \ + BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH; + } + else + { + m_ncfgs_data.ssid_from_router.ssid_len = wr_req_value_len; + m_service_state |= NCFGS_STATE_SSID_WRITTEN; + + reply_params.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + } + + UNUSED_RETURN_VALUE( \ + sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle, \ + &reply_params)); + NCFGS_TRC("< wr_req: ssid_handle"); + return; + } + + else if (wr_req_handle == m_database.keys_store_handles.value_handle) + { + NCFGS_TRC("> wr_req: keys_store_handle"); + + if (wr_req_value_len > NCFGS_KEYS_MAX_LEN) + { + reply_params.params.write.gatt_status = \ + BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH; + } + else + { + m_ncfgs_data.keys_from_router.keys_len = wr_req_value_len; + m_service_state |= NCFGS_STATE_KEYS_STORE_WRITTEN; + reply_params.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + } + + UNUSED_RETURN_VALUE( \ + sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle, \ + &reply_params)); + NCFGS_TRC("< wr_req: keys_store_handle"); + return; + } + + else if (wr_req_handle == m_database.ctrlp_handles.value_handle) + { + NCFGS_TRC("> wr_req: ctrlp_handle"); + + bool notify_app = false; + + if ((wr_req_value_len > NCFGS_CTRLP_VALUE_LEN) || \ + (wr_req_value_len < NCFGS_CTRLP_ALL_BUT_ID_DATA_LEN)) + { + reply_params.params.write.gatt_status = \ + BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH; + } + else + { + ble_ncfgs_opcode_t opcode_in = (ble_ncfgs_opcode_t) \ + p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.data[0]; + + reply_params.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + + if ((opcode_in != NCFGS_OPCODE_GOTO_JOINING_MODE) && \ + (opcode_in != NCFGS_OPCODE_GOTO_CONFIG_MODE) && \ + (opcode_in != NCFGS_OPCODE_GOTO_IDENTITY_MODE)) + { + reply_params.params.write.gatt_status = APP_GATTERR_UNKNOWN_OPCODE; + } + + if (opcode_in == NCFGS_OPCODE_GOTO_JOINING_MODE) + { + if (!((m_service_state & NCFGS_STATE_SSID_WRITTEN) && \ + (m_service_state & NCFGS_STATE_KEYS_STORE_WRITTEN))) + { + reply_params.params.write.gatt_status = APP_GATTERR_NOT_CONFIGURED; + } + } + + if (reply_params.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) + { + uint32_t err_code = ctrlp_value_decode(p_ble_evt); + if (err_code != NRF_SUCCESS) + { + reply_params.params.write.gatt_status = \ + APP_GATTERR_INVALID_ATTR_VALUE; + } + else + { + notify_app = true; + } + } + } + + UNUSED_RETURN_VALUE(sd_ble_gatts_rw_authorize_reply( + p_ble_evt->evt.gap_evt.conn_handle, + &reply_params)); + + if (notify_app == true) + { + NCFGS_TRC("> do notify parent"); + + m_app_evt_handler(&m_ncfgs_data); + + NCFGS_TRC("< do notify parent"); + } + NCFGS_TRC("< wr_req: ctrlp_handle"); + } + else + { + // Invalid handle. + reply_params.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_HANDLE; + UNUSED_RETURN_VALUE(sd_ble_gatts_rw_authorize_reply( + p_ble_evt->evt.gap_evt.conn_handle, &reply_params)); + } + } + + break; + } + + case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: + { + ble_gap_data_length_params_t dl_params; + + // Clearing the struct will effectively set members to @ref BLE_GAP_DATA_LENGTH_AUTO. + memset(&dl_params, 0, sizeof(ble_gap_data_length_params_t)); + UNUSED_RETURN_VALUE(sd_ble_gap_data_length_update(p_ble_evt->evt.gap_evt.conn_handle, &dl_params, NULL)); + break; + } + + case BLE_GAP_EVT_PHY_UPDATE_REQUEST: + { + NCFGS_TRC("> PHY update request."); + + ble_gap_phys_t const phys = + { + .rx_phys = BLE_GAP_PHY_AUTO, + .tx_phys = BLE_GAP_PHY_AUTO, + }; + + UNUSED_RETURN_VALUE(sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys); + + NCFGS_TRC("< PHY update request."); + break; + } + + default: + { + break; + } + } +} + +#endif // COMMISSIONING_ENABLED |