Quellcode durchsuchen

Provisioning BLE: Add API to set manufacturer data in scan response

- Add `wifi_prov_scheme_ble_set_mfg_data` API to set custom manufacturer data
  in BLE advertisements.
- Run format.sh script on modified files.
- Fix few typos in `protocomm_nimble.c`.

- Incorporate suggestion to remove extra check on protocomm_ble_mfg_data_len

- Remove few unnecessary comments.
Prasad Alatkar vor 4 Jahren
Ursprung
Commit
bcdedf5501

+ 18 - 0
components/protocomm/include/transports/protocomm_ble.h

@@ -26,6 +26,14 @@ extern "C" {
  */
 #define MAX_BLE_DEVNAME_LEN 29
 #define BLE_UUID128_VAL_LENGTH  16
+ /**
+ * Theoretically, the limit for max manufacturer length remains same as BLE
+ * device name i.e. 31 bytes (max scan response size) - 1 byte (length) - 1
+ * byte (type) = 29 bytes
+ * However, manufacturer data goes along with BLE device name in scan response.
+ * So, it is important to understand the actual length should be smaller than
+ * (29 - (BLE device name length) - 2). */
+#define MAX_BLE_MANUFACTURER_DATA_LEN 29
 
 /**
  * @brief   This structure maps handler required by protocomm layer to
@@ -59,6 +67,16 @@ typedef struct protocomm_ble_config {
      */
     uint8_t      service_uuid[BLE_UUID128_VAL_LENGTH];
 
+    /**
+     * BLE device manufacturer data pointer in advertisement
+     */
+    uint8_t      *manufacturer_data;
+
+    /**
+     * BLE device manufacturer data length in advertisement
+     */
+    ssize_t      manufacturer_data_len;
+
     /**
      * Number of entries in the Name-UUID lookup table
      */

+ 47 - 20
components/protocomm/src/transports/protocomm_ble.c

@@ -77,7 +77,9 @@ static esp_ble_adv_params_t adv_params = {
     .adv_filter_policy   = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
 };
 
-static char* protocomm_ble_device_name = NULL;
+static char *protocomm_ble_device_name = NULL;
+static uint8_t *protocomm_ble_mfg_data = NULL;
+static size_t protocomm_ble_mfg_data_len;
 
 static void hexdump(const char *msg, uint8_t *buf, int len)
 {
@@ -132,8 +134,8 @@ static void transport_simple_ble_read(esp_gatts_cb_event_t event, esp_gatt_if_t
         gatt_rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
         if (gatt_rsp.attr_value.len && read_buf) {
             memcpy(gatt_rsp.attr_value.value,
-                    read_buf + param->read.offset,
-                    gatt_rsp.attr_value.len);
+                   read_buf + param->read.offset,
+                   gatt_rsp.attr_value.len);
         }
         read_len -= gatt_rsp.attr_value.len;
     } else {
@@ -142,14 +144,14 @@ static void transport_simple_ble_read(esp_gatts_cb_event_t event, esp_gatt_if_t
         read_buf = NULL;
     }
     esp_err_t err = esp_ble_gatts_send_response(gatts_if, param->read.conn_id,
-                                                param->read.trans_id, status, &gatt_rsp);
+                    param->read.trans_id, status, &gatt_rsp);
     if (err != ESP_OK) {
         ESP_LOGE(TAG, "Send response error in read");
     }
 }
 
 static esp_err_t prepare_write_event_env(esp_gatt_if_t gatts_if,
-                                         esp_ble_gatts_cb_param_t *param)
+        esp_ble_gatts_cb_param_t *param)
 {
     ESP_LOGD(TAG, "prepare write, handle = %d, value len = %d, offset = %d",
              param->write.handle, param->write.len, param->write.offset);
@@ -196,10 +198,10 @@ static esp_err_t prepare_write_event_env(esp_gatt_if_t gatts_if,
                 memcpy(gatt_rsp.attr_value.value, param->write.value, param->write.len);
             }
             response_err = esp_ble_gatts_send_response(gatts_if,
-                param->write.conn_id, param->write.trans_id, status, &gatt_rsp);
+                           param->write.conn_id, param->write.trans_id, status, &gatt_rsp);
         } else {
             response_err = esp_ble_gatts_send_response(gatts_if,
-                param->write.conn_id, param->write.trans_id, status, NULL);
+                           param->write.conn_id, param->write.trans_id, status, NULL);
         }
         if (response_err != ESP_OK) {
             ESP_LOGE(TAG, "Send response error in prep write");
@@ -307,9 +309,9 @@ static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt
     esp_err_t ret;
     ESP_LOGD(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id);
     if (protoble_internal->pc_ble->sec &&
-        protoble_internal->pc_ble->sec->close_transport_session) {
+            protoble_internal->pc_ble->sec->close_transport_session) {
         ret = protoble_internal->pc_ble->sec->close_transport_session(protoble_internal->pc_ble->sec_inst,
-                                                                      param->disconnect.conn_id);
+                param->disconnect.conn_id);
         if (ret != ESP_OK) {
             ESP_LOGE(TAG, "error closing the session after disconnect");
         }
@@ -322,9 +324,9 @@ static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if
     esp_err_t ret;
     ESP_LOGD(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id);
     if (protoble_internal->pc_ble->sec &&
-        protoble_internal->pc_ble->sec->new_transport_session) {
+            protoble_internal->pc_ble->sec->new_transport_session) {
         ret = protoble_internal->pc_ble->sec->new_transport_session(protoble_internal->pc_ble->sec_inst,
-                                                                    param->connect.conn_id);
+                param->connect.conn_id);
         if (ret != ESP_OK) {
             ESP_LOGE(TAG, "error creating the session");
         }
@@ -338,8 +340,8 @@ static void transport_simple_ble_set_mtu(esp_gatts_cb_event_t event, esp_gatt_if
 }
 
 static esp_err_t protocomm_ble_add_endpoint(const char *ep_name,
-                                            protocomm_req_handler_t req_handler,
-                                            void *priv_data)
+        protocomm_req_handler_t req_handler,
+        void *priv_data)
 {
     /* Endpoint UUID already added when protocomm_ble_start() was called */
     return ESP_OK;
@@ -364,7 +366,7 @@ static ssize_t populate_gatt_db(esp_gatts_attr_db_t **gatt_db_generated)
     ssize_t gatt_db_generated_entries = 3 * protoble_internal->g_nu_lookup_count + 1;
 
     *gatt_db_generated = (esp_gatts_attr_db_t *) malloc(sizeof(esp_gatts_attr_db_t) *
-                                                        (gatt_db_generated_entries));
+                         (gatt_db_generated_entries));
     if ((*gatt_db_generated) == NULL) {
         ESP_LOGE(TAG, "Failed to assign memory to gatt_db");
         return -1;
@@ -432,6 +434,11 @@ static void protocomm_ble_cleanup(void)
         free(protocomm_ble_device_name);
         protocomm_ble_device_name = NULL;
     }
+    if (protocomm_ble_mfg_data) {
+        free(protocomm_ble_mfg_data);
+        protocomm_ble_mfg_data = NULL;
+        protocomm_ble_mfg_data_len = 0;
+    }
 }
 
 esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *config)
@@ -453,6 +460,12 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
         return ESP_ERR_NO_MEM;
     }
 
+    /* Store BLE manufacturer data pointer */
+    if (config->manufacturer_data != NULL) {
+        protocomm_ble_mfg_data = config->manufacturer_data;
+        protocomm_ble_mfg_data_len = config->manufacturer_data_len;
+    }
+
     protoble_internal = (_protocomm_ble_internal_t *) calloc(1, sizeof(_protocomm_ble_internal_t));
     if (protoble_internal == NULL) {
         ESP_LOGE(TAG, "Error allocating internal protocomm structure");
@@ -510,7 +523,7 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
 
     /* Get the total raw data length required for above entries */
     uint8_t adv_data_len = 0;
-    for (uint8_t i = 0; i < (sizeof(adv_data)/sizeof(adv_data[0])); i++) {
+    for (uint8_t i = 0; i < (sizeof(adv_data) / sizeof(adv_data[0])); i++) {
         /* Add extra bytes required per entry, i.e.
          * length (1 byte) + type (1 byte) = 2 bytes */
         adv_data_len += adv_data[i].length + 2;
@@ -531,7 +544,7 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
     }
 
     /* Form the raw advertisement data using above entries */
-    for (uint8_t i = 0, len = 0; i < (sizeof(adv_data)/sizeof(adv_data[0])); i++) {
+    for (uint8_t i = 0, len = 0; i < (sizeof(adv_data) / sizeof(adv_data[0])); i++) {
         protoble_internal->raw_adv_data_p[len++] = adv_data[i].length + 1; // + 1 byte for type
         protoble_internal->raw_adv_data_p[len++] = adv_data[i].type;
         memcpy(&protoble_internal->raw_adv_data_p[len],
@@ -556,7 +569,12 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
      *
      * Any remaining space may be used for accommodating
      * other fields in the future
+     *
+     * 2) Manufacturer Data (To be truncated depending upon available size)
+     *      Size : The maximum supported manufacturer data size
+     *              will be 31 - 2 (length + type) - ble_devname_len - 2 (length + type)
      */
+
     raw_data_info_t scan_resp_data[] = {
         {   /* If full device name can fit in the scan response then indicate
              * that by setting type to "Complete Name", else set it to "Short Name"
@@ -567,11 +585,20 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
             .length = MIN(ble_devname_len, (ESP_BLE_SCAN_RSP_DATA_LEN_MAX - 2)),
             .data_p = (uint8_t *) protocomm_ble_device_name
         },
+        {
+            0,
+        },
     };
 
+    if (protocomm_ble_mfg_data_len > 0) {
+        scan_resp_data[1].type = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE;
+        scan_resp_data[1].length = protocomm_ble_mfg_data_len;
+        scan_resp_data[1].data_p = (uint8_t *) protocomm_ble_mfg_data;
+    }
+
     /* Get the total raw scan response data length required for above entries */
     uint8_t scan_resp_data_len = 0;
-    for (int i = 0; i < (sizeof(scan_resp_data)/sizeof(scan_resp_data[0])); i++) {
+    for (int i = 0; i < (sizeof(scan_resp_data) / sizeof(scan_resp_data[0])); i++) {
         /* Add extra bytes required per entry, i.e.
          * length (1 byte) + type (1 byte) = 2 bytes */
         scan_resp_data_len += scan_resp_data[i].length + 2;
@@ -592,7 +619,7 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
     }
 
     /* Form the raw scan response data using above entries */
-    for (uint8_t i = 0, len = 0; i < (sizeof(scan_resp_data)/sizeof(scan_resp_data[0])); i++) {
+    for (uint8_t i = 0, len = 0; i < (sizeof(scan_resp_data) / sizeof(scan_resp_data[0])); i++) {
         protoble_internal->raw_scan_rsp_data_p[len++] = scan_resp_data[i].length + 1; // + 1 byte for type
         protoble_internal->raw_scan_rsp_data_p[len++] = scan_resp_data[i].type;
         memcpy(&protoble_internal->raw_scan_rsp_data_p[len],
@@ -649,8 +676,8 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
 esp_err_t protocomm_ble_stop(protocomm_t *pc)
 {
     if ((pc != NULL) &&
-        (protoble_internal != NULL ) &&
-        (pc == protoble_internal->pc_ble)) {
+            (protoble_internal != NULL ) &&
+            (pc == protoble_internal->pc_ble)) {
         esp_err_t ret = ESP_OK;
         ret = simple_ble_stop();
         if (ret) {

+ 28 - 4
components/protocomm/src/transports/protocomm_nimble.c

@@ -81,6 +81,9 @@ static struct ble_gap_adv_params adv_params;
 static char *protocomm_ble_device_name;
 static struct ble_hs_adv_fields adv_data, resp_data;
 
+static uint8_t *protocomm_ble_mfg_data;
+static size_t protocomm_ble_mfg_data_len;
+
 /**********************************************************************
 * Maintain database of uuid_name addresses to free memory afterwards  *
 **********************************************************************/
@@ -314,7 +317,7 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
 
     switch (ctxt->op) {
     case BLE_GATT_ACCESS_OP_READ_CHR:
-        ESP_LOGD(TAG, "Read attempeted for Characterstic UUID = %s, attr_handle = %d",
+        ESP_LOGD(TAG, "Read attempted for characteristic UUID = %s, attr_handle = %d",
                  ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle);
 
         rc = simple_ble_gatts_get_attr_value(attr_handle, &temp_outlen,
@@ -480,7 +483,7 @@ static int simple_ble_start(const simple_ble_cfg_t *cfg)
 {
     ble_cfg_p = (void *)cfg;
     int rc;
-    ESP_LOGD(TAG, "Free mem at start of simple_ble_init %d", esp_get_free_heap_size());
+    ESP_LOGD(TAG, "Free memory at start of simple_ble_init %d", esp_get_free_heap_size());
 
     ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
     nimble_port_init();
@@ -509,6 +512,13 @@ static int simple_ble_start(const simple_ble_cfg_t *cfg)
         resp_data.name_is_complete = 1;
     }
 
+    /* Set manufacturer data if protocomm_ble_mfg_data points to valid data */
+    if (protocomm_ble_mfg_data != NULL) {
+        resp_data.mfg_data = protocomm_ble_mfg_data;
+        resp_data.mfg_data_len = protocomm_ble_mfg_data_len;
+        ESP_LOGD(TAG, "Custom manufacturer data length = %d", protocomm_ble_mfg_data_len);
+    }
+
     /* XXX Need to have template for store */
     ble_store_config_init();
     nimble_port_freertos_init(nimble_host_task);
@@ -726,10 +736,17 @@ static void protocomm_ble_cleanup(void)
         free(protoble_internal);
         protoble_internal = NULL;
     }
+
     if (protocomm_ble_device_name) {
         free(protocomm_ble_device_name);
         protocomm_ble_device_name = NULL;
     }
+
+    if (protocomm_ble_mfg_data) {
+        free(protocomm_ble_mfg_data);
+        protocomm_ble_mfg_data = NULL;
+        protocomm_ble_mfg_data_len = 0;
+    }
 }
 
 static void free_gatt_ble_misc_memory(simple_ble_cfg_t *ble_config)
@@ -781,7 +798,9 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
 {
     /* copy the 128 bit service UUID into local buffer to use as base 128 bit
      * UUID. */
-    memcpy(ble_uuid_base, config->service_uuid, BLE_UUID128_VAL_LENGTH);
+    if (config->service_uuid != NULL) {
+        memcpy(ble_uuid_base, config->service_uuid, BLE_UUID128_VAL_LENGTH);
+    }
 
     if (!pc || !config || !config->device_name || !config->nu_lookup) {
         return ESP_ERR_INVALID_ARG;
@@ -822,13 +841,18 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
 
     /* Store BLE device name internally */
     protocomm_ble_device_name = strdup(config->device_name);
-
     if (protocomm_ble_device_name == NULL) {
         ESP_LOGE(TAG, "Error allocating memory for storing BLE device name");
         protocomm_ble_cleanup();
         return ESP_ERR_NO_MEM;
     }
 
+    /* Store BLE manufacturer data pointer */
+    if (config->manufacturer_data != NULL) {
+        protocomm_ble_mfg_data = config->manufacturer_data;
+        protocomm_ble_mfg_data_len = config->manufacturer_data_len;
+    }
+
     protoble_internal = (_protocomm_ble_internal_t *) calloc(1, sizeof(_protocomm_ble_internal_t));
     if (protoble_internal == NULL) {
         ESP_LOGE(TAG, "Error allocating internal protocomm structure");

+ 23 - 0
components/wifi_provisioning/include/wifi_provisioning/scheme_ble.h

@@ -77,6 +77,29 @@ void wifi_prov_scheme_ble_event_cb_free_bt  (void *user_data, wifi_prov_cb_event
  */
 esp_err_t wifi_prov_scheme_ble_set_service_uuid(uint8_t *uuid128);
 
+/**
+ * @brief   Set manufacturer specific data in scan response
+ *
+ * This must be called before starting provisioning, i.e. before
+ * making a call to wifi_prov_mgr_start_provisioning().
+ *
+ * @note    It is important to understand that length of custom manufacturer
+ *          data should be within limits. The manufacturer data goes into scan
+ *          response along with BLE device name. By default, BLE device name
+ *          length is of 11 Bytes, however it can vary as per application use
+ *          case. So, one has to honour the scan response data size limits i.e.
+ *          (mfg_data_len + 2) < 31 - (device_name_length + 2 ). If the
+ *          mfg_data length exceeds this limit, the length will be truncated.
+ *
+ * @param[in] mfg_data      Custom manufacturer data
+ * @param[in] mfg_data_len  Manufacturer data length
+ *
+ * @return
+ *  - ESP_OK              : Success
+ *  - ESP_ERR_INVALID_ARG : Null argument
+ */
+esp_err_t wifi_prov_scheme_ble_set_mfg_data(uint8_t *mfg_data, ssize_t mfg_data_len);
+
 #ifdef __cplusplus
 }
 #endif

+ 40 - 0
components/wifi_provisioning/src/scheme_ble.c

@@ -29,6 +29,9 @@ extern const wifi_prov_scheme_t wifi_prov_scheme_ble;
 
 static uint8_t *custom_service_uuid;
 
+static uint8_t *custom_manufacturer_data;
+static size_t custom_manufacturer_data_len;
+
 static esp_err_t prov_start(protocomm_t *pc, void *config)
 {
     if (!pc) {
@@ -60,6 +63,23 @@ esp_err_t wifi_prov_scheme_ble_set_service_uuid(uint8_t *uuid128)
     return ESP_OK;
 }
 
+esp_err_t wifi_prov_scheme_ble_set_mfg_data(uint8_t *mfg_data, ssize_t mfg_data_len)
+{
+    if (!mfg_data || !mfg_data_len) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    custom_manufacturer_data = (uint8_t *) malloc(mfg_data_len);
+    if (custom_manufacturer_data == NULL) {
+        ESP_LOGE(TAG, "Error allocating memory for mfg_data");
+        return ESP_ERR_NO_MEM;
+    }
+
+    custom_manufacturer_data_len = mfg_data_len;
+    memcpy(custom_manufacturer_data, mfg_data, mfg_data_len);
+    return ESP_OK;
+}
+
 static void *new_config(void)
 {
     protocomm_ble_config_t *ble_config = calloc(1, sizeof(protocomm_ble_config_t));
@@ -114,6 +134,26 @@ static esp_err_t set_config_service(void *config, const char *service_name, cons
     if (custom_service_uuid) {
         memcpy(ble_config->service_uuid, custom_service_uuid, sizeof(ble_config->service_uuid));
     }
+    /* Set manufacturer data if it is provided by app */
+    if (custom_manufacturer_data) {
+        size_t mfg_data_len = custom_manufacturer_data_len;
+        /* Manufacturer Data Length + 2 Byte header + BLE Device name + 2 Byte
+         * header <= 31 Bytes */
+        if (mfg_data_len > (MAX_BLE_MANUFACTURER_DATA_LEN - sizeof(ble_config->device_name) - 2)) {
+            ESP_LOGE(TAG, "Manufacturer data length is more than the max allowed size; expect truncated mfg_data ");
+            /* XXX Does it even make any sense to set truncated mfg_data ? The
+             * only reason to not return failure from here is provisioning
+             * should continue as it is with error prints for mfg_data length */
+            mfg_data_len = MAX_BLE_MANUFACTURER_DATA_LEN - sizeof(ble_config->device_name) - 2;
+        }
+
+        ble_config->manufacturer_data = custom_manufacturer_data;
+        ble_config->manufacturer_data_len = mfg_data_len;
+    } else {
+        ble_config->manufacturer_data = NULL;
+        ble_config->manufacturer_data_len = 0;
+    }
+
     return ESP_OK;
 }