mirror of https://github.com/arendst/Tasmota.git
Delete lib/libesp32_div/ESP32-HomeKit directory (#19743)
This commit is contained in:
parent
2b398d309e
commit
baef3eed91
|
@ -1,2 +0,0 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
|
@ -1,32 +0,0 @@
|
|||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Mixiaoxiao (Wang Bin)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,31 +0,0 @@
|
|||
# Arduino-HomeKit-ESP
|
||||
Arduino library version of espressif's official [esp-homekit-sdk](https://github.com/espressif/esp-homekit-sdk).
|
||||
|
||||
Currently, only for ESP32 with hardware acceleration. ESP32-S2, ESP32-C3 and future IDF based chips are all on the way.
|
||||
|
||||
Tested on my ESP32 board, works fine.
|
||||
|
||||
The performance is awesome!!!
|
||||
|
||||
The serial log is [here](https://raw.github.com/Mixiaoxiao/Arduino-HomeKit-ESP/master/extras/SerialLog.txt)
|
||||
|
||||
## Setup code
|
||||
|
||||
``111-11-111``
|
||||
|
||||
## Manual Installation
|
||||
|
||||
Refer to the official guide: [Manual installation](https://www.arduino.cc/en/guide/libraries#toc5)
|
||||
Note: this library will not publish the release version for Arduino IDE.
|
||||
|
||||
|
||||
#### Manual Installation for Windows
|
||||
|
||||
1. Click on _"Clone or Download"_ button, then click _"[Download ZIP](https://github.com/Mixiaoxiao/Arduino-HomeKit-ESP/archive/master.zip)"_ on the page.
|
||||
1. Extract the contents of the downloaded zip file.
|
||||
1. Rename the extracted folder to _"Arduino-HomeKit-ESP"_.
|
||||
1. Move this folder to your libraries directory. (under windows: `C:\Users\<USERNAME>\Documents\Arduino\libraries\`)
|
||||
1. Restart your Arduino IDE.
|
||||
1. Check out the examples.
|
||||
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
Boot OK
|
||||
WiFi connecting...
|
||||
...............
|
||||
WiFi connected, IP: 192.168.6.134
|
||||
[ 1657] Keystore initialised
|
||||
[ 1662] Accessory is not Paired with any controller
|
||||
[ 1664] Database initialised. Accessory Device ID: 90:60:09:AB:F0:1D
|
||||
[ 1664] HAP Initialization succeeded. Version : 4.0
|
||||
[ 1670] MFi auth not supported. Falling back to HAP_MFI_AUTH_NONE
|
||||
[ 1675] Setup ID: ES32
|
||||
[ 1681] HAP Main Loop Started
|
||||
[ 1684] mDNS initialised
|
||||
[ 1684] Registering HomeKit web handlers
|
||||
[ 1687] Announcing _hap._tcp mDNS service
|
||||
[ 10032] ######## Starting Pair Setup ########
|
||||
[ 10032] Pair Setup M1 Received
|
||||
[ 12073] Pair Setup M2 Successful
|
||||
[ 12501] Pair Setup M3 Received
|
||||
[ 14540] Using pair-setup without MFi.
|
||||
[ 14540] Pair Setup M4 Successful
|
||||
[ 14929] Pair Setup M5 Received
|
||||
[ 15023] Pair Setup Successful for CF87DA6B-7078-44BB-AC04-27B6F2B26D37
|
||||
[ 15027] Updated state number to 11
|
||||
[ 15028] Cleaning Pair Setup Context
|
||||
[ 15032] Re-announcing _hap._tcp mDNS service
|
||||
[ 16205] ######## Starting Pair Verify ########
|
||||
[ 16205] Pair Verify M1 Received
|
||||
[ 16327] Pair Verify M2 Successful
|
||||
[ 16385] Pair Verify M3 Received
|
||||
[ 16444] HomeKit Session active
|
||||
[ 16445] Pair Verify Successful for CF87DA6B-7078-44BB-AC04-27B6F2B26D37
|
||||
[ 16781] Events Enabled for aid=1 iid=12
|
||||
[ 16781] Events Enabled for aid=1 iid=13
|
||||
[ 17080] Events Enabled for aid=1 iid=12
|
||||
[ 17080] Events Enabled for aid=1 iid=13
|
||||
[ 22311] ######## Starting Pair Verify ########
|
||||
[ 22311] Pair Verify M1 Received
|
||||
[ 22435] Pair Verify M2 Successful
|
||||
[ 22470] Pair Verify M3 Received
|
||||
[ 22528] HomeKit Session active
|
||||
[ 22528] Pair Verify Successful for CF87DA6B-7078-44BB-AC04-27B6F2B26D37
|
||||
[ 25069] Value Changed
|
||||
[ 26605] Value Changed
|
|
@ -1,20 +0,0 @@
|
|||
#include "Arduino.h"
|
||||
#include "wifi_info.h"
|
||||
#include "hap.h"
|
||||
|
||||
extern "C" void homekit_main();
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Boot OK");
|
||||
wifi_connect();
|
||||
// Useful apis: (see hap.h)
|
||||
// hap_reset_to_factory();
|
||||
// hap_reset_homekit_data();
|
||||
// hap_reset_pairings();
|
||||
homekit_main();
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
/* HomeKit Smart Outlet Example
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <esp_log.h>
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#include <hap.h>
|
||||
|
||||
#include <hap_apple_servs.h>
|
||||
#include <hap_apple_chars.h>
|
||||
|
||||
//#include <app_wifi.h>
|
||||
//#include <app_hap_setup_payload.h>
|
||||
|
||||
static const char *TAG = "HAP outlet";
|
||||
|
||||
#define SMART_OUTLET_TASK_PRIORITY 1
|
||||
#define SMART_OUTLET_TASK_STACKSIZE 4 * 1024
|
||||
#define SMART_OUTLET_TASK_NAME "hap_outlet"
|
||||
|
||||
//#define OUTLET_IN_USE_GPIO GPIO_NUM_0
|
||||
#define OUTLET_IN_USE_GPIO -1
|
||||
|
||||
#define ESP_INTR_FLAG_DEFAULT 0
|
||||
|
||||
static xQueueHandle s_esp_evt_queue = NULL;
|
||||
/**
|
||||
* @brief the recover outlet in use gpio interrupt function
|
||||
*/
|
||||
static void IRAM_ATTR outlet_in_use_isr(void* arg)
|
||||
{
|
||||
uint32_t gpio_num = (uint32_t) arg;
|
||||
xQueueSendFromISR(s_esp_evt_queue, &gpio_num, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a GPIO Pin for Outlet in Use Detection
|
||||
*/
|
||||
static void outlet_in_use_key_init(uint32_t key_gpio_pin)
|
||||
{
|
||||
gpio_config_t io_conf;
|
||||
/* Interrupt for both the edges */
|
||||
io_conf.intr_type = GPIO_INTR_ANYEDGE;
|
||||
/* Bit mask of the pins */
|
||||
io_conf.pin_bit_mask = 1 << key_gpio_pin;
|
||||
/* Set as input mode */
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
/* Enable internal pull-up */
|
||||
io_conf.pull_up_en = 1;
|
||||
/* Disable internal pull-down */
|
||||
io_conf.pull_down_en = 0;
|
||||
/* Set the GPIO configuration */
|
||||
gpio_config(&io_conf);
|
||||
|
||||
/* Install gpio isr service */
|
||||
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
|
||||
/* Hook isr handler for specified gpio pin */
|
||||
gpio_isr_handler_add(key_gpio_pin, outlet_in_use_isr, (void*)key_gpio_pin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Smart Outlet Hardware.Here, we just enebale the Outlet-In-Use detection.
|
||||
*/
|
||||
void smart_outlet_hardware_init(gpio_num_t gpio_num)
|
||||
{
|
||||
s_esp_evt_queue = xQueueCreate(2, sizeof(uint32_t));
|
||||
if (s_esp_evt_queue != NULL) {
|
||||
outlet_in_use_key_init(gpio_num);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mandatory identify routine for the accessory.
|
||||
* In a real accessory, something like LED blink should be implemented
|
||||
* got visual identification
|
||||
*/
|
||||
static int outlet_identify(hap_acc_t *ha)
|
||||
{
|
||||
ESP_LOGI(TAG, "Accessory identified");
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
/* A dummy callback for handling a write on the "On" characteristic of Outlet.
|
||||
* In an actual accessory, this should control the hardware
|
||||
*/
|
||||
static int outlet_write(hap_write_data_t write_data[], int count,
|
||||
void *serv_priv, void *write_priv)
|
||||
{
|
||||
int i, ret = HAP_SUCCESS;
|
||||
hap_write_data_t *write;
|
||||
for (i = 0; i < count; i++) {
|
||||
write = &write_data[i];
|
||||
if (!strcmp(hap_char_get_type_uuid(write->hc), HAP_CHAR_UUID_ON)) {
|
||||
//ESP_LOGI(TAG, "Received Write. Outlet %s", write->val.b ? "On" : "Off");
|
||||
ESP_LOG_LEVEL(ESP_LOG_INFO, TAG, "Received Write. Outlet %s", write->val.b ? "On" : "Off");
|
||||
/* TODO: Control Actual Hardware */
|
||||
hap_char_update_val(write->hc, &(write->val));
|
||||
*(write->status) = HAP_STATUS_SUCCESS;
|
||||
} else {
|
||||
*(write->status) = HAP_STATUS_RES_ABSENT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*The main thread for handling the Smart Outlet Accessory */
|
||||
static void smart_outlet_thread_entry(void *p)
|
||||
{
|
||||
hap_acc_t *accessory;
|
||||
hap_serv_t *service;
|
||||
|
||||
/* Initialize the HAP core */
|
||||
hap_init(HAP_TRANSPORT_WIFI);
|
||||
|
||||
/* Initialise the mandatory parameters for Accessory which will be added as
|
||||
* the mandatory services internally
|
||||
*/
|
||||
hap_acc_cfg_t cfg = {
|
||||
.name = "Esp-Smart-Outlet",
|
||||
.manufacturer = "Espressif",
|
||||
.model = "EspSmartOutlet01",
|
||||
.serial_num = "001122334455",
|
||||
.fw_rev = "0.9.0",
|
||||
.hw_rev = NULL,
|
||||
.pv = "1.1.0",
|
||||
.identify_routine = outlet_identify,
|
||||
.cid = HAP_CID_OUTLET,
|
||||
};
|
||||
/* Create accessory object */
|
||||
accessory = hap_acc_create(&cfg);
|
||||
|
||||
/* Add a dummy Product Data */
|
||||
uint8_t product_data[] = {'E','S','P','3','2','H','A','P'};
|
||||
hap_acc_add_product_data(accessory, product_data, sizeof(product_data));
|
||||
|
||||
/* Create the Outlet Service. Include the "name" since this is a user visible service */
|
||||
service = hap_serv_outlet_create(false, false);
|
||||
hap_serv_add_char(service, hap_char_name_create("My Smart Outlet"));
|
||||
|
||||
/* Get pointer to the outlet in use characteristic which we need to monitor for state changes */
|
||||
hap_char_t *outlet_in_use = hap_serv_get_char_by_uuid(service, HAP_CHAR_UUID_OUTLET_IN_USE);
|
||||
|
||||
/* Set the write callback for the service */
|
||||
hap_serv_set_write_cb(service, outlet_write);
|
||||
|
||||
/* Add the Outlet Service to the Accessory Object */
|
||||
hap_acc_add_serv(accessory, service);
|
||||
|
||||
/* Add the Accessory to the HomeKit Database */
|
||||
hap_add_accessory(accessory);
|
||||
|
||||
/* Initialize the appliance specific hardware. This enables out-in-use detection */
|
||||
smart_outlet_hardware_init(OUTLET_IN_USE_GPIO);
|
||||
|
||||
/* For production accessories, the setup code shouldn't be programmed on to
|
||||
* the device. Instead, the setup info, derived from the setup code must
|
||||
* be used. Use the factory_nvs_gen utility to generate this data and then
|
||||
* flash it into the factory NVS partition.
|
||||
*
|
||||
* By default, the setup ID and setup info will be read from the factory_nvs
|
||||
* Flash partition and so, is not required to set here explicitly.
|
||||
*
|
||||
* However, for testing purpose, this can be overridden by using hap_set_setup_code()
|
||||
* and hap_set_setup_id() APIs, as has been done here.
|
||||
*/
|
||||
hap_set_setup_code("111-11-111");
|
||||
hap_set_setup_id("ES32");
|
||||
#ifdef CONFIG_EXAMPLE_USE_HARDCODED_SETUP_CODE
|
||||
/* Unique Setup code of the format xxx-xx-xxx. Default: 111-22-333 */
|
||||
hap_set_setup_code(CONFIG_EXAMPLE_SETUP_CODE);
|
||||
/* Unique four character Setup Id. Default: ES32 */
|
||||
hap_set_setup_id(CONFIG_EXAMPLE_SETUP_ID);
|
||||
#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
|
||||
app_hap_setup_payload(CONFIG_EXAMPLE_SETUP_CODE, CONFIG_EXAMPLE_SETUP_ID, true, cfg.cid);
|
||||
#else
|
||||
app_hap_setup_payload(CONFIG_EXAMPLE_SETUP_CODE, CONFIG_EXAMPLE_SETUP_ID, false, cfg.cid);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Enable Hardware MFi authentication (applicable only for MFi variant of SDK) */
|
||||
hap_enable_mfi_auth(HAP_MFI_AUTH_HW);
|
||||
|
||||
/* Initialize Wi-Fi */
|
||||
//app_wifi_init();
|
||||
|
||||
/* After all the initializations are done, start the HAP core */
|
||||
hap_start();
|
||||
/* Start Wi-Fi */
|
||||
//app_wifi_start(portMAX_DELAY);
|
||||
|
||||
uint32_t io_num = OUTLET_IN_USE_GPIO;
|
||||
hap_val_t appliance_value = {
|
||||
.b = true,
|
||||
};
|
||||
/* Listen for Outlet-In-Use state change events. Other read/write functionality will be handled
|
||||
* by the HAP Core.
|
||||
* When the Outlet in Use GPIO goes low, it means Outlet is not in use.
|
||||
* When the Outlet in Use GPIO goes high, it means Outlet is in use.
|
||||
* Applications can define own logic as per their hardware.
|
||||
*/
|
||||
while (1) {
|
||||
if (xQueueReceive(s_esp_evt_queue, &io_num, portMAX_DELAY) == pdFALSE) {
|
||||
ESP_LOGI(TAG, "Outlet-In-Use trigger FAIL");
|
||||
} else {
|
||||
appliance_value.b = gpio_get_level(io_num);
|
||||
/* If any state change is detected, update the Outlet In Use characteristic value */
|
||||
hap_char_update_val(outlet_in_use, &appliance_value);
|
||||
ESP_LOGI(TAG, "Outlet-In-Use triggered [%d]", appliance_value.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void homekit_main()
|
||||
{
|
||||
/* Create the application thread */
|
||||
xTaskCreate(smart_outlet_thread_entry, SMART_OUTLET_TASK_NAME, SMART_OUTLET_TASK_STACKSIZE,
|
||||
NULL, SMART_OUTLET_TASK_PRIORITY, NULL);
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* wifi_info.h
|
||||
*
|
||||
* Created on: 2020-05-15
|
||||
* Author: Mixiaoxiao (Wang Bin)
|
||||
*/
|
||||
|
||||
#ifndef WIFI_INFO_H_
|
||||
#define WIFI_INFO_H_
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#elif defined(ESP32)
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
const char *ssid = "your-ssid";
|
||||
const char *password = "your-password";
|
||||
|
||||
void wifi_connect() {
|
||||
WiFi.persistent(false);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.begin(ssid, password);
|
||||
Serial.println("WiFi connecting...");
|
||||
while (!WiFi.isConnected()) {
|
||||
delay(100);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.print("\n");
|
||||
Serial.printf("WiFi connected, IP: %s\n", WiFi.localIP().toString().c_str());
|
||||
}
|
||||
|
||||
#endif /* WIFI_INFO_H_ */
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"name":"ESP32-HomeKit",
|
||||
"version": "1.0.0",
|
||||
"description":"Apple HomeKit for ESP32",
|
||||
"keywords":"HomeKit",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": ""
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "espressif32"
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* _esp_hap_config.h
|
||||
*
|
||||
* Created on: 2020-11-23
|
||||
* Author: Mixiaoxiao
|
||||
*/
|
||||
|
||||
#ifndef ESP_HAP_CONFIG_H_
|
||||
#define ESP_HAP_CONFIG_H_
|
||||
|
||||
#define HAP_SDK_VER "4.0"
|
||||
#define MFI_VER HAP_SDK_VER
|
||||
|
||||
#define CONFIG_HAP_HTTP_STACK_SIZE 12288
|
||||
#define CONFIG_HAP_HTTP_SERVER_PORT 5556 // 80 for normal webserver
|
||||
#define CONFIG_HAP_HTTP_CONTROL_PORT 32859
|
||||
#define CONFIG_HAP_HTTP_MAX_OPEN_SOCKETS 5 // 6
|
||||
#define CONFIG_HAP_HTTP_MAX_URI_HANDLERS 16
|
||||
|
||||
#endif /* ESP_HAP_CONFIG_H_ */
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Base36 PostgreSQL input/output function for bigint
|
||||
*
|
||||
* Author: Dimitri Fontaine <dimitri@2ndQuadrant.fr>
|
||||
*
|
||||
* Taken from https://github.com/dimitri/base36/blob/master/base36.c
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define BASE36_LENGTH 13
|
||||
|
||||
typedef long long int base36;
|
||||
|
||||
static int base36_digits[36] =
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z'
|
||||
};
|
||||
|
||||
static base36 base36_powers[BASE36_LENGTH] =
|
||||
{
|
||||
1ULL,
|
||||
36ULL,
|
||||
1296ULL,
|
||||
46656ULL,
|
||||
1679616ULL,
|
||||
60466176ULL,
|
||||
2176782336ULL,
|
||||
78364164096ULL,
|
||||
2821109907456ULL,
|
||||
101559956668416ULL,
|
||||
3656158440062976ULL,
|
||||
131621703842267136ULL,
|
||||
4738381338321616896ULL
|
||||
};
|
||||
|
||||
static inline
|
||||
char *base36_to_str(base36 c)
|
||||
{
|
||||
int i, d, p = 0;
|
||||
base36 m = c;
|
||||
bool discard = true;
|
||||
char *str = calloc((BASE36_LENGTH + 1), sizeof(char));
|
||||
|
||||
for(i=BASE36_LENGTH-1; i>=0; i--)
|
||||
{
|
||||
d = m / base36_powers[i];
|
||||
m = m - base36_powers[i] * d;
|
||||
|
||||
discard = discard && (d == 0 && i >0);
|
||||
|
||||
if( !discard )
|
||||
str[p++] = base36_digits[d];
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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 <stdint.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Functions to convert Little Endian byte stream to
|
||||
* uint16, uint32 and uint64
|
||||
*/
|
||||
uint16_t get_u16_le(const void *val_ptr)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)val_ptr;
|
||||
uint16_t val;
|
||||
|
||||
val = (uint16_t)p[0];
|
||||
val |= (uint16_t)p[1] << 8;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t get_u32_le(const void *val_ptr)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)val_ptr;
|
||||
uint32_t val;
|
||||
|
||||
val = (uint32_t)p[0];
|
||||
val |= (uint32_t)p[1] << 8;
|
||||
val |= (uint32_t)p[2] << 16;
|
||||
val |= (uint32_t)p[3] << 24;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
uint64_t get_u64_le(const void *val_ptr)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)val_ptr;
|
||||
uint64_t val;
|
||||
|
||||
val = (uint64_t)p[0];
|
||||
val |= (uint64_t)p[1] << 8;
|
||||
val |= (uint64_t)p[2] << 16;
|
||||
val |= (uint64_t)p[3] << 24;
|
||||
val |= (uint64_t)p[4] << 32;
|
||||
val |= (uint64_t)p[5] << 40;
|
||||
val |= (uint64_t)p[6] << 48;
|
||||
val |= (uint64_t)p[7] << 56;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Functions to convert Big Endian byte stream to
|
||||
* uint16, uint32 and uint64
|
||||
*/
|
||||
uint16_t get_u16_be(const void *val_ptr)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)val_ptr;
|
||||
uint16_t val;
|
||||
|
||||
val = (uint16_t)p[0] << 8;
|
||||
val |= (uint16_t)p[1];
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t get_u32_be(const void *val_ptr)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)val_ptr;
|
||||
uint32_t val;
|
||||
|
||||
val = (uint32_t)p[0] << 24;
|
||||
val |= (uint32_t)p[1] << 16;
|
||||
val |= (uint32_t)p[2] << 8;
|
||||
val |= (uint32_t)p[3];
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
uint64_t get_u64_be(const void *val_ptr)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)val_ptr;
|
||||
uint64_t val;
|
||||
|
||||
val = (uint64_t)p[0] << 56;
|
||||
val |= (uint64_t)p[1] << 48;
|
||||
val |= (uint64_t)p[2] << 40;
|
||||
val |= (uint64_t)p[3] << 32;
|
||||
val |= (uint64_t)p[4] << 24;
|
||||
val |= (uint64_t)p[5] << 16;
|
||||
val |= (uint64_t)p[6] << 8;
|
||||
val |= (uint64_t)p[7];
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Functions to convert uint16, uint32 and uint64
|
||||
* to Little Endian
|
||||
*/
|
||||
void put_u16_le(void *val_ptr, const uint16_t val)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)val_ptr;
|
||||
|
||||
p[0] = (uint8_t)val & 0xff;
|
||||
p[1] = (uint8_t)(val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
void put_u32_le(void *val_ptr, const uint32_t val)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)val_ptr;
|
||||
|
||||
p[0] = (uint8_t)val & 0xff;
|
||||
p[1] = (uint8_t)(val >> 8) & 0xff;
|
||||
p[2] = (uint8_t)(val >> 16) & 0xff;
|
||||
p[3] = (uint8_t)(val >> 24) & 0xff;
|
||||
}
|
||||
|
||||
void put_u64_le(void *val_ptr, const uint64_t val)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)val_ptr;
|
||||
|
||||
p[0] = (uint8_t)val & 0xff;
|
||||
p[1] = (uint8_t)(val >> 8) & 0xff;
|
||||
p[2] = (uint8_t)(val >> 16) & 0xff;
|
||||
p[3] = (uint8_t)(val >> 24) & 0xff;
|
||||
p[4] = (uint8_t)(val >> 32) & 0xff;
|
||||
p[5] = (uint8_t)(val >> 40) & 0xff;
|
||||
p[6] = (uint8_t)(val >> 48) & 0xff;
|
||||
p[7] = (uint8_t)(val >> 56) & 0xff;
|
||||
}
|
||||
|
||||
/* Functions to convert uint16, uint32 and uint64
|
||||
* to Big Endian
|
||||
*/
|
||||
void put_u16_be(void *val_ptr, const uint16_t val)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)val_ptr;
|
||||
|
||||
p[0] = (uint8_t)(val >> 8) & 0xff;
|
||||
p[1] = (uint8_t)val & 0xff;
|
||||
}
|
||||
|
||||
void put_u32_be(void *val_ptr, const uint32_t val)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)val_ptr;
|
||||
|
||||
p[0] = (uint8_t)((val >> 24) & 0xff);
|
||||
p[1] = (uint8_t)((val >> 16) & 0xff);
|
||||
p[2] = (uint8_t)((val >> 8) & 0xff);
|
||||
p[3] = (uint8_t)(val & 0xff);
|
||||
}
|
||||
|
||||
void put_u64_be(void *val_ptr, const uint64_t val)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)val_ptr;
|
||||
|
||||
p[0] = (uint8_t)(val >> 56) & 0xff;
|
||||
p[1] = (uint8_t)(val >> 48) & 0xff;
|
||||
p[2] = (uint8_t)(val >> 40) & 0xff;
|
||||
p[3] = (uint8_t)(val >> 32) & 0xff;
|
||||
p[4] = (uint8_t)(val >> 24) & 0xff;
|
||||
p[5] = (uint8_t)(val >> 16) & 0xff;
|
||||
p[6] = (uint8_t)(val >> 8) & 0xff;
|
||||
p[7] = (uint8_t)val & 0xff;
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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.
|
||||
/**
|
||||
* \file byte_convert.h
|
||||
* \brief Conversion between integers and byte streams
|
||||
*
|
||||
* This module offers APIs to convert 16bit, 32bit and 64 bit unsigned integers
|
||||
* into Little/Big Endian byte streams
|
||||
*/
|
||||
#ifndef _BYTE_CONVERT_H
|
||||
#define _BYTE_CONVERT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Little Endian to uint16 Conversion
|
||||
* Get a uint16 integer from a little Endian byte stream
|
||||
*
|
||||
* \param[in] val_ptr Pointer to the 2 byte stream
|
||||
*
|
||||
* \return The converted uint16 integer
|
||||
*/
|
||||
uint16_t get_u16_le(const void *val_ptr);
|
||||
|
||||
/** Little Endian to uint32 Conversion
|
||||
* Get a uint32 integer from a little Endian byte stream
|
||||
*
|
||||
* \param[in] val_ptr Pointer to the 4 byte stream
|
||||
*
|
||||
* \return The converted uint32 integer
|
||||
*/
|
||||
uint32_t get_u32_le(const void *val_ptr);
|
||||
|
||||
/** Little Endian to uint64 Conversion
|
||||
* Get a uint64 integer from a little Endian byte stream
|
||||
*
|
||||
* \param[in] val_ptr Pointer to the 8 byte stream
|
||||
*
|
||||
* \return The converted uint32 integer
|
||||
*/
|
||||
uint64_t get_u64_le(const void *val_ptr);
|
||||
|
||||
/** Big Endian to uint16 Conversion
|
||||
* Get a uint16 integer from a Big Endian byte stream
|
||||
*
|
||||
* \param[in] val_ptr Pointer to the 2 byte stream
|
||||
*
|
||||
* \return The converted uint16 integer
|
||||
*/
|
||||
uint16_t get_u16_be(const void *val_ptr);
|
||||
|
||||
/** Big Endian to uint32 Conversion
|
||||
* Get a uint32 integer from a Big Endian byte stream
|
||||
*
|
||||
* \param[in] val_ptr Pointer to the 4 byte stream
|
||||
*
|
||||
* \return The converted uint32 integer
|
||||
*/
|
||||
uint32_t get_u32_be(const void *val_ptr);
|
||||
|
||||
/** Big Endian to uint64 Conversion
|
||||
* Get a uint64 integer from a Big Endian byte stream
|
||||
*
|
||||
* \param[in] val_ptr Pointer to the 8 byte stream
|
||||
*
|
||||
* \return The converted uint16 integer
|
||||
*/
|
||||
uint64_t get_u64_be(const void *val_ptr);
|
||||
|
||||
/** Uint16 to Little Endian Conversion
|
||||
*
|
||||
* Put a uint16 integer into a Little Endian byte stream
|
||||
*
|
||||
* \param[out] Pointer to a 2 byte stream that will be filled with the value
|
||||
*
|
||||
* \param[in] The uint16 integer
|
||||
*/
|
||||
void put_u16_le(void *val_ptr, const uint16_t val);
|
||||
|
||||
/** Uint32 to Little Endian Conversion
|
||||
*
|
||||
* Put a uint32 integer into a Little Endian byte stream
|
||||
*
|
||||
* \param[out] Pointer to a 4 byte stream that will be filled with the value
|
||||
*
|
||||
* \param[in] The uint32 integer
|
||||
*/
|
||||
void put_u32_le(void *val_ptr, const uint32_t val);
|
||||
|
||||
/** Uint64 to Little Endian Conversion
|
||||
*
|
||||
* Put a uint64 integer into a Little Endian byte stream
|
||||
*
|
||||
* \param[out] Pointer to a 8 byte stream that will be filled with the value
|
||||
*
|
||||
* \param[in] The uint64 integer
|
||||
*/
|
||||
void put_u64_le(void *val_ptr, const uint64_t val);
|
||||
|
||||
/** Uint16 to Big Endian Conversion
|
||||
*
|
||||
* Put a uint16 integer into a Big Endian byte stream
|
||||
*
|
||||
* \param[out] Pointer to a 2 byte stream that will be filled with the value
|
||||
*
|
||||
* \param[in] The uint16 integer
|
||||
*/
|
||||
void put_u16_be(void *val_ptr, const uint16_t val);
|
||||
|
||||
/** Uint32 to Big Endian Conversion
|
||||
*
|
||||
* Put a uint32 integer into a Big Endian byte stream
|
||||
*
|
||||
* \param[out] Pointer to a 4 byte stream that will be filled with the value
|
||||
*
|
||||
* \param[in] The uint32 integer
|
||||
*/
|
||||
void put_u32_be(void *val_ptr, const uint32_t val);
|
||||
|
||||
/** Uint64 to Big Endian Conversion
|
||||
*
|
||||
* Put a uint64 integer into a Big Endian byte stream
|
||||
*
|
||||
* \param[out] Pointer to a 8 byte stream that will be filled with the value
|
||||
*
|
||||
* \param[in] The uint64 integer
|
||||
*/
|
||||
void put_u64_be(void *val_ptr, const uint64_t val);
|
||||
#endif /* _BYTE_CONVERT_H */
|
|
@ -1,491 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <hap_platform_memory.h>
|
||||
#include <esp_hap_acc.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
#include <hap_apple_servs.h>
|
||||
#include <hap_apple_chars.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_hap_keystore.h>
|
||||
#include <esp_hap_main.h>
|
||||
|
||||
/* Primary Accessory Pointer */
|
||||
static __hap_acc_t *primary_acc;
|
||||
|
||||
/*****************************************************************************************************/
|
||||
|
||||
hap_acc_t *hap_get_first_acc()
|
||||
{
|
||||
return (hap_acc_t *)primary_acc;
|
||||
}
|
||||
|
||||
hap_acc_t *hap_acc_get_next(hap_acc_t *ha)
|
||||
{
|
||||
if (!ha)
|
||||
return NULL;
|
||||
|
||||
__hap_acc_t *_ha = (__hap_acc_t *)ha;
|
||||
return (hap_acc_t *)_ha->next;
|
||||
}
|
||||
/* Service write callback to handle "Identify" */
|
||||
static int hap_acc_info_write(hap_write_data_t write_data[], int count,
|
||||
void *serv_priv, void *write_priv)
|
||||
{
|
||||
int i;
|
||||
__hap_char_t *_hc;
|
||||
for (i = 0; i < count; i++) {
|
||||
_hc = (__hap_char_t *)write_data[i].hc;
|
||||
if (!strcmp(_hc->type_uuid, HAP_CHAR_UUID_IDENTIFY)) {
|
||||
__hap_acc_t *_ha = (__hap_acc_t *)serv_priv;
|
||||
if (_ha) {
|
||||
_ha->identify_routine((hap_acc_t *)_ha);
|
||||
*(write_data->status) = HAP_STATUS_SUCCESS;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*(write_data->status) = HAP_STATUS_VAL_INVALID;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP create an accessory
|
||||
*/
|
||||
hap_acc_t *hap_acc_create(hap_acc_cfg_t *acc_cfg)
|
||||
{
|
||||
static bool first = true;
|
||||
int ret = 0;
|
||||
__hap_acc_t *_ha = hap_platform_memory_calloc(1, sizeof(__hap_acc_t));
|
||||
if (!_ha) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_ha->identify_routine = acc_cfg->identify_routine;
|
||||
_ha->next_iid = 1;
|
||||
|
||||
/* Add the Accessory Information Service internally */
|
||||
hap_serv_t *hs = hap_serv_create("3E");
|
||||
if (!hs) {
|
||||
goto acc_create_fail;
|
||||
}
|
||||
ret = hap_serv_add_char(hs, hap_char_bool_create(HAP_CHAR_UUID_IDENTIFY, HAP_CHAR_PERM_PW, false));
|
||||
ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_MANUFACTURER, HAP_CHAR_PERM_PR, acc_cfg->manufacturer));
|
||||
ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_MODEL, HAP_CHAR_PERM_PR, acc_cfg->model));
|
||||
ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_NAME, HAP_CHAR_PERM_PR, acc_cfg->name));
|
||||
ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_SERIAL_NUMBER, HAP_CHAR_PERM_PR, acc_cfg->serial_num));
|
||||
ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_FIRMWARE_REVISION, HAP_CHAR_PERM_PR, acc_cfg->fw_rev));
|
||||
if (acc_cfg->hw_rev) {
|
||||
ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_HARDWARE_REVISION, HAP_CHAR_PERM_PR, acc_cfg->hw_rev));
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
goto acc_create_fail;
|
||||
}
|
||||
|
||||
hap_serv_set_write_cb(hs, hap_acc_info_write);
|
||||
hap_serv_set_priv(hs,(void *)_ha);
|
||||
hap_acc_add_serv((hap_acc_t *)_ha, hs);
|
||||
|
||||
if (first) {
|
||||
/* Add the Procol Information Service Internally */
|
||||
hs = hap_serv_create("A2");
|
||||
if (!hs) {
|
||||
goto acc_create_fail;
|
||||
}
|
||||
ret = hap_serv_add_char(hs, hap_char_string_create("37", HAP_CHAR_PERM_PR, "1.1.0"));
|
||||
|
||||
if (ret) {
|
||||
goto acc_create_fail;
|
||||
}
|
||||
hap_acc_add_serv((hap_acc_t *)_ha, hs);
|
||||
hap_priv.cid = acc_cfg->cid;
|
||||
first = false;
|
||||
}
|
||||
|
||||
return (hap_acc_t *)_ha;
|
||||
|
||||
acc_create_fail:
|
||||
hap_acc_delete((hap_acc_t *)_ha);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hap_acc_add_accessory_flags(hap_acc_t *ha, uint32_t flags)
|
||||
{
|
||||
if (!ha) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION);
|
||||
if (!hs) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
return hap_serv_add_char(hs, hap_char_accessory_flags_create(flags));
|
||||
|
||||
}
|
||||
|
||||
int hap_acc_update_accessory_flags(hap_acc_t *ha, uint32_t flags)
|
||||
{
|
||||
if (!ha) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION);
|
||||
if (!hs) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_char_t *hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_ACCESSORY_FLAGS);
|
||||
if (!hc) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_val_t val = {
|
||||
.u = flags,
|
||||
};
|
||||
return hap_char_update_val(hc, &val);
|
||||
}
|
||||
|
||||
int hap_acc_add_product_data(hap_acc_t *ha, uint8_t *product_data, size_t data_size)
|
||||
{
|
||||
if (!ha) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION);
|
||||
if (!hs) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if (data_size != 8) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Product data size is not 8");
|
||||
}
|
||||
uint8_t *buf = calloc(1, data_size);
|
||||
if (!buf) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
memcpy(buf, product_data, data_size);
|
||||
hap_data_val_t data_val = {
|
||||
.buf = buf,
|
||||
.buflen = data_size
|
||||
};
|
||||
return hap_serv_add_char(hs, hap_char_product_data_create(&data_val));
|
||||
}
|
||||
|
||||
const hap_val_t *hap_get_product_data()
|
||||
{
|
||||
hap_char_t *acc_info = hap_acc_get_serv_by_uuid(hap_get_first_acc(), HAP_SERV_UUID_ACCESSORY_INFORMATION);
|
||||
if (acc_info) {
|
||||
hap_char_t *product_data = hap_serv_get_char_by_uuid(acc_info, HAP_CHAR_UUID_PRODUCT_DATA);
|
||||
if (product_data) {
|
||||
return hap_char_get_val(product_data);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* @brief check if accessory's AID matches the target AID
|
||||
*/
|
||||
bool hap_check_aid(__hap_acc_t *accessory, int32_t aid)
|
||||
{
|
||||
return accessory->aid == aid ? true : false;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_acc_get_first_serv(hap_acc_t *ha)
|
||||
{
|
||||
return ((__hap_acc_t *)ha)->servs;
|
||||
}
|
||||
/**
|
||||
* @brief get target service by it's type description string
|
||||
*/
|
||||
hap_serv_t *hap_acc_get_serv_by_iid(hap_acc_t *ha, int32_t iid)
|
||||
{
|
||||
if (!ha)
|
||||
return NULL;
|
||||
|
||||
hap_serv_t *hs;
|
||||
for (hs = hap_acc_get_first_serv(ha); hs; hs = hap_serv_get_next(hs)) {
|
||||
if (((__hap_serv_t *)hs)->iid == iid)
|
||||
return hs;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_acc_get_serv_by_uuid(hap_acc_t *ha, const char *uuid)
|
||||
{
|
||||
if (!ha)
|
||||
return NULL;
|
||||
|
||||
hap_serv_t *hs;
|
||||
for (hs = hap_acc_get_first_serv(ha); hs; hs = hap_serv_get_next(hs)) {
|
||||
if (!strcmp(((__hap_serv_t *)hs)->type_uuid, uuid))
|
||||
return hs;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get target characteristics by it's IID
|
||||
*/
|
||||
hap_char_t *hap_acc_get_char_by_iid(hap_acc_t *ha, int32_t iid)
|
||||
{
|
||||
if (!ha)
|
||||
return NULL;
|
||||
hap_serv_t *hs;
|
||||
hap_char_t *hc;
|
||||
for (hs = hap_acc_get_first_serv(ha); hs; hs = hap_serv_get_next(hs)) {
|
||||
hc = hap_serv_get_char_by_iid(hs, iid);
|
||||
if (hc)
|
||||
return hc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hap_acc_get_info(hap_acc_cfg_t *acc_cfg)
|
||||
{
|
||||
ESP_MFI_ASSERT(acc_cfg);
|
||||
hap_acc_t *ha = hap_get_first_acc();
|
||||
|
||||
ESP_MFI_ASSERT(ha);
|
||||
|
||||
hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION);
|
||||
|
||||
hap_char_t *hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_NAME);
|
||||
acc_cfg->name = ((__hap_char_t *)hc)->val.s;
|
||||
|
||||
hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_MODEL);
|
||||
acc_cfg->model = ((__hap_char_t *)hc)->val.s;
|
||||
|
||||
hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_MANUFACTURER);
|
||||
acc_cfg->manufacturer = ((__hap_char_t *)hc)->val.s;
|
||||
|
||||
hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_SERIAL_NUMBER);
|
||||
acc_cfg->serial_num = ((__hap_char_t *)hc)->val.s;
|
||||
|
||||
hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_FIRMWARE_REVISION);
|
||||
acc_cfg->fw_rev = ((__hap_char_t *)hc)->val.s;
|
||||
|
||||
hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_HARDWARE_REVISION);
|
||||
if (hc) {
|
||||
acc_cfg->hw_rev = ((__hap_char_t *)hc)->val.s;
|
||||
} else {
|
||||
acc_cfg->hw_rev = NULL;
|
||||
}
|
||||
|
||||
hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_PROTOCOL_INFORMATION);
|
||||
|
||||
hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_VERSION);
|
||||
acc_cfg->pv = ((__hap_char_t *)hc)->val.s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add a characteristics to a service
|
||||
*/
|
||||
int hap_acc_add_serv(hap_acc_t *ha, hap_serv_t *hs)
|
||||
{
|
||||
ESP_MFI_ASSERT(ha);
|
||||
ESP_MFI_ASSERT(hs);
|
||||
__hap_acc_t *_ha = (__hap_acc_t *)ha;
|
||||
__hap_serv_t *_hs = (__hap_serv_t *)hs;
|
||||
|
||||
if (_hs->parent) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Service already added");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/* If the accessory has no services, add this as the first */
|
||||
if (!_ha->servs) {
|
||||
_ha->servs = hs;
|
||||
} else {
|
||||
/* Else loop through the services to get to the last one,
|
||||
* and add this at the end
|
||||
*/
|
||||
__hap_serv_t *temp = (__hap_serv_t *)_ha->servs;
|
||||
while (temp->next_serv)
|
||||
temp = (__hap_serv_t *)temp->next_serv;
|
||||
temp->next_serv = hs;
|
||||
}
|
||||
_hs->iid = _ha->next_iid++;
|
||||
__hap_char_t *_hc = (__hap_char_t *)_hs->chars;
|
||||
while(_hc) {
|
||||
_hc->iid = _ha->next_iid++;
|
||||
_hc = (__hap_char_t *)_hc->next_char;
|
||||
}
|
||||
_hs->parent = ha;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hap_add_acc_to_list(__hap_acc_t *primary, __hap_acc_t *new)
|
||||
{
|
||||
__hap_acc_t *cur = primary;
|
||||
while (cur->next) {
|
||||
cur = cur->next;
|
||||
}
|
||||
cur->next = new;
|
||||
}
|
||||
|
||||
static void hap_remove_acc_from_list(__hap_acc_t *primary, __hap_acc_t *old)
|
||||
{
|
||||
__hap_acc_t *cur = primary;
|
||||
while (cur->next != old) {
|
||||
cur = cur->next;
|
||||
}
|
||||
cur->next = cur->next->next;
|
||||
}
|
||||
|
||||
#define HAP_BRIDGE_KEYSTORE "hap_bridge"
|
||||
|
||||
int hap_get_unique_aid(const char *id)
|
||||
{
|
||||
if (!id) {
|
||||
return -1;
|
||||
}
|
||||
int aid = 0;
|
||||
size_t aid_size = sizeof(aid);
|
||||
if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, id, (uint8_t *)&aid, &aid_size) != HAP_SUCCESS) {
|
||||
aid = hap_get_next_aid();
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Assigning aid = %d for Bridged accessory %s", aid, id);
|
||||
hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, id, (uint8_t *)&aid, sizeof(aid));
|
||||
} else {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Using aid = %d for Bridged accessory %s", aid, id);
|
||||
}
|
||||
return aid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP add accessory to HAP kernel
|
||||
*/
|
||||
void hap_add_accessory(hap_acc_t *ha)
|
||||
{
|
||||
if (!ha) {
|
||||
return;
|
||||
}
|
||||
if (primary_acc) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Primary Accessory already added. Use hap_add_bridged_accessory() instead");
|
||||
return;
|
||||
}
|
||||
__hap_acc_t *_ha = (__hap_acc_t *)ha;
|
||||
_ha->aid = 1;
|
||||
primary_acc = _ha;
|
||||
if (hap_priv.cfg.unique_param >= UNIQUE_NAME) {
|
||||
char name[74];
|
||||
uint8_t eth_mac[6];
|
||||
esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
|
||||
hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION);
|
||||
hap_char_t *hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_NAME);
|
||||
snprintf(name, sizeof(name), "%s-%02X%02X%02X", ((__hap_char_t *)hc)->val.s,
|
||||
eth_mac[3], eth_mac[4], eth_mac[5]);
|
||||
hap_platform_memory_free(((__hap_char_t *)hc)->val.s);
|
||||
((__hap_char_t *)hc)->val.s = strdup(name);
|
||||
}
|
||||
hap_acc_get_info(&hap_priv.primary_acc);
|
||||
}
|
||||
|
||||
void hap_add_bridged_accessory(hap_acc_t *ha, int aid)
|
||||
{
|
||||
if (!ha) {
|
||||
return;
|
||||
}
|
||||
__hap_acc_t *_ha = (__hap_acc_t *)ha;
|
||||
if (aid) {
|
||||
_ha->aid = aid;
|
||||
} else {
|
||||
_ha->aid = hap_get_next_aid();
|
||||
}
|
||||
|
||||
hap_add_acc_to_list(primary_acc, _ha);
|
||||
if (!hap_priv.cfg.disable_config_num_update) {
|
||||
hap_update_config_number();
|
||||
}
|
||||
}
|
||||
|
||||
void hap_remove_bridged_accessory(hap_acc_t *ha)
|
||||
{
|
||||
if ((__hap_acc_t *)ha == primary_acc) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Cannot remove primary accessory");
|
||||
} else {
|
||||
if (ha) {
|
||||
hap_remove_acc_from_list(primary_acc, (__hap_acc_t *)ha);
|
||||
if (!hap_priv.cfg.disable_config_num_update) {
|
||||
hap_update_config_number();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief HAP delete target accessory
|
||||
*/
|
||||
void hap_acc_delete(hap_acc_t *ha)
|
||||
{
|
||||
/* Returning success even if pointer is NULL, because it means
|
||||
* that the accessory is absent and as good as deleted
|
||||
*/
|
||||
if (!ha)
|
||||
return;
|
||||
__hap_acc_t *_ha = (__hap_acc_t *)ha;
|
||||
__hap_serv_t *_hs = (__hap_serv_t *)_ha->servs;
|
||||
while (_hs) {
|
||||
_ha->servs = _hs->next_serv;
|
||||
hap_serv_delete((hap_serv_t *)_hs);
|
||||
_hs = (__hap_serv_t *)_ha->servs;
|
||||
}
|
||||
hap_platform_memory_free(_ha);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP get target accessory AID
|
||||
*/
|
||||
uint32_t hap_acc_get_aid(hap_acc_t *ha)
|
||||
{
|
||||
ESP_MFI_ASSERT(ha);
|
||||
__hap_acc_t *_ha = (__hap_acc_t *)ha;
|
||||
|
||||
return _ha->aid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief delete all accessories
|
||||
*/
|
||||
void hap_delete_all_accessories(void)
|
||||
{
|
||||
__hap_acc_t *next, *ha = primary_acc;
|
||||
while (ha) {
|
||||
next = ha->next;
|
||||
hap_acc_delete((hap_acc_t *)ha);
|
||||
ha = next;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief get target accessory by AID
|
||||
*/
|
||||
hap_acc_t *hap_acc_get_by_aid(int32_t aid)
|
||||
{
|
||||
hap_acc_t *ha;
|
||||
for (ha = hap_get_first_acc(); ha; ha = hap_acc_get_next(ha)) {
|
||||
if (((__hap_acc_t *)ha)->aid == aid) {
|
||||
return ha;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HAP_ACC_H_
|
||||
#define _HAP_ACC_H_
|
||||
|
||||
#include <hap.h>
|
||||
#include <esp_hap_serv.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
typedef struct esp_mfi_accessory {
|
||||
struct esp_mfi_accessory *next;
|
||||
uint32_t aid; /* accessory AID */
|
||||
hap_serv_t *servs; /* service list */
|
||||
bool power_off;
|
||||
uint32_t next_iid;
|
||||
hap_identify_routine_t identify_routine;
|
||||
} __hap_acc_t;
|
||||
hap_char_t *hap_acc_get_char_by_iid(hap_acc_t *ha, int32_t iid);
|
||||
hap_acc_t *hap_acc_get_by_aid(int32_t aid);
|
||||
int hap_acc_get_info(hap_acc_cfg_t *acc_cfg);
|
||||
const hap_val_t *hap_get_product_data();
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HAP_ACC_H_ */
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <hap_platform_memory.h>
|
||||
#include <esp_hap_main.h>
|
||||
#include <esp_hap_mdns.h>
|
||||
#include <esp_hap_wifi.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
static char *new_name;
|
||||
|
||||
void hap_bct_change_name(const char *name)
|
||||
{
|
||||
if (new_name) {
|
||||
hap_platform_memory_free(new_name);
|
||||
}
|
||||
new_name = strdup(name);
|
||||
hap_send_event(HAP_INTERNAL_EVENT_BCT_CHANGE_NAME);
|
||||
}
|
||||
|
||||
void hap_bct_hot_plug()
|
||||
{
|
||||
hap_send_event(HAP_INTERNAL_EVENT_BCT_HOT_PLUG);
|
||||
}
|
||||
|
||||
void hap_handle_bct_change_name()
|
||||
{
|
||||
if (!new_name) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No BCT name specified");
|
||||
return;
|
||||
} else {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Changing BCT Name to %s", new_name);
|
||||
}
|
||||
if (hap_mdns_serv_name_change(&hap_priv.hap_mdns_handle, new_name) != HAP_SUCCESS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to change BCT name");
|
||||
}
|
||||
hap_platform_memory_free(new_name);
|
||||
new_name = NULL;
|
||||
}
|
||||
|
||||
void hap_handle_hot_plug()
|
||||
{
|
||||
esp_wifi_stop();
|
||||
vTaskDelay((10 * 1000) / portTICK_PERIOD_MS); /* Wait for 10 seconds */
|
||||
esp_wifi_start();
|
||||
esp_wifi_connect();
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_BCT_PRIV_H_
|
||||
#define _HAP_BCT_PRIV_H_
|
||||
void hap_handle_bct_change_name();
|
||||
void hap_handle_hot_plug();
|
||||
#endif /* _HAP_BCT_PRIV_H_ */
|
|
@ -1,601 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <hap_platform_memory.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "esp_mfi_debug.h"
|
||||
|
||||
#include <esp_hap_main.h>
|
||||
#include <esp_hap_acc.h>
|
||||
#include <esp_hap_char.h>
|
||||
#include <esp_hap_ip_services.h>
|
||||
#include <esp_hap_database.h>
|
||||
|
||||
static QueueHandle_t hap_event_queue;
|
||||
|
||||
/**
|
||||
* @brief get characteristics's value
|
||||
*/
|
||||
hap_val_t *esp_mfi_characteristics_get_value(__hap_char_t *_hc)
|
||||
{
|
||||
return &_hc->val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if characteristics has the specific permission
|
||||
*/
|
||||
bool hap_char_has_permission(__hap_char_t *_hc, uint16_t permission)
|
||||
{
|
||||
return _hc->permission & permission ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief compute the mod of a and b: a % b
|
||||
*/
|
||||
static double esp_mfi_fmod(double a, double b)
|
||||
{
|
||||
if (a < 1e-06 || b < 1e-06)
|
||||
return 0;
|
||||
|
||||
while (!((long long)a) || !((long long)b)) {
|
||||
a *= 10.0;
|
||||
b *= 10.0;
|
||||
}
|
||||
|
||||
return fmod(a, b);
|
||||
}
|
||||
|
||||
int hap_event_queue_init()
|
||||
{
|
||||
hap_event_queue = xQueueCreate( hap_priv.cfg.max_event_notif_chars,
|
||||
sizeof(hap_char_t *) );
|
||||
if (hap_event_queue) {
|
||||
return HAP_SUCCESS;
|
||||
} else {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
hap_char_t * hap_get_pending_notif_char()
|
||||
{
|
||||
hap_char_t *hc;
|
||||
if (xQueueReceive(hap_event_queue, &hc, 0) != pdTRUE) {
|
||||
return NULL;
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
static int hap_queue_event(hap_char_t *hc)
|
||||
{
|
||||
int ret;
|
||||
if (!hap_event_queue) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if (xPortInIsrContext() == pdTRUE) {
|
||||
ret = xQueueSendFromISR(hap_event_queue, &hc, NULL);
|
||||
} else {
|
||||
ret = xQueueSend(hap_event_queue, &hc, 0);
|
||||
}
|
||||
if (ret == pdTRUE) {
|
||||
hap_send_event(HAP_INTERNAL_EVENT_TRIGGER_NOTIF);
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief check if characteristics value is at the range
|
||||
*/
|
||||
int hap_char_check_val_constraints(__hap_char_t *_hc, hap_val_t *val)
|
||||
{
|
||||
if (!_hc->constraint_flags)
|
||||
return HAP_SUCCESS;
|
||||
|
||||
if (_hc->format == HAP_CHAR_FORMAT_INT) {
|
||||
int value = val->i;
|
||||
int remainder;
|
||||
|
||||
if (value > _hc->max.i
|
||||
|| value < _hc->min.i)
|
||||
return HAP_FAIL;
|
||||
|
||||
if (!_hc->step.i)
|
||||
return HAP_SUCCESS;
|
||||
|
||||
remainder = (value - _hc->min.i) % _hc->step.i;
|
||||
if (remainder)
|
||||
return HAP_FAIL;
|
||||
} else if (_hc->format == HAP_CHAR_FORMAT_FLOAT) {
|
||||
float value = val->f;
|
||||
|
||||
if (value > _hc->max.f
|
||||
|| value < _hc->min.f)
|
||||
return HAP_FAIL;
|
||||
# if 0
|
||||
/* Check for step value for floats has a high chance of failure,
|
||||
* because of precision issues. Hence, better to skip it.
|
||||
*/
|
||||
double remainder;
|
||||
if (_hc->step.f == 0.0)
|
||||
return HAP_SUCCESS;
|
||||
|
||||
remainder = esp_mfi_fmod(value - _hc->min.f, _hc->step.f);
|
||||
if (remainder != 0.0)
|
||||
return HAP_FAIL;
|
||||
#endif
|
||||
} else if (_hc->format == HAP_CHAR_FORMAT_UINT8
|
||||
|| _hc->format == HAP_CHAR_FORMAT_UINT16
|
||||
|| _hc->format == HAP_CHAR_FORMAT_UINT32) {
|
||||
uint32_t value = val->u;
|
||||
uint32_t remainder;
|
||||
|
||||
|
||||
if (value > _hc->max.u
|
||||
|| value < _hc->min.u)
|
||||
return HAP_FAIL;
|
||||
|
||||
if (!_hc->step.u)
|
||||
return HAP_SUCCESS;
|
||||
|
||||
remainder = (value - _hc->min.u) % _hc->step.u;
|
||||
if (remainder)
|
||||
return HAP_FAIL;
|
||||
} else if (_hc->format == HAP_CHAR_FORMAT_UINT64) {
|
||||
/* TODO: Add support. Currently, there is no particular 64-bit characteristic */
|
||||
}
|
||||
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief user update characteristics value, preparing for notification
|
||||
*/
|
||||
int hap_char_update_val(hap_char_t *hc, hap_val_t *val)
|
||||
{
|
||||
if (!hc || !val) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
_hc->update_called = true;
|
||||
if (hap_char_check_val_constraints(_hc, val) != HAP_SUCCESS)
|
||||
return HAP_FAIL;
|
||||
/* Boolean to track if the value has changed.
|
||||
* This will be later used to decide if an event notification
|
||||
* is required or not. If the new and old values are same,
|
||||
* there is no need of a notification
|
||||
*/
|
||||
bool value_changed = false;
|
||||
|
||||
switch (_hc->format) {
|
||||
case HAP_CHAR_FORMAT_BOOL:
|
||||
if (_hc->val.b != val->b) {
|
||||
_hc->val.b = val->b;
|
||||
value_changed = true;
|
||||
}
|
||||
break;
|
||||
case HAP_CHAR_FORMAT_INT:
|
||||
case HAP_CHAR_FORMAT_UINT8:
|
||||
case HAP_CHAR_FORMAT_UINT16:
|
||||
case HAP_CHAR_FORMAT_UINT32:
|
||||
if (_hc->val.i != val->i) {
|
||||
_hc->val.i = val->i;
|
||||
value_changed = true;
|
||||
}
|
||||
break;
|
||||
case HAP_CHAR_FORMAT_FLOAT:
|
||||
if (_hc->val.f != val->f) {
|
||||
_hc->val.f = val->f;
|
||||
value_changed = true;
|
||||
}
|
||||
break;
|
||||
case HAP_CHAR_FORMAT_STRING:
|
||||
/* Not checking all combinations to find if value has changed,
|
||||
* since generally we do not expect dynamic string values
|
||||
*
|
||||
* Eg.
|
||||
* Both (old and new) values being NULL
|
||||
* Old value NULL, New non-NULL
|
||||
* Old value non-NULL, new NULL
|
||||
*/
|
||||
if (_hc->val.s && val->s && !strcmp(_hc->val.s, val->s))
|
||||
value_changed = false;
|
||||
else
|
||||
value_changed = true;
|
||||
|
||||
if (_hc->val.s) {
|
||||
hap_platform_memory_free(_hc->val.s);
|
||||
_hc->val.s = NULL;
|
||||
}
|
||||
|
||||
if (val->s) {
|
||||
_hc->val.s = strdup(val->s);
|
||||
if (!_hc->val.s)
|
||||
return HAP_FAIL;
|
||||
}
|
||||
break;
|
||||
case HAP_CHAR_FORMAT_DATA:
|
||||
case HAP_CHAR_FORMAT_TLV8: {
|
||||
_hc->val.d.buf = val->d.buf;
|
||||
_hc->val.d.buflen = val->d.buflen;
|
||||
value_changed = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (value_changed || (_hc->permission & HAP_CHAR_PERM_SPECIAL_READ)) {
|
||||
ESP_MFI_DEBUG_INTR(ESP_MFI_DEBUG_INFO, "Value Changed");
|
||||
hap_queue_event(hc);
|
||||
} else {
|
||||
/* If there is no value change, reset the owner flag here itself, as no notification
|
||||
* is being sent anyways. In the absence of this, if there is a GET /characteristics
|
||||
* followed by some value change from hardware, the owner_ctrl stays assigned to a
|
||||
* stale value, and so the controller misses a notification.
|
||||
*/
|
||||
_hc->owner_ctrl = 0;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
const hap_val_t *hap_char_get_val(hap_char_t *hc)
|
||||
{
|
||||
if (!hc)
|
||||
return NULL;
|
||||
return &((__hap_char_t *)hc)->val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the minimum value of characteristic
|
||||
*/
|
||||
const hap_val_t *hap_char_get_min_val(hap_char_t *hc)
|
||||
{
|
||||
if (hc) {
|
||||
if(((__hap_char_t *)hc)->constraint_flags & HAP_CHAR_MIN_FLAG) {
|
||||
return &((__hap_char_t *)hc)->min;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the maximum value of characteristic
|
||||
*/
|
||||
const hap_val_t *hap_char_get_max_val(hap_char_t *hc)
|
||||
{
|
||||
if (hc) {
|
||||
if(((__hap_char_t *)hc)->constraint_flags & HAP_CHAR_MAX_FLAG || ((__hap_char_t *)hc)->constraint_flags & HAP_CHAR_MAXLEN_FLAG) {
|
||||
return &((__hap_char_t *)hc)->max;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the step value of characteristic
|
||||
*/
|
||||
const hap_val_t *hap_char_get_step_val(hap_char_t *hc)
|
||||
{
|
||||
if (hc) {
|
||||
if (((__hap_char_t *)hc)->constraint_flags & HAP_CHAR_STEP_FLAG) {
|
||||
return &((__hap_char_t *)hc)->step;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP create a characteristics
|
||||
*/
|
||||
static hap_char_t *hap_char_create(const char *type_uuid, uint32_t permission, hap_char_format_t format, hap_val_t val)
|
||||
{
|
||||
__hap_char_t *new_ch;
|
||||
|
||||
ESP_MFI_ASSERT(type_uuid);
|
||||
|
||||
if (HAP_CHAR_FORMAT_STRING == format && val.s) {
|
||||
if (strlen(val.s) > HAP_CHAR_STRING_MAX_LEN)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_ch = hap_platform_memory_calloc(1, sizeof(__hap_char_t));
|
||||
if (!new_ch) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_ch->val = val;
|
||||
new_ch->type_uuid = type_uuid;
|
||||
new_ch->format = format;
|
||||
new_ch->permission = permission;
|
||||
|
||||
return (hap_char_t *) new_ch;
|
||||
}
|
||||
|
||||
hap_char_t *hap_char_bool_create(const char *type_uuid, uint16_t perms, bool b)
|
||||
{
|
||||
hap_val_t val = {.b = b};
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_BOOL, val);
|
||||
}
|
||||
hap_char_t *hap_char_uint8_create(const char *type_uuid, uint16_t perms, uint8_t u8)
|
||||
{
|
||||
hap_val_t val = {.u = u8};
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT8, val);
|
||||
}
|
||||
hap_char_t *hap_char_uint16_create(const char *type_uuid, uint16_t perms, uint16_t u16)
|
||||
{
|
||||
hap_val_t val = {.u = u16};
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT16, val);
|
||||
}
|
||||
hap_char_t *hap_char_uint32_create(const char *type_uuid, uint16_t perms, uint32_t u32)
|
||||
{
|
||||
hap_val_t val = {.u = u32};
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT32, val);
|
||||
}
|
||||
hap_char_t *hap_char_uint64_create(const char *type_uuid, uint16_t perms, uint64_t u64)
|
||||
{
|
||||
hap_val_t val = {.i64 = u64};
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT64, val);
|
||||
}
|
||||
hap_char_t *hap_char_int_create(const char *type_uuid, uint16_t perms, int i32)
|
||||
{
|
||||
hap_val_t val = {.i = i32};
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_INT, val);
|
||||
}
|
||||
hap_char_t *hap_char_float_create(const char *type_uuid, uint16_t perms, float f)
|
||||
{
|
||||
hap_val_t val = {.f = f};
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_FLOAT, val);
|
||||
}
|
||||
hap_char_t *hap_char_string_create(const char *type_uuid, uint16_t perms, const char *s)
|
||||
{
|
||||
hap_val_t val;
|
||||
if (s)
|
||||
val.s = strdup(s);
|
||||
else
|
||||
val.s = NULL;
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_STRING, val);
|
||||
}
|
||||
|
||||
hap_char_t *hap_char_data_create(const char *type_uuid, uint16_t perms, hap_data_val_t *d)
|
||||
{
|
||||
hap_val_t val = {0};
|
||||
if (d) {
|
||||
val.d = *d;
|
||||
}
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_DATA, val);
|
||||
}
|
||||
|
||||
hap_char_t *hap_char_tlv8_create(const char *type_uuid, uint16_t perms, hap_tlv8_val_t *t)
|
||||
{
|
||||
hap_val_t val = {0};
|
||||
if (t) {
|
||||
val.t = *t;
|
||||
}
|
||||
return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_TLV8, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP get target characteristics IID
|
||||
*/
|
||||
uint32_t hap_char_get_iid(hap_char_t *hc)
|
||||
{
|
||||
ESP_MFI_ASSERT(hc);
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
|
||||
return tmp->iid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP get target characteristics type UUID
|
||||
*/
|
||||
const char * hap_char_get_type_uuid(hap_char_t *hc)
|
||||
{
|
||||
ESP_MFI_ASSERT(hc);
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
|
||||
return tmp->type_uuid;
|
||||
}
|
||||
|
||||
uint16_t hap_char_get_perm(hap_char_t *hc)
|
||||
{
|
||||
if (!hc)
|
||||
return 0;
|
||||
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
return tmp->permission;
|
||||
}
|
||||
|
||||
hap_char_format_t hap_char_get_format(hap_char_t *hc)
|
||||
{
|
||||
if (!hc)
|
||||
return 0;
|
||||
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
return tmp->format;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP delete target characteristics
|
||||
*/
|
||||
void hap_char_delete(hap_char_t *hc)
|
||||
{
|
||||
ESP_MFI_ASSERT(hc);
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
if (_hc->format == HAP_CHAR_FORMAT_STRING) {
|
||||
if (_hc->val.s) {
|
||||
hap_platform_memory_free(_hc->val.s);
|
||||
}
|
||||
}
|
||||
if (_hc->valid_vals) {
|
||||
hap_platform_memory_free(_hc->valid_vals);
|
||||
}
|
||||
if (_hc->valid_vals_range) {
|
||||
hap_platform_memory_free(_hc->valid_vals_range);
|
||||
}
|
||||
hap_platform_memory_free(_hc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP configure the characteristics's value description
|
||||
*/
|
||||
void hap_char_int_set_constraints(hap_char_t *hc, int min, int max, int step)
|
||||
{
|
||||
ESP_MFI_ASSERT(hc);
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
tmp->min.i = min;
|
||||
tmp->max.i = max;
|
||||
tmp->step.i = step;
|
||||
if (step) {
|
||||
tmp->constraint_flags |= (HAP_CHAR_MIN_FLAG | HAP_CHAR_MAX_FLAG | HAP_CHAR_STEP_FLAG);
|
||||
} else {
|
||||
tmp->constraint_flags |= (HAP_CHAR_MIN_FLAG | HAP_CHAR_MAX_FLAG);
|
||||
}
|
||||
}
|
||||
void hap_char_float_set_constraints(hap_char_t *hc, float min, float max, float step)
|
||||
{
|
||||
ESP_MFI_ASSERT(hc);
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
tmp->min.f = min;
|
||||
tmp->max.f = max;
|
||||
tmp->step.f = step;
|
||||
if (step) {
|
||||
tmp->constraint_flags |= (HAP_CHAR_MIN_FLAG | HAP_CHAR_MAX_FLAG | HAP_CHAR_STEP_FLAG);
|
||||
} else {
|
||||
tmp->constraint_flags |= (HAP_CHAR_MIN_FLAG | HAP_CHAR_MAX_FLAG);
|
||||
}
|
||||
}
|
||||
|
||||
void hap_char_string_set_maxlen(hap_char_t *hc, int maxlen)
|
||||
{
|
||||
ESP_MFI_ASSERT(hc);
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
if (maxlen > HAP_CHAR_STRING_MAX_LEN) {
|
||||
maxlen = HAP_CHAR_STRING_MAX_LEN;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_WARN, "Characteristic string length larger than maximum value(%d), falling back to the maximum value.", HAP_CHAR_STRING_MAX_LEN);
|
||||
}
|
||||
tmp->max.i = maxlen;
|
||||
tmp->constraint_flags |= HAP_CHAR_MAXLEN_FLAG;
|
||||
}
|
||||
|
||||
void hap_char_add_description(hap_char_t *hc, const char *description)
|
||||
{
|
||||
ESP_MFI_ASSERT(hc);
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
tmp->description = (char *)description;
|
||||
}
|
||||
void hap_char_add_unit(hap_char_t *hc, const char *unit)
|
||||
{
|
||||
ESP_MFI_ASSERT(hc);
|
||||
__hap_char_t *tmp = (__hap_char_t *)hc;
|
||||
tmp->unit = (char *)unit;
|
||||
}
|
||||
hap_char_t *hap_char_get_next(hap_char_t *hc)
|
||||
{
|
||||
return ((__hap_char_t *)hc)->next_char;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_char_get_parent(hap_char_t *hc)
|
||||
{
|
||||
return ((__hap_char_t *)hc)->parent;
|
||||
|
||||
}
|
||||
|
||||
#define set_bit(val, index) ((val) |= (1 << index))
|
||||
#define reset_bit(val, index) ((val) &= ~(1 << index))
|
||||
void hap_char_manage_notification(hap_char_t *hc, int index, bool ev)
|
||||
{
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
if (ev)
|
||||
set_bit(_hc->ev_ctrls, index);
|
||||
else
|
||||
reset_bit(_hc->ev_ctrls, index);
|
||||
}
|
||||
|
||||
bool hap_char_is_ctrl_subscribed(hap_char_t *hc, int index)
|
||||
{
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
return (_hc->ev_ctrls & (1 << index)) ? true : false;
|
||||
}
|
||||
|
||||
void hap_char_set_owner_ctrl(hap_char_t *hc, int index)
|
||||
{
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
_hc->owner_ctrl = 0;
|
||||
set_bit(_hc->owner_ctrl, index);
|
||||
}
|
||||
|
||||
bool hap_char_is_ctrl_owner(hap_char_t *hc, int index)
|
||||
{
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
return (_hc->owner_ctrl & (1 << index)) ? true : false;
|
||||
}
|
||||
|
||||
void hap_char_set_iid(hap_char_t *hc, int32_t iid)
|
||||
{
|
||||
if (hc) {
|
||||
((__hap_char_t *)hc)->iid = iid;
|
||||
}
|
||||
}
|
||||
|
||||
void hap_disable_all_char_notif(int index)
|
||||
{
|
||||
/* Just loop through all characteristic objects and reset the
|
||||
* bit indicating event notifications. This is the simplest way
|
||||
*/
|
||||
hap_acc_t *ha;
|
||||
hap_serv_t *hs;
|
||||
hap_char_t *hc;
|
||||
for (ha = hap_get_first_acc(); ha; ha = hap_acc_get_next(ha)) {
|
||||
for (hs = hap_acc_get_first_serv(ha); hs; hs = hap_serv_get_next(hs)) {
|
||||
for (hc = hap_serv_get_first_char(hs); hc; hc = hap_char_get_next(hc)) {
|
||||
reset_bit(((__hap_char_t *)hc)->ev_ctrls, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hap_char_add_valid_vals(hap_char_t *hc, const uint8_t *valid_vals, size_t valid_val_cnt)
|
||||
{
|
||||
if (!hc)
|
||||
return;
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
_hc->valid_vals = hap_platform_memory_malloc(valid_val_cnt);
|
||||
if (_hc->valid_vals) {
|
||||
memcpy(_hc->valid_vals, valid_vals, valid_val_cnt);
|
||||
_hc->valid_vals_cnt = valid_val_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
void hap_char_add_valid_vals_range(hap_char_t *hc, uint8_t start_val, uint8_t end_val)
|
||||
{
|
||||
if (!hc)
|
||||
return;
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
_hc->valid_vals_range = hap_platform_memory_malloc(sizeof(uint8_t));
|
||||
if (_hc->valid_vals_range) {
|
||||
_hc->valid_vals_range[0] = start_val;
|
||||
_hc->valid_vals_range[1] = end_val;
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HAP_CHAR_H_
|
||||
#define _HAP_CHAR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include <hap.h>
|
||||
#include <esp_hap_serv.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#define HAP_CHAR_MIN_FLAG (1 << 0)
|
||||
#define HAP_CHAR_MAX_FLAG (1 << 1)
|
||||
#define HAP_CHAR_STEP_FLAG (1 << 2)
|
||||
#define HAP_CHAR_MAXLEN_FLAG (1 << 3)
|
||||
#define HAP_CHAR_MAXDATALEN_FLAG (1 << 4)
|
||||
|
||||
/**
|
||||
* @brief characteristics object information
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t iid; /* Characteristic instance ID */
|
||||
const char *type_uuid; /* Apple's characteristic UUID */
|
||||
uint16_t permission; /* Characteristic permission */
|
||||
hap_char_format_t format; /* data type of the value */
|
||||
hap_val_t val;
|
||||
bool ev; /* check if characteristics supports event */
|
||||
char *description; /* characteristics's description */
|
||||
char *unit;
|
||||
|
||||
/* Characteristics's father subsystem */
|
||||
hap_serv_t *parent;
|
||||
|
||||
uint8_t constraint_flags;
|
||||
|
||||
hap_val_t max; /* maximum value, maxlen, max data len*/
|
||||
hap_val_t min; /* minimum value */
|
||||
hap_val_t step; /* step value */
|
||||
|
||||
hap_char_t *next_char;
|
||||
/* Bitmap to indicate which controllers have enabled notifications
|
||||
*/
|
||||
uint16_t ev_ctrls;
|
||||
|
||||
/* Bitmap indicating the last controller that modified the value.
|
||||
* No notification should be sent to the owner
|
||||
*/
|
||||
uint16_t owner_ctrl;
|
||||
|
||||
/* Pointer to a valid values range. It will be a 2 byte array, if set from application */
|
||||
uint8_t *valid_vals_range;
|
||||
/* Since a list of valid values can have any length, using a pointer here,
|
||||
* which will be allocated if valid values are set for a characteristic
|
||||
*/
|
||||
uint8_t *valid_vals;
|
||||
size_t valid_vals_cnt;
|
||||
bool update_called;
|
||||
} __hap_char_t;
|
||||
|
||||
void hap_char_manage_notification(hap_char_t *hc, int index, bool ev);
|
||||
bool hap_char_is_ctrl_subscribed(hap_char_t *hc, int index);
|
||||
void hap_char_set_owner_ctrl(hap_char_t *hc, int index);
|
||||
bool hap_char_is_ctrl_owner(hap_char_t *hc, int index);
|
||||
void hap_disable_all_char_notif(int index);
|
||||
int hap_char_check_val_constraints(__hap_char_t *_hc, hap_val_t *val);
|
||||
int hap_event_queue_init();
|
||||
hap_char_t * hap_get_pending_notif_char();
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HAP_CHAR_H_ */
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <hap.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
#include <esp_hap_main.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_hap_controllers.h>
|
||||
#include <esp_hap_keystore.h>
|
||||
|
||||
#define HAP_KEYSTORE_NAMESPACE_CTRL "hap_ctrl"
|
||||
|
||||
int hap_controllers_init()
|
||||
{
|
||||
memset(hap_priv.controllers, 0, sizeof(hap_priv.controllers));
|
||||
char index_str[4];
|
||||
uint8_t i;
|
||||
size_t info_size;
|
||||
bool acc_paired = false;
|
||||
for (i = 0; i < HAP_MAX_CONTROLLERS; i++) {
|
||||
snprintf(index_str, sizeof(index_str), "%d", i);
|
||||
info_size = sizeof(hap_ctrl_info_t);
|
||||
if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_CTRL, index_str,
|
||||
(uint8_t *)&hap_priv.controllers[i].info, &info_size) == HAP_SUCCESS) {
|
||||
if (info_size == sizeof(hap_ctrl_info_t)) {
|
||||
hap_priv.controllers[i].index = i;
|
||||
hap_priv.controllers[i].valid = true;
|
||||
acc_paired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (acc_paired) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Accessory is Paired with atleast one controller");
|
||||
} else {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Accessory is not Paired with any controller");
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
hap_ctrl_data_t *hap_controller_get_empty_loc()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_CONTROLLERS; i++) {
|
||||
if (!hap_priv.controllers[i].valid) {
|
||||
hap_priv.controllers[i].index = i;
|
||||
return &hap_priv.controllers[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hap_get_paired_controller_count()
|
||||
{
|
||||
int i, cnt = 0;
|
||||
for (i = 0; i < HAP_MAX_CONTROLLERS; i++) {
|
||||
if (hap_priv.controllers[i].valid) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
bool is_accessory_paired()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_CONTROLLERS; i++) {
|
||||
if (hap_priv.controllers[i].valid)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_admin_paired()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_CONTROLLERS; i++) {
|
||||
if (hap_priv.controllers[i].valid && hap_priv.controllers[i].info.perms)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int hap_controller_save(hap_ctrl_data_t *ctrl_data)
|
||||
{
|
||||
ctrl_data->valid = true;
|
||||
char index_str[4];
|
||||
snprintf(index_str, sizeof(index_str), "%d", ctrl_data->index);
|
||||
int ret = hap_keystore_set(HAP_KEYSTORE_NAMESPACE_CTRL, index_str,
|
||||
(const uint8_t *)&ctrl_data->info, (size_t)sizeof(hap_ctrl_info_t));
|
||||
|
||||
if (ret != HAP_SUCCESS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to store controller %d", ctrl_data->index);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_report_event(HAP_EVENT_CTRL_PAIRED, ctrl_data->info.id, sizeof(ctrl_data->info.id));
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
void hap_controller_remove(hap_ctrl_data_t *ctrl_data)
|
||||
{
|
||||
if (!ctrl_data)
|
||||
return;
|
||||
char index_str[4];
|
||||
snprintf(index_str, sizeof(index_str), "%d", ctrl_data->index);
|
||||
char id[HAP_CTRL_ID_LEN];
|
||||
strncpy(id, ctrl_data->info.id, sizeof(id));
|
||||
hap_keystore_delete(HAP_KEYSTORE_NAMESPACE_CTRL, index_str);
|
||||
memset(ctrl_data, 0, sizeof(hap_ctrl_data_t));
|
||||
hap_report_event(HAP_EVENT_CTRL_UNPAIRED, id, sizeof(id));
|
||||
}
|
||||
|
||||
hap_ctrl_data_t *hap_get_controller(char *ctrl_id)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_CONTROLLERS; i++) {
|
||||
if (hap_priv.controllers[i].valid
|
||||
&& (!strcmp(hap_priv.controllers[i].info.id, ctrl_id)))
|
||||
return &hap_priv.controllers[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hap_erase_controller_info()
|
||||
{
|
||||
hap_keystore_delete_namespace(HAP_KEYSTORE_NAMESPACE_CTRL);
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_CONTROLLERS_H_
|
||||
#define _HAP_CONTROLLERS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define HAP_MAX_CONTROLLERS 16
|
||||
#define HAP_CTRL_ID_LEN 64
|
||||
#define ED_KEY_LEN 32
|
||||
|
||||
|
||||
typedef struct {
|
||||
char id[HAP_CTRL_ID_LEN];
|
||||
uint8_t ltpk[ED_KEY_LEN];
|
||||
uint8_t perms;
|
||||
} __attribute__((packed)) hap_ctrl_info_t;
|
||||
|
||||
typedef struct {
|
||||
hap_ctrl_info_t info;
|
||||
/* If "valid" is false, it means that the entry is invalid,
|
||||
* irrespective of the values of other members, and can be
|
||||
* used to store new controller info
|
||||
*/
|
||||
bool valid;
|
||||
/* Index is used just for better managing the keystore data */
|
||||
uint8_t index;
|
||||
} hap_ctrl_data_t;
|
||||
|
||||
int hap_controllers_init();
|
||||
bool is_accessory_paired();
|
||||
bool is_admin_paired();
|
||||
hap_ctrl_data_t *hap_controller_get_empty_loc();
|
||||
int hap_controller_save(hap_ctrl_data_t *ctrl_data);
|
||||
void hap_controller_remove(hap_ctrl_data_t *ctrl_data);
|
||||
hap_ctrl_data_t *hap_get_controller(char *ctrl_id);
|
||||
void hap_erase_controller_info();
|
||||
|
||||
#endif /* _HAP_CONTROLLERS_H_ */
|
|
@ -1,334 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sodium/crypto_sign_ed25519.h>
|
||||
#include <string.h>
|
||||
#include <hap_platform_memory.h>
|
||||
|
||||
#include <esp_mfi_rand.h>
|
||||
#include <esp_mfi_sha.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
#include <esp_hap_main.h>
|
||||
#include <esp_hap_keystore.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_hap_controllers.h>
|
||||
|
||||
#include <esp_mfi_base64.h>
|
||||
|
||||
#define HAP_KEY_ACC_ID "acc_id"
|
||||
#define HAP_KEY_LTSKA "ltska"
|
||||
#define HAP_KEY_LTPKA "ltpka"
|
||||
#define HAP_KEY_CONFIG_NUM "config_num"
|
||||
#define HAP_KEY_FW_REV "fw_rev"
|
||||
#define HAP_KEY_CUR_AID "cur_aid"
|
||||
#define HAP_KEY_STATE_NUM "state_num"
|
||||
|
||||
#define HAP_KEY_SETUP_ID "setup_id"
|
||||
#define HAP_KEY_SETUP_SALT "setup_salt"
|
||||
#define HAP_KEY_SETUP_VERIFIER "setup_verifier"
|
||||
|
||||
#define HAP_LOOP_STACK (4 * 1024)
|
||||
#define HAP_MAIN_THREAD_PRIORITY 7
|
||||
#define HAP_MAX_NOTIF_CHARS 8
|
||||
#define HAP_SOCK_RECV_TIMEOUT 10
|
||||
#define HAP_SOCK_SEND_TIMEOUT 10
|
||||
|
||||
hap_priv_t hap_priv = {
|
||||
.cfg = {
|
||||
.task_stack_size = HAP_LOOP_STACK,
|
||||
.task_priority = HAP_MAIN_THREAD_PRIORITY,
|
||||
.max_event_notif_chars = HAP_MAX_NOTIF_CHARS,
|
||||
.unique_param = UNIQUE_SSID,
|
||||
.recv_timeout = HAP_SOCK_RECV_TIMEOUT,
|
||||
.send_timeout = HAP_SOCK_SEND_TIMEOUT,
|
||||
.sw_token_max_len = HAP_SW_TOKEN_MAX_LEN,
|
||||
}
|
||||
};
|
||||
|
||||
static void hap_save_config_number()
|
||||
{
|
||||
|
||||
hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_CONFIG_NUM,
|
||||
(uint8_t *)&hap_priv.config_num, sizeof(hap_priv.config_num));
|
||||
}
|
||||
|
||||
static void hap_get_config_number()
|
||||
{
|
||||
size_t config_num_len = sizeof(hap_priv.config_num);
|
||||
if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_CONFIG_NUM,
|
||||
(uint8_t *)&hap_priv.config_num, &config_num_len) != HAP_SUCCESS) {
|
||||
hap_priv.config_num = 1;
|
||||
hap_save_config_number();
|
||||
}
|
||||
if (hap_priv.config_num > 65535) {
|
||||
hap_priv.config_num = 1;
|
||||
hap_save_config_number();
|
||||
}
|
||||
}
|
||||
|
||||
void hap_increment_and_save_config_num()
|
||||
{
|
||||
hap_priv.config_num++;
|
||||
if (hap_priv.config_num > 65535) {
|
||||
hap_priv.config_num = 1;
|
||||
}
|
||||
hap_save_config_number();
|
||||
}
|
||||
|
||||
|
||||
static void hap_save_state_number()
|
||||
{
|
||||
hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_STATE_NUM,
|
||||
(uint8_t *)&hap_priv.state_num, sizeof(hap_priv.state_num));
|
||||
}
|
||||
|
||||
void hap_increment_and_save_state_num()
|
||||
{
|
||||
if (is_accessory_paired()) {
|
||||
hap_priv.state_num++;
|
||||
/* If value becomes 0 after incrementing, it means that it has wrapped around.
|
||||
* So, reset to 1
|
||||
*/
|
||||
if (hap_priv.state_num == 0) {
|
||||
hap_priv.state_num = 1;
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Updated state number to %d", hap_priv.state_num);
|
||||
hap_save_state_number();
|
||||
}
|
||||
}
|
||||
|
||||
static void hap_init_state_number()
|
||||
{
|
||||
size_t state_num_len = sizeof(hap_priv.state_num);
|
||||
if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_STATE_NUM,
|
||||
(uint8_t *)&hap_priv.state_num, &state_num_len) != HAP_SUCCESS) {
|
||||
/* If state number is not found, initialise with 1 and store.
|
||||
*/
|
||||
hap_priv.state_num = 1;
|
||||
hap_save_state_number();
|
||||
} else {
|
||||
hap_increment_and_save_state_num();
|
||||
}
|
||||
}
|
||||
|
||||
static void hap_save_cur_aid()
|
||||
{
|
||||
hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_CUR_AID,
|
||||
(uint8_t *)&hap_priv.cur_aid, sizeof(hap_priv.cur_aid));
|
||||
}
|
||||
|
||||
static void hap_get_cur_aid()
|
||||
{
|
||||
size_t aid_len = sizeof(hap_priv.cur_aid);
|
||||
if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_CUR_AID,
|
||||
(uint8_t *)&hap_priv.cur_aid, &aid_len) != HAP_SUCCESS) {
|
||||
/* AID = 1 is reserved for Primary Accessory. So, we set the initial
|
||||
* value to 1, so that the bridged accessories get assigned aid from
|
||||
* 2 onwards
|
||||
*/
|
||||
hap_priv.cur_aid = 1;
|
||||
hap_save_cur_aid();
|
||||
}
|
||||
}
|
||||
|
||||
static int hap_get_setup_id()
|
||||
{
|
||||
/* Read setup id from NVS, only if it is not already set from the accessory code */
|
||||
if (!strlen(hap_priv.setup_id)) {
|
||||
size_t setup_id_len = sizeof(hap_priv.setup_id);
|
||||
if (hap_factory_keystore_get(HAP_FACTORY_NAMESPACE_HAP_SETUP, HAP_KEY_SETUP_ID,
|
||||
(uint8_t *)hap_priv.setup_id, &setup_id_len) != HAP_SUCCESS) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
static int hap_get_setup_info()
|
||||
{
|
||||
/* If the setup code has been set directly, no need to check for setup info */
|
||||
if (hap_priv.setup_code) {
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
/* If the setup info has been set externally, directly from the accessory code,
|
||||
* no need to check in the NVS
|
||||
*/
|
||||
if (!hap_priv.setup_info) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Getting setup info from factory NVS");
|
||||
hap_priv.setup_info = hap_platform_memory_calloc(1, sizeof(hap_setup_info_t));
|
||||
if (!hap_priv.setup_info)
|
||||
return HAP_FAIL;
|
||||
size_t salt_len = sizeof(hap_priv.setup_info->salt);
|
||||
size_t verifier_len = sizeof(hap_priv.setup_info->verifier);
|
||||
int ret = hap_factory_keystore_get(HAP_FACTORY_NAMESPACE_HAP_SETUP, HAP_KEY_SETUP_SALT,
|
||||
hap_priv.setup_info->salt, &salt_len);
|
||||
ret |= hap_factory_keystore_get(HAP_FACTORY_NAMESPACE_HAP_SETUP, HAP_KEY_SETUP_VERIFIER,
|
||||
hap_priv.setup_info->verifier, &verifier_len);
|
||||
if (ret != HAP_SUCCESS) {
|
||||
hap_platform_memory_free(hap_priv.setup_info);
|
||||
hap_priv.setup_info = NULL;
|
||||
return HAP_FAIL;
|
||||
}
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
static void hap_check_fw_version()
|
||||
{
|
||||
char fw_rev[64] = {0};
|
||||
size_t fw_rev_len = sizeof(fw_rev);
|
||||
/* Check if the firmware revision is stored in NVS */
|
||||
if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_FW_REV,
|
||||
(uint8_t *)fw_rev, &fw_rev_len) == HAP_SUCCESS) {
|
||||
/* If the firmware revision is found, compare with the current revision.
|
||||
* If it is the same, no need to do anything. So, just return
|
||||
*/
|
||||
if (strncmp(fw_rev, hap_priv.primary_acc.fw_rev, sizeof(fw_rev)) == 0) {
|
||||
return;
|
||||
} else {
|
||||
/* If there is a version mismatch, it means that the firmware was upgraded.
|
||||
* Update config number in that case
|
||||
*/
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "FW Update detected. Incrementing config number");
|
||||
hap_increment_and_save_config_num();
|
||||
}
|
||||
}
|
||||
/* Save the new firmare revision to NVS */
|
||||
hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_FW_REV,
|
||||
(uint8_t *)hap_priv.primary_acc.fw_rev,
|
||||
strlen(hap_priv.primary_acc.fw_rev));
|
||||
}
|
||||
|
||||
int hap_acc_setup_init()
|
||||
{
|
||||
if (hap_get_setup_id() != HAP_SUCCESS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Setup ID absent");
|
||||
return HAP_FAIL;
|
||||
} else {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Setup ID: %s", hap_priv.setup_id);
|
||||
}
|
||||
|
||||
if (hap_get_setup_info() != HAP_SUCCESS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Setup Info absent");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
uint8_t digest[MFI_SHA512_SIZE] = {0};
|
||||
esp_mfi_sha_ctx_t ctx = 0;
|
||||
ctx = esp_mfi_sha512_new();
|
||||
if (!ctx) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Out of Memory");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
/* Compute setup hash by taking a SHA512 hash of the setup id and device id */
|
||||
esp_mfi_sha512_init(ctx);
|
||||
esp_mfi_sha512_update(ctx, (const uint8_t *)hap_priv.setup_id, strlen(hap_priv.setup_id));
|
||||
esp_mfi_sha512_update(ctx, (const uint8_t *)hap_priv.acc_id, strlen(hap_priv.acc_id));
|
||||
esp_mfi_sha512_final(ctx, digest);
|
||||
/* Copy only the first 4 bytes as the setup hash */
|
||||
memcpy(hap_priv.setup_hash, digest, SETUP_HASH_LEN);
|
||||
esp_mfi_sha512_free(ctx);
|
||||
|
||||
int hash_size = sizeof(hap_priv.setup_hash_str);
|
||||
esp_mfi_base64_encode((const char *)hap_priv.setup_hash, SETUP_HASH_LEN,
|
||||
hap_priv.setup_hash_str, hash_size, &hash_size);
|
||||
|
||||
hap_check_fw_version();
|
||||
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_database_init(void)
|
||||
{
|
||||
uint8_t id[6];
|
||||
size_t val_size = sizeof(id);
|
||||
if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_ACC_ID, id, &val_size) == HAP_SUCCESS) {
|
||||
val_size = sizeof(hap_priv.ltska);
|
||||
hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_LTSKA, hap_priv.ltska, &val_size);
|
||||
val_size = sizeof(hap_priv.ltpka);
|
||||
hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_LTPKA, hap_priv.ltpka, &val_size);
|
||||
} else {
|
||||
/* If the accessory ID is not found in keystore, create and store a new random ID */
|
||||
esp_mfi_get_random(id, sizeof(id));
|
||||
hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_ACC_ID, id, sizeof(id));
|
||||
/* Also create a new ED25519 key pair */
|
||||
esp_mfi_get_random(hap_priv.ltska, sizeof(hap_priv.ltska));
|
||||
crypto_sign_ed25519_keypair(hap_priv.ltpka, hap_priv.ltska);
|
||||
hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_LTSKA, hap_priv.ltska, sizeof(hap_priv.ltska));
|
||||
hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_LTPKA, hap_priv.ltpka, sizeof(hap_priv.ltpka));
|
||||
}
|
||||
|
||||
memcpy(hap_priv.raw_acc_id, id, sizeof(hap_priv.raw_acc_id));
|
||||
snprintf(hap_priv.acc_id, sizeof(hap_priv.acc_id), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
id[0], id[1], id[2], id[3], id[4], id[5]);
|
||||
|
||||
hap_controllers_init();
|
||||
hap_get_config_number();
|
||||
hap_get_cur_aid();
|
||||
hap_init_state_number();
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Database initialised. Accessory Device ID: %s", hap_priv.acc_id);
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
char *hap_get_acc_id()
|
||||
{
|
||||
return hap_priv.acc_id;
|
||||
}
|
||||
|
||||
int hap_get_next_aid(char *id)
|
||||
{
|
||||
hap_priv.cur_aid++;
|
||||
hap_save_cur_aid();
|
||||
return hap_priv.cur_aid;
|
||||
}
|
||||
|
||||
void hap_erase_accessory_info()
|
||||
{
|
||||
hap_keystore_delete_namespace(HAP_KEYSTORE_NAMESPACE_HAPMAIN);
|
||||
}
|
||||
|
||||
void hap_configure_unique_param(hap_unique_param_t param)
|
||||
{
|
||||
hap_priv.cfg.unique_param = param;
|
||||
}
|
||||
|
||||
int hap_get_config(hap_cfg_t *cfg)
|
||||
{
|
||||
if (!cfg) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
*cfg = hap_priv.cfg;
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_set_config(const hap_cfg_t *cfg)
|
||||
{
|
||||
if (!cfg) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_priv.cfg = *cfg;
|
||||
return HAP_SUCCESS;
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_DATABASE_H_
|
||||
#define _HAP_DATABASE_H_
|
||||
|
||||
#include <hap.h>
|
||||
#include <esp_hap_controllers.h>
|
||||
#include <esp_hap_pair_common.h>
|
||||
#include <esp_hap_mdns.h>
|
||||
#include <esp_hap_secure_message.h>
|
||||
#include <esp_http_server.h>
|
||||
|
||||
#define HAP_KEYSTORE_NAMESPACE_HAPMAIN "hap_main"
|
||||
#define HAP_FACTORY_NAMESPACE_HAP_SETUP "hap_setup"
|
||||
|
||||
#define HAP_MAX_SESSIONS 8
|
||||
#define SETUP_ID_LEN 4
|
||||
#define SETUP_HASH_LEN 4
|
||||
|
||||
#define HAP_ACC_ID_LEN 18 /* AA:BB:CC:XX:YY:ZZ\0 */
|
||||
#define ED_KEY_LEN 32
|
||||
#define HAP_SW_TOKEN_MAX_LEN 1200
|
||||
|
||||
|
||||
typedef struct {
|
||||
hap_acc_cfg_t primary_acc;
|
||||
uint32_t config_num;
|
||||
uint32_t cur_aid;
|
||||
uint8_t raw_acc_id[6];
|
||||
char acc_id[HAP_ACC_ID_LEN];
|
||||
char setup_id[SETUP_ID_LEN + 1];
|
||||
uint8_t setup_hash[SETUP_HASH_LEN];
|
||||
char setup_hash_str[SETUP_HASH_LEN * 2 + 1];
|
||||
uint8_t ltska[ED_KEY_LEN];
|
||||
uint8_t ltpka[ED_KEY_LEN];
|
||||
hap_cid_t cid;
|
||||
hap_ctrl_data_t controllers[HAP_MAX_CONTROLLERS];
|
||||
hap_secure_session_t *sessions[HAP_MAX_SESSIONS];
|
||||
uint8_t pair_attempts;
|
||||
hap_mdns_handle_t wac_mdns_handle;
|
||||
hap_mdns_handle_t hap_mdns_handle;
|
||||
hap_setup_info_t *setup_info;
|
||||
char *setup_code;
|
||||
char *ssid;
|
||||
char *password;
|
||||
hap_software_token_info_t *token_info;
|
||||
uint8_t features;
|
||||
hap_event_handler_t hap_event_handler;
|
||||
char *softap_ssid;
|
||||
void (*ext_nw_prov_start)(void *data, const char *name);
|
||||
void (*ext_nw_prov_stop)(void *data);
|
||||
void *ext_nw_prov_data;
|
||||
hap_cfg_t cfg;
|
||||
hap_transport_t transport;
|
||||
uint32_t pairing_flags;
|
||||
httpd_handle_t server;
|
||||
uint8_t *product_data;
|
||||
uint16_t state_num;
|
||||
bool disconnected_event_sent;
|
||||
hap_mfi_auth_type_t auth_type;
|
||||
} hap_priv_t;
|
||||
|
||||
extern hap_priv_t hap_priv;
|
||||
int hap_database_init(void);
|
||||
char *hap_get_acc_id();
|
||||
int hap_get_next_aid();
|
||||
int hap_acc_setup_init();
|
||||
void hap_erase_accessory_info();
|
||||
void hap_increment_and_save_config_num();
|
||||
void hap_increment_and_save_state_num();
|
||||
#endif /* _HAP_DATABASE_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_IP_SERVICES_H_
|
||||
#define _HAP_IP_SERVICES_H_
|
||||
#include <stdbool.h>
|
||||
#include <esp_http_server.h>
|
||||
int hap_http_session_not_authorized(httpd_req_t *req);
|
||||
int hap_httpd_get_data(httpd_req_t *req, char *buffer, int len);
|
||||
int hap_httpd_start();
|
||||
int hap_ip_services_start();
|
||||
int hap_mdns_announce(bool first);
|
||||
int hap_mdns_deannounce();
|
||||
void hap_http_send_notif();
|
||||
#endif /* _HAP_IP_SERVICES_H_ */
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <hap.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
#include <hap_platform_keystore.h>
|
||||
|
||||
static bool keystore_init_done;
|
||||
static char *hap_platform_nvs_partition;
|
||||
static char *hap_platform_factory_nvs_partition;
|
||||
|
||||
int hap_keystore_init()
|
||||
{
|
||||
if (keystore_init_done) {
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
hap_platform_nvs_partition = hap_platform_keystore_get_nvs_partition_name();
|
||||
|
||||
// hap_platfrom_keystore_erase_partition(hap_platform_nvs_partition);
|
||||
|
||||
int err = hap_platform_keystore_init_partition(hap_platform_nvs_partition, false);
|
||||
if (err != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Error (%d) NVS init failed", err);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
/* Not cheking the return value, as this partition may be absent */
|
||||
hap_platform_factory_nvs_partition = hap_platform_keystore_get_factory_nvs_partition_name();
|
||||
hap_platform_keystore_init_partition(hap_platform_factory_nvs_partition, true);
|
||||
|
||||
keystore_init_done = true;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Keystore initialised");
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int __hap_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size)
|
||||
{
|
||||
if (!keystore_init_done) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int err = hap_platform_keystore_get(part_name, name_space, key, val, val_size);
|
||||
if (err != 0) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
int hap_keystore_get(const char *name_space, const char *key, uint8_t *val, size_t *val_size)
|
||||
{
|
||||
|
||||
return __hap_keystore_get(hap_platform_nvs_partition, name_space, key, val, val_size);
|
||||
}
|
||||
int hap_factory_keystore_get(const char *name_space, const char *key, uint8_t *val, size_t *val_size)
|
||||
{
|
||||
return __hap_keystore_get(hap_platform_factory_nvs_partition, name_space, key, val, val_size);
|
||||
}
|
||||
|
||||
int __hap_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len)
|
||||
|
||||
{
|
||||
if (!keystore_init_done) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int err = hap_platform_keystore_set(part_name, name_space, key, val, val_len);
|
||||
if (err != 0) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_keystore_set(const char *name_space, const char *key, const uint8_t *val, const size_t val_len)
|
||||
{
|
||||
return __hap_keystore_set(hap_platform_nvs_partition, name_space, key, val, val_len);
|
||||
}
|
||||
|
||||
int hap_factory_keystore_set(const char *name_space, const char *key, const uint8_t *val, const size_t val_len)
|
||||
{
|
||||
return __hap_keystore_set(hap_platform_factory_nvs_partition, name_space, key, val, val_len);
|
||||
}
|
||||
|
||||
int hap_keystore_delete(const char *name_space, const char *key)
|
||||
{
|
||||
if (!keystore_init_done) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int err = hap_platform_keystore_delete(hap_platform_nvs_partition, name_space, key);
|
||||
if (err != 0) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_keystore_delete_namespace(const char *name_space)
|
||||
{
|
||||
if (!keystore_init_done) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int err = hap_platform_keystore_delete_namespace(hap_platform_nvs_partition, name_space);
|
||||
if (err != 0) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
void hap_keystore_erase_all_data()
|
||||
{
|
||||
hap_platfrom_keystore_erase_partition(hap_platform_nvs_partition);
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_KEYSTORE_H_
|
||||
#define _HAP_KEYSTORE_H_
|
||||
#include <hap.h>
|
||||
int hap_keystore_init();
|
||||
int hap_keystore_get(const char *name_space, const char *key, uint8_t *val, size_t *val_size);
|
||||
int hap_keystore_set(const char *name_space, const char *key, const uint8_t *val, const size_t val_len);
|
||||
int hap_keystore_delete(const char *name_space, const char *key);
|
||||
int hap_keystore_delete_namespace(const char *name_space);
|
||||
int hap_factory_keystore_set(const char *name_space, const char *key, const uint8_t *val, const size_t val_len);
|
||||
void hap_keystore_erase_all_data();
|
||||
#endif /* _HAP_KEYSTORE_H_ */
|
|
@ -1,379 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_wifi.h>
|
||||
|
||||
#include <esp_mfi_debug.h>
|
||||
#include <esp_hap_acc.h>
|
||||
#include <esp_hap_char.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_hap_ip_services.h>
|
||||
#include <esp_hap_wifi.h>
|
||||
#include <esp_hap_mdns.h>
|
||||
#include <esp_hap_keystore.h>
|
||||
#include <esp_hap_main.h>
|
||||
#include <esp_hap_wac.h>
|
||||
#include <esp_hap_bct_priv.h>
|
||||
#include <esp_hap_pair_verify.h>
|
||||
#include <hap_platform_os.h>
|
||||
#include <_esp_hap_config.h>
|
||||
#include <hap_platform_httpd.h>
|
||||
#include <esp_hap_ip_services.h>
|
||||
|
||||
static QueueHandle_t xQueue;
|
||||
ESP_EVENT_DEFINE_BASE(HAP_EVENT);
|
||||
// static TaskHandle_t hap_loop_handle;
|
||||
|
||||
const char * hap_get_version(void)
|
||||
{
|
||||
return MFI_VER;
|
||||
}
|
||||
static void hap_nw_configured_sm(hap_internal_event_t event, hap_state_t *state)
|
||||
{
|
||||
switch (event) {
|
||||
case HAP_INTERNAL_EVENT_ACC_PAIRED:
|
||||
hap_mdns_announce(false);
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_ACC_UNPAIRED:
|
||||
hap_mdns_announce(false);
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_CONFIG_NUM_UPDATED:
|
||||
hap_increment_and_save_config_num();
|
||||
hap_mdns_announce(false);
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_BCT_CHANGE_NAME:
|
||||
/* Waiting for sometime to allow the response to reach the host */
|
||||
vTaskDelay(1000 / hap_platform_os_get_msec_per_tick());
|
||||
hap_handle_bct_change_name();
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_BCT_HOT_PLUG:
|
||||
/* Waiting for sometime to allow the response to reach the host */
|
||||
vTaskDelay(1000 / hap_platform_os_get_msec_per_tick());
|
||||
hap_handle_hot_plug();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hap_common_sm(hap_internal_event_t event)
|
||||
{
|
||||
const char *reboot_reason = HAP_REBOOT_REASON_UNKNOWN;
|
||||
switch (event) {
|
||||
case HAP_INTERNAL_EVENT_RESET_PAIRINGS:
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting all Pairing Information");
|
||||
/* Wait for some time before erasing the information, so that the callee
|
||||
* gets some time for any additional operations
|
||||
*/
|
||||
vTaskDelay(1000 / hap_platform_os_get_msec_per_tick());
|
||||
hap_close_all_sessions();
|
||||
hap_mdns_deannounce();
|
||||
hap_erase_controller_info();
|
||||
hap_erase_accessory_info();
|
||||
reboot_reason = HAP_REBOOT_REASON_RESET_PAIRINGS;
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_RESET_TO_FACTORY:
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting to Factory Defaults");
|
||||
/* Wait for some time before erasing the information, so that the callee
|
||||
* gets some time for any additional operations
|
||||
*/
|
||||
vTaskDelay(1000 / hap_platform_os_get_msec_per_tick());
|
||||
hap_close_all_sessions();
|
||||
hap_mdns_deannounce();
|
||||
hap_keystore_erase_all_data();
|
||||
reboot_reason = HAP_REBOOT_REASON_RESET_TO_FACTORY;
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_RESET_HOMEKIT_DATA:
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting all HomeKit Data");
|
||||
/* Wait for some time before erasing the information, so that the callee
|
||||
* gets some time for any additional operations
|
||||
*/
|
||||
vTaskDelay(1000 / hap_platform_os_get_msec_per_tick());
|
||||
hap_close_all_sessions();
|
||||
hap_mdns_deannounce();
|
||||
hap_erase_controller_info();
|
||||
hap_erase_network_info();
|
||||
hap_erase_accessory_info();
|
||||
reboot_reason = HAP_REBOOT_REASON_RESET_HOMEKIT_DATA;
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_REBOOT:
|
||||
vTaskDelay(1000 / hap_platform_os_get_msec_per_tick());
|
||||
/* Wait for some time and then close all the active sessions
|
||||
*/
|
||||
hap_close_all_sessions();
|
||||
hap_mdns_deannounce();
|
||||
reboot_reason = HAP_REBOOT_REASON_REBOOT_ACC;
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_RESET_NETWORK:
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting Network Credentials");
|
||||
/* Wait for some time, close all the active sessions and then
|
||||
* erase network info.
|
||||
*/
|
||||
vTaskDelay(1000 / hap_platform_os_get_msec_per_tick());
|
||||
hap_close_all_sessions();
|
||||
hap_mdns_deannounce();
|
||||
hap_erase_network_info();
|
||||
reboot_reason = HAP_REBOOT_REASON_RESET_NETWORK;
|
||||
break;
|
||||
case HAP_INTERNAL_EVENT_TRIGGER_NOTIF:
|
||||
/* TODO: Avoid direct http function. Notification could be even for iCloud or BLE.
|
||||
*/
|
||||
hap_http_send_notif();
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for some time after peeforming the operations and then reboot */
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Rebooting...");
|
||||
hap_report_event(HAP_EVENT_ACC_REBOOTING, (void*)reboot_reason, strlen(reboot_reason) + 1);
|
||||
vTaskDelay(1000 / hap_platform_os_get_msec_per_tick());
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
static void hap_loop_task(void *param)
|
||||
{
|
||||
hap_state_t cur_state = HAP_STATE_NONE;
|
||||
xQueue = xQueueCreate( 10, sizeof(hap_event_ctx_t) );
|
||||
hap_event_ctx_t hap_event;
|
||||
bool loop_continue = true;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HAP Main Loop Started");
|
||||
while (loop_continue) {
|
||||
if (xQueueReceive(xQueue, &hap_event, portMAX_DELAY) != pdTRUE) {
|
||||
continue;
|
||||
}
|
||||
if (hap_event.event == HAP_INTERNAL_EVENT_LOOP_STOP) {
|
||||
loop_continue = false;
|
||||
continue;
|
||||
}
|
||||
hap_common_sm(hap_event.event);
|
||||
hap_nw_configured_sm(hap_event.event, &cur_state);
|
||||
}
|
||||
vQueueDelete(xQueue);
|
||||
xQueue = NULL;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static bool loop_started;
|
||||
int hap_loop_start()
|
||||
{
|
||||
if (!loop_started) {
|
||||
loop_started = true;
|
||||
xTaskCreate(hap_loop_task, "hap-loop", hap_priv.cfg.task_stack_size, NULL,
|
||||
hap_priv.cfg.task_priority, NULL);
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
bool is_hap_loop_started()
|
||||
{
|
||||
return loop_started;
|
||||
}
|
||||
int hap_send_event(hap_internal_event_t event)
|
||||
{
|
||||
if (!is_hap_loop_started()) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if (!xQueue) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_event_ctx_t hap_event = {
|
||||
.event = event,
|
||||
};
|
||||
BaseType_t ret;
|
||||
if (xPortInIsrContext() == pdTRUE) {
|
||||
ret = xQueueSendFromISR(xQueue, &hap_event, NULL);
|
||||
} else {
|
||||
ret = xQueueSend(xQueue, &hap_event, 0);
|
||||
}
|
||||
if (ret == pdTRUE) {
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int hap_update_config_number()
|
||||
{
|
||||
return hap_send_event(HAP_INTERNAL_EVENT_CONFIG_NUM_UPDATED);
|
||||
}
|
||||
|
||||
int hap_loop_stop()
|
||||
{
|
||||
return hap_send_event(HAP_INTERNAL_EVENT_LOOP_STOP);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void hap_network_event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
if (((event_base == WIFI_EVENT) && (event_id == WIFI_EVENT_STA_CONNECTED)) ||
|
||||
((event_base == ETH_EVENT) && (event_id == ETHERNET_EVENT_CONNECTED))){
|
||||
hap_send_event(HAP_INTERNAL_EVENT_NETWORK_CONNECTED);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
int hap_init(hap_transport_t method)
|
||||
{
|
||||
int ret = HAP_SUCCESS;
|
||||
if (!(method & (HAP_TRANSPORT_WIFI | HAP_TRANSPORT_ETHERNET))) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid Transport");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
hap_priv.transport = method;
|
||||
|
||||
ret = hap_keystore_init();
|
||||
if (ret != 0 ) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP Key Store Init failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hap_database_init();
|
||||
if (ret != 0 ) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP Database Init failed");
|
||||
return ret;
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HAP Initialization succeeded. Version : %s", hap_get_version());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hap_deinit(void)
|
||||
{
|
||||
int ret = HAP_SUCCESS;
|
||||
//todo
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hap_reset_to_factory()
|
||||
{
|
||||
return hap_send_event(HAP_INTERNAL_EVENT_RESET_TO_FACTORY);
|
||||
}
|
||||
|
||||
int hap_reset_homekit_data()
|
||||
{
|
||||
return hap_send_event(HAP_INTERNAL_EVENT_RESET_HOMEKIT_DATA);
|
||||
}
|
||||
|
||||
int hap_reset_pairings()
|
||||
{
|
||||
return hap_send_event(HAP_INTERNAL_EVENT_RESET_PAIRINGS);
|
||||
}
|
||||
|
||||
int hap_reboot_accessory()
|
||||
{
|
||||
return hap_send_event(HAP_INTERNAL_EVENT_REBOOT);
|
||||
}
|
||||
|
||||
int hap_reset_network()
|
||||
{
|
||||
return hap_send_event(HAP_INTERNAL_EVENT_RESET_NETWORK);
|
||||
}
|
||||
|
||||
int hap_start(void)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef CONFIG_HAP_MFI_ENABLE
|
||||
if (hap_priv.auth_type == HAP_MFI_AUTH_HW) {
|
||||
ret = hap_enable_hw_auth();
|
||||
} else if (hap_priv.auth_type == HAP_MFI_AUTH_SW) {
|
||||
ret = hap_enable_sw_auth();
|
||||
}
|
||||
#endif /* CONFIG_HAP_MFI_ENABLE */
|
||||
if (ret != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to enable MFi %s authentication",
|
||||
hap_priv.auth_type == HAP_MFI_AUTH_HW ? "HW" : "SW");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
if (!hap_get_first_acc()) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to start HAP. Please add an Accessory before hap_start()");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
ret = hap_acc_setup_init();
|
||||
if (ret != HAP_SUCCESS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Accessory Setup init failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hap_httpd_start();
|
||||
if (ret != HAP_SUCCESS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HTTPD START Failed [%d]", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hap_event_queue_init();
|
||||
if (ret != HAP_SUCCESS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Queue Initialisation for Event Notifications Failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hap_loop_start();
|
||||
if (ret != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP Loop Failed: [%d]", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = hap_mdns_init();
|
||||
if (ret != 0 ) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP mDNS Init failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hap_ip_services_start();
|
||||
if (ret != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP IP Services Start Failed [%d]", ret);
|
||||
return ret;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_stop(void)
|
||||
{
|
||||
int ret = HAP_SUCCESS;
|
||||
hap_mdns_deannounce();
|
||||
hap_mdns_deinit();
|
||||
httpd_handle_t _handle = hap_platform_httpd_get_handle();
|
||||
if(_handle != NULL) hap_platform_httpd_stop(_handle);
|
||||
ret = hap_loop_stop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hap_report_event(hap_event_t event, void *data, size_t data_size)
|
||||
{
|
||||
if (hap_priv.hap_event_handler) {
|
||||
hap_priv.hap_event_handler(event, data);
|
||||
}
|
||||
esp_event_post(HAP_EVENT, event, data, data_size, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void hap_register_event_handler(hap_event_handler_t handler)
|
||||
{
|
||||
hap_priv.hap_event_handler = handler;
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HAP_MAIN_LOOP_H_
|
||||
#define _HAP_MAIN_LOOP_H_
|
||||
#include <stdbool.h>
|
||||
#include <hap.h>
|
||||
|
||||
#define HAP_FF_HARDWARE_AUTH 0x01
|
||||
#define HAP_FF_SW_TOKEN_AUTH 0x02
|
||||
|
||||
|
||||
#define HAP_SF_ACC_UNPAIRED 0x01
|
||||
#define HAP_SF_ACC_UNCONFIGURED 0x02
|
||||
#define HAP_SF_PROBLEM_DETECTED 0x04
|
||||
|
||||
typedef enum {
|
||||
HAP_INTERNAL_EVENT_LOOP_STOP = 1,
|
||||
HAP_INTERNAL_EVENT_ACC_PAIRED,
|
||||
HAP_INTERNAL_EVENT_ACC_UNPAIRED,
|
||||
HAP_INTERNAL_EVENT_CONFIG_NUM_UPDATED,
|
||||
HAP_INTERNAL_EVENT_BCT_CHANGE_NAME,
|
||||
HAP_INTERNAL_EVENT_BCT_HOT_PLUG,
|
||||
HAP_INTERNAL_EVENT_RESET_PAIRINGS,
|
||||
HAP_INTERNAL_EVENT_RESET_TO_FACTORY,
|
||||
HAP_INTERNAL_EVENT_REBOOT,
|
||||
HAP_INTERNAL_EVENT_RESET_NETWORK,
|
||||
HAP_INTERNAL_EVENT_TRIGGER_NOTIF,
|
||||
HAP_INTERNAL_EVENT_RESET_HOMEKIT_DATA,
|
||||
} hap_internal_event_t;
|
||||
|
||||
typedef struct {
|
||||
hap_internal_event_t event;
|
||||
} hap_event_ctx_t;
|
||||
|
||||
typedef enum {
|
||||
HAP_STATE_NONE = 0,
|
||||
HAP_STATE_NW_UNCONFIGURED,
|
||||
HAP_STATE_NW_CONFIGURED,
|
||||
} hap_state_t;
|
||||
|
||||
int hap_loop_start();
|
||||
int hap_loop_stop();
|
||||
int hap_send_event(hap_internal_event_t event);
|
||||
int hap_update_config_number();
|
||||
bool is_hap_loop_started();
|
||||
void hap_report_event(hap_event_t event, void *data, size_t data_size);
|
||||
int hap_enable_hw_auth(void);
|
||||
int hap_enable_sw_auth(void);
|
||||
|
||||
#endif /* _HAP_MAIN_LOOP_H_ */
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <esp_hap_mdns.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
static bool mdns_init_done;
|
||||
|
||||
int hap_mdns_serv_start(hap_mdns_handle_t *handle, const char *name, const char *type,
|
||||
const char *protocol, int port, mdns_txt_item_t *txt_records, size_t num_txt)
|
||||
{
|
||||
strcpy(handle->type, type);
|
||||
strcpy(handle->proto, protocol);
|
||||
if (mdns_service_add(name, type, protocol, port, txt_records, num_txt) != 0) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_mdns_serv_update_txt(hap_mdns_handle_t *handle, mdns_txt_item_t *txt_records, size_t num_txt)
|
||||
{
|
||||
if (mdns_service_txt_set(handle->type, handle->proto, txt_records, num_txt) != 0) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_mdns_serv_name_change(hap_mdns_handle_t *handle, const char * instance_name)
|
||||
{
|
||||
if (mdns_service_instance_name_set(handle->type, handle->proto, instance_name) == ESP_OK) {
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int hap_mdns_serv_stop(hap_mdns_handle_t *handle)
|
||||
{
|
||||
if (mdns_service_remove(handle->type, handle->proto) == ESP_OK) {
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int hap_mdns_init()
|
||||
{
|
||||
int ret = HAP_SUCCESS;
|
||||
if (!mdns_init_done) {
|
||||
ret = mdns_init();
|
||||
if (ret == ESP_OK) {
|
||||
mdns_hostname_set("MyHost");
|
||||
mdns_init_done = true;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "mDNS initialised");
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
}
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int hap_mdns_deinit()
|
||||
{
|
||||
mdns_free();
|
||||
mdns_init_done = false;
|
||||
return HAP_SUCCESS;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_MDNS_H_
|
||||
#define _HAP_MDNS_H_
|
||||
|
||||
#include <mdns.h>
|
||||
#include <hap.h>
|
||||
|
||||
typedef struct {
|
||||
char type[32];
|
||||
char proto[32];
|
||||
} hap_mdns_handle_t;
|
||||
|
||||
int hap_mdns_serv_start(hap_mdns_handle_t *handle, const char *name, const char *type,
|
||||
const char *protocol, int port, mdns_txt_item_t *txt_records, size_t num_txt);
|
||||
int hap_mdns_serv_update_txt(hap_mdns_handle_t *handle, mdns_txt_item_t *txt_records, size_t num_txt);
|
||||
int hap_mdns_serv_name_change(hap_mdns_handle_t *handle, const char * instance_name);
|
||||
int hap_mdns_serv_stop(hap_mdns_handle_t *handle);
|
||||
int hap_mdns_init();
|
||||
int hap_mdns_deinit();
|
||||
|
||||
#endif /* _HAP_MDNS_H_ */
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <sodium/crypto_aead_chacha20poly1305.h>
|
||||
#include <byte_convert.h>
|
||||
|
||||
#include <esp_mfi_debug.h>
|
||||
#include <hap.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_hap_pair_common.h>
|
||||
#include <esp_hap_pair_verify.h>
|
||||
|
||||
#define HAP_MAX_NW_FRAME_SIZE 1024 /* As per HAP Specifications */
|
||||
#define AUTH_TAG_LEN 16
|
||||
typedef struct {
|
||||
uint8_t pkt_size[2];
|
||||
uint8_t data[HAP_MAX_NW_FRAME_SIZE];
|
||||
/* The Poly auth tag buffer will get used only if the data length is
|
||||
* greater than HAP_MAX_NW_FRAME_SIZE - 16.
|
||||
* Else, the auth tag would be included in the data buffer itself
|
||||
*/
|
||||
uint8_t poly_auth_tag[AUTH_TAG_LEN];
|
||||
} hap_encrypt_frame_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t pkt_size;
|
||||
uint16_t bytes_read;
|
||||
uint8_t data[HAP_MAX_NW_FRAME_SIZE + AUTH_TAG_LEN];
|
||||
hap_secure_session_t *session;
|
||||
} hap_decrypt_frame_t;
|
||||
|
||||
typedef int (*hap_decrypt_read_fn_t) (uint8_t *buf, int buf_size, void *context);
|
||||
static int min(int val1, int val2)
|
||||
{
|
||||
if (val1 < val2)
|
||||
return val1;
|
||||
return val2;
|
||||
}
|
||||
static int hap_httpd_raw_recv(uint8_t *buf, int buf_size, void *context)
|
||||
{
|
||||
int sock = *((int *)context);
|
||||
return recv(sock, buf, buf_size, 0);
|
||||
}
|
||||
|
||||
/* Frame format as per HAP Specifications:
|
||||
* <2: AAD for Little Endian length of encrypted data (n) in bytes>
|
||||
* <n: Encrypted data according to AEAD algorithm, upto 1024 bytes>
|
||||
* <16: authTag according to AEAD algorithm>
|
||||
*/
|
||||
int hap_encrypt_data(hap_encrypt_frame_t *frame, hap_secure_session_t *session,
|
||||
uint8_t *buf, int buflen)
|
||||
{
|
||||
if (!session)
|
||||
return HAP_FAIL;
|
||||
put_u16_le(frame->pkt_size, buflen);
|
||||
/* Encrypt the received data as per Chacha20-Poly1305 AEAD algorithm.
|
||||
* The authTag will be appended at the end of data. Hence, pointer given as
|
||||
* frame->data + nlen
|
||||
*/
|
||||
unsigned long long mlen = 16;
|
||||
uint8_t newnonce[12];
|
||||
memset(newnonce, 0, sizeof newnonce);
|
||||
memcpy(newnonce+4, session->encrypt_nonce, 8);
|
||||
crypto_aead_chacha20poly1305_ietf_encrypt_detached(frame->data, frame->data + buflen, &mlen,
|
||||
buf, buflen, frame->pkt_size, 2, NULL, newnonce, session->encrypt_key);
|
||||
|
||||
/* Increment nonce after every frame */
|
||||
uint64_t int_nonce = get_u64_le(session->encrypt_nonce);
|
||||
int_nonce++;
|
||||
put_u64_le(session->encrypt_nonce, int_nonce);
|
||||
return 2 + buflen + 16; /* Total length of the encrypted data */
|
||||
}
|
||||
|
||||
#include <esp_hap_main.h>
|
||||
void hap_close_ctrl_sessions_fix(hap_secure_session_t *session)
|
||||
{
|
||||
if (!session)
|
||||
return;
|
||||
int i;
|
||||
printf("---- hap_close_ctrl_sessions_fix begin -----\n");
|
||||
for (i = 0; i < HAP_MAX_SESSIONS; i++) {
|
||||
if (!hap_priv.sessions[i])
|
||||
continue;
|
||||
if (hap_priv.sessions[i] == session) {
|
||||
hap_report_event(HAP_EVENT_CTRL_DISCONNECTED, (session->ctrl->info.id),
|
||||
sizeof((session->ctrl->info.id)));
|
||||
/* TODO: Use some generic function and not a direct HTTPD function
|
||||
*/
|
||||
printf("---- trigger_close fd: %d\n", hap_priv.sessions[i]->conn_identifier);
|
||||
httpd_sess_trigger_close(hap_priv.server, hap_priv.sessions[i]->conn_identifier);
|
||||
}
|
||||
}
|
||||
printf("---- hap_close_ctrl_sessions_fix end ----\n");
|
||||
}
|
||||
|
||||
int hap_decrypt_error(hap_secure_session_t *session)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Decryption error/Connection lost. Marking session as invalid");
|
||||
if (session) {
|
||||
session->state = STATE_INVALID;
|
||||
//hap_close_ctrl_sessions(session->ctrl);
|
||||
hap_close_ctrl_sessions_fix(session);
|
||||
}
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int hap_decrypt_data(hap_decrypt_frame_t *frame, hap_secure_session_t *session,
|
||||
void *buf, int buf_size, hap_decrypt_read_fn_t read_fn, void *context)
|
||||
{
|
||||
if (!frame || !session)
|
||||
return -1;
|
||||
if (frame->session != session) {
|
||||
memset(frame, 0, sizeof(hap_decrypt_frame_t));
|
||||
frame->session = session;
|
||||
}
|
||||
if ((frame->pkt_size - frame->bytes_read) == 0) {
|
||||
int len = read_fn(frame->data, 2, context);
|
||||
if (len == 0) { //nothing received, but we should NOT consider this is a 'decrypt_error'
|
||||
return 0;
|
||||
}
|
||||
if (len < 2) {
|
||||
//len is -1 or 1
|
||||
//len = -1: socket disconnected
|
||||
//len = 1: try receiving 2 bytes timeout (SO_RCVTIMEO is set in esp_hap_ip_services.c)
|
||||
printf("---- error 1 ----, len: %d\n", len);
|
||||
//Decryption error/Connection lost on ESP32 with multiple Apple devices running Home
|
||||
//https://github.com/espressif/esp-homekit-sdk/issues/14
|
||||
//---- error 1 ----, len: 0
|
||||
return hap_decrypt_error(session);
|
||||
}
|
||||
|
||||
frame->pkt_size = get_u16_le(frame->data);
|
||||
frame->bytes_read = 0;
|
||||
uint16_t bytes_to_read = frame->pkt_size + AUTH_TAG_LEN; /* +AUTH_TAG_LEN as the receivedd packet will also have the auth Tag */
|
||||
while (bytes_to_read) {
|
||||
int num_bytes = read_fn(&frame->data[frame->bytes_read],
|
||||
bytes_to_read, context);
|
||||
if (num_bytes <= 0) {
|
||||
printf("---- error 2 ----\n");
|
||||
return hap_decrypt_error(session);
|
||||
}
|
||||
bytes_to_read -= num_bytes;
|
||||
frame->bytes_read += num_bytes;
|
||||
}
|
||||
frame->bytes_read -= AUTH_TAG_LEN; /* -AUTH_TAG_LEN to get only the data length */
|
||||
uint8_t aad[2];
|
||||
int ret;
|
||||
put_u16_le(aad, frame->pkt_size); /* Packet size is the AAD for AEAD */
|
||||
uint8_t newnonce[12];
|
||||
memset(newnonce, 0, sizeof newnonce);
|
||||
memcpy(newnonce+4, session->decrypt_nonce, 8);
|
||||
ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached(frame->data, NULL, frame->data, frame->pkt_size,
|
||||
&frame->data[frame->bytes_read], aad, 2, newnonce, session->decrypt_key);
|
||||
if (ret != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "AEAD decryption failure");
|
||||
printf("---- error 3 ----\n");
|
||||
return hap_decrypt_error(session);
|
||||
}
|
||||
frame->bytes_read = 0;
|
||||
/* Increment nonce after every frame */
|
||||
int64_t int_nonce = get_u64_le(session->decrypt_nonce);
|
||||
int_nonce++;
|
||||
put_u64_le(session->decrypt_nonce, int_nonce);
|
||||
}
|
||||
int bytes = min(frame->pkt_size - frame->bytes_read, buf_size);
|
||||
memcpy(buf, &frame->data[frame->bytes_read], bytes);
|
||||
frame->bytes_read += bytes;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int hap_httpd_send(httpd_handle_t hd, int sockfd, const char *buf, unsigned buf_len, int flags)
|
||||
{
|
||||
hap_secure_session_t *session = httpd_sess_get_ctx(hap_priv.server, sockfd);
|
||||
if (session && (session->state == STATE_VERIFIED)) {
|
||||
uint8_t *buf_ptr = (uint8_t *)buf;
|
||||
int tmp_buf_len = buf_len;
|
||||
while (tmp_buf_len) {
|
||||
hap_encrypt_frame_t encrypt_frame;
|
||||
memset(&encrypt_frame, 0, sizeof(encrypt_frame));
|
||||
int len = min(tmp_buf_len, HAP_MAX_NW_FRAME_SIZE);
|
||||
int send_len = hap_encrypt_data(&encrypt_frame, session, buf_ptr, len);
|
||||
if (send(sockfd, (uint8_t *)&encrypt_frame, send_len, flags) <= 0)
|
||||
return HAP_FAIL;
|
||||
tmp_buf_len -= len;
|
||||
buf_ptr += len;
|
||||
}
|
||||
/* Return the total length at the end since this API expects so
|
||||
*/
|
||||
return buf_len;
|
||||
}
|
||||
return send(sockfd, buf, buf_len, flags);
|
||||
}
|
||||
|
||||
int hap_httpd_recv(httpd_handle_t hd, int sockfd, char *buf, unsigned buf_len, int flags)
|
||||
{
|
||||
static hap_decrypt_frame_t decrypt_frame;
|
||||
hap_secure_session_t *session = httpd_sess_get_ctx(hap_priv.server, sockfd);
|
||||
if (session) {
|
||||
if (session->state == STATE_VERIFIED) {
|
||||
return hap_decrypt_data(&decrypt_frame, session, buf, buf_len,
|
||||
hap_httpd_raw_recv, &sockfd);
|
||||
} else {
|
||||
/* If the session state is invalid, we return an error.
|
||||
* The errno is set here explicitly, so that even if the higher layers
|
||||
* query for it, they do not get a stale value.
|
||||
* EACCES means permission denied, which indeed is the case here.
|
||||
*/
|
||||
errno = EACCES;
|
||||
return HAP_FAIL;
|
||||
}
|
||||
}
|
||||
return recv(sockfd, buf, buf_len, sockfd);
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_NETWORK_IO_H_
|
||||
#define _HAP_NETWORK_IO_H_
|
||||
#include <stdint.h>
|
||||
#include <hap_platform_httpd.h>
|
||||
int hap_httpd_send(httpd_handle_t hd, int sockfd, const char *buf, unsigned buf_len, int flags);
|
||||
int hap_httpd_recv(httpd_handle_t hd, int sockfd, char *buf, unsigned buf_len, int flags);
|
||||
|
||||
#endif /* _HAP_NETWORK_IO_H_ */
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <esp_hap_pair_common.h>
|
||||
|
||||
void hap_tlv_data_init(hap_tlv_data_t *tlv_data, uint8_t *buf, int buf_size)
|
||||
{
|
||||
tlv_data->bufptr = buf;
|
||||
tlv_data->bufsize = buf_size;
|
||||
tlv_data->curlen = 0;
|
||||
}
|
||||
|
||||
int get_tlv_length(uint8_t *buf, int buflen, uint8_t type)
|
||||
{
|
||||
if (!buf )
|
||||
return -1;
|
||||
int curlen = 0;
|
||||
int val_len = 0;
|
||||
bool found = false;
|
||||
while (buflen > 0) {
|
||||
if (buf[curlen] == type) {
|
||||
uint8_t len = buf[curlen + 1];
|
||||
if ((buflen - len) < 2)
|
||||
return -1;
|
||||
val_len += len;
|
||||
if (len < 255)
|
||||
return val_len;
|
||||
else
|
||||
found = true;
|
||||
|
||||
} else if (found)
|
||||
return val_len;
|
||||
|
||||
/* buf[curlen +1] will give the Length */
|
||||
buflen -= (2 + buf[curlen + 1]);
|
||||
curlen += (2 + buf[curlen + 1]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int get_value_from_tlv(uint8_t *buf, int buflen, uint8_t type, void *val, int val_size)
|
||||
{
|
||||
if (!buf || !val)
|
||||
return -1;
|
||||
int curlen = 0;
|
||||
int val_len = 0;
|
||||
bool found = false;
|
||||
while (buflen > 0) {
|
||||
if (buf[curlen] == type) {
|
||||
uint8_t len = buf[curlen + 1];
|
||||
if ((val_size < len) || ((buflen - len) < 2))
|
||||
return -1;
|
||||
memcpy(val + val_len, &buf[curlen + 2], len);
|
||||
val_len += len;
|
||||
val_size -= len;
|
||||
if (len < 255)
|
||||
return val_len;
|
||||
else
|
||||
found = true;
|
||||
|
||||
} else if (found)
|
||||
return val_len;
|
||||
|
||||
/* buf[curlen +1] will give the Length */
|
||||
buflen -= (2 + buf[curlen + 1]);
|
||||
curlen += (2 + buf[curlen + 1]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int add_tlv(hap_tlv_data_t *tlv_data, uint8_t type, int len, void *val)
|
||||
{
|
||||
if(!tlv_data->bufptr || ((len + 2) > (tlv_data->bufsize - tlv_data->curlen)))
|
||||
return -1;
|
||||
uint8_t *buf_ptr = (uint8_t *)val;
|
||||
int orig_len = tlv_data->curlen;
|
||||
do {
|
||||
tlv_data->bufptr[tlv_data->curlen++] = type;
|
||||
int tmp_len;
|
||||
if (len > 255)
|
||||
tmp_len = 255;
|
||||
else
|
||||
tmp_len = len;
|
||||
tlv_data->bufptr[tlv_data->curlen++] = tmp_len;
|
||||
memcpy(&tlv_data->bufptr[tlv_data->curlen], buf_ptr, tmp_len);
|
||||
tlv_data->curlen += tmp_len;
|
||||
buf_ptr += tmp_len;
|
||||
len -= tmp_len;
|
||||
} while (len);
|
||||
return tlv_data->curlen - orig_len;
|
||||
}
|
||||
void hap_prepare_error_tlv(uint8_t state, uint8_t error, void *buf, int bufsize, int *outlen)
|
||||
{
|
||||
hap_tlv_data_t tlv_data;
|
||||
tlv_data.bufptr = buf;
|
||||
tlv_data.bufsize = bufsize;
|
||||
tlv_data.curlen = 0;
|
||||
/* Not doing any error handling because the size required for "state" and "error" will
|
||||
* be too small to cause any error, and we anyways dont have any specific action to
|
||||
* do in case if error in add_tlv()
|
||||
*/
|
||||
add_tlv(&tlv_data, kTLVType_State, sizeof(state), &state);
|
||||
add_tlv(&tlv_data, kTLVType_Error, sizeof(error), &error);
|
||||
*outlen = tlv_data.curlen;
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_PAIR_COMMON_H_
|
||||
#define _HAP_PAIR_COMMON_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <esp_hap_controllers.h>
|
||||
#define ENCRYPT_KEY_LEN 32
|
||||
#define POLY_AUTHTAG_LEN 16
|
||||
#define CURVE_KEY_LEN 32
|
||||
#define ED_SIGN_LEN 64
|
||||
#define NONCE_LEN 8
|
||||
|
||||
#define STATE_M0 0
|
||||
#define STATE_M1 1
|
||||
#define STATE_M2 2
|
||||
#define STATE_M3 3
|
||||
#define STATE_M4 4
|
||||
#define STATE_M5 5
|
||||
#define STATE_M6 6
|
||||
#define STATE_VERIFIED 0x55
|
||||
#define STATE_INVALID 0xaa
|
||||
|
||||
typedef enum {
|
||||
HAP_METHOD_RESERVED = 0,
|
||||
HAP_METHOD_PAIR_SETUP = 1,
|
||||
HAP_METHOD_PAIR_VERIFY = 2,
|
||||
HAP_METHOD_ADD_PAIRING = 3,
|
||||
HAP_METHOD_REMOVE_PAIRING = 4,
|
||||
HAP_METHOD_LIST_PAIRINGS = 5,
|
||||
} hap_pairing_methods_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
kTLVError_Unknown = 0x01,
|
||||
kTLVError_Authentication = 0x02,
|
||||
kTLVError_Backoff = 0x03,
|
||||
kTLVError_MaxPeers = 0x04,
|
||||
kTLVError_MaxTries = 0x05,
|
||||
kTLVError_Unavailable = 0x06,
|
||||
kTLVError_Busy = 0x07,
|
||||
} hap_tlv_error_t;
|
||||
|
||||
typedef enum {
|
||||
kTLVType_Method = 0x00,
|
||||
kTLVType_Identifier = 0x01,
|
||||
kTLVType_Salt = 0x02,
|
||||
kTLVType_PublicKey = 0x03,
|
||||
kTLVType_Proof = 0x04,
|
||||
kTLVType_EncryptedData = 0x05,
|
||||
kTLVType_State = 0x06,
|
||||
kTLVType_Error = 0x07,
|
||||
kTLVType_RetryDelay = 0x08,
|
||||
kTLVType_Certificate = 0x09,
|
||||
kTLVType_Signature = 0x0a,
|
||||
kTLVType_Permissions = 0x0b,
|
||||
kTLVType_FragmentedData = 0x0c,
|
||||
kTLVType_FragmentLast = 0x0d,
|
||||
kTLVType_Flags = 0x13,
|
||||
kTLVType_OwnershipProofToken = 0x1A,
|
||||
kTLVType_ProductData = 0x1C,
|
||||
kTLVType_Separator = 0xff,
|
||||
} hap_tlv_type_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *bufptr;
|
||||
int bufsize;
|
||||
int curlen;
|
||||
} hap_tlv_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t state;
|
||||
uint8_t encrypt_key[ENCRYPT_KEY_LEN];
|
||||
uint8_t decrypt_key[ENCRYPT_KEY_LEN];
|
||||
uint8_t encrypt_nonce[NONCE_LEN];
|
||||
uint8_t decrypt_nonce[NONCE_LEN];
|
||||
hap_ctrl_data_t *ctrl;
|
||||
uint64_t pid;
|
||||
int64_t ttl;
|
||||
int64_t prepare_time;
|
||||
/* TODO: As of now, this identifier will be the socket
|
||||
* number, since only http is supported.
|
||||
* Need to make this generic later.
|
||||
*/
|
||||
int conn_identifier;
|
||||
} hap_secure_session_t;
|
||||
|
||||
void hap_tlv_data_init(hap_tlv_data_t *tlv_data, uint8_t *buf, int buf_size);
|
||||
int get_value_from_tlv(uint8_t *buf, int buf_len, uint8_t type, void *val, int val_size);
|
||||
int get_tlv_length(uint8_t *buf, int buflen, uint8_t type);
|
||||
int add_tlv(hap_tlv_data_t *tlv_data, uint8_t type, int len, void *val);
|
||||
void hap_prepare_error_tlv(uint8_t state, uint8_t error, void *buf, int buf_size, int *out_len);
|
||||
#endif /* _HAP_PAIR_COMMON_H_ */
|
|
@ -1,563 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/timers.h>
|
||||
#include <mu_srp.h>
|
||||
#include <sodium/crypto_aead_chacha20poly1305.h>
|
||||
#include <hkdf-sha.h>
|
||||
#include <sodium/crypto_sign_ed25519.h>
|
||||
#include <hexdump.h>
|
||||
#include <hap_platform_memory.h>
|
||||
#include <hap_platform_os.h>
|
||||
|
||||
#include <esp_hap_pair_common.h>
|
||||
#include <esp_hap_pair_setup.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_hap_main.h>
|
||||
#include <esp_hap_acc.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
/* Maximum attempts allowed for Pair Setup, as per HAP Specifications */
|
||||
#define HAP_PAIR_SETUP_MAX_ATTEMPTS 100
|
||||
|
||||
#define PAIR_SETUP_ENCRYPT_SALT "Pair-Setup-Encrypt-Salt"
|
||||
#define PAIR_SETUP_ENCRYPT_INFO "Pair-Setup-Encrypt-Info"
|
||||
#define PAIR_SETUP_CTRL_SIGN_SALT "Pair-Setup-Controller-Sign-Salt"
|
||||
#define PAIR_SETUP_CTRL_SIGN_INFO "Pair-Setup-Controller-Sign-Info"
|
||||
#define PAIR_SETUP_ACC_SIGN_SALT "Pair-Setup-Accessory-Sign-Salt"
|
||||
#define PAIR_SETUP_ACC_SIGN_INFO "Pair-Setup-Accessory-Sign-Info"
|
||||
|
||||
#define PS_CTX_INIT 1
|
||||
#define PS_CTX_DEINIT 2
|
||||
|
||||
/* Timeout if pair setup not completed in 1 minute (60sec)*/
|
||||
#define HAP_SETUP_TIMEOUT_IN_TICKS ((40 * 1000) / hap_platform_os_get_msec_per_tick())
|
||||
|
||||
static int hap_pair_setup_process_srp_start(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen,
|
||||
int bufsize, int *outlen)
|
||||
{
|
||||
/* Pair setup is not allowed if the accessory is already paired */
|
||||
if (is_accessory_paired()) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Accessory is already paired. "
|
||||
"Please use \"Add Pairing\" to add more controllers");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unavailable, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/* Pair Setup is not allowed if the failed attempts have exceeded the
|
||||
* maximum allowed attempts.
|
||||
*/
|
||||
if (hap_priv.pair_attempts >= HAP_PAIR_SETUP_MAX_ATTEMPTS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Too many attempts. Aborting");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_MaxTries, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
ps_ctx->ctrl = hap_controller_get_empty_loc();
|
||||
if (!ps_ctx->ctrl) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No empty controller slot. Aborting");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
uint8_t state;
|
||||
if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) ||
|
||||
(get_value_from_tlv(buf, inlen, kTLVType_Method,
|
||||
&ps_ctx->method, sizeof(ps_ctx->method)) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if (state != STATE_M1) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M1 Received");
|
||||
|
||||
int flags_len;
|
||||
if ((flags_len = get_value_from_tlv(buf, inlen, kTLVType_Flags, &ps_ctx->pairing_flags, sizeof(ps_ctx->pairing_flags))) > 0) {
|
||||
ps_ctx->pairing_flags_len = flags_len;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Got pairing flags %x", ps_ctx->pairing_flags);
|
||||
|
||||
/* If the Split pairing flag is not set, it is an error */
|
||||
if (!(ps_ctx->pairing_flags & PAIR_FLAG_SPLIT)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Pairing Flags received, but the Split flag is not set");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/* If either the current or the previous request didn't have transient flag set, return authentication error */
|
||||
if (!((ps_ctx->pairing_flags | hap_priv.pairing_flags) & PAIR_FLAG_TRANSIENT)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Split pairing received before preceding Transient Pairing");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
}
|
||||
hap_priv.pairing_flags = ps_ctx->pairing_flags;
|
||||
|
||||
int len_B = 0;
|
||||
char *bytes_B;
|
||||
|
||||
/* Create SRP Salt and Verifier for the provided pairing PIN */
|
||||
mu_srp_init(&ps_ctx->srp_hd, MU_NG_3072);
|
||||
|
||||
/* If a setup code is explicitly set, use it */
|
||||
if (hap_priv.setup_code) {
|
||||
ps_ctx->len_s = 16;
|
||||
mu_srp_srv_pubkey(&ps_ctx->srp_hd, "Pair-Setup", (const char*)hap_priv.setup_code, strlen(hap_priv.setup_code),
|
||||
ps_ctx->len_s, &bytes_B, &len_B, &ps_ctx->bytes_s);
|
||||
} else {
|
||||
/* Else, use the salt and verifier for SRP. This should be the default production case
|
||||
*/
|
||||
if (mu_srp_set_salt_verifier(&ps_ctx->srp_hd, (char *)hap_priv.setup_info->salt, sizeof(hap_priv.setup_info->salt),
|
||||
(char *)hap_priv.setup_info->verifier, sizeof(hap_priv.setup_info->verifier)) < 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP-6a Salt-Verifier Init Failed");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
ps_ctx->bytes_s = (char *)hap_priv.setup_info->salt;
|
||||
ps_ctx->len_s = sizeof(hap_priv.setup_info->salt);
|
||||
mu_srp_srv_pubkey_from_salt_verifier(&ps_ctx->srp_hd, &bytes_B, &len_B);
|
||||
}
|
||||
if (!ps_ctx->bytes_s || !bytes_B) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP-6a Verifier Creation Failed");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
hex_dbg_with_name("salt", (uint8_t *)ps_ctx->bytes_s, ps_ctx->len_s);
|
||||
hex_dbg_with_name("acc_srp_public_key", (uint8_t *)bytes_B, len_B);
|
||||
|
||||
/* Construct the response M2 */
|
||||
hap_tlv_data_t tlv_data;
|
||||
tlv_data.bufptr = buf;
|
||||
tlv_data.bufsize = bufsize;
|
||||
tlv_data.curlen = 0;
|
||||
state = STATE_M2;
|
||||
if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) ||
|
||||
(add_tlv(&tlv_data, kTLVType_PublicKey, len_B, (void *)bytes_B) < 0) ||
|
||||
(add_tlv(&tlv_data, kTLVType_Salt, ps_ctx->len_s, ps_ctx->bytes_s) < 0 )) {
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
/* Not adding any error check here, because without the pairing flags, the pairing will
|
||||
* anyways fail later.
|
||||
*/
|
||||
if (ps_ctx->pairing_flags_len) {
|
||||
add_tlv(&tlv_data, kTLVType_Flags, ps_ctx->pairing_flags_len, &ps_ctx->pairing_flags);
|
||||
}
|
||||
*outlen = tlv_data.curlen;
|
||||
ps_ctx->state = state;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M2 Successful");
|
||||
hap_report_event(HAP_EVENT_PAIRING_STARTED, NULL, 0);
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int hap_pair_setup_process_srp_verify(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen,
|
||||
int bufsize, int *outlen)
|
||||
{
|
||||
uint8_t state;
|
||||
char ctrl_public_key[384];
|
||||
int ctrl_public_key_len;
|
||||
char ctrl_proof[64];
|
||||
int ctrl_proof_len;
|
||||
|
||||
if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) ||
|
||||
((ctrl_public_key_len = get_value_from_tlv(buf, inlen, kTLVType_PublicKey,
|
||||
ctrl_public_key, sizeof(ctrl_public_key))) < 0) ||
|
||||
((ctrl_proof_len = get_value_from_tlv(buf, inlen, kTLVType_Proof,
|
||||
ctrl_proof, sizeof(ctrl_proof))) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if (state != STATE_M3) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M3 Received");
|
||||
|
||||
hex_dbg_with_name("ctrl_srp_public_key", (uint8_t *)ctrl_public_key, ctrl_public_key_len);
|
||||
hex_dbg_with_name("ctrl_proof", (uint8_t *)ctrl_proof, ctrl_proof_len);
|
||||
mu_srp_get_session_key(&ps_ctx->srp_hd, ctrl_public_key, ctrl_public_key_len, &ps_ctx->shared_secret, &ps_ctx->secret_len);
|
||||
char host_proof[SHA512HashSize];
|
||||
int ret = mu_srp_exchange_proofs(&ps_ctx->srp_hd, "Pair-Setup", ctrl_proof, host_proof);
|
||||
if (ret != 1) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP Verify: Controller Authentication failed");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
hap_report_event(HAP_EVENT_PAIRING_ABORTED, NULL, 0);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
int acc_proof_length = SHA512HashSize;
|
||||
|
||||
hkdf(SHA512, (uint8_t *) PAIR_SETUP_ENCRYPT_SALT, strlen(PAIR_SETUP_ENCRYPT_SALT),
|
||||
(uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len,
|
||||
(uint8_t *) PAIR_SETUP_ENCRYPT_INFO, strlen(PAIR_SETUP_ENCRYPT_INFO),
|
||||
ps_ctx->session_key, sizeof(ps_ctx->session_key));
|
||||
|
||||
/* Construct the response M4 */
|
||||
hap_tlv_data_t tlv_data;
|
||||
tlv_data.bufptr = buf;
|
||||
tlv_data.bufsize = bufsize;
|
||||
tlv_data.curlen = 0;
|
||||
state = STATE_M4;
|
||||
if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) ||
|
||||
(add_tlv(&tlv_data, kTLVType_Proof, acc_proof_length,
|
||||
(void *)host_proof) < 0)) {
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hap_tlv_error_t tlv_error = 0;
|
||||
if (hap_pair_setup_manage_mfi_auth(ps_ctx, &tlv_data, &tlv_error) != ESP_OK) {
|
||||
hap_prepare_error_tlv(STATE_M4, tlv_error, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
*outlen = tlv_data.curlen;
|
||||
ps_ctx->state = state;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M4 Successful");
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
static int hap_pair_setup_process_exchange(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen,
|
||||
int bufsize, int *outlen)
|
||||
{
|
||||
uint8_t state;
|
||||
uint8_t edata[220];
|
||||
int edata_len;
|
||||
int ret;
|
||||
|
||||
if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) ||
|
||||
((edata_len = get_value_from_tlv(buf, inlen, kTLVType_EncryptedData,
|
||||
edata, sizeof(edata))) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received");
|
||||
hap_prepare_error_tlv(STATE_M6, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hex_dbg_with_name("recv_encrypted_data", edata, edata_len);
|
||||
if (state != STATE_M5) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received");
|
||||
hap_prepare_error_tlv(STATE_M6, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M5 Received");
|
||||
edata_len -= 16; /* 16 bytes for the authTag */
|
||||
uint8_t newnonce[12];
|
||||
memset(newnonce, 0, sizeof newnonce);
|
||||
memcpy(newnonce+4, (uint8_t *)PS_NONCE2, 8);
|
||||
ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached(edata, NULL, edata, edata_len,
|
||||
&edata[edata_len], NULL, 0, newnonce, ps_ctx->session_key);
|
||||
if (ret != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Decryption Failed");
|
||||
hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hex_dbg_with_name("subtlv", edata, edata_len);
|
||||
int ctrl_id_len;
|
||||
unsigned char ed_sign[64];
|
||||
unsigned long long ed_sign_len;
|
||||
if (((ctrl_id_len = get_value_from_tlv(edata, edata_len, kTLVType_Identifier,
|
||||
ps_ctx->ctrl->info.id, sizeof(ps_ctx->ctrl->info.id))) < 0) ||
|
||||
(get_value_from_tlv(edata, edata_len, kTLVType_PublicKey,
|
||||
ps_ctx->ctrl->info.ltpk, ED_KEY_LEN) != ED_KEY_LEN) ||
|
||||
(get_value_from_tlv(edata, edata_len, kTLVType_Signature,
|
||||
ed_sign, sizeof(ed_sign)) != sizeof(ed_sign))) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid subTLV received");
|
||||
hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
ps_ctx->ctrl->info.id[ctrl_id_len] = 0; /* NULL termination */
|
||||
hex_dbg_with_name("ctrl_id", (uint8_t *)ps_ctx->ctrl->info.id, ctrl_id_len);
|
||||
hex_dbg_with_name("ltpkc", ps_ctx->ctrl->info.ltpk, ED_KEY_LEN);
|
||||
hex_dbg_with_name("ctrl_sign", ed_sign, sizeof(ed_sign));
|
||||
|
||||
/* Derive iOSDeviceX from SRP shared secret using HKDF-SHA512 */
|
||||
uint8_t ios_device_x[32];
|
||||
hkdf(SHA512, (unsigned char *) PAIR_SETUP_CTRL_SIGN_SALT,
|
||||
strlen(PAIR_SETUP_CTRL_SIGN_SALT), (uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len,
|
||||
(unsigned char *) PAIR_SETUP_CTRL_SIGN_INFO,
|
||||
strlen(PAIR_SETUP_CTRL_SIGN_INFO),
|
||||
ios_device_x, sizeof(ios_device_x));
|
||||
/* Construct iOSDeviceInfo by concatenating
|
||||
* iOSDeviceX
|
||||
* iOSDevicePairingID (ctrl_id)
|
||||
* iOSDeviceLTPK (ltpkc)
|
||||
*/
|
||||
uint8_t info_buf[HAP_CTRL_ID_LEN + 32 + ED_KEY_LEN];
|
||||
uint8_t *ios_dev_info = info_buf;
|
||||
int ios_dev_info_len = 0;
|
||||
memcpy(ios_dev_info, ios_device_x, sizeof(ios_device_x));
|
||||
ios_dev_info_len += sizeof(ios_device_x);
|
||||
memcpy(&ios_dev_info[ios_dev_info_len], ps_ctx->ctrl->info.id, ctrl_id_len);
|
||||
ios_dev_info_len += ctrl_id_len;
|
||||
memcpy(&ios_dev_info[ios_dev_info_len], ps_ctx->ctrl->info.ltpk, ED_KEY_LEN);
|
||||
ios_dev_info_len += ED_KEY_LEN;
|
||||
|
||||
ret = crypto_sign_ed25519_verify_detached(ed_sign, ios_dev_info, ios_dev_info_len, ps_ctx->ctrl->info.ltpk);
|
||||
/* Verify Signature of constructed iOSDeviceInfo using the iOSDeviceLTPK */
|
||||
if (ret != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid Signature");
|
||||
hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
hex_dbg_with_name("ltpka", hap_priv.ltpka, sizeof(hap_priv.ltpka));
|
||||
|
||||
/* Derive AccessoryX from the SRP shared secret using HKDF-SHA512 */
|
||||
uint8_t acc_x[32];
|
||||
hkdf(SHA512, (unsigned char *) PAIR_SETUP_ACC_SIGN_SALT,
|
||||
strlen(PAIR_SETUP_ACC_SIGN_SALT), (uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len,
|
||||
(unsigned char *) PAIR_SETUP_ACC_SIGN_INFO,
|
||||
strlen(PAIR_SETUP_ACC_SIGN_INFO),
|
||||
acc_x, sizeof(acc_x));
|
||||
/* Construct AccessoryInfo by concatenating
|
||||
* AccessoryX
|
||||
* AccessoryPairingID (acc_id)
|
||||
* AccessoryLTPK (ltpka)
|
||||
*/
|
||||
uint8_t *acc_info = info_buf;
|
||||
int acc_info_len = 0;
|
||||
memcpy(acc_info, acc_x, sizeof(acc_x));
|
||||
acc_info_len += sizeof(acc_x);
|
||||
memcpy(&ios_dev_info[acc_info_len], hap_priv.acc_id, strlen(hap_priv.acc_id));
|
||||
acc_info_len += strlen(hap_priv.acc_id);
|
||||
memcpy(&ios_dev_info[acc_info_len], hap_priv.ltpka, sizeof(hap_priv.ltpka));
|
||||
acc_info_len += sizeof(hap_priv.ltpka);
|
||||
|
||||
/* Generate AccessorySignature by signing AccessoryInfo with AccessoryLTSK
|
||||
*/
|
||||
crypto_sign_ed25519_detached(ed_sign, &ed_sign_len, acc_info, acc_info_len, hap_priv.ltska);
|
||||
hex_dbg_with_name("acc_sign", ed_sign, sizeof(ed_sign));
|
||||
|
||||
/* Create subTLV with:
|
||||
* kTLVType_Identifier : Accessory ID (acc_id)
|
||||
* kTLVType_PublicKey : Accessory LTPK
|
||||
* kTLVType_Signature : AccessorySignature
|
||||
*/
|
||||
|
||||
uint8_t subtlv[6 + HAP_ACC_ID_LEN + ED_KEY_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN];
|
||||
|
||||
hap_tlv_data_t tlv_data;
|
||||
tlv_data.bufptr = subtlv;
|
||||
tlv_data.bufsize = sizeof(subtlv);
|
||||
tlv_data.curlen = 0;
|
||||
add_tlv(&tlv_data, kTLVType_Identifier, strlen(hap_priv.acc_id), hap_priv.acc_id);
|
||||
add_tlv(&tlv_data, kTLVType_PublicKey, sizeof(hap_priv.ltpka), hap_priv.ltpka);
|
||||
add_tlv(&tlv_data, kTLVType_Signature, sizeof(ed_sign), ed_sign);
|
||||
int subtlv_len = tlv_data.curlen;
|
||||
hex_dbg_with_name("subtlv", subtlv, subtlv_len);
|
||||
|
||||
/* Encrypt the subTLV using the session key */
|
||||
|
||||
unsigned long long mlen = 16;
|
||||
memset(newnonce, 0, sizeof newnonce);
|
||||
memcpy(newnonce+4, (uint8_t *) PS_NONCE3, 8);
|
||||
crypto_aead_chacha20poly1305_ietf_encrypt_detached(subtlv, &subtlv[subtlv_len], &mlen, subtlv,
|
||||
subtlv_len, NULL, 0, NULL, newnonce, ps_ctx->session_key);
|
||||
hex_dbg_with_name("send_encrypt_data", subtlv, subtlv_len + 16);
|
||||
|
||||
/* Construct the response M6 */
|
||||
tlv_data.bufptr = buf;
|
||||
tlv_data.bufsize = bufsize;
|
||||
tlv_data.curlen = 0;
|
||||
state = STATE_M6;
|
||||
if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) ||
|
||||
(add_tlv(&tlv_data, kTLVType_EncryptedData, subtlv_len + 16,
|
||||
subtlv) < 0)) {
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
*outlen = tlv_data.curlen;
|
||||
ps_ctx->state = state;
|
||||
ps_ctx->ctrl->info.perms = 1; /* Controller added using pair setup is always an admin */
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup Successful for %s", ps_ctx->ctrl->info.id);
|
||||
/* Reset the Pairing Attempts count */
|
||||
hap_priv.pair_attempts = 0;
|
||||
hap_controller_save(ps_ctx->ctrl);
|
||||
hap_send_event(HAP_INTERNAL_EVENT_ACC_PAIRED);
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
static uint8_t hap_pair_setup_get_received_state(uint8_t *buf, int inlen)
|
||||
{
|
||||
uint8_t state = 0;
|
||||
get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state));
|
||||
return state;
|
||||
}
|
||||
|
||||
static void hap_pair_setup_timeout(TimerHandle_t handle)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Clearing Pair Setup Context due to inactivity");
|
||||
pair_setup_ctx_t *ps_ctx = pvTimerGetTimerID(handle);
|
||||
if (ps_ctx) {
|
||||
httpd_sess_trigger_close(hap_priv.server, ps_ctx->sock_fd);
|
||||
hap_report_event(HAP_EVENT_PAIRING_ABORTED, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pair Setup can have only a single context at a time as the specification does not allow
|
||||
* multiple controllers to perform Pair Setup Simultaneously.
|
||||
*
|
||||
* The purpose of this function is to manage allocation and resetting of the context by
|
||||
* using a static variable rather than a global variable.
|
||||
*/
|
||||
static pair_setup_ctx_t *hap_pair_setup_ctx_action(int action)
|
||||
{
|
||||
static pair_setup_ctx_t *ps_ctx;
|
||||
/* If the call is to initialise the context, check if it is already
|
||||
* initialised.
|
||||
*/
|
||||
if (action == PS_CTX_INIT) {
|
||||
/* If the context is already initialised, it means that pair setup
|
||||
* is already in progress. So, return NULL.
|
||||
* Else, allocate the context.
|
||||
*/
|
||||
if (ps_ctx)
|
||||
return NULL;
|
||||
else {
|
||||
ps_ctx = hap_platform_memory_calloc(sizeof(pair_setup_ctx_t), 1);
|
||||
if (ps_ctx) {
|
||||
ps_ctx->timer = xTimerCreate("hap_setup_timer", HAP_SETUP_TIMEOUT_IN_TICKS,
|
||||
pdFALSE, (void *) ps_ctx, hap_pair_setup_timeout);
|
||||
xTimerStart(ps_ctx->timer, 0);
|
||||
}
|
||||
}
|
||||
} else if (action == PS_CTX_DEINIT) {
|
||||
/* If the call is to de-initialise the context, clean it up
|
||||
* and set the pointer to NULL
|
||||
*/
|
||||
if (ps_ctx) {
|
||||
if (ps_ctx->timer) {
|
||||
xTimerStop(ps_ctx->timer, 0);
|
||||
xTimerDelete(ps_ctx->timer, 100);
|
||||
}
|
||||
mu_srp_free(&ps_ctx->srp_hd);
|
||||
hap_platform_memory_free(ps_ctx);
|
||||
}
|
||||
ps_ctx = NULL;
|
||||
}
|
||||
return ps_ctx;
|
||||
}
|
||||
|
||||
|
||||
void hap_pair_setup_ctx_clean(void *sess_ctx)
|
||||
{
|
||||
if (sess_ctx) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Cleaning Pair Setup Context");
|
||||
hap_pair_setup_ctx_action(PS_CTX_DEINIT);
|
||||
}
|
||||
}
|
||||
|
||||
int hap_pair_setup_context_init(int sock_fd, void **ctx, uint8_t *buf, int bufsize, int *outlen)
|
||||
{
|
||||
pair_setup_ctx_t *ps_ctx = hap_pair_setup_ctx_action(PS_CTX_INIT);
|
||||
|
||||
if (!ps_ctx) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR,"######## Aborted! Pair Setup in Progress with another controller ########");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Busy, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
ps_ctx->sock_fd = sock_fd;
|
||||
*ctx = ps_ctx;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "######## Starting Pair Setup ########");
|
||||
return HAP_SUCCESS;
|
||||
|
||||
}
|
||||
int hap_pair_setup_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen)
|
||||
{
|
||||
pair_setup_ctx_t *ps_ctx = (pair_setup_ctx_t *)(*ctx);
|
||||
|
||||
uint8_t recv_state = hap_pair_setup_get_received_state(buf, inlen);
|
||||
if (!ps_ctx) {
|
||||
hap_prepare_error_tlv(recv_state + 1, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
/* Receiving STATE_M1 in the message while the pair-setup was already in progress means
|
||||
* that pair setup was restarted. Handle it accordingly
|
||||
*/
|
||||
if ((recv_state == STATE_M1) && (ps_ctx->state != STATE_M0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Restarting Pair Setup");
|
||||
int sock_fd = ps_ctx->sock_fd;
|
||||
hap_pair_setup_ctx_clean(ps_ctx);
|
||||
int ret = hap_pair_setup_context_init(sock_fd, ctx, buf, bufsize, outlen);
|
||||
if (ret != HAP_SUCCESS)
|
||||
return ret;
|
||||
ps_ctx = (pair_setup_ctx_t *)(*ctx);
|
||||
}
|
||||
if (ps_ctx->state == STATE_M0) {
|
||||
return hap_pair_setup_process_srp_start(ps_ctx, buf, inlen, bufsize, outlen);
|
||||
} else if (ps_ctx->state == STATE_M2) {
|
||||
hap_priv.pair_attempts++;
|
||||
int ret = hap_pair_setup_process_srp_verify(ps_ctx, buf, inlen, bufsize, outlen);
|
||||
if (ps_ctx->session) {
|
||||
*ctx = ps_ctx->session;
|
||||
hap_pair_setup_ctx_clean(ps_ctx);
|
||||
}
|
||||
return ret;
|
||||
} else if (ps_ctx->state == STATE_M4) {
|
||||
int ret = hap_pair_setup_process_exchange(ps_ctx, buf, inlen, bufsize, outlen);
|
||||
/* If last step of pair setup is successful, it means that the context would
|
||||
* be no more required. Hence, clear it.
|
||||
*/
|
||||
if (ret == HAP_SUCCESS) {
|
||||
hap_pair_setup_ctx_clean(ps_ctx);
|
||||
*ctx = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
void hap_set_setup_code(const char *setup_code)
|
||||
{
|
||||
if (hap_priv.setup_code)
|
||||
hap_platform_memory_free(hap_priv.setup_code);
|
||||
hap_priv.setup_code = strdup(setup_code);
|
||||
}
|
||||
|
||||
int hap_set_setup_info(const hap_setup_info_t *setup_info)
|
||||
{
|
||||
if (!setup_info)
|
||||
return HAP_FAIL;
|
||||
if (hap_priv.setup_info)
|
||||
hap_platform_memory_free(hap_priv.setup_info);
|
||||
hap_priv.setup_info = hap_platform_memory_calloc(1, sizeof(hap_setup_info_t));
|
||||
if (!hap_priv.setup_info)
|
||||
return HAP_FAIL;
|
||||
memcpy(hap_priv.setup_info, setup_info, sizeof(hap_setup_info_t));
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_set_setup_id(const char *setup_id)
|
||||
{
|
||||
if (setup_id == NULL || strlen(setup_id) != SETUP_ID_LEN)
|
||||
return HAP_FAIL;
|
||||
strcpy(hap_priv.setup_id, setup_id);
|
||||
return HAP_SUCCESS;
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_PAIR_SETUP_H_
|
||||
#define _HAP_PAIR_SETUP_H_
|
||||
#include <stdint.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/timers.h>
|
||||
#include <mu_srp.h>
|
||||
#include <esp_hap_pair_common.h>
|
||||
|
||||
#define PS_NONCE1 "PS-Msg04"
|
||||
#define PS_NONCE2 "PS-Msg05"
|
||||
#define PS_NONCE3 "PS-Msg06"
|
||||
|
||||
#define PAIR_FLAG_TRANSIENT 0x00000010
|
||||
#define PAIR_FLAG_SPLIT 0x01000000
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t state;
|
||||
uint8_t method;
|
||||
uint32_t pairing_flags;
|
||||
int8_t pairing_flags_len;
|
||||
int len_s;
|
||||
char *bytes_s;
|
||||
int secret_len;
|
||||
char *shared_secret;
|
||||
mu_srp_handle_t srp_hd;
|
||||
hap_ctrl_data_t *ctrl;
|
||||
uint8_t session_key[32];
|
||||
TimerHandle_t timer;
|
||||
hap_secure_session_t *session;
|
||||
int sock_fd;
|
||||
} pair_setup_ctx_t;
|
||||
int hap_pair_setup_context_init(int sock_fd, void **ctx, uint8_t *buf, int bufsize, int *outlen);
|
||||
int hap_pair_setup_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen);
|
||||
void hap_pair_setup_ctx_clean(void *sess_ctx);
|
||||
int hap_pair_setup_manage_mfi_auth(pair_setup_ctx_t *ps_ctx, hap_tlv_data_t *tlv_data, hap_tlv_error_t *tlv_error);
|
||||
#endif /* _HAP_PAIR_SETUP_H_ */
|
|
@ -1,464 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sodium/crypto_scalarmult_curve25519.h>
|
||||
#include <sodium/crypto_sign_ed25519.h>
|
||||
#include <hkdf-sha.h>
|
||||
#include <sodium/crypto_aead_chacha20poly1305.h>
|
||||
#include <esp_http_server.h>
|
||||
#include <hap_platform_memory.h>
|
||||
|
||||
#include <esp_hap_main.h>
|
||||
#include <esp_hap_pair_common.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_hap_char.h>
|
||||
#include <hexdump.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
#include <esp_mfi_rand.h>
|
||||
|
||||
#define PAIR_VERIFY_ENCRYPT_SALT "Pair-Verify-Encrypt-Salt"
|
||||
#define PAIR_VERIFY_ENCRYPT_INFO "Pair-Verify-Encrypt-Info"
|
||||
#define PV_NONCE1 "PV-Msg02"
|
||||
#define PV_NONCE2 "PV-Msg03"
|
||||
#define CONTROL_SALT "Control-Salt"
|
||||
#define CONTROL_READ_INFO "Control-Read-Encryption-Key"
|
||||
#define CONTROL_WRITE_INFO "Control-Write-Encryption-Key"
|
||||
|
||||
typedef struct {
|
||||
/* It is important that "state" should be the first element of the structure.
|
||||
* It will be the first element, even in hap_secure_session_t.
|
||||
* This will be useful while checking the state from the context, irrespective
|
||||
* of whether the context points to pair_verify_ctx_t or hap_secure_session_t.
|
||||
*/
|
||||
uint8_t state;
|
||||
uint8_t ctrl_curve_pk[CURVE_KEY_LEN];
|
||||
uint8_t acc_curve_pk[CURVE_KEY_LEN];
|
||||
uint8_t hkdf_key[ENCRYPT_KEY_LEN];
|
||||
uint8_t shared_secret[CURVE_KEY_LEN];
|
||||
hap_secure_session_t *session;
|
||||
} pair_verify_ctx_t;
|
||||
|
||||
void hap_close_ctrl_sessions(hap_ctrl_data_t *ctrl)
|
||||
{
|
||||
if (!ctrl)
|
||||
return;
|
||||
int i;
|
||||
printf("---- hap_close_ctrl_sessions begin -----\n");
|
||||
for (i = 0; i < HAP_MAX_SESSIONS; i++) {
|
||||
if (!hap_priv.sessions[i])
|
||||
continue;
|
||||
if (hap_priv.sessions[i]->ctrl == ctrl) {
|
||||
hap_report_event(HAP_EVENT_CTRL_DISCONNECTED, (ctrl->info.id),
|
||||
sizeof((ctrl->info.id)));
|
||||
/* TODO: Use some generic function and not a direct HTTPD function
|
||||
*/
|
||||
printf("---- trigger_close fd: %d\n", hap_priv.sessions[i]->conn_identifier);
|
||||
httpd_sess_trigger_close(hap_priv.server, hap_priv.sessions[i]->conn_identifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("----hap_close_ctrl_sessions end ----\n");
|
||||
}
|
||||
|
||||
int hap_get_ctrl_session_index(hap_secure_session_t *session)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_SESSIONS; i++) {
|
||||
if (hap_priv.sessions[i] == session)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void hap_close_all_sessions()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_SESSIONS; i++) {
|
||||
if (hap_priv.sessions[i]) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Closing Session");
|
||||
hap_close_ctrl_sessions(hap_priv.sessions[i]->ctrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hap_add_secure_session(hap_secure_session_t *session)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_SESSIONS; i++) {
|
||||
if (hap_priv.sessions[i] == NULL) {
|
||||
hap_priv.sessions[i] = session;
|
||||
hap_report_event(HAP_EVENT_CTRL_CONNECTED, session->ctrl->info.id,
|
||||
sizeof(session->ctrl->info.id));
|
||||
/* Set the disconnected_event_sent flag here to false so that an
|
||||
* event can be sent later for a state change, when no controller
|
||||
* is connected.
|
||||
* HAP Spec R15 say that the state number should change only once
|
||||
* between accessory disconneted (from all controllers) to connected
|
||||
* state.
|
||||
*/
|
||||
hap_priv.disconnected_event_sent = false;
|
||||
//ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HomeKit Session active");
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HomeKit Session active, fd: %d", session->conn_identifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hap_free_session(void *session)
|
||||
{
|
||||
if (!session)
|
||||
return;
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_SESSIONS; i++) {
|
||||
if (hap_priv.sessions[i] == session) {
|
||||
/* Disable all characteristic notifications on this session */
|
||||
int fd = (hap_priv.sessions[i])->conn_identifier;
|
||||
hap_disable_all_char_notif(i);
|
||||
hap_priv.sessions[i] = NULL;
|
||||
//ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HomeKit Session terminated");
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HomeKit Session terminated, fd: %d", fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hap_platform_memory_free(session);
|
||||
}
|
||||
|
||||
static int hap_pair_verify_process_start(pair_verify_ctx_t *pv_ctx, uint8_t *buf, int inlen,
|
||||
int bufsize, int *outlen)
|
||||
{
|
||||
/* Parse the data received from the controller */
|
||||
uint8_t state;
|
||||
if (!pv_ctx) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No context");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) ||
|
||||
(get_value_from_tlv(buf, inlen, kTLVType_PublicKey, pv_ctx->ctrl_curve_pk,
|
||||
CURVE_KEY_LEN) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if (state != STATE_M1) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Verify M1 Received");
|
||||
hex_dbg_with_name("ctrl curve pk", pv_ctx->ctrl_curve_pk, 32);
|
||||
|
||||
/* Generate a new Curve25519 Key Pair */
|
||||
uint8_t acc_curve_sk[CURVE_KEY_LEN];
|
||||
esp_mfi_get_random(acc_curve_sk, CURVE_KEY_LEN);
|
||||
/* This particular value of basepoint is required to generate the public key
|
||||
* from secret key
|
||||
*/
|
||||
uint8_t basepoint[32] = {9};
|
||||
if (crypto_scalarmult_curve25519(pv_ctx->acc_curve_pk, acc_curve_sk, basepoint) == -1) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Curve25519 Error");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
hex_dbg_with_name("acc curve sk", acc_curve_sk, 32);
|
||||
hex_dbg_with_name("acc curve pk", pv_ctx->acc_curve_pk, 32);
|
||||
if (crypto_scalarmult_curve25519(pv_ctx->shared_secret, acc_curve_sk, pv_ctx->ctrl_curve_pk) == -1) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Curve25519 Error");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
hex_dbg_with_name("shared secret", pv_ctx->shared_secret, 32);
|
||||
|
||||
/* Construct AccessoryInfo by concatenating
|
||||
* a. Accessory's Curve25519 Public Key
|
||||
* b. Accessory ID
|
||||
* c. Controller's Curve25519 Public Key received in M1
|
||||
*/
|
||||
uint8_t acc_info[2 * CURVE_KEY_LEN + HAP_ACC_ID_LEN];
|
||||
int acc_info_len = 0;
|
||||
memcpy(acc_info, pv_ctx->acc_curve_pk, CURVE_KEY_LEN);
|
||||
acc_info_len += CURVE_KEY_LEN;
|
||||
memcpy(acc_info + acc_info_len, hap_priv.acc_id, strlen(hap_priv.acc_id));
|
||||
acc_info_len += strlen(hap_priv.acc_id);
|
||||
memcpy(acc_info + acc_info_len, pv_ctx->ctrl_curve_pk, CURVE_KEY_LEN);
|
||||
acc_info_len += CURVE_KEY_LEN;
|
||||
|
||||
hex_dbg_with_name("acc_info", acc_info, acc_info_len);
|
||||
|
||||
/* Use Ed25519 to generate AccessorySignature by signing AccessoryInfo
|
||||
* with its Long Term Secret Key AccessoryLTSK
|
||||
*/
|
||||
unsigned char ed_sign[64];
|
||||
unsigned long long ed_sign_len;
|
||||
crypto_sign_ed25519_detached(ed_sign, &ed_sign_len, acc_info, acc_info_len, hap_priv.ltska);
|
||||
hex_dbg_with_name("sign", ed_sign, 64);
|
||||
|
||||
/* Construct a subTLV with
|
||||
* kTLVType_Identifier : Accessory Identifier
|
||||
* kTLVType_Signature : AccessorySignature generated above
|
||||
*/
|
||||
uint8_t subtlv[4 + HAP_ACC_ID_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN];
|
||||
hap_tlv_data_t tlv_data;
|
||||
tlv_data.bufptr = subtlv;
|
||||
tlv_data.bufsize = sizeof(subtlv);
|
||||
tlv_data.curlen = 0;
|
||||
add_tlv(&tlv_data, kTLVType_Identifier, strlen(hap_priv.acc_id), hap_priv.acc_id);
|
||||
add_tlv(&tlv_data, kTLVType_Signature, sizeof(ed_sign), ed_sign);
|
||||
int subtlv_len = tlv_data.curlen;
|
||||
hex_dbg_with_name("subtlv", subtlv, subtlv_len);
|
||||
|
||||
/* Derive Symmetric Session encryption key SessionKey from the curve
|
||||
* shared secret using HKDF-SHA-512
|
||||
*/
|
||||
hkdf(SHA512, (unsigned char *) PAIR_VERIFY_ENCRYPT_SALT,
|
||||
strlen(PAIR_VERIFY_ENCRYPT_SALT),
|
||||
pv_ctx->shared_secret, sizeof(pv_ctx->shared_secret),
|
||||
(unsigned char *) PAIR_VERIFY_ENCRYPT_INFO,
|
||||
strlen(PAIR_VERIFY_ENCRYPT_INFO),
|
||||
pv_ctx->hkdf_key, sizeof(pv_ctx->hkdf_key));
|
||||
/* Encrypt the sub TLV to get encryptedData and an authTag using
|
||||
* Chacha20-Poly1305 AEAD Algorithm
|
||||
*/
|
||||
uint8_t edata[4 + HAP_ACC_ID_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN];
|
||||
unsigned long long mlen = 16;
|
||||
uint8_t newnonce[12];
|
||||
memset(newnonce, 0, sizeof newnonce);
|
||||
memcpy(newnonce+4, PV_NONCE1, 8);
|
||||
|
||||
crypto_aead_chacha20poly1305_ietf_encrypt_detached(edata, edata + subtlv_len, &mlen, subtlv, subtlv_len, NULL, 0, NULL, newnonce, pv_ctx->hkdf_key);
|
||||
|
||||
int edata_len = subtlv_len + POLY_AUTHTAG_LEN;
|
||||
|
||||
hex_dbg_with_name("encrypt_data", edata, edata_len);
|
||||
|
||||
/* Construct the response M2 */
|
||||
tlv_data.bufptr = buf;
|
||||
tlv_data.bufsize = bufsize;
|
||||
tlv_data.curlen = 0;
|
||||
state = STATE_M2;
|
||||
if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) ||
|
||||
(add_tlv(&tlv_data, kTLVType_PublicKey, CURVE_KEY_LEN,
|
||||
pv_ctx->acc_curve_pk) < 0) ||
|
||||
(add_tlv(&tlv_data, kTLVType_EncryptedData, edata_len, edata) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
*outlen = tlv_data.curlen;
|
||||
hex_dbg_with_name("M2", buf, *outlen);
|
||||
pv_ctx->state = STATE_M2;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Verify M2 Successful");
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
static int hap_pair_verify_process_finish(pair_verify_ctx_t *pv_ctx, uint8_t *buf, int inlen,
|
||||
int bufsize, int *outlen)
|
||||
{
|
||||
/* Parse the data received from the controller */
|
||||
uint8_t state;
|
||||
if (!pv_ctx) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No context");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
uint8_t edata[4 + HAP_CTRL_ID_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN];
|
||||
int edata_len;
|
||||
if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) ||
|
||||
((edata_len = get_value_from_tlv(buf, inlen, kTLVType_EncryptedData,
|
||||
edata, sizeof(edata))) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if (state != STATE_M3) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Verify M3 Received");
|
||||
|
||||
/* Decrypt the received data to get the subTLV */
|
||||
uint8_t newnonce[12];
|
||||
memset(newnonce, 0, sizeof newnonce);
|
||||
memcpy(newnonce+4, PV_NONCE2, 8);
|
||||
int ret;
|
||||
ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached(edata, NULL, edata, edata_len - POLY_AUTHTAG_LEN, edata + edata_len - POLY_AUTHTAG_LEN, NULL, 0, newnonce, pv_ctx->hkdf_key);
|
||||
if (ret != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Decryption error");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/* Parse the subTLV to get the iOSDevicePairingID and iOSDeviceSignature
|
||||
*/
|
||||
edata_len = edata_len - POLY_AUTHTAG_LEN;
|
||||
unsigned char ed_sign[64];
|
||||
char ctrl_id[HAP_CTRL_ID_LEN];
|
||||
memset(ctrl_id, 0, sizeof(ctrl_id));
|
||||
if ((get_value_from_tlv(edata, edata_len, kTLVType_Identifier,
|
||||
ctrl_id, sizeof(ctrl_id)) < 0) ||
|
||||
(get_value_from_tlv(edata, edata_len, kTLVType_Signature,
|
||||
ed_sign, sizeof(ed_sign)) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Wrong subTLV received");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/* Check if the controller is present in the database i.e. check
|
||||
* if the controller was paired with the accessory
|
||||
*/
|
||||
hap_ctrl_data_t *ctrl = hap_get_controller(ctrl_id);
|
||||
if (!ctrl) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No ctrl details found");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/* Construct iOSDeviceInfo by concatenating
|
||||
* a. Controllers's Curve25519 Public Key (received in M1)
|
||||
* b. Controller ID
|
||||
* c. Accessory's Curve25519 Public Key (sent in M2)
|
||||
*/
|
||||
uint8_t ios_dev_info[2 * CURVE_KEY_LEN + HAP_CTRL_ID_LEN];
|
||||
int ios_dev_info_len = 0;
|
||||
memcpy(ios_dev_info, pv_ctx->ctrl_curve_pk, CURVE_KEY_LEN);
|
||||
ios_dev_info_len += CURVE_KEY_LEN;
|
||||
memcpy(ios_dev_info + ios_dev_info_len, ctrl_id, strlen(ctrl_id));
|
||||
ios_dev_info_len += strlen(ctrl_id);
|
||||
memcpy(ios_dev_info + ios_dev_info_len, pv_ctx->acc_curve_pk,
|
||||
CURVE_KEY_LEN);
|
||||
ios_dev_info_len += CURVE_KEY_LEN;
|
||||
|
||||
/* Validate the signature with the received iOSDeviceSignature */
|
||||
if (crypto_sign_ed25519_verify_detached(ed_sign, ios_dev_info, ios_dev_info_len, ctrl->info.ltpk) != 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Signature mismatch");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/* Allocate memory for the secure session information */
|
||||
hap_secure_session_t *session = hap_platform_memory_calloc(sizeof(hap_secure_session_t), 1);
|
||||
if (!session) {
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Memory allocation failed");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
/* Construct the response M4 */
|
||||
hap_tlv_data_t tlv_data;
|
||||
tlv_data.bufptr = buf;
|
||||
tlv_data.bufsize = bufsize;
|
||||
tlv_data.curlen = 0;
|
||||
state = STATE_M4;
|
||||
if (add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) {
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
hap_platform_memory_free(session);
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
*outlen = tlv_data.curlen;
|
||||
|
||||
/* Generate the Encryption and Decryption Keys.
|
||||
* Since, read and write are from the controller's point of view,
|
||||
* encryption key uses READ_INFO and decryption key uses WRITE_INFO
|
||||
*
|
||||
* Also, set the nonce to zero
|
||||
*/
|
||||
hkdf(SHA512, (unsigned char *) CONTROL_SALT, strlen(CONTROL_SALT),
|
||||
pv_ctx->shared_secret, sizeof(pv_ctx->shared_secret),
|
||||
(unsigned char *) CONTROL_READ_INFO, strlen(CONTROL_READ_INFO),
|
||||
session->encrypt_key, sizeof(session->encrypt_key));
|
||||
|
||||
hkdf(SHA512, (unsigned char *) CONTROL_SALT, strlen(CONTROL_SALT),
|
||||
pv_ctx->shared_secret, sizeof(pv_ctx->shared_secret),
|
||||
(unsigned char *) CONTROL_WRITE_INFO, strlen(CONTROL_WRITE_INFO),
|
||||
session->decrypt_key, sizeof(session->decrypt_key));
|
||||
|
||||
session->state = STATE_VERIFIED;
|
||||
pv_ctx->state = STATE_VERIFIED;
|
||||
|
||||
memset(session->encrypt_nonce, 0, sizeof(session->encrypt_nonce));
|
||||
memset(session->decrypt_nonce, 0, sizeof(session->decrypt_nonce));
|
||||
session->ctrl = ctrl;
|
||||
|
||||
pv_ctx->session = session;
|
||||
|
||||
/* Add the session information to database */
|
||||
hap_add_secure_session(session);
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Verify Successful for %s", ctrl_id);
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_pair_verify_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen)
|
||||
{
|
||||
pair_verify_ctx_t *pv_ctx = (pair_verify_ctx_t *)(*ctx);
|
||||
if (pv_ctx) {
|
||||
if (pv_ctx->state == STATE_M0)
|
||||
return hap_pair_verify_process_start(pv_ctx, buf, inlen,
|
||||
bufsize, outlen);
|
||||
else if (pv_ctx->state == STATE_M2) {
|
||||
int ret = hap_pair_verify_process_finish(pv_ctx, buf, inlen,
|
||||
bufsize, outlen);
|
||||
/* Successful finish means that the pair verify was successful.
|
||||
* So, we clear the old context and assign the secure_session
|
||||
* as the new context
|
||||
*/
|
||||
if (ret == HAP_SUCCESS) {
|
||||
hap_secure_session_t *session = pv_ctx->session;
|
||||
hap_platform_memory_free(pv_ctx);
|
||||
*ctx = session;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Error processing Pair Verify Data");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
int hap_pair_verify_context_init(void **ctx, uint8_t *buf, int bufsize, int *outlen)
|
||||
{
|
||||
pair_verify_ctx_t *pv_ctx;
|
||||
|
||||
pv_ctx = (pair_verify_ctx_t *) hap_platform_memory_calloc(sizeof(pair_verify_ctx_t), 1);
|
||||
if (!pv_ctx) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to create Pair Verify Context");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
*ctx = pv_ctx;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "######## Starting Pair Verify ########");
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t hap_pair_verify_get_state(void *ctx)
|
||||
{
|
||||
pair_verify_ctx_t *pv_ctx = (pair_verify_ctx_t *)ctx;
|
||||
if (pv_ctx)
|
||||
return pv_ctx->state;
|
||||
return 0;
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_PAIR_VERIFY_H_
|
||||
#define _HAP_PAIR_VERIFY_H_
|
||||
#include <esp_hap_pair_common.h>
|
||||
#include <esp_hap_controllers.h>
|
||||
int hap_pair_verify_context_init(void **ctx, uint8_t *buf, int bufsize, int *outlen);
|
||||
int hap_pair_verify_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen);
|
||||
uint8_t hap_pair_verify_get_state(void *ctx);
|
||||
void hap_free_session(void *session);
|
||||
int hap_get_ctrl_session_index(hap_secure_session_t *session);
|
||||
void hap_close_ctrl_sessions(hap_ctrl_data_t *ctrl);
|
||||
void hap_close_all_sessions();
|
||||
#endif /* _HAP_PAIR_VERIFY_H_ */
|
|
@ -1,255 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <esp_hap_database.h>
|
||||
#include <esp_hap_controllers.h>
|
||||
#include <esp_hap_pair_common.h>
|
||||
#include <esp_hap_pair_verify.h>
|
||||
#include <esp_hap_main.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
bool hap_is_req_admin(void *__session)
|
||||
{
|
||||
hap_secure_session_t *session = (hap_secure_session_t *)__session;
|
||||
if (!session) {
|
||||
return false;
|
||||
}
|
||||
if ((session->state == STATE_VERIFIED) && (session->ctrl->info.perms == 1)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char *hap_req_get_ctrl_id(void *__session)
|
||||
{
|
||||
hap_secure_session_t *session = (hap_secure_session_t *)__session;
|
||||
if (!session)
|
||||
return NULL;
|
||||
|
||||
if (session->state == STATE_VERIFIED) {
|
||||
return session->ctrl->info.id;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool hap_is_req_secure(hap_secure_session_t *session)
|
||||
{
|
||||
if (!session) {
|
||||
return false;
|
||||
}
|
||||
if (session->state == STATE_VERIFIED) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void hap_remove_all_controllers()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HAP_MAX_CONTROLLERS; i++) {
|
||||
if (hap_priv.controllers[i].valid) {
|
||||
hap_close_ctrl_sessions(&hap_priv.controllers[i]);
|
||||
hap_controller_remove(&hap_priv.controllers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
static int hap_process_pair_remove(uint8_t *buf, int inlen, int bufsize, int *outlen)
|
||||
{
|
||||
bool acc_unpaired = false;
|
||||
char ctrl_id[HAP_CTRL_ID_LEN];
|
||||
memset(ctrl_id, 0, HAP_CTRL_ID_LEN);
|
||||
if (get_value_from_tlv(buf, inlen, kTLVType_Identifier,
|
||||
ctrl_id, sizeof(ctrl_id)) < 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Identifier not found");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Removing Controller %s", ctrl_id);
|
||||
hap_ctrl_data_t *ctrl = hap_get_controller(ctrl_id);
|
||||
hap_close_ctrl_sessions(ctrl);
|
||||
hap_controller_remove(ctrl);
|
||||
|
||||
if (!is_admin_paired()) {
|
||||
acc_unpaired = true;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Last Admin controller removed. Removing all other controllers.");
|
||||
hap_remove_all_controllers();
|
||||
}
|
||||
|
||||
hap_tlv_data_t tlv_data = {
|
||||
.bufptr = buf,
|
||||
.bufsize = bufsize,
|
||||
.curlen = 0,
|
||||
};
|
||||
uint8_t state = STATE_M2;
|
||||
if (add_tlv(&tlv_data, kTLVType_State, sizeof(state), &state) < 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
*outlen = tlv_data.curlen;
|
||||
if (acc_unpaired) {
|
||||
hap_send_event(HAP_INTERNAL_EVENT_ACC_UNPAIRED);
|
||||
}
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
static int hap_process_pair_add(uint8_t *buf, int inlen, int bufsize, int *outlen)
|
||||
{
|
||||
char ctrl_id[HAP_CTRL_ID_LEN];
|
||||
uint8_t ltpkc[ED_KEY_LEN];
|
||||
uint8_t perms;
|
||||
memset(ctrl_id, 0, HAP_CTRL_ID_LEN);
|
||||
if ((get_value_from_tlv(buf, inlen, kTLVType_Identifier,
|
||||
ctrl_id, sizeof(ctrl_id)) < 0) ||
|
||||
(get_value_from_tlv(buf, inlen, kTLVType_PublicKey,
|
||||
ltpkc, sizeof(ltpkc)) < 0) ||
|
||||
(get_value_from_tlv(buf, inlen, kTLVType_Permissions,
|
||||
&perms, sizeof(perms)) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received");
|
||||
hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
hap_ctrl_data_t *ctrl = hap_get_controller(ctrl_id);
|
||||
if (ctrl) {
|
||||
/* If controller already exists, but the key does not match, return error */
|
||||
if (memcmp(ltpkc, ctrl->info.ltpk, ED_KEY_LEN)) {
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
} else {
|
||||
/* Else, just change the permissions */
|
||||
ctrl->info.perms = perms;
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Modifying Existing Controller %s", ctrl_id);
|
||||
hap_controller_save(ctrl);
|
||||
}
|
||||
} else {
|
||||
/* Check if there is space available for a new controller */
|
||||
ctrl = hap_controller_get_empty_loc();
|
||||
if (!ctrl) {
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_MaxPeers, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
strcpy(ctrl->info.id, ctrl_id);
|
||||
memcpy(ctrl->info.ltpk, ltpkc, ED_KEY_LEN);
|
||||
ctrl->info.perms = perms;
|
||||
hap_controller_save(ctrl);
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Added Controller %s", ctrl_id);
|
||||
}
|
||||
hap_tlv_data_t tlv_data = {
|
||||
.bufptr = buf,
|
||||
.bufsize = bufsize,
|
||||
.curlen = 0,
|
||||
};
|
||||
uint8_t state = STATE_M2;
|
||||
if (add_tlv(&tlv_data, kTLVType_State, sizeof(state), &state) < 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
*outlen = tlv_data.curlen;
|
||||
return HAP_SUCCESS;
|
||||
|
||||
}
|
||||
static int hap_process_pair_list(uint8_t *buf, int inlen, int bufsize, int *outlen)
|
||||
{
|
||||
hap_tlv_data_t tlv_data = {
|
||||
.bufptr = buf,
|
||||
.bufsize = bufsize,
|
||||
.curlen = 0,
|
||||
};
|
||||
int i;
|
||||
hap_ctrl_data_t *ctrl;
|
||||
hap_ctrl_info_t *ctrl_info;
|
||||
bool entry_added = false;
|
||||
for (i = 0; i < HAP_MAX_CONTROLLERS; i++) {
|
||||
ctrl = &hap_priv.controllers[i];
|
||||
if (!ctrl->valid)
|
||||
continue;
|
||||
/* If an entry is already added, include a separator */
|
||||
if (entry_added) {
|
||||
if (add_tlv(&tlv_data, kTLVType_Separator, 0, NULL) < 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown,
|
||||
buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
} else {
|
||||
/* Else, since this is the first entry, add the state */
|
||||
uint8_t state = STATE_M2;
|
||||
if (add_tlv(&tlv_data, kTLVType_State, sizeof(state), &state) < 0) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown,
|
||||
buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
}
|
||||
ctrl_info = &ctrl->info;
|
||||
if ((add_tlv(&tlv_data, kTLVType_Identifier,
|
||||
strlen(ctrl_info->id), ctrl_info->id) < 0) ||
|
||||
(add_tlv(&tlv_data, kTLVType_PublicKey,
|
||||
ED_KEY_LEN, ctrl_info->ltpk) < 0) ||
|
||||
(add_tlv(&tlv_data, kTLVType_Permissions,
|
||||
1, &ctrl_info->perms) < 0)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
entry_added = true;
|
||||
}
|
||||
*outlen = tlv_data.curlen;
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int hap_pairings_process(void *ctx, uint8_t *buf, int inlen, int bufsize, int *outlen)
|
||||
{
|
||||
if (!hap_is_req_admin(ctx)) {
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Authentication, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
uint8_t state, method;
|
||||
if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) ||
|
||||
(get_value_from_tlv(buf, inlen, kTLVType_Method,
|
||||
&method, sizeof(method)) < 0) ||
|
||||
(state != STATE_M1)) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received");
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
||||
if (method == HAP_METHOD_ADD_PAIRING) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Add Pairing received");
|
||||
return hap_process_pair_add(buf, inlen, bufsize, outlen);
|
||||
} else if (method == HAP_METHOD_REMOVE_PAIRING) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Remove Pairing received");
|
||||
return hap_process_pair_remove(buf, inlen, bufsize, outlen);
|
||||
} else if (method == HAP_METHOD_LIST_PAIRINGS) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "List Pairings received");
|
||||
return hap_process_pair_list(buf, inlen, bufsize, outlen);
|
||||
}
|
||||
hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen);
|
||||
return HAP_FAIL;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_PAIRINGS_H_
|
||||
#define _HAP_PAIRINGS_H_
|
||||
#include <esp_hap_pair_common.h>
|
||||
int hap_pairings_process(void *ctx, uint8_t *buf, int inlen, int bufsize, int *outlen);
|
||||
bool hap_is_req_secure(hap_secure_session_t *session);
|
||||
#endif /* _HAP_PAIRINGS_H_ */
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_SECURE_MESSAGE_H_
|
||||
#define _HAP_SECURE_MESSAGE_H_
|
||||
#include <stdint.h>
|
||||
#include <esp_http_server.h>
|
||||
/** Information for Software Token based authentication.
|
||||
* To be used only if MFi chip is not present on the accessory
|
||||
*/
|
||||
typedef struct {
|
||||
/** UUID for the accessory */
|
||||
uint8_t uuid[16];
|
||||
/** Token associated with the UUID */
|
||||
uint8_t *token;
|
||||
/* Length of the above token */
|
||||
size_t token_len;
|
||||
} hap_software_token_info_t;
|
||||
|
||||
int hap_register_secure_message_handler(httpd_handle_t handle);
|
||||
int hap_unregister_secure_message_handler(httpd_handle_t handle);
|
||||
#endif /* _HAP_SECURE_MESSAGE_H_ */
|
|
@ -1,329 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <hap_platform_memory.h>
|
||||
|
||||
#include <esp_hap_serv.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
void hap_serv_mark_primary(hap_serv_t *hs)
|
||||
{
|
||||
if (hs) {
|
||||
((__hap_serv_t *)hs)->primary = true;
|
||||
}
|
||||
}
|
||||
|
||||
void hap_serv_mark_hidden(hap_serv_t *hs)
|
||||
{
|
||||
if (hs) {
|
||||
((__hap_serv_t *)hs)->hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get service hidden attribute
|
||||
*/
|
||||
bool hap_serv_get_hidden(hap_serv_t *hs)
|
||||
{
|
||||
if (hs) {
|
||||
return ((__hap_serv_t *)hs)->hidden;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void hap_serv_set_iid(hap_serv_t *hs, int32_t iid)
|
||||
{
|
||||
if (hs) {
|
||||
((__hap_serv_t *)hs)->iid = iid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get service "primary" attribute
|
||||
*/
|
||||
bool hap_serv_get_primary(hap_serv_t *hs)
|
||||
{
|
||||
if (hs) {
|
||||
return ((__hap_serv_t *)hs)->primary;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
hap_char_t *hap_serv_get_first_char(hap_serv_t *hs)
|
||||
{
|
||||
return ((__hap_serv_t *)hs)->chars;
|
||||
}
|
||||
/**
|
||||
* @brief get target characteristics by it's IID
|
||||
*/
|
||||
hap_char_t *hap_serv_get_char_by_iid(hap_serv_t *hs, int32_t iid)
|
||||
{
|
||||
if (!hs)
|
||||
return NULL;
|
||||
|
||||
hap_char_t *hc;
|
||||
for (hc = hap_serv_get_first_char(hs); hc; hc = hap_char_get_next(hc)) {
|
||||
if (((__hap_char_t *)hc)->iid == iid)
|
||||
return hc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get target characteristics by it's UUID
|
||||
*/
|
||||
hap_char_t *hap_serv_get_char_by_uuid(hap_serv_t *hs, const char *uuid)
|
||||
{
|
||||
if (!hs | !uuid)
|
||||
return NULL;
|
||||
|
||||
hap_char_t *hc;
|
||||
for (hc = hap_serv_get_first_char(hs); hc; hc = hap_char_get_next(hc)) {
|
||||
if (!strcmp(((__hap_char_t *)hc)->type_uuid, uuid))
|
||||
return hc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get characteristics UUID prefix number
|
||||
*/
|
||||
const char *hap_serv_get_uuid(hap_serv_t *hs)
|
||||
{
|
||||
return ((__hap_serv_t *)hs)->type_uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default service bulk read callback, which will be registered while creating a service.
|
||||
* It will internally call the actual read routines
|
||||
*/
|
||||
static int hap_serv_def_bulk_read_cb(hap_read_data_t read_data[], int count,
|
||||
void *serv_priv, void *read_priv)
|
||||
{
|
||||
int i;
|
||||
if (!count) {
|
||||
return HAP_FAIL;
|
||||
}
|
||||
__hap_serv_t *hs = (__hap_serv_t *)hap_char_get_parent(read_data[0].hc);
|
||||
/* If no read routine is registered, just return success so that the cached values
|
||||
* will be used
|
||||
*/
|
||||
if (!hs->read_cb) {
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
|
||||
int ret = HAP_SUCCESS;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (hs->read_cb(read_data[i].hc, read_data[i].status, serv_priv, read_priv) != HAP_SUCCESS) {
|
||||
ret = HAP_FAIL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* @brief HAP create a service
|
||||
*/
|
||||
hap_serv_t *hap_serv_create(const char *type_uuid)
|
||||
{
|
||||
ESP_MFI_ASSERT(type_uuid);
|
||||
__hap_serv_t *_hs = hap_platform_memory_calloc(1, sizeof(__hap_serv_t));
|
||||
if (!_hs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_hs->type_uuid = type_uuid;
|
||||
_hs->bulk_read = hap_serv_def_bulk_read_cb;
|
||||
|
||||
return (hap_serv_t *)_hs;
|
||||
}
|
||||
|
||||
int hap_serv_link_serv(hap_serv_t *hs, hap_serv_t *linked_serv)
|
||||
{
|
||||
if (!hs || !linked_serv)
|
||||
return HAP_FAIL;
|
||||
|
||||
hap_linked_serv_t *cur = hap_platform_memory_calloc(1, sizeof(hap_linked_serv_t));
|
||||
if (!cur)
|
||||
return HAP_FAIL;
|
||||
cur->hs = linked_serv;
|
||||
|
||||
__hap_serv_t *_hs = (__hap_serv_t *)hs;
|
||||
hap_linked_serv_t *linked = _hs->linked_servs;
|
||||
|
||||
if (!linked) {
|
||||
_hs->linked_servs = cur;
|
||||
return HAP_SUCCESS;
|
||||
} else {
|
||||
while(linked->next) {
|
||||
linked = linked->next;
|
||||
}
|
||||
linked->next = cur;
|
||||
return HAP_SUCCESS;
|
||||
}
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP get target service IID
|
||||
*/
|
||||
uint32_t hap_serv_get_iid(hap_serv_t *hs)
|
||||
{
|
||||
if (!hs)
|
||||
return 0;
|
||||
|
||||
__hap_serv_t *tmp = (__hap_serv_t *)hs;
|
||||
|
||||
return tmp->iid;
|
||||
}
|
||||
|
||||
const char *hap_serv_get_type_uuid(hap_serv_t *hs)
|
||||
{
|
||||
if (!hs)
|
||||
return 0;
|
||||
|
||||
__hap_serv_t *tmp = (__hap_serv_t *)hs;
|
||||
|
||||
return tmp->type_uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HAP delete target service
|
||||
*/
|
||||
void hap_serv_delete(hap_serv_t *hs)
|
||||
{
|
||||
/* Returning success even if pointer is NULL, because it means
|
||||
* that the service is absent and as good as deleted
|
||||
*/
|
||||
if (!hs)
|
||||
return;
|
||||
__hap_serv_t *_hs = (__hap_serv_t *)hs;
|
||||
__hap_char_t *_hc = (__hap_char_t *)_hs->chars;
|
||||
while (_hc) {
|
||||
_hs->chars = _hc->next_char;
|
||||
hap_char_delete((hap_char_t *)_hc);
|
||||
_hc = (__hap_char_t *)_hs->chars;
|
||||
}
|
||||
if (_hs->linked_servs) {
|
||||
hap_linked_serv_t *cur = _hs->linked_servs;
|
||||
hap_linked_serv_t *next = cur->next;
|
||||
while (next) {
|
||||
hap_platform_memory_free(cur);
|
||||
cur = next;
|
||||
next = cur->next;
|
||||
}
|
||||
hap_platform_memory_free(cur);
|
||||
}
|
||||
hap_platform_memory_free(hs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add a characteristics to a service
|
||||
*/
|
||||
int hap_serv_add_char(hap_serv_t *hs, hap_char_t *hc)
|
||||
{
|
||||
if (!hs || !hc)
|
||||
return -1;
|
||||
__hap_serv_t *_hs = (__hap_serv_t *)hs;
|
||||
__hap_char_t *_hc = (__hap_char_t *)hc;
|
||||
|
||||
if (_hc->parent) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Characteristic already added");
|
||||
return HAP_FAIL;
|
||||
}
|
||||
|
||||
/* If the service has no characteristics, add this as the first */
|
||||
if (!_hs->chars) {
|
||||
_hs->chars = hc;
|
||||
} else {
|
||||
/* Else loop through the characteristics to get to the last one,
|
||||
* and add this at the end
|
||||
*/
|
||||
__hap_char_t *temp = (__hap_char_t *)_hs->chars;
|
||||
while (temp->next_char)
|
||||
temp = (__hap_char_t *)temp->next_char;
|
||||
temp->next_char = hc;
|
||||
}
|
||||
if (_hs->parent) {
|
||||
_hc->iid = ((__hap_acc_t *)(_hs->parent))->next_iid++;
|
||||
}
|
||||
_hc->parent = hs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hap_serv_set_write_cb(hap_serv_t *hs, hap_serv_write_t write)
|
||||
{
|
||||
if (hs) {
|
||||
((__hap_serv_t *)hs)->write_cb = write;
|
||||
}
|
||||
}
|
||||
|
||||
void hap_serv_set_read_cb(hap_serv_t *hs, hap_serv_read_t read)
|
||||
{
|
||||
if (hs) {
|
||||
((__hap_serv_t *)hs)->read_cb = read;
|
||||
}
|
||||
}
|
||||
|
||||
void hap_serv_set_bulk_read_cb(hap_serv_t *hs, hap_serv_bulk_read_t read)
|
||||
{
|
||||
if (hs) {
|
||||
((__hap_serv_t *)hs)->bulk_read = read;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hap_serv_t *hap_serv_get_next(hap_serv_t *hs)
|
||||
{
|
||||
if (hs) {
|
||||
return ((__hap_serv_t *)hs)->next_serv;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
hap_acc_t *hap_serv_get_parent(hap_serv_t *hs)
|
||||
{
|
||||
if (hs) {
|
||||
return ((__hap_serv_t *)hs)->parent;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void hap_serv_set_priv(hap_serv_t *hs, void *priv)
|
||||
{
|
||||
if (hs) {
|
||||
((__hap_serv_t *)hs)->priv = priv;
|
||||
}
|
||||
}
|
||||
|
||||
void *hap_serv_get_priv(hap_serv_t *hs)
|
||||
{
|
||||
if (hs) {
|
||||
return ((__hap_serv_t *)hs)->priv;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HAP_SERV_H_
|
||||
#define _HAP_SERV_H_
|
||||
|
||||
#include <hap.h>
|
||||
#include <esp_hap_char.h>
|
||||
#include <esp_hap_acc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct hap_linked_serv {
|
||||
hap_serv_t *hs;
|
||||
struct hap_linked_serv *next;
|
||||
} hap_linked_serv_t;
|
||||
|
||||
typedef struct hap_linked_serv hap_linked_serv_t;
|
||||
|
||||
/**
|
||||
* HAP service information
|
||||
*/
|
||||
typedef struct {
|
||||
const char *type_uuid; /* String that defines the type of the service. */
|
||||
|
||||
uint32_t iid; /* service instance ID */
|
||||
|
||||
bool hidden; /* If set it to be True, the service is not visible to user. */
|
||||
bool primary; /* If set it to be True, this is the primary service of the accessory. */
|
||||
|
||||
/**
|
||||
* List of Characteristic objects. Must not be empty. The maximum number of characteristics
|
||||
* allowed is 100, and each characteristic in the array must have a unique type.
|
||||
*/
|
||||
hap_char_t *chars;
|
||||
hap_acc_t *parent;
|
||||
hap_serv_t *next_serv;
|
||||
|
||||
hap_serv_write_t write_cb;
|
||||
hap_serv_read_t read_cb;
|
||||
hap_serv_bulk_read_t bulk_read;
|
||||
hap_linked_serv_t *linked_servs;
|
||||
void *priv;
|
||||
} __hap_serv_t;
|
||||
|
||||
bool hap_serv_get_hidden(hap_serv_t *hs);
|
||||
bool hap_serv_get_primary(hap_serv_t *hs);
|
||||
hap_char_t *hap_serv_get_char_by_iid(hap_serv_t *hs, int32_t iid);
|
||||
const char *hap_serv_get_uuid(hap_serv_t *hs);
|
||||
hap_serv_t *hap_serv_create(const char *type_uuid);
|
||||
void hap_serv_delete(hap_serv_t *hs);
|
||||
int hap_serv_add_char(hap_serv_t *hs, hap_char_t *hc);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HAP_SERV_H_ */
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_log.h>
|
||||
#include <hap.h>
|
||||
|
||||
#include <base36.h>
|
||||
|
||||
static const char *TAG = "esp_hap_setup_payload";
|
||||
|
||||
#define SETUP_CODE_MASK 0x0000000007ffffff
|
||||
#define HAP_OVER_IP_MASK 0x0000000010000000
|
||||
#define WAC_MASK 0x0000000040000000
|
||||
#define SETUP_PAYLOAD_PREFIX "X-HM://00"
|
||||
|
||||
static void remove_chars(char *str, char c)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
while(str[i]) {
|
||||
if (str[i] != c) {
|
||||
str[j] = str[i];
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
str[j] = 0;
|
||||
}
|
||||
|
||||
char *esp_hap_get_setup_payload(char *setup_code, char *setup_id, bool wac_support, hap_cid_t cid)
|
||||
{
|
||||
if (!setup_code || !setup_id) {
|
||||
ESP_LOGE(TAG, "Setup code or Setup ID cannot be NULL");
|
||||
return NULL;
|
||||
}
|
||||
uint64_t payload = 0;
|
||||
if (strlen(setup_code) != 10 || strlen(setup_id) != 4) {
|
||||
ESP_LOGE(TAG, "Setup code or Setup ID not correct. Eg. 111-22-333, ES32");
|
||||
return NULL;
|
||||
}
|
||||
char setup_code_copy[11];
|
||||
strcpy(setup_code_copy, setup_code);
|
||||
remove_chars(setup_code_copy, '-');
|
||||
int64_t code = atoi(setup_code_copy);
|
||||
int64_t category = cid;
|
||||
category <<= 31;
|
||||
|
||||
payload |= code;
|
||||
payload |= category;
|
||||
payload |= HAP_OVER_IP_MASK;
|
||||
if (wac_support) {
|
||||
payload |= WAC_MASK;
|
||||
}
|
||||
char *base36_str = base36_to_str(payload);
|
||||
char setup_payload[24];
|
||||
snprintf(setup_payload, sizeof(setup_payload), "%s%s%s", SETUP_PAYLOAD_PREFIX, base36_str, setup_id);
|
||||
free(base36_str);
|
||||
return strdup(setup_payload);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HAP_WAC_H_
|
||||
#define _HAP_WAC_H_
|
||||
int hap_wac_start(void);
|
||||
int hap_wac2_network_switch(void);
|
||||
int hap_wac2_finish(void);
|
||||
int hap_wac2_stop(void);
|
||||
bool hap_is_mfi_auth_enabled();
|
||||
#endif /* _HAP_WAC_H_ */
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <esp_log.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
#include <string.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_hap_database.h>
|
||||
|
||||
esp_err_t hap_wifi_is_provisioned(bool *provisioned)
|
||||
{
|
||||
if (!provisioned) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*provisioned = false;
|
||||
|
||||
/* Get Wi-Fi Station configuration */
|
||||
wifi_config_t wifi_cfg;
|
||||
if (esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (strlen((const char *) wifi_cfg.sta.ssid)) {
|
||||
*provisioned = true;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
bool hap_is_network_configured(void)
|
||||
{
|
||||
/* If only the Ethernet is enabled, return true */
|
||||
if (hap_priv.transport == HAP_TRANSPORT_ETHERNET) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool provisioned = false;
|
||||
hap_wifi_is_provisioned(&provisioned);
|
||||
return provisioned;
|
||||
}
|
||||
|
||||
void hap_erase_network_info(void)
|
||||
{
|
||||
esp_wifi_restore();
|
||||
}
|
||||
|
||||
esp_err_t hap_wifi_softap_start(char *ssid)
|
||||
{
|
||||
if (!ssid) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SSID cannot be NULL");
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Starting SoftAP with SSID: %s", ssid);
|
||||
wifi_config_t wifi_config = {
|
||||
.ap = {
|
||||
.ssid = "",
|
||||
.ssid_len = 0,
|
||||
.max_connection = 4,
|
||||
.password = "",
|
||||
.authmode = WIFI_AUTH_OPEN
|
||||
},
|
||||
};
|
||||
size_t ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid));
|
||||
memcpy(wifi_config.ap.ssid, ssid, ssid_len);
|
||||
wifi_mode_t mode;
|
||||
esp_wifi_get_mode(&mode);
|
||||
if (mode == WIFI_MODE_STA) {
|
||||
esp_wifi_set_mode(WIFI_MODE_APSTA);
|
||||
} else {
|
||||
esp_wifi_set_mode(WIFI_MODE_AP);
|
||||
}
|
||||
esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config);
|
||||
esp_wifi_start();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t hap_wifi_softap_stop(void)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Stopping SoftAP.");
|
||||
wifi_mode_t mode;
|
||||
esp_wifi_get_mode(&mode);
|
||||
if (mode == WIFI_MODE_AP) {
|
||||
esp_wifi_stop();
|
||||
}
|
||||
esp_wifi_set_mode(WIFI_MODE_STA);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t hap_wifi_sta_connect(wifi_config_t *config)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Connecting to Wi-Fi.");
|
||||
wifi_mode_t mode;
|
||||
esp_wifi_get_mode(&mode);
|
||||
if (mode == WIFI_MODE_AP || mode == WIFI_MODE_APSTA) {
|
||||
esp_wifi_set_mode(WIFI_MODE_APSTA);
|
||||
} else {
|
||||
esp_wifi_set_mode(WIFI_MODE_STA);
|
||||
}
|
||||
esp_wifi_set_config(ESP_IF_WIFI_STA, config);
|
||||
esp_wifi_start();
|
||||
esp_wifi_connect();
|
||||
return ESP_OK;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_WIFI_H_
|
||||
#define _HAP_WIFI_H_
|
||||
#include <hap.h>
|
||||
bool hap_is_network_configured();
|
||||
void hap_wifi_restart();
|
||||
void hap_erase_network_info();
|
||||
#endif /* _HAP_WIFI_H_ */
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include "mbedtls/aes.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_mfi_aes.h"
|
||||
|
||||
static const char* TAG = "mfi_aes_adapter";
|
||||
|
||||
/*!
|
||||
* @group AES 128-bit Counter Mode API
|
||||
|
||||
* @abstract API to encrypt or decrypt using AES-128 in counter mode.
|
||||
*
|
||||
* Call esp_mfi_aes_ctr_init to initialize the context. Don't use the context until it has been initialized.
|
||||
* Call esp_mfi_aes_ctr_update to encrypt or decrypt N bytes of input and generate N bytes of output.
|
||||
* Call esp_mfi_aes_ctr_final to finalize the context. After finalizing, you must call AES_CTR_Init to use it again.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint8_t key[MFI_AES_CTR_SIZE];
|
||||
uint8_t nonce[MFI_AES_CTR_SIZE];
|
||||
} aes_ctr_context_t;
|
||||
|
||||
/**
|
||||
* @bref Create AES context
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return the AES context point
|
||||
*/
|
||||
esp_mfi_aes_ctr_t esp_mfi_aes_ctr_new(void)
|
||||
{
|
||||
aes_ctr_context_t *context = NULL;
|
||||
context = (aes_ctr_context_t *) malloc(sizeof(aes_ctr_context_t));
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Initialize AES context, include initialize the key and nonce
|
||||
*
|
||||
* @param incontext AES context point
|
||||
* inkey AES key
|
||||
* innonce AES nonce
|
||||
*
|
||||
* @return the result
|
||||
* 0 : sucessful
|
||||
* others : failed
|
||||
*/
|
||||
int esp_mfi_aes_ctr_init(esp_mfi_aes_ctr_t incontext, const uint8_t inkey[MFI_AES_CTR_SIZE], const uint8_t innonce[MFI_AES_CTR_SIZE])
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (incontext == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
aes_ctr_context_t *context = incontext;
|
||||
|
||||
memcpy(context->key, inkey, MFI_AES_CTR_SIZE);
|
||||
memcpy(context->nonce, innonce, MFI_AES_CTR_SIZE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Update AES context
|
||||
*
|
||||
* @param incontext AES context point
|
||||
* insrc the data point of update
|
||||
* insrclen the data length
|
||||
* indst the data pint of output
|
||||
*
|
||||
* @return the result
|
||||
* 0 : sucessful
|
||||
* others : failed
|
||||
*/
|
||||
int esp_mfi_aes_ctr_update(esp_mfi_aes_ctr_t incontext, const void *insrc, uint16_t insrclen, void *indst)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (incontext == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
aes_ctr_context_t *context = incontext;
|
||||
size_t offset = 0;
|
||||
uint8_t stream_block[MFI_AES_CTR_SIZE];
|
||||
mbedtls_aes_context ctx;
|
||||
mbedtls_aes_init(&ctx);
|
||||
|
||||
ret = mbedtls_aes_setkey_enc( &ctx, context->key, 128);
|
||||
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mfi aes setkey[%d]", ret);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = mbedtls_aes_crypt_ctr(&ctx, insrclen, &offset, context->nonce, stream_block, (uint8_t *) insrc, indst);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mfi aes crypt[%d]", ret);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Destory AES context point
|
||||
*
|
||||
* @param incontext AES context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_aes_ctr_final(esp_mfi_aes_ctr_t incontext)
|
||||
{
|
||||
if (incontext) {
|
||||
memset((aes_ctr_context_t *) incontext, 0, sizeof(aes_ctr_context_t));
|
||||
free(incontext);
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef ESP_MFI_AES_H_
|
||||
#define ESP_MFI_AES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MFI_AES_CTR_SIZE 16
|
||||
|
||||
typedef void* esp_mfi_aes_ctr_t;
|
||||
|
||||
/**
|
||||
* @brief Create AES context
|
||||
*
|
||||
* @return pointer of the AES context
|
||||
*/
|
||||
esp_mfi_aes_ctr_t esp_mfi_aes_ctr_new(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize AES context, including the key and nonce
|
||||
*
|
||||
* @param incontext pointer of the AES context
|
||||
* @param inkey AES key
|
||||
* @param innonce AES nonce
|
||||
*
|
||||
* @return
|
||||
* - 0 : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
int esp_mfi_aes_ctr_init(esp_mfi_aes_ctr_t incontext, const uint8_t inkey[MFI_AES_CTR_SIZE], const uint8_t innonce[MFI_AES_CTR_SIZE]);
|
||||
|
||||
/**
|
||||
* @brief Update AES context
|
||||
*
|
||||
* @param incontext AES context point
|
||||
* @param insrc pointer of the source data to be updated
|
||||
* @param insrclen source data length
|
||||
* @param indst pointer of the updated data
|
||||
*
|
||||
* @return
|
||||
* - 0 : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
int esp_mfi_aes_ctr_update(esp_mfi_aes_ctr_t incontext, const void *insrc, uint16_t insrclen, void *indst);
|
||||
|
||||
/**
|
||||
* @brief Destroy AES context pointer
|
||||
*
|
||||
* @param incontext pointer of the AES context
|
||||
*/
|
||||
void esp_mfi_aes_ctr_final(esp_mfi_aes_ctr_t incontext);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ESP_MFI_AES_H_ */
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include "mbedtls/base64.h"
|
||||
|
||||
/**
|
||||
* @brief transform bin data to base64 data
|
||||
*/
|
||||
int esp_mfi_base64_encode(const char *src, int len, char *dest, int dest_len, int *out_len)
|
||||
{
|
||||
int ret = mbedtls_base64_encode((unsigned char *)dest, dest_len, (size_t *)out_len, (unsigned char *)src, len);
|
||||
if (ret != 0){
|
||||
return -EINVAL;
|
||||
} else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief transform base64 data to bin data
|
||||
*/
|
||||
int esp_mfi_base64_decode(const char *src, int len, char *dest, int dest_len, int *out_len)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = mbedtls_base64_decode((unsigned char *)dest, dest_len, (size_t *)out_len, (unsigned char *)src, len);
|
||||
if (ret != 0) {
|
||||
return -EINVAL;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef ESP_MFI_BASE64_H_
|
||||
#define ESP_MFI_BASE64_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief transform bin data to base64 data
|
||||
*
|
||||
* @param src input data point
|
||||
* @param len input data length
|
||||
* @param dest output data point
|
||||
* @param dest_len output data buffer length
|
||||
* @param out_len output data length
|
||||
*
|
||||
* @return
|
||||
* - 0 : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
int esp_mfi_base64_encode(const char *src, int len, char *dest, int dest_len, int *out_len);
|
||||
|
||||
/**
|
||||
* @brief transform base64 data to bin data
|
||||
*
|
||||
* @param src input data point
|
||||
* @param len input data length
|
||||
* @param dest output data point
|
||||
* @param dest_len output data buffer length
|
||||
* @param out_len output data length
|
||||
*
|
||||
* @return
|
||||
* - 0 : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
int esp_mfi_base64_decode(const char *src, int len, char *dest, int dest_len, int *out_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ESP_MFI_BASE64_H_ */
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <hap.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
|
||||
#define RED_CHAR 31
|
||||
#define GREEN_CHAR 32
|
||||
#define YELLOW_CHAR 33
|
||||
#define BLUE_CHAR 34
|
||||
#define CYAN_CHAR 36
|
||||
#define WHITE_CHAR 37
|
||||
|
||||
#ifdef CONFIG_MFI_DEBUG_LEVEL_INIT
|
||||
#define MFI_DEBUG_LEVEL_INIT CONFIG_MFI_DEBUG_LEVEL_INIT
|
||||
#else /* CONFIG_MFI_DEBUG_LEVEL_INIT */
|
||||
#define MFI_DEBUG_LEVEL_INIT 0
|
||||
#endif /* CONFIG_MFI_DEBUG_LEVEL_INIT */
|
||||
|
||||
static uint32_t mfi_debug_level = MFI_DEBUG_LEVEL_INIT;
|
||||
|
||||
/**
|
||||
* @bref set the MFI debugging level
|
||||
*/
|
||||
int esp_mfi_set_debug_level(uint32_t level)
|
||||
{
|
||||
mfi_debug_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref get the MFI debugging level and output data color
|
||||
*/
|
||||
uint32_t esp_mfi_get_debug_level(uint32_t level, uint32_t *color)
|
||||
{
|
||||
const uint32_t prospect_table[] = {
|
||||
0, /* no */
|
||||
WHITE_CHAR, /* information: 1, color(37: white) */
|
||||
GREEN_CHAR, /* warn : 3, color(32: green) */
|
||||
RED_CHAR, /* error : 3, color(31: red) */
|
||||
YELLOW_CHAR, /* assert : 4, color(33: yellow) */
|
||||
CYAN_CHAR /* block : 5, color(36: cyan) */
|
||||
/* others : n, color(34: blue) */
|
||||
};
|
||||
const uint32_t prospect_table_size = sizeof(prospect_table) / sizeof(prospect_table[0]);
|
||||
|
||||
if (level < prospect_table_size)
|
||||
*color = prospect_table[level];
|
||||
else
|
||||
*color = BLUE_CHAR;
|
||||
|
||||
return mfi_debug_level;
|
||||
}
|
||||
|
||||
void hap_set_debug_level(hap_debug_level_t level)
|
||||
{
|
||||
esp_mfi_set_debug_level(level);
|
||||
}
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ESP_MFI_DEBUG_H_
|
||||
#define ESP_MFI_DEBUG_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#define ESP_MFI_DEBUG_FL "\n"
|
||||
#define CONFIG_ESP_MFI_DEBUG_ENABLE
|
||||
#ifdef CONFIG_ESP_MFI_DEBUG_ENABLE
|
||||
// #define ESP_MFI_DEBUG_ENABLE
|
||||
#endif /* CONFIG_ESP_MFI_DEBUG_ENABLE */
|
||||
|
||||
#define CONFIG_ESP_MFI_ASSERT
|
||||
#ifdef CONFIG_ESP_MFI_ASSERT
|
||||
// #define ESP_MFI_ASSERT_ENABLE
|
||||
#endif /* CONFIG_ESP_MFI_ASSERT */
|
||||
|
||||
#define CONFIG_MFI_DEBUG_LEVEL_INIT 0
|
||||
#define CONFIG_ESP_MFI_ASSERT_BLOCK
|
||||
#ifdef CONFIG_ESP_MFI_ASSERT_BLOCK
|
||||
#define ESP_MFI_ASSERT_BLOCK() while (1)
|
||||
#else /* CONFIG_ESP_MFI_ASSERT_BLOCK */
|
||||
#define ESP_MFI_ASSERT_BLOCK()
|
||||
#endif /* CONFIG_ESP_MFI_ASSERT_BLOCK */
|
||||
|
||||
/* debug level with different color */
|
||||
#define ESP_MFI_DEBUG_INFO 1
|
||||
#define ESP_MFI_DEBUG_WARN 2
|
||||
#define ESP_MFI_DEBUG_ERR 3
|
||||
#define ESP_MFI_DEBUG_ASSERT 4
|
||||
#define ESP_MFI_DEBUG_BLOCK 5
|
||||
|
||||
/**
|
||||
* @bref set the MFI debugging level
|
||||
*
|
||||
* @param level debugging level
|
||||
*
|
||||
* @return the result
|
||||
* = 0 : OK
|
||||
* others : failed
|
||||
*/
|
||||
int esp_mfi_set_debug_level(uint32_t level);
|
||||
|
||||
/**
|
||||
* @bref get the MFI debugging level and output data color
|
||||
*
|
||||
* @param level input debug level
|
||||
* @param color data color
|
||||
*
|
||||
* @return MFI debugging level
|
||||
*/
|
||||
uint32_t esp_mfi_get_debug_level(uint32_t level, uint32_t *color);
|
||||
|
||||
/**
|
||||
* @bref format the string and data, then output it
|
||||
*
|
||||
* @param level if level > MFI_DEBUG_LEVEL then output it
|
||||
* @param fmt format string
|
||||
* @param ... parameters of format string
|
||||
*
|
||||
* @return none
|
||||
*
|
||||
* void ESP_MFI_DEBUG(unsigned int level, const char *fmt, ...);
|
||||
*/
|
||||
#ifdef ESP_MFI_DEBUG_ENABLE
|
||||
/*
|
||||
#define ESP_MFI_DEBUG(l, fmt, ...) \
|
||||
{ \
|
||||
uint32_t __color_LINE; \
|
||||
if (l > esp_mfi_get_debug_level(l, &__color_LINE)) { \
|
||||
printf("\e[1;%dm" fmt "\e[0m" ESP_MFI_DEBUG_FL, \
|
||||
__color_LINE, ##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
#define ESP_MFI_DEBUG_INTR(l, fmt, ...) \
|
||||
{ \
|
||||
uint32_t __color_LINE; \
|
||||
if (l > esp_mfi_get_debug_level(l, &__color_LINE)) { \
|
||||
ets_printf("\e[1;%dm" fmt "\e[0m" ESP_MFI_DEBUG_FL, \
|
||||
__color_LINE, ##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ESP_MFI_DEBUG(l, fmt, ...) \
|
||||
{ \
|
||||
uint32_t __color_LINE; \
|
||||
if (l > esp_mfi_get_debug_level(l, &__color_LINE)) { \
|
||||
printf("[%7lu] " fmt "\n", ((unsigned long) (esp_timer_get_time() / 1000ULL)), ##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
#define ESP_MFI_DEBUG_INTR(l, fmt, ...) \
|
||||
{ \
|
||||
uint32_t __color_LINE; \
|
||||
if (l > esp_mfi_get_debug_level(l, &__color_LINE)) { \
|
||||
printf("[%7lu] " fmt "\n", ((unsigned long) (esp_timer_get_time() / 1000ULL)), ##__VA_ARGS__); \
|
||||
} \
|
||||
}*/
|
||||
|
||||
#define ESP_MFI_DEBUG(l, fmt, ...) \
|
||||
{ \
|
||||
printf("[%7lu] " fmt "\n", ((unsigned long) (esp_timer_get_time() / 1000ULL)), ##__VA_ARGS__); \
|
||||
}
|
||||
#define ESP_MFI_DEBUG_INTR(l, fmt, ...) \
|
||||
{ \
|
||||
printf("[%7lu] " fmt "\n", ((unsigned long) (esp_timer_get_time() / 1000ULL)), ##__VA_ARGS__); \
|
||||
}
|
||||
#else /* ESP_MFI_DEBUG_ENABLE */
|
||||
#define ESP_MFI_DEBUG(l, fmt, ...)
|
||||
#define ESP_MFI_DEBUG_INTR(l, fmt, ...)
|
||||
#endif /* ESP_MFI_DEBUG_ENABLE */
|
||||
|
||||
/**
|
||||
* @bref if the signal is false(0) do something depended on configuration
|
||||
*
|
||||
* @param conditions checking conditions
|
||||
*
|
||||
* @return none
|
||||
*
|
||||
* void ESP_MFI_ASSERT(int conditions);
|
||||
*/
|
||||
#ifdef ESP_MFI_ASSERT_ENABLE
|
||||
#define ESP_MFI_ASSERT(cond) \
|
||||
{ \
|
||||
if (!(cond)) { \
|
||||
printf("\e[1;33m" "ESP_MFI assert file %s line %d" ESP_MFI_DEBUG_FL, \
|
||||
__FILE__, __LINE__); \
|
||||
ESP_MFI_ASSERT_BLOCK(); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define ESP_MFI_ASSERT(cond)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @bref check if data length matches given length
|
||||
*
|
||||
* @param optlen data length
|
||||
* @param opttype data
|
||||
*
|
||||
* @return none
|
||||
*
|
||||
* void ESP_MFI_CHECK_OPTLEN(int conditions, (all type) data);
|
||||
*/
|
||||
#define ESP_MFI_CHECK_OPTLEN(optlen, opttype) \
|
||||
do { \
|
||||
if ((optlen) > sizeof(opttype)) { \
|
||||
return -1; \
|
||||
} \
|
||||
} while(0) \
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ESP_MFI_DEBUG_H_ */
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <esp_http_server.h>
|
||||
#include <esp_mfi_debug.h>
|
||||
#include <esp_hap_pair_common.h>
|
||||
#include <esp_hap_pair_setup.h>
|
||||
#include <esp_hap_database.h>
|
||||
#include <hap.h>
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(HAP_WAC_EVENT);
|
||||
|
||||
int hap_pair_setup_manage_mfi_auth(pair_setup_ctx_t *ps_ctx, hap_tlv_data_t *tlv_data, hap_tlv_error_t *tlv_error)
|
||||
{
|
||||
|
||||
if (ps_ctx->method == HAP_METHOD_PAIR_SETUP) {
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Secure pair setup not supported. Please use MFi variant of the SDK.");
|
||||
*tlv_error = kTLVError_Unknown;
|
||||
return HAP_FAIL;
|
||||
}
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_WARN, "Using pair-setup without MFi.");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int hap_enable_mfi_auth(hap_mfi_auth_type_t auth_type)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_WARN, "MFi auth not supported. Falling back to HAP_MFI_AUTH_NONE");
|
||||
hap_priv.auth_type = HAP_MFI_AUTH_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hap_wac_start(void)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "WAC not supported. Please use MFi variant of the SDK.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int hap_wac_stop(void)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "WAC not supported. Please use MFi variant of the SDK.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
int hap_enable_hw_auth(void)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "MFi HW Auth not supported. Please use MFi variant of the SDK.");
|
||||
return ESP_FAIL;
|
||||
|
||||
}
|
||||
int hap_enable_sw_auth(void)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "MFi SW Auth not supported. Please use MFi variant of the SDK.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
int hap_register_secure_message_handler(httpd_handle_t handle)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "MFi SW Auth not supported. Please use MFi variant of the SDK.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
int hap_unregister_secure_message_handler(httpd_handle_t handle)
|
||||
{
|
||||
ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "MFi SW Auth not supported. Please use MFi variant of the SDK.");
|
||||
return ESP_FAIL;
|
||||
}
|
|
@ -1,689 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#else
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_I2C_SOFTWARE
|
||||
#include "driver/gpio.h"
|
||||
#else
|
||||
#include "driver/i2c.h"
|
||||
#endif
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_mfi_i2c.h"
|
||||
|
||||
static const char *TAG = "mfi_i2c";
|
||||
|
||||
#ifndef CONFIG_I2C_SOFTWARE
|
||||
|
||||
#define I2C_MASTER_NUM I2C_NUM_0
|
||||
#define I2C_MASTER_FREQ_HZ CONFIG_IC2_SPEED
|
||||
#define I2C_MASTER_RX_BUF_DISABLE 0
|
||||
#define I2C_MASTER_TX_BUF_DISABLE 0
|
||||
#define ACK_CHECK_EN 1
|
||||
#define ACK_VAL 0
|
||||
#define NACK_VAL 1
|
||||
|
||||
/* To use GPIOs 17/18 for the Hardware I2C, replace the numbers 26/27 below
|
||||
*/
|
||||
#define I2C_MASTER_SDA_GPIO CONFIG_SDA_GPIO
|
||||
#define I2C_MASTER_SCL_GPIO CONFIG_SCL_GPIO
|
||||
|
||||
#define I2C_MASTER_MAX_READ CONFIG_I2C_MAX_READ_COUNT
|
||||
#define I2C_MASTER_RETRY_TIMES 500
|
||||
#define I2C_MASTER_TICKS_TIMES 2 * I2C_MASTER_RETRY_TIMES
|
||||
#define I2C_MASTER_MAX_RETRY 10
|
||||
#define I2C_MASTER_INTERNAL_TIMES 8 * I2C_MASTER_RETRY_TIMES
|
||||
/**
|
||||
* @brief Initialize I2C information
|
||||
*/
|
||||
int esp_mfi_i2c_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
i2c_config_t conf;
|
||||
int i2c_master_port = I2C_MASTER_NUM;
|
||||
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
conf.sda_io_num = I2C_MASTER_SDA_GPIO;
|
||||
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.scl_io_num = I2C_MASTER_SCL_GPIO;
|
||||
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
|
||||
|
||||
ret = i2c_param_config(i2c_master_port, &conf);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "I2C parameter initial fail %d", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "I2C driver initial fail %d", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief write data buffer to slave
|
||||
*/
|
||||
int esp_mfi_i2c_write(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if (!buff)
|
||||
return -EINVAL;
|
||||
|
||||
ESP_LOGI(TAG, "Writing to HW I2C");
|
||||
|
||||
int ret = 0;
|
||||
i2c_cmd_handle_t cmd = NULL;
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
// Send write address of the CP
|
||||
i2c_master_write_byte(cmd, slvaddr, ACK_CHECK_EN);
|
||||
// Send register address to slave.
|
||||
i2c_master_write_byte(cmd, regaddr, ACK_CHECK_EN);
|
||||
// Send data out.
|
||||
i2c_master_write(cmd, buff, len, ACK_CHECK_EN);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TICKS_TIMES / portTICK_RATE_MS);
|
||||
i ++;
|
||||
i2c_cmd_link_delete(cmd);
|
||||
ets_delay_us(I2C_MASTER_RETRY_TIMES);
|
||||
} while(ret != ESP_OK && i < I2C_MASTER_MAX_RETRY);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Write data to slave fail %d.", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief read data form slave
|
||||
*/
|
||||
int esp_mfi_i2c_read(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len)
|
||||
{
|
||||
uint16_t i, j = 0;
|
||||
|
||||
if (!buff)
|
||||
return -EINVAL;
|
||||
|
||||
ESP_LOGI(TAG, "Reading from HW I2C");
|
||||
|
||||
int ret = 0;
|
||||
i2c_cmd_handle_t cmd = NULL;
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
for (j = 0; j < I2C_MASTER_MAX_READ; j++) {
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
// Send write address of the CP
|
||||
i2c_master_write_byte(cmd, slvaddr, ACK_CHECK_EN);
|
||||
// Send register address to slave.
|
||||
i2c_master_write_byte(cmd, regaddr, ACK_CHECK_EN);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TICKS_TIMES / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if (ret == ESP_OK) {
|
||||
break;
|
||||
} else {
|
||||
ets_delay_us(I2C_MASTER_INTERNAL_TIMES);
|
||||
}
|
||||
}
|
||||
|
||||
ets_delay_us(I2C_MASTER_INTERNAL_TIMES);
|
||||
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write_byte(cmd, slvaddr + 1, ACK_CHECK_EN);
|
||||
if (len == 1)
|
||||
i2c_master_read_byte(cmd, buff, NACK_VAL);
|
||||
else {
|
||||
i2c_master_read(cmd, buff, len - 1, ACK_VAL);
|
||||
i2c_master_read_byte(cmd, buff + len - 1, NACK_VAL);
|
||||
}
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TICKS_TIMES / portTICK_RATE_MS);
|
||||
i ++;
|
||||
i2c_cmd_link_delete(cmd);
|
||||
} while (ret != ESP_OK && i < I2C_MASTER_MAX_RETRY);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Read data from slave fail %d.", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define MFI_CP_BUSY_RETRY_TIMES CONFIG_I2C_RETRY_COUNT
|
||||
|
||||
#define GPIO_Pin_26 GPIO_SEL_26
|
||||
#define GPIO_Pin_27 GPIO_SEL_27
|
||||
|
||||
#define gpio_set_output_level(a, b) gpio_set_level(a, b)
|
||||
#define gpio_get_input_level(a) gpio_get_level(a)
|
||||
|
||||
#define GPIO_Mode_Input_OutOD GPIO_MODE_INPUT_OUTPUT_OD
|
||||
#define GPIO_PullDown_DIS GPIO_PULLDOWN_DISABLE
|
||||
#define GPIO_PullUp_EN GPIO_PULLUP_ENABLE
|
||||
#define GPIO_Mode_Out_OD GPIO_MODE_OUTPUT_OD
|
||||
|
||||
#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO26_U
|
||||
#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO27_U
|
||||
#define I2C_MASTER_SDA_GPIO 26
|
||||
#define I2C_MASTER_SDA_PIN GPIO_Pin_26
|
||||
#define I2C_MASTER_SDA_FUNC FUNC_GPIO26_GPIO26
|
||||
#define I2C_MASTER_SCL_GPIO 27
|
||||
#define I2C_MASTER_SCL_PIN GPIO_Pin_27
|
||||
#define I2C_MASTER_SCL_FUNC FUNC_GPIO27_GPIO27
|
||||
|
||||
#define I2C_MASTER_SDA_HIGH_SCL_HIGH() \
|
||||
gpio_set_output_level(I2C_MASTER_SDA_GPIO,1); \
|
||||
gpio_set_output_level(I2C_MASTER_SCL_GPIO,1);
|
||||
|
||||
#define I2C_MASTER_SDA_HIGH_SCL_LOW() \
|
||||
gpio_set_output_level(I2C_MASTER_SDA_GPIO,1); \
|
||||
gpio_set_output_level(I2C_MASTER_SCL_GPIO,0);
|
||||
|
||||
#define I2C_MASTER_SDA_LOW_SCL_HIGH() \
|
||||
gpio_set_output_level(I2C_MASTER_SDA_GPIO,0); \
|
||||
gpio_set_output_level(I2C_MASTER_SCL_GPIO,1);
|
||||
|
||||
#define I2C_MASTER_SDA_LOW_SCL_LOW() \
|
||||
gpio_set_output_level(I2C_MASTER_SDA_GPIO,0); \
|
||||
gpio_set_output_level(I2C_MASTER_SCL_GPIO,0);
|
||||
|
||||
#define i2c_master_wait ets_delay_us
|
||||
|
||||
static void i2c_master_init(void);
|
||||
static void i2c_master_stop(void);
|
||||
|
||||
static uint8_t s_last_sda;
|
||||
static uint8_t s_last_scl;
|
||||
|
||||
/**
|
||||
* @brief set I2C SDA and SCL bit value for half CLK cycle
|
||||
*/
|
||||
static void i2c_master_setDC(uint8_t SDA, uint8_t SCL)
|
||||
{
|
||||
SDA &= 0x01;
|
||||
SCL &= 0x01;
|
||||
s_last_sda = SDA;
|
||||
s_last_scl = SCL;
|
||||
|
||||
if ((0 == SDA) && (0 == SCL)) {
|
||||
I2C_MASTER_SDA_LOW_SCL_LOW();
|
||||
} else if ((0 == SDA) && (1 == SCL)) {
|
||||
I2C_MASTER_SDA_LOW_SCL_HIGH();
|
||||
} else if ((1 == SDA) && (0 == SCL)) {
|
||||
I2C_MASTER_SDA_HIGH_SCL_LOW();
|
||||
} else {
|
||||
I2C_MASTER_SDA_HIGH_SCL_HIGH();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get I2C SDA bit value
|
||||
*/
|
||||
static uint8_t i2c_master_getDC(void)
|
||||
{
|
||||
uint8_t sda_out;
|
||||
|
||||
sda_out = gpio_get_input_level(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
|
||||
|
||||
return sda_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief initialize I2C bus to enable i2c operations
|
||||
*/
|
||||
static void i2c_master_init(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
|
||||
// when SCL = 0, toggle SDA to clear up
|
||||
i2c_master_setDC(0, 0) ;
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0) ;
|
||||
i2c_master_wait(5);
|
||||
|
||||
// set data_cnt to max value
|
||||
for (i = 0; i < 28; i++) {
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
}
|
||||
|
||||
// reset all
|
||||
i2c_master_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief configure SDA and SCL GPIO to open-drain output mode
|
||||
*/
|
||||
static void i2c_master_gpio_init(void)
|
||||
{
|
||||
|
||||
gpio_config_t io_config;
|
||||
io_config.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
io_config.mode = GPIO_MODE_INPUT_OUTPUT_OD;
|
||||
io_config.pin_bit_mask = I2C_MASTER_SDA_PIN;
|
||||
io_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_config.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
|
||||
gpio_config(&io_config);
|
||||
|
||||
io_config.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
io_config.mode = GPIO_MODE_OUTPUT_OD;
|
||||
io_config.pin_bit_mask = I2C_MASTER_SCL_PIN;
|
||||
io_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_config.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
|
||||
|
||||
gpio_config(&io_config);
|
||||
|
||||
gpio_pullup_en(I2C_MASTER_SDA_GPIO);
|
||||
gpio_pullup_en(I2C_MASTER_SCL_GPIO);
|
||||
gpio_pulldown_dis(I2C_MASTER_SDA_GPIO);
|
||||
gpio_pulldown_dis(I2C_MASTER_SCL_GPIO);
|
||||
|
||||
i2c_master_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set I2C to start operation
|
||||
*/
|
||||
static void i2c_master_start(void)
|
||||
{
|
||||
i2c_master_setDC(1, s_last_scl);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
i2c_master_setDC(0, 1);
|
||||
i2c_master_wait(5); // sda 0, scl 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set i2c to stop sending state
|
||||
*/
|
||||
static void i2c_master_stop(void)
|
||||
{
|
||||
i2c_master_wait(5);
|
||||
|
||||
i2c_master_setDC(0, s_last_scl);
|
||||
i2c_master_wait(5); // sda 0
|
||||
i2c_master_setDC(0, 1);
|
||||
i2c_master_wait(5); // sda 0, scl 1
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set ack to i2c bus as level value
|
||||
*/
|
||||
static void i2c_master_setAck(uint8_t level)
|
||||
{
|
||||
i2c_master_setDC(s_last_sda, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(level, 0);
|
||||
i2c_master_wait(5); // sda level, scl 0
|
||||
i2c_master_setDC(level, 1);
|
||||
i2c_master_wait(8); // sda level, scl 1
|
||||
i2c_master_setDC(level, 0);
|
||||
i2c_master_wait(5); // sda level, scl 0
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief confirm if peer send ack
|
||||
*/
|
||||
static uint8_t i2c_master_getAck(void)
|
||||
{
|
||||
uint8_t retVal;
|
||||
|
||||
i2c_master_setDC(s_last_sda, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5);
|
||||
|
||||
retVal = i2c_master_getDC();
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get I2C response
|
||||
*/
|
||||
static bool i2c_master_checkAck(void)
|
||||
{
|
||||
if (i2c_master_getAck()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief send I2C ack signal
|
||||
*/
|
||||
static void i2c_master_send_ack(void)
|
||||
{
|
||||
i2c_master_setAck(0x0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief send I2C not ack signal
|
||||
*/
|
||||
static void i2c_master_send_nack(void)
|
||||
{
|
||||
i2c_master_setAck(0x1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief read byte from i2c bus
|
||||
*/
|
||||
static uint8_t i2c_master_readByte(void)
|
||||
{
|
||||
uint8_t retVal = 0;
|
||||
uint8_t k, i;
|
||||
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(s_last_sda, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
|
||||
k = i2c_master_getDC();
|
||||
i2c_master_wait(5);
|
||||
|
||||
if (i == 7) {
|
||||
i2c_master_wait(3);
|
||||
}
|
||||
|
||||
k <<= (7 - i);
|
||||
retVal |= k;
|
||||
}
|
||||
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write byte to i2c
|
||||
*/
|
||||
static void i2c_master_writeByte(uint8_t wrdata)
|
||||
{
|
||||
uint8_t dat;
|
||||
int8_t i;
|
||||
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(s_last_sda, 0);
|
||||
i2c_master_wait(5);
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
dat = wrdata >> i;
|
||||
i2c_master_setDC(dat, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(dat, 1);
|
||||
i2c_master_wait(5);
|
||||
|
||||
if (i == 0) {
|
||||
i2c_master_wait(3); ////
|
||||
}
|
||||
|
||||
i2c_master_setDC(dat, 0);
|
||||
i2c_master_wait(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write byte to i2c and get check ack
|
||||
*/
|
||||
static bool i2c_write_byte(uint8_t data, uint8_t iter)
|
||||
{
|
||||
if (iter == 0) {
|
||||
iter = 1;
|
||||
}
|
||||
|
||||
while (iter--) {
|
||||
i2c_master_writeByte(data);
|
||||
|
||||
if (i2c_master_getAck()) {
|
||||
i2c_master_stop();
|
||||
ets_delay_us(500); // Wait 500us and retry.
|
||||
i2c_master_start();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i2c_master_stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write byte to target register of target I2C slave
|
||||
*/
|
||||
static void i2c_write_reg(uint8_t slave_add, uint8_t reg_add, uint16_t data)
|
||||
{
|
||||
i2c_master_start();
|
||||
if (false == i2c_write_byte(slave_add, 30)) {
|
||||
ESP_LOGE(TAG, "1Slave is busy, [%02x]TIME OUT\n", slave_add);
|
||||
}
|
||||
if (false == i2c_write_byte(reg_add, 30)) {
|
||||
ESP_LOGE(TAG, "2Slave is busy, [%02x]TIME OUT\n", reg_add);
|
||||
}
|
||||
if (false == i2c_write_byte((data >> 8), 30)) {
|
||||
ESP_LOGE(TAG, "3Slave is busy, [%02x]TIME OUT\n", data);
|
||||
}
|
||||
if (false == i2c_write_byte((data & 0xFF), 30)) {
|
||||
ESP_LOGE(TAG, "3Slave is busy, [%02x]TIME OUT\n", data);
|
||||
}
|
||||
i2c_master_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief a block of data to I2C
|
||||
*/
|
||||
static void i2s_write_arr(const uint8_t *data, size_t len)
|
||||
{
|
||||
if (data == NULL || len <= 0) return;
|
||||
|
||||
i2c_master_start();
|
||||
|
||||
int i = 0;
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (false == i2c_write_byte(data[i], 30)) {
|
||||
ESP_LOGE(TAG, "Slave is busy, [%02x]TIME OUT\n", data[i]);
|
||||
}
|
||||
}
|
||||
i2c_master_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize I2C information
|
||||
*/
|
||||
int esp_mfi_i2c_init(void)
|
||||
{
|
||||
i2c_master_gpio_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finish I2C information
|
||||
*/
|
||||
int esp_mfi_i2c_end(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write one byte data to slave
|
||||
*/
|
||||
static int esp_mfi_i2c_write_byte(uint8_t data, uint16_t retrytimes)
|
||||
{
|
||||
uint16_t times = retrytimes;
|
||||
if (0 == times) {
|
||||
times = 1;
|
||||
}
|
||||
|
||||
while (times--) {
|
||||
i2c_master_writeByte(data);
|
||||
if (i2c_master_getAck()) {
|
||||
i2c_master_wait(500); /**< Wait 500us and retry */
|
||||
i2c_master_stop();
|
||||
i2c_master_wait(500); /**< Wait 500us and retry */
|
||||
i2c_master_start();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_master_stop();
|
||||
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write data buffer to slave
|
||||
*/
|
||||
int esp_mfi_i2c_write(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if (!buff)
|
||||
return -EINVAL;
|
||||
|
||||
ESP_LOGI(TAG, "Writing to SW I2C");
|
||||
|
||||
i2c_master_start();
|
||||
|
||||
/**< Send write address of the CP */
|
||||
if (esp_mfi_i2c_write_byte(slvaddr, MFI_CP_BUSY_RETRY_TIMES) != 0) {
|
||||
ESP_LOGE(TAG, "Slave is busy, time out.");
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
/**< Send register address to slave */
|
||||
if (esp_mfi_i2c_write_byte(regaddr, 0) != 0) {
|
||||
ESP_LOGE(TAG, "Write register address[0x%02x] to slave.", regaddr);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/**< Send data out */
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (esp_mfi_i2c_write_byte(*buff++, 0) != 0) {
|
||||
ESP_LOGE(TAG, "Write data[0x%02x] to slave.", *buff);
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_master_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief read data form slave
|
||||
*/
|
||||
int esp_mfi_i2c_read(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if (!buff)
|
||||
return -EINVAL;
|
||||
|
||||
ESP_LOGI(TAG, "Reading from SW I2C");
|
||||
|
||||
i2c_master_start();
|
||||
|
||||
/**< Send write address of the CP */
|
||||
if (esp_mfi_i2c_write_byte(slvaddr, MFI_CP_BUSY_RETRY_TIMES) != 0) {
|
||||
ESP_LOGE(TAG, "Slave is busy, time out.");
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
/**< Send register address to slave */
|
||||
if (esp_mfi_i2c_write_byte(regaddr, 0) != 0) {
|
||||
ESP_LOGE(TAG, "Write register address[0x%02x] to slave.", regaddr);
|
||||
return -ENODATA;
|
||||
}
|
||||
i2c_master_stop();
|
||||
|
||||
i2c_master_wait(4000);
|
||||
|
||||
/**< Send read address of the CP */
|
||||
if (esp_mfi_i2c_write_byte((slvaddr + 1), MFI_CP_BUSY_RETRY_TIMES) != 0) {
|
||||
ESP_LOGE(TAG, "Slave is busy, time out.");
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
buff[i] = i2c_master_readByte();
|
||||
|
||||
i2c_master_setAck((i == (len - 1)) ? 1 : 0);
|
||||
}
|
||||
|
||||
i2c_master_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ESP_MFI_I2C_H_
|
||||
#define ESP_MFI_I2C_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize I2C
|
||||
*
|
||||
* @return
|
||||
* - 0 : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
int esp_mfi_i2c_init(void);
|
||||
|
||||
/**
|
||||
* @brief I2C operation end
|
||||
*
|
||||
* @return
|
||||
* - 0 : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
int esp_mfi_i2c_end(void);
|
||||
|
||||
/**
|
||||
* @brief Write data to I2C slave
|
||||
*
|
||||
* @param slvaddr address of slave
|
||||
* @param regaddr address of register
|
||||
* @param buff pointer of data to write
|
||||
* @param len the data length
|
||||
*
|
||||
* @return
|
||||
* - 0 : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
int esp_mfi_i2c_write(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Read data from I2C slave
|
||||
*
|
||||
* @param slvaddr address of slave
|
||||
* @param regaddr address of register
|
||||
* @param buff pointer of data read
|
||||
* @param len the data length
|
||||
*
|
||||
* @return
|
||||
* - 0 : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
int esp_mfi_i2c_read(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ESP_MFI_I2C_H_ */
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <esp_system.h>
|
||||
|
||||
/**
|
||||
* @bref Obtain a series of random bytes
|
||||
*
|
||||
* @param buf the random bytes were copied point
|
||||
* len the number of bytes requested
|
||||
*
|
||||
* @return the result
|
||||
* > 0 : the number of bytes that were copied to the buffer
|
||||
* others : failed
|
||||
*/
|
||||
int esp_mfi_get_random(uint8_t *buf, uint16_t len)
|
||||
{
|
||||
int i, j;
|
||||
unsigned long tmp;
|
||||
|
||||
for (i = 0; i < ((len + 3) & ~3) / 4; i++) {
|
||||
tmp = esp_random();
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
if ((i * 4 + j) < len) {
|
||||
buf[i * 4 + j] = (uint8_t) (tmp >> (j * 8));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ESP_MFI_RAND_H_
|
||||
#define ESP_MFI_RAND_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get a random number of bytes specified.
|
||||
*
|
||||
* @param buf pointer of the random number it gets
|
||||
* @param len specified bytes of the random number
|
||||
*
|
||||
* @return
|
||||
* - > 0 : the actual length(bytes) of the random number
|
||||
* - others : failure
|
||||
*/
|
||||
int esp_mfi_get_random(uint8_t *buf, uint16_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ESP_MFI_RAND_H_ */
|
|
@ -1,279 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mbedtls/sha1.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/sha512.h"
|
||||
|
||||
#include "esp_mfi_sha.h"
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
#define mbedtls_sha512_starts mbedtls_sha512_starts_ret
|
||||
#define mbedtls_sha512_update mbedtls_sha512_update_ret
|
||||
#define mbedtls_sha512_finish mbedtls_sha512_finish_ret
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @bref Create SHA1 context
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return the SHA1 context point
|
||||
*/
|
||||
esp_mfi_sha_ctx_t esp_mfi_sha1_new(void)
|
||||
{
|
||||
mbedtls_sha1_context *context = NULL;
|
||||
context = (mbedtls_sha1_context *) malloc(sizeof(mbedtls_sha1_context));
|
||||
mbedtls_sha1_init(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Free SHA1 context
|
||||
*
|
||||
* @param ctx the SHA1 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha1_free(esp_mfi_sha_ctx_t ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
mbedtls_sha1_free( (mbedtls_sha1_context *)ctx);
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Init SHA1 context
|
||||
*
|
||||
* @param ctx the SHA1 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha1_init(esp_mfi_sha_ctx_t ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha1_starts((mbedtls_sha1_context *) ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Update SHA1 context
|
||||
*
|
||||
* @param ctx the SHA1 context point
|
||||
* msg input data point
|
||||
* len input data length
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha1_update(esp_mfi_sha_ctx_t ctx, const uint8_t * msg, int len)
|
||||
{
|
||||
if (ctx == NULL || msg == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha1_update((mbedtls_sha1_context *) ctx, msg, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Final SHA1 context
|
||||
*
|
||||
* @param digest output data point
|
||||
* ctx the SHA1 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha1_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest)
|
||||
{
|
||||
if (ctx == NULL || digest == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha1_finish((mbedtls_sha1_context *) ctx, digest);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA256 declarations
|
||||
*/
|
||||
|
||||
/**
|
||||
* @bref Create SHA256 context
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return the SHA256 context point
|
||||
*/
|
||||
esp_mfi_sha_ctx_t esp_mfi_sha256_new(void)
|
||||
{
|
||||
mbedtls_sha256_context *context = NULL;
|
||||
context = (mbedtls_sha256_context *) malloc(sizeof(mbedtls_sha256_context));
|
||||
mbedtls_sha256_init(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Free SHA256 context
|
||||
*
|
||||
* @param ctx the SHA256 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha256_free(esp_mfi_sha_ctx_t ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
mbedtls_sha256_free((mbedtls_sha256_context *)ctx);
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Init SHA256 context
|
||||
*
|
||||
* @param ctx the SHA256 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha256_init(esp_mfi_sha_ctx_t ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha256_starts((mbedtls_sha256_context *) ctx, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Update SHA256 context
|
||||
*
|
||||
* @param ctx the SHA256 context point
|
||||
* msg input data point
|
||||
* len input data length
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha256_update(esp_mfi_sha_ctx_t ctx, const uint8_t *input, int len)
|
||||
{
|
||||
if (ctx == NULL || input == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha256_update((mbedtls_sha256_context *) ctx, input, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Final SHA256 context
|
||||
*
|
||||
* @param digest output data point
|
||||
* ctx the SHA256 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha256_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest)
|
||||
{
|
||||
if (ctx == NULL || digest == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha256_finish((mbedtls_sha256_context *) ctx, digest);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA512 declarations
|
||||
*/
|
||||
|
||||
/**
|
||||
* @bref Create SHA512 context
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return the SHA512 context point
|
||||
*/
|
||||
esp_mfi_sha_ctx_t esp_mfi_sha512_new(void)
|
||||
{
|
||||
mbedtls_sha512_context *context = NULL;
|
||||
context = (mbedtls_sha512_context *) malloc(sizeof(mbedtls_sha512_context));
|
||||
mbedtls_sha512_init(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Free SHA512 context
|
||||
*
|
||||
* @param ctx the SHA512 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha512_free(esp_mfi_sha_ctx_t ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
mbedtls_sha512_free((mbedtls_sha512_context *)ctx);
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Init SHA512 context
|
||||
*
|
||||
* @param ctx the SHA512 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha512_init(esp_mfi_sha_ctx_t ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha512_starts((mbedtls_sha512_context *) ctx, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Update SHA512 context
|
||||
*
|
||||
* @param ctx the SHA512 context point
|
||||
* msg input data point
|
||||
* len input data length
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha512_update(esp_mfi_sha_ctx_t ctx, const uint8_t *input, int len)
|
||||
{
|
||||
if (ctx == NULL || input == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha512_update((mbedtls_sha512_context *) ctx, input, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @bref Final SHA512 context
|
||||
*
|
||||
* @param digest output data point
|
||||
* ctx the SHA512 context point
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void esp_mfi_sha512_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest)
|
||||
{
|
||||
if (ctx == NULL || digest == NULL)
|
||||
return;
|
||||
|
||||
mbedtls_sha512_finish((mbedtls_sha512_context *) ctx, digest);
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ESP_MFI_SHA_H_
|
||||
#define ESP_MFI_SHA_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void* esp_mfi_sha_ctx_t;
|
||||
|
||||
/*
|
||||
* SHA1 declarations
|
||||
*/
|
||||
|
||||
#define MFI_SHA1_SIZE 20
|
||||
|
||||
/**
|
||||
* @brief Create SHA1 context
|
||||
*
|
||||
* @return pointer of the SHA1 context
|
||||
*/
|
||||
esp_mfi_sha_ctx_t esp_mfi_sha1_new(void);
|
||||
|
||||
/**
|
||||
* @brief Init SHA1 context
|
||||
*
|
||||
* @param ctx pointer of the SHA1 context
|
||||
*/
|
||||
void esp_mfi_sha1_init(esp_mfi_sha_ctx_t ctx);
|
||||
|
||||
/**
|
||||
* @brief Update SHA1 context
|
||||
*
|
||||
* @param ctx pointer of the SHA1 context
|
||||
* @param msg pointer of the input data
|
||||
* @param len input data length
|
||||
*/
|
||||
void esp_mfi_sha1_update(esp_mfi_sha_ctx_t ctx, const uint8_t *msg, int len);
|
||||
|
||||
/**
|
||||
* @brief Final SHA1 context
|
||||
*
|
||||
* @param digest pointer of output data
|
||||
* @param ctx pointer of the SHA1 context
|
||||
*/
|
||||
void esp_mfi_sha1_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest);
|
||||
|
||||
/**
|
||||
* @brief Free SHA1 context
|
||||
*
|
||||
* @param ctx pointer of the SHA1 context
|
||||
*/
|
||||
void esp_mfi_sha1_free(esp_mfi_sha_ctx_t ctx);
|
||||
|
||||
/*
|
||||
* SHA256 declarations
|
||||
*/
|
||||
|
||||
#define MFI_SHA256_SIZE 32
|
||||
|
||||
/**
|
||||
* @brief Create SHA256 context
|
||||
*
|
||||
* @return pointer of the SHA256 context
|
||||
*/
|
||||
esp_mfi_sha_ctx_t esp_mfi_sha256_new(void);
|
||||
|
||||
/**
|
||||
* @brief Init SHA256 context
|
||||
*
|
||||
* @param ctx pointer of the SHA256 context
|
||||
*/
|
||||
void esp_mfi_sha256_init(esp_mfi_sha_ctx_t ctx);
|
||||
|
||||
/**
|
||||
* @brief Update SHA256 context
|
||||
*
|
||||
* @param ctx pointer of the SHA256 context
|
||||
* @param msg pointer of input data
|
||||
* @param len input data length
|
||||
*/
|
||||
void esp_mfi_sha256_update(esp_mfi_sha_ctx_t ctx, const uint8_t *input, int len);
|
||||
|
||||
/**
|
||||
* @brief Final SHA256 context
|
||||
*
|
||||
* @param digest pointer of output data
|
||||
* @param ctx pointer of the SHA256 context
|
||||
*/
|
||||
void esp_mfi_sha256_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest);
|
||||
|
||||
/**
|
||||
* @brief Free SHA256 context
|
||||
*
|
||||
* @param ctx pointer of the SHA256 context
|
||||
*/
|
||||
void esp_mfi_sha256_free(esp_mfi_sha_ctx_t ctx);
|
||||
|
||||
/*
|
||||
* SHA512 declarations
|
||||
*/
|
||||
|
||||
#define MFI_SHA512_SIZE 64
|
||||
|
||||
/**
|
||||
* @brief Create SHA512 context
|
||||
*
|
||||
* @return pointer of the SHA512 context
|
||||
*/
|
||||
esp_mfi_sha_ctx_t esp_mfi_sha512_new(void);
|
||||
|
||||
/**
|
||||
* @brief Init SHA512 context
|
||||
*
|
||||
* @param ctx pointer of the SHA512 context
|
||||
*/
|
||||
void esp_mfi_sha512_init(esp_mfi_sha_ctx_t ctx);
|
||||
|
||||
/**
|
||||
* @brief Update SHA512 context
|
||||
*
|
||||
* @param ctx pointer of the SHA512 context
|
||||
* @param msg pointer of input data
|
||||
* @param len input data length
|
||||
*/
|
||||
void esp_mfi_sha512_update(esp_mfi_sha_ctx_t ctx, const uint8_t *input, int len);
|
||||
|
||||
/**
|
||||
* @brief Final SHA512 context
|
||||
*
|
||||
* @param digest pointer of output data
|
||||
* @param ctx pointer of the SHA512 context
|
||||
*/
|
||||
void esp_mfi_sha512_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest);
|
||||
|
||||
/**
|
||||
* @brief Free SHA512 context
|
||||
*
|
||||
* @param ctx pointer of the SHA512 context
|
||||
*/
|
||||
void esp_mfi_sha512_free(esp_mfi_sha_ctx_t ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ESP_MFI_SHA_H_ */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,721 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <hap.h>
|
||||
#include <hap_apple_servs.h>
|
||||
#include <hap_apple_chars.h>
|
||||
|
||||
hap_serv_t *hap_serv_accessory_information_create(hap_acc_cfg_t *cfg)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_ACCESSORY_INFORMATION);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_name_create(cfg->name)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (hap_serv_add_char(hs, hap_char_model_create(cfg->model)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (hap_serv_add_char(hs, hap_char_manufacturer_create(cfg->manufacturer)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (hap_serv_add_char(hs, hap_char_serial_number_create(cfg->serial_num)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (hap_serv_add_char(hs, hap_char_firmware_revision_create(cfg->fw_rev)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (hap_serv_add_char(hs, hap_char_identify_create()) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (cfg->hw_rev) {
|
||||
if (hap_serv_add_char(hs, hap_char_hardware_revision_create(cfg->hw_rev)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_protocol_information_create(char *version)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_PROTOCOL_INFORMATION);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_version_create(version)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_fan_create(bool on)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_FAN);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_on_create(on)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_garage_door_opener_create(uint8_t curr_door_state, uint8_t targ_door_state, bool obstr_detect)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_GARAGE_DOOR_OPENER);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_door_state_create(curr_door_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_door_state_create(targ_door_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_obstruction_detect_create(obstr_detect)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_lightbulb_create(bool on)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LIGHTBULB);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_on_create(on)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_lock_management_create(hap_tlv8_val_t *lock_control_point, char * version)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LOCK_MANAGEMENT);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_lock_control_point_create(lock_control_point)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_version_create(version)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_lock_mechanism_create(uint8_t lock_curr_state, uint8_t lock_targ_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LOCK_MECHANISM);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_lock_current_state_create(lock_curr_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_lock_target_state_create(lock_targ_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_outlet_create(bool on, bool outlet_in_use)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_OUTLET);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_on_create(on)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_outlet_in_use_create(outlet_in_use)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_switch_create(bool on)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SWITCH);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_on_create(on)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_thermostat_create(uint8_t curr_heating_cooling_state, uint8_t targ_heating_cooling_state, float curr_temp,
|
||||
float targ_temp, uint8_t temp_disp_units)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_THERMOSTAT);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_heating_cooling_state_create(curr_heating_cooling_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_heating_cooling_state_create(targ_heating_cooling_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_temperature_create(curr_temp)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_temperature_create(targ_temp)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_temperature_display_units_create(temp_disp_units)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_air_quality_sensor_create(uint8_t air_quality)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_AIR_QUALITY_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_air_quality_create(air_quality)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_security_system_create(uint8_t security_sys_curr_state, uint8_t security_sys_targ_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SECURITY_SYSTEM);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_security_system_current_state_create(security_sys_curr_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_security_system_target_state_create(security_sys_targ_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_carbon_monoxide_sensor_create(uint8_t carbon_monoxide_detected)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_CARBON_MONOXIDE_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_carbon_monoxide_detected_create(carbon_monoxide_detected)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_contact_sensor_create(uint8_t contact_sensor_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_CONTACT_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_contact_sensor_state_create(contact_sensor_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_door_create(uint8_t curr_pos, uint8_t targ_pos, uint8_t pos_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_DOOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_position_create(curr_pos)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_position_create(targ_pos)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_position_state_create(pos_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_humidity_sensor_create(float curr_rel_humidity)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_HUMIDITY_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_relative_humidity_create(curr_rel_humidity)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_leak_sensor_create(uint8_t leak_detected)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LEAK_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_leak_detected_create(leak_detected)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_light_sensor_create(float curr_ambient_light_level)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LIGHT_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_ambient_light_level_create(curr_ambient_light_level)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_motion_sensor_create(bool motion_detected)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_MOTION_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_motion_detected_create(motion_detected)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_occupancy_sensor_create(uint8_t occupancy_detected)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_OCCUPANCY_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_occupancy_detected_create(occupancy_detected)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_smoke_sensor_create(uint8_t smoke_detected)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SMOKE_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_smoke_detected_create(smoke_detected)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_stateless_programmable_switch_create(uint8_t programmable_switch_event)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_STATLESS_PROGRAMMABLE_SWITCH);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_programmable_switch_event_create(programmable_switch_event)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_wattage_create(float curr_watts)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LIGHT_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_wattage_create(curr_watts)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
hap_serv_t *hap_serv_temperature_sensor_create(float curr_temp)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_TEMPERATURE_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_temperature_create(curr_temp)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_window_create(uint8_t curr_pos, uint8_t targ_pos, uint8_t pos_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_WINDOW);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_position_create(curr_pos)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_position_create(targ_pos)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_position_state_create(pos_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_window_covering_create(uint8_t targ_pos, uint8_t curr_pos, uint8_t pos_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_WINDOW_COVERING);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_position_create(targ_pos)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_position_create(curr_pos)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_position_state_create(pos_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_battery_service_create(uint8_t battery_level, uint8_t charging_state, uint8_t status_low_battery)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_BATTERY_SERVICE);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_battery_level_create(battery_level)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_charging_state_create(charging_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_status_low_battery_create(status_low_battery)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_carbon_dioxide_sensor_create(uint8_t carbon_dioxide_detected)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_CARBON_DIOXIDE_SENSOR);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_carbon_dioxide_detected_create(carbon_dioxide_detected)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_fan_v2_create(uint8_t active)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_FAN_V2);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_slat_create(uint8_t curr_slat_state, uint8_t slat_type)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SLAT);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_slat_state_create(curr_slat_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_slat_type_create(slat_type)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_filter_maintenance_create(uint8_t filter_change_indication)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_FILTER_MAINTENANCE);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_filter_change_indication_create(filter_change_indication)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_air_purifier_create(uint8_t active, uint8_t curr_air_purifier_state, uint8_t
|
||||
targ_air_purifier_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_AIR_PURIFIER);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_air_purifier_state_create(curr_air_purifier_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_air_purifier_state_create(targ_air_purifier_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_heater_cooler_create(uint8_t active, float curr_temp, uint8_t curr_heater_cooler_state, uint8_t targ_heater_cooler_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_HEATER_COOLER);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_temperature_create(curr_temp)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_heater_cooler_state_create(curr_heater_cooler_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_heater_cooler_state_create(targ_heater_cooler_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_humidifier_dehumidifier_create(uint8_t active, float curr_rel_humidity, uint8_t
|
||||
curr_humid_dehumid_state, uint8_t targ_humid_dehumid_state)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_HUMIDIFIER_DEHUMIDIFIER);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_relative_humidity_create(curr_rel_humidity)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_current_humidifier_dehumidifier_state_create(curr_humid_dehumid_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_target_humidifier_dehumidifier_state_create(targ_humid_dehumid_state)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_service_label_create(uint8_t service_label_namespace)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SERVICE_LABEL);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_service_label_namespace_create(service_label_namespace)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_irrigation_system_create(uint8_t active, uint8_t prog_mode, uint8_t in_use)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_IRRIGATION_SYSTEM);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_program_mode_create(prog_mode)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_in_use_create(in_use)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_valve_create(uint8_t active, uint8_t in_use, uint8_t valve_type)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_VALVE);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_in_use_create(in_use)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_valve_type_create(valve_type)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hap_serv_t *hap_serv_faucet_create(uint8_t active)
|
||||
{
|
||||
hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_FAUCET);
|
||||
if (!hs) {
|
||||
return NULL;
|
||||
}
|
||||
if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
return hs;
|
||||
err:
|
||||
hap_serv_delete(hs);
|
||||
return NULL;
|
||||
}
|
|
@ -1,564 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
/** HAP Apple Services
|
||||
*
|
||||
* This offers helper APIs for all the standard HomeKit Services defined by Apple
|
||||
*/
|
||||
#ifndef _HAP_APPLE_SERVS_H_
|
||||
#define _HAP_APPLE_SERVS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <hap.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HAP_SERV_UUID_ACCESSORY_INFORMATION "3E"
|
||||
#define HAP_SERV_UUID_PROTOCOL_INFORMATION "A2"
|
||||
#define HAP_SERV_UUID_FAN "40"
|
||||
#define HAP_SERV_UUID_GARAGE_DOOR_OPENER "41"
|
||||
#define HAP_SERV_UUID_LIGHTBULB "43"
|
||||
#define HAP_SERV_UUID_LOCK_MANAGEMENT "44"
|
||||
#define HAP_SERV_UUID_LOCK_MECHANISM "45"
|
||||
#define HAP_SERV_UUID_SWITCH "49"
|
||||
#define HAP_SERV_UUID_OUTLET "47"
|
||||
#define HAP_SERV_UUID_THERMOSTAT "4A"
|
||||
#define HAP_SERV_UUID_AIR_QUALITY_SENSOR "8D"
|
||||
#define HAP_SERV_UUID_SECURITY_SYSTEM "7E"
|
||||
#define HAP_SERV_UUID_CARBON_MONOXIDE_SENSOR "7F"
|
||||
#define HAP_SERV_UUID_CONTACT_SENSOR "80"
|
||||
#define HAP_SERV_UUID_DOOR "81"
|
||||
#define HAP_SERV_UUID_HUMIDITY_SENSOR "82"
|
||||
#define HAP_SERV_UUID_LEAK_SENSOR "83"
|
||||
#define HAP_SERV_UUID_LIGHT_SENSOR "84"
|
||||
#define HAP_SERV_UUID_MOTION_SENSOR "85"
|
||||
#define HAP_SERV_UUID_OCCUPANCY_SENSOR "86"
|
||||
#define HAP_SERV_UUID_SMOKE_SENSOR "87"
|
||||
#define HAP_SERV_UUID_STATLESS_PROGRAMMABLE_SWITCH "89"
|
||||
#define HAP_SERV_UUID_TEMPERATURE_SENSOR "8A"
|
||||
#define HAP_SERV_UUID_WINDOW "8B"
|
||||
#define HAP_SERV_UUID_WINDOW_COVERING "8C"
|
||||
#define HAP_SERV_UUID_BATTERY_SERVICE "96"
|
||||
#define HAP_SERV_UUID_CARBON_DIOXIDE_SENSOR "97"
|
||||
#define HAP_SERV_UUID_FAN_V2 "B7"
|
||||
#define HAP_SERV_UUID_SLAT "B9"
|
||||
#define HAP_SERV_UUID_FILTER_MAINTENANCE "BA"
|
||||
#define HAP_SERV_UUID_AIR_PURIFIER "BB"
|
||||
#define HAP_SERV_UUID_HEATER_COOLER "BC"
|
||||
#define HAP_SERV_UUID_HUMIDIFIER_DEHUMIDIFIER "BD"
|
||||
#define HAP_SERV_UUID_SERVICE_LABEL "CC"
|
||||
#define HAP_SERV_UUID_IRRIGATION_SYSTEM "CF"
|
||||
#define HAP_SERV_UUID_VALVE "D0"
|
||||
#define HAP_SERV_UUID_FAUCET "D7"
|
||||
|
||||
|
||||
/** Create Accessory Information Service
|
||||
*
|
||||
* This API will create the Accessory Information Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] cfg The accessory configuration to be used to create the service
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_accessory_information_create(hap_acc_cfg_t *cfg);
|
||||
|
||||
/** Create Protocol Information Service
|
||||
*
|
||||
* This API will create the Protocol Information Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] version The Protocol Version string
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_protocol_information_create(char *version);
|
||||
|
||||
/** Create Fan Service
|
||||
*
|
||||
* This API will create the Fan Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] on Initial "On" state of the service
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_fan_create(bool on);
|
||||
|
||||
/** Create Garage Door Opener Service
|
||||
*
|
||||
* This API will create the Garage Door Opener Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] curr_door_state Initial value of the current door state characteristic
|
||||
* @param[in] targ_door_state Value of the target door state characteristic
|
||||
* @param[in] obstr_detect Value of the obstruction detected characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_garage_door_opener_create(uint8_t curr_door_state, uint8_t targ_door_state, bool obstr_detect)
|
||||
;
|
||||
|
||||
/** Create Light Bulb Service
|
||||
*
|
||||
* This API will create the Light Bulb Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] on Initial "On" state of the service
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_lightbulb_create(bool on);
|
||||
|
||||
/** Create Lock Management Service
|
||||
*
|
||||
* This API will create the Lock Management Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] lock_control_point Accepts data from TLV8 commands
|
||||
* @param[in] version The Protocol Version string
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_lock_management_create(hap_tlv8_val_t *lock_control_point, char * version);
|
||||
|
||||
/** Create Lock Mechanism Service
|
||||
*
|
||||
* This API will create the Lock Mechanism Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] lock_curr_state Current lock state of the service
|
||||
* @param[in] lock_targ_state Target lock state of the service
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_lock_mechanism_create(uint8_t lock_curr_state, uint8_t lock_targ_state);
|
||||
|
||||
/** Create Outlet Service
|
||||
*
|
||||
* This API will create the Outlet Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] on Initial "On" state of the service
|
||||
* @param[in] outlet_in_use Initial value of the outlet in use characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_outlet_create(bool on, bool outlet_in_use);
|
||||
|
||||
/** Create Switch Service
|
||||
*
|
||||
* This API will create the Switch Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] on Initial "On" state of the service
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_switch_create(bool on);
|
||||
|
||||
/** Create Thermostat Service
|
||||
*
|
||||
* This API will create the Thermostat Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] curr_heating_cooling_state Initial value of Current Heating Cooling State characteristic
|
||||
* @param[in] targ_heating_cooling_state Initial value of Target Heating Cooling State characteristic
|
||||
* @param[in] curr_temp Initial value of Current Temperature characteristic
|
||||
* @param[in] targ_temp Initial value of Target Temperature characteristic
|
||||
* @param[in] temp_disp_units Initial value of Temperature Display Units characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_thermostat_create(uint8_t curr_heating_cooling_state, uint8_t targ_heating_cooling_state, float curr_temp, float targ_temp, uint8_t temp_disp_units);
|
||||
|
||||
/** Create Air Quality Sensor Service
|
||||
*
|
||||
* This API will create the Air Quality Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] air_quality Initial value of Air Quality characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_air_quality_sensor_create(uint8_t air_quality);
|
||||
|
||||
/** Create Security System Current State Service
|
||||
*
|
||||
* This API will create the Security System Current State Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] security_sys_curr_state Initial value of Security System Current State characteristic
|
||||
* @param[in] security_sys_targ_state Initial value of Security System Target State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_security_system_create(uint8_t security_sys_curr_state, uint8_t security_sys_targ_state);
|
||||
|
||||
/** Create Carbon Monoxide Sensor Service
|
||||
*
|
||||
* This API will create the Carbon Monoxide Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] carbon_monoxide_detected Initial value of Carbon Monoxide Sensor characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_carbon_monoxide_sensor_create(uint8_t carbon_monoxide_detected);
|
||||
|
||||
/** Create Contact Sensor Service
|
||||
*
|
||||
* This API will create the Contact Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] contact_sensor_state Initial value of Contact Sensor State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_contact_sensor_create(uint8_t contact_sensor_state);
|
||||
|
||||
/** Create Door Service
|
||||
*
|
||||
* This API will create the Door Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] curr_pos Initial value of Current Position characteristic
|
||||
* @param[in] targ_pos Initial value of Target Position characteristic
|
||||
* @param[in] pos_state Initial value of Position State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_door_create(uint8_t curr_pos, uint8_t targ_pos, uint8_t pos_state);
|
||||
|
||||
/** Create Humidity Sensor Service
|
||||
*
|
||||
* This API will create the Humidity Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] curr_relative_humidity Initial value of Humidity Sensor State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_humidity_sensor_create(float curr_relative_humidity);
|
||||
|
||||
/** Leak Sensor Service
|
||||
*
|
||||
* This API will create the Leak Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] leak_detected Initial value of Leak Detected State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_leak_sensor_create(uint8_t leak_detected);
|
||||
|
||||
/** Light Sensor Service
|
||||
*
|
||||
* This API will create the Light Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] curr_ambient_light_level Initial value of Current Ambient Light Level characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_light_sensor_create(float curr_ambient_light_level);
|
||||
|
||||
/** Motion Sensor Service
|
||||
*
|
||||
* This API will create the Motion Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] motion_detected Initial value of Motion Detected characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_motion_sensor_create(bool motion_detected);
|
||||
|
||||
/** Occupancy Sensor Service
|
||||
*
|
||||
* This API will create the Occupancy Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] occupancy_detected Initial value of Occupancy Detected characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_occupancy_sensor_create(uint8_t occupancy_detected);
|
||||
|
||||
/** Smoke Sensor Service
|
||||
*
|
||||
* This API will create the Smoke Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] smoke_detected Initial value of Smoke Detected characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_smoke_sensor_create(uint8_t smoke_detected);
|
||||
|
||||
/** Stateless Programmable Switch Service
|
||||
*
|
||||
* This API will create the Stateless Programmable Switch Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] programmable_switch_event Initial value of Programmable Switch Event characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_stateless_programmable_switch_create(uint8_t programmable_switch_event);
|
||||
|
||||
/** Temperature Sensor Service
|
||||
*
|
||||
* This API will create the Temperature Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] curr_temp Initial value of Current Temprature characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_temperature_sensor_create(float curr_temp);
|
||||
|
||||
/** Window Service
|
||||
*
|
||||
* This API will create the Window Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] curr_pos Initial value of Current Position characteristic
|
||||
* @param[in] targ_pos Initial value of Target Position characteristic
|
||||
* @param[in] pos_state Initial value of Position State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_window_create(uint8_t curr_pos, uint8_t targ_pos, uint8_t pos_state);
|
||||
|
||||
/** Window Covering Service
|
||||
*
|
||||
* This API will create the Window Covering Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] targ_pos Initial value of Target Position characteristic
|
||||
* @param[in] curr_pos Initial value of Current Position characteristic
|
||||
* @param[in] pos_state Initial value of Position State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_window_covering_create(uint8_t targ_pos, uint8_t curr_pos, uint8_t pos_state);
|
||||
|
||||
/** Battery Service
|
||||
*
|
||||
* This API will create the Battery Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] battery_level Initial value of Battery Level characteristic
|
||||
* @param[in] charging_state Initial value of Charging State characteristic
|
||||
* @param[in] status_low_battery Initial value of Status Low Battery characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_battery_service_create(uint8_t battery_level, uint8_t charging_state, uint8_t status_low_battery);
|
||||
|
||||
/** Create Carbon Dioxide Sensor Service
|
||||
*
|
||||
* This API will create the Carbon Dioxide Sensor Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] carbon_dioxide_detected Initial value of Carbon Dioxide Sensor characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_carbon_dioxide_sensor_create(uint8_t carbon_dioxide_detected);
|
||||
|
||||
/** Fan v2 Service
|
||||
*
|
||||
* This API will create the Fan v2 Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] active Value of Active characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_fan_v2_create(uint8_t active);
|
||||
|
||||
/** Slat Service
|
||||
*
|
||||
* This API will create the Slat Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] curr_slat_state Value of Current Slat State characteristic
|
||||
* @param[in] slat_type Value of Slat Type characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_slat_create(uint8_t curr_slat_state, uint8_t slat_type);
|
||||
|
||||
/** Filter Maintenance Service
|
||||
*
|
||||
* This API will create the Filter Maintenance Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] filter_change_indication Value of Filter Change Indication characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_filter_maintenance_create(uint8_t filter_change_indication);
|
||||
|
||||
/** Air Purifier Service
|
||||
*
|
||||
* This API will create the Air Purifier Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] active Value of Active characteristic
|
||||
* @param[in] curr_air_purifier_state Value of Current Air Purifier State characteristic
|
||||
* @param[in] targ_air_purifier_state Value of Target Air Purifier State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_air_purifier_create(uint8_t active, uint8_t curr_air_purifier_state, uint8_t
|
||||
targ_air_purifier_state);
|
||||
|
||||
/** Heater Cooler Service
|
||||
*
|
||||
* This API will create the Heater Cooler Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] active Value of Active characteristic
|
||||
* @param[in] curr_temp Value of Current Temperature characteristic
|
||||
* @param[in] curr_heater_cooler_state Value of Current Heater Cooler State characteristic
|
||||
* @param[in] targ_heater_cooler_state Value of Target Heater Cooler State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_heater_cooler_create(uint8_t active, float curr_temp, uint8_t curr_heater_cooler_state, uint8_t targ_heater_cooler_state);
|
||||
|
||||
/** Create Humidifer Dehumidfier Service
|
||||
*
|
||||
* This API will create the Humidifer Dehumidfier Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] active Initial value of Active characteristic
|
||||
* @param[in] curr_rel_humid Initial value of Current Relative Humidity characteristic
|
||||
* @param[in] curr_humid_dehumid_state Initial value of Current Humidifier Dehumidifier State characteristic
|
||||
* @param[in] targ_humid_dehumid_state Initial value of Target Humidifier Dehumidifier State characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_humidifier_dehumidifier_create(uint8_t active, float curr_rel_humid, uint8_t
|
||||
curr_humid_dehumid_state, uint8_t targ_humid_dehumid_state);
|
||||
|
||||
/** Create Service Label Service
|
||||
*
|
||||
* This API will create the Service Label Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] service_label_namespace Initial value of Service Label Service characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_service_label_create(uint8_t service_label_namespace);
|
||||
|
||||
/** Create Irrigation System Service
|
||||
*
|
||||
* This API will create the Irrigation System Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] active Initial value of active characteristic
|
||||
* @param[in] prog_mode Initial value of Program Mode characteristic
|
||||
* @param[in] in_use Initial value of In Use characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_irrigation_system_create(uint8_t active, uint8_t prog_mode, uint8_t in_use);
|
||||
|
||||
/** Create Valve Service
|
||||
*
|
||||
* This API will create the Valve Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] active Initial value of active characteristic
|
||||
* @param[in] in_use Initial value of In Use characteristic
|
||||
* @param[in] valve_type Initial value of Valve Type characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_valve_create(uint8_t active, uint8_t in_use, uint8_t valve_type);
|
||||
|
||||
/** Create Faucet Service
|
||||
*
|
||||
* This API will create the Faucet Service with the mandatory
|
||||
* characteristics as per the HAP Specs.
|
||||
*
|
||||
* @param[in] active Initial value of active characteristic
|
||||
*
|
||||
* @return Pointer to the service object on success
|
||||
* @return NULL on failure
|
||||
*/
|
||||
hap_serv_t *hap_serv_faucet_create(uint8_t active);
|
||||
|
||||
|
||||
hap_serv_t *hap_serv_wattage_create(float curr_watts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HAP_APPLE_SERVS_H_ */
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_BCT_H_
|
||||
#define _HAP_BCT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Change the name of the Bonjour Service for BCT
|
||||
*
|
||||
* This is required as per the "Manual Name Change" step of "Tester Interaction"
|
||||
* section of Bonjour Conformance Test.
|
||||
*
|
||||
* @param[in] name The desired new name for the service. For BCT 1.4 or earlier: "New - Bonjour Service Name".
|
||||
* For BCT 1.5 or later: "New-BCT"
|
||||
*/
|
||||
void hap_bct_change_name(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Trigger a Hot plug of the network interface for BCT
|
||||
*
|
||||
* This is required as per the "Cable Change Handling" and "Hot Plugging" steps
|
||||
* of "Tester Interaction" section of Bonjout Conformance Test
|
||||
*/
|
||||
void hap_bct_hot_plug();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HAP_BCT_H_ */
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <esp_http_server.h>
|
||||
#include <_esp_hap_config.h>
|
||||
|
||||
httpd_handle_t *int_handle;
|
||||
int hap_platform_httpd_start(httpd_handle_t *handle)
|
||||
{
|
||||
httpd_config_t config = {
|
||||
.task_priority = tskIDLE_PRIORITY+5,
|
||||
.stack_size = CONFIG_HAP_HTTP_STACK_SIZE,
|
||||
.server_port = CONFIG_HAP_HTTP_SERVER_PORT,
|
||||
.ctrl_port = CONFIG_HAP_HTTP_CONTROL_PORT,
|
||||
.max_open_sockets = CONFIG_HAP_HTTP_MAX_OPEN_SOCKETS,
|
||||
.max_uri_handlers = CONFIG_HAP_HTTP_MAX_URI_HANDLERS,
|
||||
.max_resp_headers = 8,
|
||||
.backlog_conn = 5,
|
||||
.lru_purge_enable = true,
|
||||
.recv_wait_timeout = 5,
|
||||
.send_wait_timeout = 5,
|
||||
};
|
||||
esp_err_t err = httpd_start(handle, &config);
|
||||
if (err == ESP_OK) {
|
||||
int_handle = handle;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int hap_platform_httpd_stop(httpd_handle_t *handle)
|
||||
{
|
||||
esp_err_t err = httpd_stop(*handle);
|
||||
if (err == ESP_OK) {
|
||||
int_handle = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int hap_platform_httpd_get_port()
|
||||
{
|
||||
return CONFIG_HAP_HTTP_SERVER_PORT;
|
||||
}
|
||||
|
||||
void * hap_platform_httpd_get_sess_ctx(httpd_req_t *req)
|
||||
{
|
||||
if (req) {
|
||||
return req->sess_ctx;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t hap_platform_httpd_set_sess_ctx(httpd_req_t *req, void *ctx, httpd_free_ctx_fn_t free_ctx, bool ignore_ctx_changes)
|
||||
{
|
||||
if (req) {
|
||||
req->sess_ctx = ctx;
|
||||
req->free_ctx = free_ctx;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP8266
|
||||
req->ignore_sess_ctx_changes = ignore_ctx_changes;
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static const char * hap_platform_httpd_rqtype_to_string(int method)
|
||||
{
|
||||
switch (method) {
|
||||
case HTTP_GET:
|
||||
return "GET";
|
||||
case HTTP_POST:
|
||||
return "POST";
|
||||
case HTTP_PUT:
|
||||
return "PUT";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
const char *hap_platform_httpd_get_req_method(httpd_req_t *req)
|
||||
{
|
||||
if (req) {
|
||||
return hap_platform_httpd_rqtype_to_string(req->method);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *hap_platform_httpd_get_req_uri(httpd_req_t *req)
|
||||
{
|
||||
if (req) {
|
||||
return req->uri;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hap_platform_httpd_get_content_len(httpd_req_t *req)
|
||||
{
|
||||
if (req) {
|
||||
return req->content_len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
httpd_handle_t *hap_platform_httpd_get_handle()
|
||||
{
|
||||
return int_handle;
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_PLATFORM_HTTPD_H_
|
||||
#define _HAP_PLATFORM_HTTPD_H_
|
||||
#include <esp_http_server.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Start the webserver
|
||||
*
|
||||
* This API will be called by the HAP Core to start the webserver.
|
||||
*
|
||||
* @param[out] handle Pointer to the handle that should be populated by this
|
||||
* function on a success.
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* @return error code otherwise
|
||||
*/
|
||||
int hap_platform_httpd_start(httpd_handle_t *handle);
|
||||
|
||||
/** Stop the webserver
|
||||
*
|
||||
* This API will be called by the HAP Core to stop the webserver.
|
||||
*
|
||||
* @param[in] handle Pointer to the handle created in hap_platform_httpd_start
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* @return error code otherwise
|
||||
*/
|
||||
int hap_platform_httpd_stop(httpd_handle_t *handle);
|
||||
|
||||
/** Get the current HTTP Port
|
||||
*
|
||||
* This API will be called by the HAP Core to get the HTTP Port being used. This will
|
||||
* be used for the mDNS announcement
|
||||
*
|
||||
* @return Configured HTTP Port
|
||||
*/
|
||||
int hap_platform_httpd_get_port();
|
||||
|
||||
/** Get the HTTPD session context
|
||||
*
|
||||
* This API will be called by the HAP Core to get the context associated with a given
|
||||
* session. It is generally used to maintain pairing information.
|
||||
*
|
||||
* @param[in] req HTTPD Request structure.
|
||||
*
|
||||
* @return pointer to the session context.
|
||||
*/
|
||||
void * hap_platform_httpd_get_sess_ctx(httpd_req_t *req);
|
||||
|
||||
/** Set the HTTPD session context
|
||||
*
|
||||
* This API will be called by the HAP Core to set the context associated with a given
|
||||
* session. It is generally used to maintain pairing information.
|
||||
*
|
||||
* @param[in] req HTTPD Request structure.
|
||||
* @param[in] ctx The context to be set for the given session.
|
||||
* @param[in] free_fn Pointer to a function that will be used by the HTTP Server to clear the context when the session closes
|
||||
* @param[in] ignore_ctx_changes Flag to indicate if the HTTP Server should ignore changes to the context across different requests.
|
||||
* If set to false, the server will try clearing the old context, if it detects any change.
|
||||
*
|
||||
* @return ESP_OK in success
|
||||
* @return ESP_FAIL if req is nULL
|
||||
*/
|
||||
esp_err_t hap_platform_httpd_set_sess_ctx(httpd_req_t *req, void *ctx, httpd_free_ctx_fn_t free_ctx, bool ignore_ctx_changes);
|
||||
|
||||
/** Get the HTTP request method
|
||||
*
|
||||
* This API will be called by the HAP Core to get the HTTP request method
|
||||
* in string format (Eg. GET, POST, etc.)
|
||||
*
|
||||
* @param[in] HTTPD Request structure.
|
||||
*
|
||||
* @return Pointer to a string indicating the HTTP method.
|
||||
*/
|
||||
const char *hap_platform_httpd_get_req_method(httpd_req_t *req);
|
||||
|
||||
/** Get the HTTP request URI
|
||||
*
|
||||
* This API will be called by the HAP Core to get the request URI string.
|
||||
*
|
||||
* @param[in] HTTPD Request structure.
|
||||
*
|
||||
* @return Pointer to the URI string.
|
||||
*/
|
||||
const char *hap_platform_httpd_get_req_uri(httpd_req_t *req);
|
||||
|
||||
/** Get the HTTP request content length
|
||||
*
|
||||
* This API will be called by the HAP Core to get the content length of the request.
|
||||
*
|
||||
* @param[in] HTTPD Request structure.
|
||||
*
|
||||
* @return Content length.
|
||||
*/
|
||||
int hap_platform_httpd_get_content_len(httpd_req_t *req);
|
||||
|
||||
/**
|
||||
* Get the HAP HTTPD Handle
|
||||
*
|
||||
* If an application wants to register additional HTTPD endpoints on the same server
|
||||
* instance being used by HomeKit, this API can be used to get the handle. This
|
||||
* should be used only after hap_start().
|
||||
*
|
||||
* @return HomeKit HTTPD Handle
|
||||
*/
|
||||
httpd_handle_t *hap_platform_httpd_get_handle();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _HAP_PLATFORM_HTTPD_H_ */
|
|
@ -1,337 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <string.h>
|
||||
#include <FS.h>
|
||||
|
||||
#define HAP_PLATFORM_DEF_NVS_PARTITION "nvs"
|
||||
#define HAP_PLATFORM_DEF_FACTORY_NVS_PARTITION "factory_nvs"
|
||||
|
||||
extern "C" {
|
||||
|
||||
static const char *TAG = "hap_platform_keystore";
|
||||
|
||||
const char * hap_platform_keystore_get_nvs_partition_name() {
|
||||
return HAP_PLATFORM_DEF_NVS_PARTITION;
|
||||
}
|
||||
|
||||
const char * hap_platform_keystore_get_factory_nvs_partition_name() {
|
||||
return HAP_PLATFORM_DEF_FACTORY_NVS_PARTITION;
|
||||
}
|
||||
|
||||
#define HAP_USE_LITTLEFS
|
||||
|
||||
#ifdef HAP_USE_LITTLEFS
|
||||
|
||||
#include <LittleFS.h>
|
||||
|
||||
extern FS *ffsp;
|
||||
|
||||
int hap_platform_keystore_init_partition(const char *part_name, bool read_only) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hap_platform_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size) {
|
||||
char path[48];
|
||||
strcpy(path, "/");
|
||||
strcat(path, part_name);
|
||||
|
||||
File fp = ffsp->open(path, "r");
|
||||
if (!fp) {
|
||||
ffsp->mkdir(path);
|
||||
return -1;
|
||||
}
|
||||
fp.close();
|
||||
|
||||
strcat(path, "/");
|
||||
strcat(path, name_space);
|
||||
fp = ffsp->open(path, "r");
|
||||
if (!fp) {
|
||||
ffsp->mkdir(path);
|
||||
return -1;
|
||||
}
|
||||
fp.close();
|
||||
|
||||
strcat(path, "/");
|
||||
strcat(path, key);
|
||||
fp = ffsp->open(path, "r");
|
||||
if (fp) {
|
||||
fp.read(val, *val_size);
|
||||
fp.close();
|
||||
} else {
|
||||
*val_size = 0;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hap_platform_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len) {
|
||||
char path[48];
|
||||
strcpy(path, "/");
|
||||
strcat(path, part_name);
|
||||
|
||||
File fp = ffsp->open(path, "r");
|
||||
if (!fp) {
|
||||
ffsp->mkdir(path);
|
||||
}
|
||||
fp.close();
|
||||
|
||||
strcat(path, "/");
|
||||
strcat(path, name_space);
|
||||
fp = ffsp->open(path, "r");
|
||||
if (!fp) {
|
||||
ffsp->mkdir(path);
|
||||
}
|
||||
fp.close();
|
||||
|
||||
strcat(path, "/");
|
||||
strcat(path, key);
|
||||
fp = ffsp->open(path, "w");
|
||||
if (fp) {
|
||||
fp.write(val, val_len);
|
||||
fp.close();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hap_platform_keystore_delete(const char *part_name, const char *name_space, const char *key) {
|
||||
char path[48];
|
||||
strcpy(path, "/");
|
||||
strcat(path, part_name);
|
||||
strcat(path, "/");
|
||||
strcat(path, name_space);
|
||||
strcat(path, "/");
|
||||
strcat(path, key);
|
||||
ffsp->remove(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// should
|
||||
int hap_platform_keystore_delete_namespace(const char *part_name, const char *name_space) {
|
||||
char path[48];
|
||||
strcpy(path, "/");
|
||||
strcat(path, part_name);
|
||||
strcat(path, "/");
|
||||
strcat(path, name_space);
|
||||
File fp = ffsp->open(path, "r");
|
||||
if (fp.isDirectory()) {
|
||||
while (true) {
|
||||
File entry = fp.openNextFile();
|
||||
if (!entry) break;
|
||||
char p[48];
|
||||
strcpy(p,entry.name());
|
||||
entry.close();
|
||||
ffsp->remove(p);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// last resort only
|
||||
int hap_platfrom_keystore_erase_partition(const char *part_name) {
|
||||
char path[48];
|
||||
strcpy(path, "/");
|
||||
strcat(path, part_name);
|
||||
File fp = ffsp->open(path, "r");
|
||||
if (fp.isDirectory()) {
|
||||
while (true) {
|
||||
File entry = fp.openNextFile();
|
||||
if (!entry) break;
|
||||
const char *ep = entry.name();
|
||||
if (*ep=='/') ep++;
|
||||
char *lcp = strrchr(ep,'/');
|
||||
if (lcp) {
|
||||
ep = lcp + 1;
|
||||
}
|
||||
char p[48];
|
||||
strcpy(p,entry.name());
|
||||
if (entry.isDirectory()) {
|
||||
hap_platform_keystore_delete_namespace(part_name, ep);
|
||||
entry.close();
|
||||
ffsp->rmdir(p);
|
||||
} else {
|
||||
entry.close();
|
||||
ffsp->remove(p);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
int hap_platform_keystore_init_partition(const char *part_name, bool read_only)
|
||||
{
|
||||
esp_err_t err;
|
||||
nvs_sec_cfg_t *cfg = NULL;
|
||||
nvs_sec_cfg_t sec_cfg;
|
||||
esp_partition_iterator_t iterator = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL);
|
||||
if (iterator) {
|
||||
const esp_partition_t *partition = esp_partition_get(iterator);
|
||||
err = nvs_flash_read_security_cfg(partition, &sec_cfg);
|
||||
if (err == ESP_OK) {
|
||||
cfg = &sec_cfg;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "No NVS keys found");
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "No NVS keys partition found");
|
||||
}
|
||||
if (!cfg) {
|
||||
ESP_LOGE(TAG, "NVS partition '%s' not encrypted", part_name);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "NVS partition '%s' is encrypted", part_name);
|
||||
}
|
||||
if (read_only) {
|
||||
err = nvs_flash_secure_init_partition(part_name, cfg);
|
||||
} else {
|
||||
err = nvs_flash_secure_init_partition(part_name, cfg);
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase_partition(part_name));
|
||||
err = nvs_flash_secure_init_partition(part_name, cfg);
|
||||
}
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
int hap_platform_keystore_init_partition(const char *part_name, bool read_only)
|
||||
{
|
||||
esp_err_t err;
|
||||
if (read_only) {
|
||||
err = nvs_flash_init_partition(part_name);
|
||||
} else {
|
||||
err = nvs_flash_init_partition(part_name);
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase_partition(part_name));
|
||||
err = nvs_flash_init_partition(part_name);
|
||||
}
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_NVS_ENCRYPTION */
|
||||
|
||||
int hap_platform_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size)
|
||||
{
|
||||
nvs_handle handle;
|
||||
esp_err_t err = nvs_open_from_partition(part_name, name_space, NVS_READONLY, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return -1;
|
||||
} else {
|
||||
err = nvs_get_blob(handle, key, val, val_size);
|
||||
nvs_close(handle);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hap_platform_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len)
|
||||
|
||||
{
|
||||
nvs_handle handle;
|
||||
esp_err_t err = nvs_open_from_partition(part_name, name_space, NVS_READWRITE, &handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error (%d) opening NVS handle!", err);
|
||||
} else {
|
||||
err = nvs_set_blob(handle, key, val, val_len);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write %s", key);
|
||||
} else {
|
||||
nvs_commit(handle);
|
||||
}
|
||||
nvs_close(handle);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hap_platform_keystore_delete(const char *part_name, const char *name_space, const char *key)
|
||||
{
|
||||
nvs_handle handle;
|
||||
esp_err_t err = nvs_open_from_partition(part_name, name_space, NVS_READWRITE, &handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error (%d) opening NVS handle!", err);
|
||||
} else {
|
||||
err = nvs_erase_key(handle, key);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to delete %s", key);
|
||||
} else {
|
||||
nvs_commit(handle);
|
||||
}
|
||||
nvs_close(handle);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hap_platform_keystore_delete_namespace(const char *part_name, const char *name_space)
|
||||
{
|
||||
nvs_handle handle;
|
||||
esp_err_t err = nvs_open_from_partition(part_name, name_space, NVS_READWRITE, &handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error (%d) opening NVS handle!", err);
|
||||
} else {
|
||||
err = nvs_erase_all(handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to delete %s", name_space);
|
||||
} else {
|
||||
nvs_commit(handle);
|
||||
}
|
||||
nvs_close(handle);
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hap_platfrom_keystore_erase_partition(const char *part_name)
|
||||
{
|
||||
esp_err_t err = nvs_flash_erase_partition(part_name);
|
||||
if (err == ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif // USE_LITTLEFS
|
||||
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HAP_PLATFORM_KEYSTORE_H_
|
||||
#define _HAP_PLATFORM_KEYSTORE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Get NVS Partition Name
|
||||
*
|
||||
* @return pointer to an allocated string indicating NVS partition Name
|
||||
*/
|
||||
char * hap_platform_keystore_get_nvs_partition_name();
|
||||
|
||||
|
||||
/** Get Factory NVS Partition Name
|
||||
*
|
||||
* @return pointer to an allocated string indicating Factory NVS partition Name
|
||||
*/
|
||||
char * hap_platform_keystore_get_factory_nvs_partition_name();
|
||||
|
||||
/** Initialise Key Store Partition
|
||||
*
|
||||
* @param[in] part_name Name of Partition
|
||||
* @param[in] read_only True for Read-Only, False for Read-Write
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int hap_platform_keystore_init_partition(const char *part_name, bool read_only);
|
||||
|
||||
/** Get Value from Key Store
|
||||
*
|
||||
* @param[in] part_name Name of Partition
|
||||
* @param[in] name_space Name space for the key
|
||||
* @param[in] key Name of the key
|
||||
* @param[out] val Allocated buffer into which the value will be read
|
||||
* @param[in,out] val_size Size of the allocated value buffer. Will hold the size of value read on success
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int hap_platform_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size);
|
||||
|
||||
/** Set Value in Key Store
|
||||
*
|
||||
* @param[in] part_name Name of Partition
|
||||
* @param[in] name_space Name space for the key
|
||||
* @param[in] key Name of the key
|
||||
* @param[in] val Pointer to the value buffer
|
||||
* @param[in] val_len Length of the value buffer
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int hap_platform_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len);
|
||||
|
||||
/** Delete Entry from Key Store
|
||||
*
|
||||
* @param[in] part_name Name of Partition
|
||||
* @param[in] name_space Name space for the key
|
||||
* @param[in] key Name of the key
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int hap_platform_keystore_delete(const char *part_name, const char *name_space, const char *key);
|
||||
|
||||
/** Delete Name space from Key Store
|
||||
*
|
||||
* @param[in] part_name Name of Partition
|
||||
* @param[in] name_space Name space for the key
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int hap_platform_keystore_delete_namespace(const char *part_name, const char *name_space);
|
||||
|
||||
/** Erase a Key Store partition
|
||||
*
|
||||
* @param[in] part_name Name of Partition
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
*/
|
||||
int hap_platfrom_keystore_erase_partition(const char *part_name);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _HAP_PLATFORM_KEYSTORE_H_ */
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
//Tasmota Patch
|
||||
extern void *special_malloc(uint32_t size);
|
||||
extern void *special_calloc(size_t num, size_t size);
|
||||
|
||||
extern "C" {
|
||||
void * hap_platform_memory_malloc(size_t size)
|
||||
{
|
||||
return special_malloc((uint32_t)size);
|
||||
// return malloc(size);
|
||||
}
|
||||
|
||||
void * hap_platform_memory_calloc(size_t count, size_t size)
|
||||
{
|
||||
return special_calloc(count,size);
|
||||
// return calloc(count, size);
|
||||
}
|
||||
|
||||
void hap_platform_memory_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
} //extern "C"
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_PLATFORM_MEMORY_H_
|
||||
#define _HAP_PLATFORM_MEMORY_H_
|
||||
#include <stdlib.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** Allocate memory
|
||||
*
|
||||
* This API allocates "size" bytes of memory and returns a pointer to the allocated memory.
|
||||
*
|
||||
* @param[in] size Number of bytes to be allocated
|
||||
*
|
||||
* @return pointer to the allocated memory
|
||||
* @return NULL on failure
|
||||
*/
|
||||
void * hap_platform_memory_malloc(size_t size);
|
||||
|
||||
/** Allocate contiguous memory for items
|
||||
*
|
||||
* This API contiguously allocates enough space for "count" objects that are "size" bytes of memory each
|
||||
* and returns a pointer to the allocated memory. The allocated memory is filled with bytes of value zero.
|
||||
*
|
||||
* @param[in] count Number of items
|
||||
* @param[in] size Size of each item
|
||||
*
|
||||
* @return pointer to the allocated memory
|
||||
* @return NULL on failure
|
||||
*/
|
||||
void * hap_platform_memory_calloc(size_t count, size_t size);
|
||||
|
||||
/** Free allocate memory
|
||||
*
|
||||
* This API frees the memory allocated by hap_platform_memory_malloc() or hap_platform_memory_calloc()
|
||||
*
|
||||
* @param[in] ptr Pointer to the allocated memory
|
||||
*/
|
||||
void hap_platform_memory_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _HAP_PLATFORM_MEMORY_H_ */
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/FreeRTOSConfig.h>
|
||||
#include <freertos/portmacro.h>
|
||||
|
||||
uint16_t hap_platform_os_get_msec_per_tick()
|
||||
{
|
||||
return portTICK_PERIOD_MS;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAP_PLATFORM_OS_H_
|
||||
#define _HAP_PLATFORM_OS_H_
|
||||
#include <stdint.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** Return the OS tick period in milliseconds
|
||||
*
|
||||
* @return the milliseconds per tick as configured for the OS
|
||||
*/
|
||||
uint16_t hap_platform_os_get_msec_per_tick();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _HAP_PLATFORM_OS_H_ */
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HAP_WAC_H_
|
||||
#define _HAP_WAC_H_
|
||||
#include <stdint.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_err.h>
|
||||
/** HomeKit Event Base */
|
||||
ESP_EVENT_DECLARE_BASE(HAP_WAC_EVENT);
|
||||
/** HomeKit Events */
|
||||
typedef enum {
|
||||
/* WAC has started. Associated data is NULL */
|
||||
HAP_WAC_EVENT_STARTED,
|
||||
/** WAC has timed out because of inactivity. Associated data is NULL.
|
||||
* Appropriate indications should be given to the user, so that the accessory can be rebooted
|
||||
* for restarting WAC.
|
||||
*/
|
||||
HAP_WAC_EVENT_TIMEOUT,
|
||||
/** WAC was successful and will stop after some time. Associated data is NULL.
|
||||
*/
|
||||
HAP_WAC_EVENT_SUCCESS,
|
||||
/** WAC is requesting to start SoftAP. Associated data is a pointer to a NULL terminated SSID.
|
||||
* Using this SSID isn't required, but recommended. The network security should be "Open" for
|
||||
* WAC to work. If SoftAP has already been started, nothing needs to be done for this event.
|
||||
* The helper function hap_wifi_softap_start() can be used for this.
|
||||
*/
|
||||
HAP_WAC_EVENT_REQ_SOFTAP_START,
|
||||
/** WAC is requesting to stop SoftAP. Associated data is NULL.
|
||||
* The helper function hap_wifi_softap_stop() can be used for this.
|
||||
*/
|
||||
HAP_WAC_EVENT_REQ_SOFTAP_STOP,
|
||||
/** WAC has received the Wi-Fi credentials. Associated data is a pointer to wifi_config_t
|
||||
* structure. This should be used to connect to the Wi-Fi network.
|
||||
* The helper function hap_wifi_sta_connect() can be used for this.
|
||||
*/
|
||||
HAP_WAC_EVENT_RECV_CRED,
|
||||
/** WAC has stopped */
|
||||
HAP_WAC_EVENT_STOPPED
|
||||
} hap_wac_event_t;
|
||||
|
||||
/** Start WAC Provisioning.
|
||||
*
|
||||
* This should be called when the accessory boots up in an unprovisioned mode.
|
||||
* The helper function hap_wifi_is_provisioned() function can be used to find
|
||||
* if the accessory is provisioned or not.
|
||||
*
|
||||
* @return 0 on success.
|
||||
* @return -1 on failure.
|
||||
*/
|
||||
int hap_wac_start(void);
|
||||
|
||||
/** Stop WAC Provisioning.
|
||||
*
|
||||
* This should be used only if WAC needs to be stopped explicitly (say, after
|
||||
* provisioning was done using some other means). Else, WAC stops automatically,
|
||||
* either after the timeout or after successful provisioning.
|
||||
*
|
||||
* @return 0 on success.
|
||||
* @return -1 on failure.
|
||||
*/
|
||||
int hap_wac_stop(void);
|
||||
|
||||
/** Check is accessory is provisioned
|
||||
*
|
||||
* @param[out] provisioned Pointer to an allocated boolean variable. Will
|
||||
* be set to true if accessory is provisioned, else false.
|
||||
*
|
||||
* @return ESP_OK on success.
|
||||
* @return error on failure.
|
||||
*/
|
||||
esp_err_t hap_wifi_is_provisioned(bool *provisioned);
|
||||
|
||||
/** Start SoftAP
|
||||
*
|
||||
* @param[in] ssid NULL terminated ssid string.
|
||||
*
|
||||
* @return ESP_OK on success.
|
||||
* @return error on failure.
|
||||
*/
|
||||
esp_err_t hap_wifi_softap_start(char *ssid);
|
||||
|
||||
/** Stop Soft AP
|
||||
*
|
||||
* @return ESP_OK on success.
|
||||
* @return error on failure.
|
||||
*/
|
||||
esp_err_t hap_wifi_softap_stop(void);
|
||||
|
||||
/** Connect to Wi-Fi network with given configuration
|
||||
*
|
||||
* @param[in] config Pointer to \ref wifi_config_t structure.
|
||||
*
|
||||
* @return ESP_OK on success.
|
||||
* @return error on failure.
|
||||
*/
|
||||
esp_err_t hap_wifi_sta_connect(wifi_config_t *config);
|
||||
|
||||
#endif /* _HAP_WAC_H_ */
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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 <hexbin.h>
|
||||
static int hex2bin_byte(uint8_t *byte)
|
||||
{
|
||||
if (*byte >= '0' && *byte <= '9')
|
||||
*byte -= '0';
|
||||
else if (*byte >= 'a' && *byte <= 'f')
|
||||
*byte -= ('a' - 0x0a);
|
||||
else if (*byte >= 'A' && *byte <= 'F')
|
||||
*byte -= ('A' - 0x0a);
|
||||
else
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hex2bin(const char *ihex, size_t ilen, uint8_t *obin, size_t *olen)
|
||||
{
|
||||
if (ilen > (2 * (*olen))) {
|
||||
return -1;
|
||||
} else if (ilen % 2) {
|
||||
return -1;
|
||||
}
|
||||
int i, j;
|
||||
uint8_t byte;
|
||||
for (i = 0, j = 0; i < ilen / 2; i++) {
|
||||
byte = ihex[j++];
|
||||
if (hex2bin_byte(&byte) < 0) {
|
||||
return -1;
|
||||
}
|
||||
obin[i] = (byte << 4);
|
||||
byte = ihex[j++];
|
||||
if (hex2bin_byte(&byte) < 0) {
|
||||
return -1;
|
||||
}
|
||||
obin[i] |= byte;
|
||||
}
|
||||
*olen = i;
|
||||
return 0;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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 _HEXBIN_H_
|
||||
#define _HEXBIN_H_
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
int hex2bin(const char *ihex, size_t ilen, uint8_t *obin, size_t *olen);
|
||||
#endif /* _HEXBIN_H_ */
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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 <stdio.h>
|
||||
|
||||
//#define HEX_DBG_ENABLE
|
||||
|
||||
#ifdef HEX_DBG_ENABLE
|
||||
void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len)
|
||||
{
|
||||
int i;
|
||||
printf("%s: ", name);
|
||||
for (i = 0; i < buf_len; i++) {
|
||||
if (i % 16 == 0)
|
||||
printf("\r\n");
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
#else
|
||||
void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len)
|
||||
{
|
||||
}
|
||||
#endif /* HEX_DBG_ENABLED */
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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 _HEXDUMP_H_
|
||||
#define _HEXDUMP_H_
|
||||
void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len);
|
||||
|
||||
#endif /* _HEXDUMP_H_ */
|
|
@ -1,358 +0,0 @@
|
|||
/**************************** sha.h ****************************/
|
||||
/***************** See RFC 6234 for details. *******************/
|
||||
/*
|
||||
Copyright (c) 2011 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and
|
||||
the following disclaimer.
|
||||
|
||||
- Redistributions in binary form 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.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor
|
||||
the names of specific contributors, may be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
#ifndef _SHA_H_
|
||||
#define _SHA_H_
|
||||
|
||||
/*
|
||||
* Description:
|
||||
* This file implements the Secure Hash Algorithms
|
||||
* as defined in the U.S. National Institute of Standards
|
||||
* and Technology Federal Information Processing Standards
|
||||
* Publication (FIPS PUB) 180-3 published in October 2008
|
||||
* and formerly defined in its predecessors, FIPS PUB 180-1
|
||||
* and FIP PUB 180-2.
|
||||
*
|
||||
* A combined document showing all algorithms is available at
|
||||
* http://csrc.nist.gov/publications/fips/
|
||||
* fips180-3/fips180-3_final.pdf
|
||||
*
|
||||
* The five hashes are defined in these sizes:
|
||||
* SHA-1 20 byte / 160 bit
|
||||
* SHA-224 28 byte / 224 bit
|
||||
* SHA-256 32 byte / 256 bit
|
||||
* SHA-384 48 byte / 384 bit
|
||||
* SHA-512 64 byte / 512 bit
|
||||
*
|
||||
* Compilation Note:
|
||||
* These files may be compiled with two options:
|
||||
* USE_32BIT_ONLY - use 32-bit arithmetic only, for systems
|
||||
* without 64-bit integers
|
||||
*
|
||||
* USE_MODIFIED_MACROS - use alternate form of the SHA_Ch()
|
||||
* and SHA_Maj() macros that are equivalent
|
||||
* and potentially faster on many systems
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
/*
|
||||
* If you do not have the ISO standard stdint.h header file, then you
|
||||
* must typedef the following:
|
||||
* name meaning
|
||||
* uint64_t unsigned 64-bit integer
|
||||
* uint32_t unsigned 32-bit integer
|
||||
* uint8_t unsigned 8-bit integer (i.e., unsigned char)
|
||||
* int_least16_t integer of >= 16 bits
|
||||
*
|
||||
* See stdint-example.h
|
||||
*/
|
||||
|
||||
#ifndef _SHA_enum_
|
||||
#define _SHA_enum_
|
||||
/*
|
||||
* All SHA functions return one of these values.
|
||||
*/
|
||||
enum {
|
||||
shaSuccess = 0,
|
||||
shaNull, /* Null pointer parameter */
|
||||
shaInputTooLong, /* input data too long */
|
||||
shaStateError, /* called Input after FinalBits or Result */
|
||||
shaBadParam /* passed a bad parameter */
|
||||
};
|
||||
#endif /* _SHA_enum_ */
|
||||
|
||||
/*
|
||||
* These constants hold size information for each of the SHA
|
||||
* hashing operations
|
||||
*/
|
||||
enum {
|
||||
SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64,
|
||||
SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128,
|
||||
SHA512_Message_Block_Size = 128,
|
||||
USHA_Max_Message_Block_Size = SHA512_Message_Block_Size,
|
||||
|
||||
SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32,
|
||||
SHA384HashSize = 48, SHA512HashSize = 64,
|
||||
USHAMaxHashSize = SHA512HashSize,
|
||||
|
||||
SHA1HashSizeBits = 160, SHA224HashSizeBits = 224,
|
||||
SHA256HashSizeBits = 256, SHA384HashSizeBits = 384,
|
||||
SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits
|
||||
};
|
||||
|
||||
/*
|
||||
* These constants are used in the USHA (Unified SHA) functions.
|
||||
*/
|
||||
typedef enum SHAversion {
|
||||
SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
} SHAversion;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-1
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA1Context {
|
||||
uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
|
||||
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 512-bit message blocks */
|
||||
uint8_t Message_Block[SHA1_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA1Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-256
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA256Context {
|
||||
uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */
|
||||
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 512-bit message blocks */
|
||||
uint8_t Message_Block[SHA256_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA256Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-512
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA512Context {
|
||||
#ifdef USE_32BIT_ONLY
|
||||
uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */
|
||||
uint32_t Length[4]; /* Message length in bits */
|
||||
#else /* !USE_32BIT_ONLY */
|
||||
uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */
|
||||
uint64_t Length_High, Length_Low; /* Message length in bits */
|
||||
#endif /* USE_32BIT_ONLY */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 1024-bit message blocks */
|
||||
uint8_t Message_Block[SHA512_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed?*/
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA512Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-224
|
||||
* hashing operation. It uses the SHA-256 structure for computation.
|
||||
*/
|
||||
typedef struct SHA256Context SHA224Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-384
|
||||
* hashing operation. It uses the SHA-512 structure for computation.
|
||||
*/
|
||||
typedef struct SHA512Context SHA384Context;
|
||||
|
||||
/*
|
||||
* This structure holds context information for all SHA
|
||||
* hashing operations.
|
||||
*/
|
||||
typedef struct USHAContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
union {
|
||||
SHA1Context sha1Context;
|
||||
SHA224Context sha224Context; SHA256Context sha256Context;
|
||||
SHA384Context sha384Context; SHA512Context sha512Context;
|
||||
} ctx;
|
||||
|
||||
} USHAContext;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the HMAC
|
||||
* keyed-hashing operation.
|
||||
*/
|
||||
typedef struct HMACContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
int hashSize; /* hash size of SHA being used */
|
||||
int blockSize; /* block size of SHA being used */
|
||||
USHAContext shaContext; /* SHA context */
|
||||
unsigned char k_opad[USHA_Max_Message_Block_Size];
|
||||
/* outer padding - key XORd with opad */
|
||||
int Computed; /* Is the MAC computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
|
||||
} HMACContext;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the HKDF
|
||||
* extract-and-expand Key Derivation Functions.
|
||||
*/
|
||||
typedef struct HKDFContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
HMACContext hmacContext;
|
||||
int hashSize; /* hash size of SHA being used */
|
||||
unsigned char prk[USHAMaxHashSize];
|
||||
/* pseudo-random key - output of hkdfInput */
|
||||
int Computed; /* Is the key material computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} HKDFContext;
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
|
||||
/* SHA-1 */
|
||||
extern int SHA1Reset(SHA1Context *);
|
||||
extern int SHA1Input(SHA1Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA1FinalBits(SHA1Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA1Result(SHA1Context *,
|
||||
uint8_t Message_Digest[SHA1HashSize]);
|
||||
|
||||
/* SHA-224 */
|
||||
extern int SHA224Reset(SHA224Context *);
|
||||
extern int SHA224Input(SHA224Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA224FinalBits(SHA224Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA224Result(SHA224Context *,
|
||||
uint8_t Message_Digest[SHA224HashSize]);
|
||||
|
||||
/* SHA-256 */
|
||||
extern int SHA256Reset(SHA256Context *);
|
||||
extern int SHA256Input(SHA256Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA256FinalBits(SHA256Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA256Result(SHA256Context *,
|
||||
uint8_t Message_Digest[SHA256HashSize]);
|
||||
|
||||
/* SHA-384 */
|
||||
extern int SHA384Reset(SHA384Context *);
|
||||
extern int SHA384Input(SHA384Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA384FinalBits(SHA384Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA384Result(SHA384Context *,
|
||||
uint8_t Message_Digest[SHA384HashSize]);
|
||||
|
||||
/* SHA-512 */
|
||||
extern int SHA512Reset(SHA512Context *);
|
||||
extern int SHA512Input(SHA512Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA512FinalBits(SHA512Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA512Result(SHA512Context *,
|
||||
uint8_t Message_Digest[SHA512HashSize]);
|
||||
|
||||
/* Unified SHA functions, chosen by whichSha */
|
||||
extern int USHAReset(USHAContext *context, SHAversion whichSha);
|
||||
extern int USHAInput(USHAContext *context,
|
||||
const uint8_t *bytes, unsigned int bytecount);
|
||||
extern int USHAFinalBits(USHAContext *context,
|
||||
uint8_t bits, unsigned int bit_count);
|
||||
extern int USHAResult(USHAContext *context,
|
||||
uint8_t Message_Digest[USHAMaxHashSize]);
|
||||
extern int USHABlockSize(enum SHAversion whichSha);
|
||||
extern int USHAHashSize(enum SHAversion whichSha);
|
||||
extern int USHAHashSizeBits(enum SHAversion whichSha);
|
||||
extern const char *USHAHashName(enum SHAversion whichSha);
|
||||
|
||||
/*
|
||||
* HMAC Keyed-Hashing for Message Authentication, RFC 2104,
|
||||
* for all SHAs.
|
||||
* This interface allows a fixed-length text input to be used.
|
||||
*/
|
||||
extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */
|
||||
const unsigned char *text, /* pointer to data stream */
|
||||
int text_len, /* length of data stream */
|
||||
const unsigned char *key, /* pointer to authentication key */
|
||||
int key_len, /* length of authentication key */
|
||||
uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
|
||||
|
||||
/*
|
||||
* HMAC Keyed-Hashing for Message Authentication, RFC 2104,
|
||||
* for all SHAs.
|
||||
* This interface allows any length of text input to be used.
|
||||
*/
|
||||
extern int hmacReset(HMACContext *context, enum SHAversion whichSha,
|
||||
const unsigned char *key, int key_len);
|
||||
extern int hmacInput(HMACContext *context, const unsigned char *text,
|
||||
int text_len);
|
||||
extern int hmacFinalBits(HMACContext *context, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int hmacResult(HMACContext *context,
|
||||
uint8_t digest[USHAMaxHashSize]);
|
||||
|
||||
/*
|
||||
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
|
||||
* RFC 5869, for all SHAs.
|
||||
*/
|
||||
extern int hkdf(SHAversion whichSha, const unsigned char *salt,
|
||||
int salt_len, const unsigned char *ikm, int ikm_len,
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[ ], int okm_len);
|
||||
extern int hkdfExtract(SHAversion whichSha, const unsigned char *salt,
|
||||
int salt_len, const unsigned char *ikm,
|
||||
int ikm_len, uint8_t prk[USHAMaxHashSize]);
|
||||
extern int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
|
||||
int prk_len, const unsigned char *info,
|
||||
int info_len, uint8_t okm[ ], int okm_len);
|
||||
|
||||
/*
|
||||
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
|
||||
* RFC 5869, for all SHAs.
|
||||
* This interface allows any length of text input to be used.
|
||||
*/
|
||||
extern int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
|
||||
const unsigned char *salt, int salt_len);
|
||||
extern int hkdfInput(HKDFContext *context, const unsigned char *ikm,
|
||||
int ikm_len);
|
||||
extern int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
|
||||
unsigned int ikm_bit_count);
|
||||
extern int hkdfResult(HKDFContext *context,
|
||||
uint8_t prk[USHAMaxHashSize],
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[USHAMaxHashSize], int okm_len);
|
||||
#endif /* _SHA_H_ */
|
||||
|
|
@ -1,335 +0,0 @@
|
|||
/**************************** hkdf.c ***************************/
|
||||
/***************** See RFC 6234 for details. *******************/
|
||||
/* Copyright (c) 2011 IETF Trust and the persons identified as */
|
||||
/* authors of the code. All rights reserved. */
|
||||
/* See sha.h for terms of use and redistribution. */
|
||||
|
||||
/*
|
||||
* Description:
|
||||
* This file implements the HKDF algorithm (HMAC-based
|
||||
* Extract-and-Expand Key Derivation Function, RFC 5869),
|
||||
* expressed in terms of the various SHA algorithms.
|
||||
*/
|
||||
|
||||
#include "sha.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* hkdf
|
||||
*
|
||||
* Description:
|
||||
* This function will generate keying material using HKDF.
|
||||
*
|
||||
* Parameters:
|
||||
* whichSha: [in]
|
||||
* One of SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
* salt[ ]: [in]
|
||||
* The optional salt value (a non-secret random value);
|
||||
* if not provided (salt == NULL), it is set internally
|
||||
* to a string of HashLen(whichSha) zeros.
|
||||
* salt_len: [in]
|
||||
* The length of the salt value. (Ignored if salt == NULL.)
|
||||
* ikm[ ]: [in]
|
||||
* Input keying material.
|
||||
* ikm_len: [in]
|
||||
* The length of the input keying material.
|
||||
* info[ ]: [in]
|
||||
* The optional context and application specific information.
|
||||
* If info == NULL or a zero-length string, it is ignored.
|
||||
* info_len: [in]
|
||||
* The length of the optional context and application specific
|
||||
* information. (Ignored if info == NULL.)
|
||||
* okm[ ]: [out]
|
||||
* Where the HKDF is to be stored.
|
||||
* okm_len: [in]
|
||||
* The length of the buffer to hold okm.
|
||||
* okm_len must be <= 255 * USHABlockSize(whichSha)
|
||||
*
|
||||
* Notes:
|
||||
* Calls hkdfExtract() and hkdfExpand().
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hkdf(SHAversion whichSha,
|
||||
const unsigned char *salt, int salt_len,
|
||||
const unsigned char *ikm, int ikm_len,
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[ ], int okm_len)
|
||||
{
|
||||
uint8_t prk[USHAMaxHashSize];
|
||||
return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) ||
|
||||
hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
|
||||
info_len, okm, okm_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* hkdfExtract
|
||||
*
|
||||
* Description:
|
||||
* This function will perform HKDF extraction.
|
||||
*
|
||||
* Parameters:
|
||||
* whichSha: [in]
|
||||
* One of SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
* salt[ ]: [in]
|
||||
* The optional salt value (a non-secret random value);
|
||||
* if not provided (salt == NULL), it is set internally
|
||||
* to a string of HashLen(whichSha) zeros.
|
||||
* salt_len: [in]
|
||||
* The length of the salt value. (Ignored if salt == NULL.)
|
||||
* ikm[ ]: [in]
|
||||
* Input keying material.
|
||||
* ikm_len: [in]
|
||||
* The length of the input keying material.
|
||||
* prk[ ]: [out]
|
||||
* Array where the HKDF extraction is to be stored.
|
||||
* Must be larger than USHAHashSize(whichSha);
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hkdfExtract(SHAversion whichSha,
|
||||
const unsigned char *salt, int salt_len,
|
||||
const unsigned char *ikm, int ikm_len,
|
||||
uint8_t prk[USHAMaxHashSize])
|
||||
{
|
||||
unsigned char nullSalt[USHAMaxHashSize];
|
||||
if (salt == 0) {
|
||||
salt = nullSalt;
|
||||
salt_len = USHAHashSize(whichSha);
|
||||
memset(nullSalt, '\0', salt_len);
|
||||
} else if (salt_len < 0) {
|
||||
return shaBadParam;
|
||||
}
|
||||
return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
|
||||
}
|
||||
|
||||
/*
|
||||
* hkdfExpand
|
||||
*
|
||||
* Description:
|
||||
* This function will perform HKDF expansion.
|
||||
*
|
||||
* Parameters:
|
||||
* whichSha: [in]
|
||||
* One of SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
* prk[ ]: [in]
|
||||
* The pseudo-random key to be expanded; either obtained
|
||||
* directly from a cryptographically strong, uniformly
|
||||
* distributed pseudo-random number generator, or as the
|
||||
* output from hkdfExtract().
|
||||
* prk_len: [in]
|
||||
* The length of the pseudo-random key in prk;
|
||||
* should at least be equal to USHAHashSize(whichSHA).
|
||||
* info[ ]: [in]
|
||||
* The optional context and application specific information.
|
||||
* If info == NULL or a zero-length string, it is ignored.
|
||||
* info_len: [in]
|
||||
* The length of the optional context and application specific
|
||||
* information. (Ignored if info == NULL.)
|
||||
* okm[ ]: [out]
|
||||
* Where the HKDF is to be stored.
|
||||
* okm_len: [in]
|
||||
* The length of the buffer to hold okm.
|
||||
* okm_len must be <= 255 * USHABlockSize(whichSha)
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], int prk_len,
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[ ], int okm_len)
|
||||
{
|
||||
int hash_len, N;
|
||||
unsigned char T[USHAMaxHashSize];
|
||||
int Tlen, where, i;
|
||||
|
||||
if (info == 0) {
|
||||
info = (const unsigned char *)"";
|
||||
info_len = 0;
|
||||
} else if (info_len < 0) {
|
||||
return shaBadParam;
|
||||
}
|
||||
if (okm_len <= 0) return shaBadParam;
|
||||
if (!okm) return shaBadParam;
|
||||
|
||||
hash_len = USHAHashSize(whichSha);
|
||||
if (prk_len < hash_len) return shaBadParam;
|
||||
N = okm_len / hash_len;
|
||||
if ((okm_len % hash_len) != 0) N++;
|
||||
if (N > 255) return shaBadParam;
|
||||
|
||||
Tlen = 0;
|
||||
where = 0;
|
||||
for (i = 1; i <= N; i++) {
|
||||
HMACContext context;
|
||||
unsigned char c = i;
|
||||
int ret = hmacReset(&context, whichSha, prk, prk_len) ||
|
||||
hmacInput(&context, T, Tlen) ||
|
||||
hmacInput(&context, info, info_len) ||
|
||||
hmacInput(&context, &c, 1) ||
|
||||
hmacResult(&context, T);
|
||||
if (ret != shaSuccess) return ret;
|
||||
memcpy(okm + where, T,
|
||||
(i != N) ? hash_len : (okm_len - where));
|
||||
where += hash_len;
|
||||
Tlen = hash_len;
|
||||
}
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* hkdfReset
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the hkdfContext in preparation
|
||||
* for key derivation using the modular HKDF interface for
|
||||
* arbitrary length inputs.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to reset.
|
||||
* whichSha: [in]
|
||||
* One of SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
* salt[ ]: [in]
|
||||
* The optional salt value (a non-secret random value);
|
||||
* if not provided (salt == NULL), it is set internally
|
||||
* to a string of HashLen(whichSha) zeros.
|
||||
* salt_len: [in]
|
||||
* The length of the salt value. (Ignored if salt == NULL.)
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
|
||||
const unsigned char *salt, int salt_len)
|
||||
{
|
||||
unsigned char nullSalt[USHAMaxHashSize];
|
||||
if (!context) return shaNull;
|
||||
|
||||
context->whichSha = whichSha;
|
||||
context->hashSize = USHAHashSize(whichSha);
|
||||
if (salt == 0) {
|
||||
salt = nullSalt;
|
||||
salt_len = context->hashSize;
|
||||
memset(nullSalt, '\0', salt_len);
|
||||
}
|
||||
|
||||
return hmacReset(&context->hmacContext, whichSha, salt, salt_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* hkdfInput
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion
|
||||
* of the input keying material. It may be called multiple times.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The HKDF context to update.
|
||||
* ikm[ ]: [in]
|
||||
* An array of octets representing the next portion of
|
||||
* the input keying material.
|
||||
* ikm_len: [in]
|
||||
* The length of ikm.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hkdfInput(HKDFContext *context, const unsigned char *ikm,
|
||||
int ikm_len)
|
||||
{
|
||||
if (!context) return shaNull;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
if (context->Computed) return context->Corrupted = shaStateError;
|
||||
return hmacInput(&context->hmacContext, ikm, ikm_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* hkdfFinalBits
|
||||
*
|
||||
* Description:
|
||||
* This function will add in any final bits of the
|
||||
* input keying material.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The HKDF context to update
|
||||
* ikm_bits: [in]
|
||||
* The final bits of the input keying material, in the upper
|
||||
* portion of the byte. (Use 0b###00000 instead of 0b00000###
|
||||
* to input the three bits ###.)
|
||||
* ikm_bit_count: [in]
|
||||
* The number of bits in message_bits, between 1 and 7.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
|
||||
unsigned int ikm_bit_count)
|
||||
{
|
||||
if (!context) return shaNull;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
if (context->Computed) return context->Corrupted = shaStateError;
|
||||
return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* hkdfResult
|
||||
*
|
||||
* Description:
|
||||
* This function will finish the HKDF extraction and perform the
|
||||
* final HKDF expansion.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The HKDF context to use to calculate the HKDF hash.
|
||||
* prk[ ]: [out]
|
||||
* An optional location to store the HKDF extraction.
|
||||
* Either NULL, or pointer to a buffer that must be
|
||||
* larger than USHAHashSize(whichSha);
|
||||
* info[ ]: [in]
|
||||
* The optional context and application specific information.
|
||||
* If info == NULL or a zero-length string, it is ignored.
|
||||
* info_len: [in]
|
||||
* The length of the optional context and application specific
|
||||
* information. (Ignored if info == NULL.)
|
||||
* okm[ ]: [out]
|
||||
* Where the HKDF is to be stored.
|
||||
* okm_len: [in]
|
||||
* The length of the buffer to hold okm.
|
||||
* okm_len must be <= 255 * USHABlockSize(whichSha)
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hkdfResult(HKDFContext *context,
|
||||
uint8_t prk[USHAMaxHashSize],
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[ ], int okm_len)
|
||||
{
|
||||
uint8_t prkbuf[USHAMaxHashSize];
|
||||
int ret;
|
||||
|
||||
if (!context) return shaNull;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
if (context->Computed) return context->Corrupted = shaStateError;
|
||||
if (!okm) return context->Corrupted = shaBadParam;
|
||||
if (!prk) prk = prkbuf;
|
||||
|
||||
ret = hmacResult(&context->hmacContext, prk) ||
|
||||
hkdfExpand(context->whichSha, prk, context->hashSize, info,
|
||||
info_len, okm, okm_len);
|
||||
context->Computed = 1;
|
||||
return context->Corrupted = ret;
|
||||
}
|
||||
|
|
@ -1,249 +0,0 @@
|
|||
/**************************** hmac.c ***************************/
|
||||
/***************** See RFC 6234 for details. *******************/
|
||||
/* Copyright (c) 2011 IETF Trust and the persons identified as */
|
||||
/* authors of the code. All rights reserved. */
|
||||
/* See sha.h for terms of use and redistribution. */
|
||||
|
||||
/*
|
||||
* Description:
|
||||
* This file implements the HMAC algorithm (Keyed-Hashing for
|
||||
* Message Authentication, [RFC 2104]), expressed in terms of
|
||||
* the various SHA algorithms.
|
||||
*/
|
||||
|
||||
#include "sha.h"
|
||||
|
||||
/*
|
||||
* hmac
|
||||
*
|
||||
* Description:
|
||||
* This function will compute an HMAC message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* whichSha: [in]
|
||||
* One of SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
* message_array[ ]: [in]
|
||||
* An array of octets representing the message.
|
||||
* Note: in RFC 2104, this parameter is known
|
||||
* as 'text'.
|
||||
* length: [in]
|
||||
* The length of the message in message_array.
|
||||
* key[ ]: [in]
|
||||
* The secret shared key.
|
||||
* key_len: [in]
|
||||
* The length of the secret shared key.
|
||||
* digest[ ]: [out]
|
||||
* Where the digest is to be returned.
|
||||
* NOTE: The length of the digest is determined by
|
||||
* the value of whichSha.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
|
||||
int hmac(SHAversion whichSha,
|
||||
const unsigned char *message_array, int length,
|
||||
const unsigned char *key, int key_len,
|
||||
uint8_t digest[USHAMaxHashSize])
|
||||
{
|
||||
HMACContext context;
|
||||
return hmacReset(&context, whichSha, key, key_len) ||
|
||||
hmacInput(&context, message_array, length) ||
|
||||
hmacResult(&context, digest);
|
||||
}
|
||||
|
||||
/*
|
||||
* hmacReset
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the hmacContext in preparation
|
||||
* for computing a new HMAC message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to reset.
|
||||
* whichSha: [in]
|
||||
* One of SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
* key[ ]: [in]
|
||||
* The secret shared key.
|
||||
* key_len: [in]
|
||||
* The length of the secret shared key.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hmacReset(HMACContext *context, enum SHAversion whichSha,
|
||||
const unsigned char *key, int key_len)
|
||||
{
|
||||
int i, blocksize, hashsize, ret;
|
||||
|
||||
/* inner padding - key XORd with ipad */
|
||||
unsigned char k_ipad[USHA_Max_Message_Block_Size];
|
||||
|
||||
/* temporary buffer when keylen > blocksize */
|
||||
unsigned char tempkey[USHAMaxHashSize];
|
||||
|
||||
if (!context) return shaNull;
|
||||
context->Computed = 0;
|
||||
context->Corrupted = shaSuccess;
|
||||
|
||||
blocksize = context->blockSize = USHABlockSize(whichSha);
|
||||
hashsize = context->hashSize = USHAHashSize(whichSha);
|
||||
context->whichSha = whichSha;
|
||||
|
||||
/*
|
||||
* If key is longer than the hash blocksize,
|
||||
* reset it to key = HASH(key).
|
||||
*/
|
||||
if (key_len > blocksize) {
|
||||
USHAContext tcontext;
|
||||
int err = USHAReset(&tcontext, whichSha) ||
|
||||
USHAInput(&tcontext, key, key_len) ||
|
||||
USHAResult(&tcontext, tempkey);
|
||||
if (err != shaSuccess) return err;
|
||||
|
||||
key = tempkey;
|
||||
key_len = hashsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* The HMAC transform looks like:
|
||||
*
|
||||
* SHA(K XOR opad, SHA(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key, 0-padded to a total of blocksize bytes,
|
||||
* ipad is the byte 0x36 repeated blocksize times,
|
||||
* opad is the byte 0x5c repeated blocksize times,
|
||||
* and text is the data being protected.
|
||||
*/
|
||||
|
||||
/* store key into the pads, XOR'd with ipad and opad values */
|
||||
for (i = 0; i < key_len; i++) {
|
||||
k_ipad[i] = key[i] ^ 0x36;
|
||||
context->k_opad[i] = key[i] ^ 0x5c;
|
||||
}
|
||||
/* remaining pad bytes are '\0' XOR'd with ipad and opad values */
|
||||
for ( ; i < blocksize; i++) {
|
||||
k_ipad[i] = 0x36;
|
||||
context->k_opad[i] = 0x5c;
|
||||
}
|
||||
|
||||
/* perform inner hash */
|
||||
/* init context for 1st pass */
|
||||
ret = USHAReset(&context->shaContext, whichSha) ||
|
||||
/* and start with inner pad */
|
||||
USHAInput(&context->shaContext, k_ipad, blocksize);
|
||||
return context->Corrupted = ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* hmacInput
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion
|
||||
* of the message. It may be called multiple times.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The HMAC context to update.
|
||||
* text[ ]: [in]
|
||||
* An array of octets representing the next portion of
|
||||
* the message.
|
||||
* text_len: [in]
|
||||
* The length of the message in text.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hmacInput(HMACContext *context, const unsigned char *text,
|
||||
int text_len)
|
||||
{
|
||||
if (!context) return shaNull;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
if (context->Computed) return context->Corrupted = shaStateError;
|
||||
/* then text of datagram */
|
||||
return context->Corrupted =
|
||||
USHAInput(&context->shaContext, text, text_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* hmacFinalBits
|
||||
*
|
||||
* Description:
|
||||
* This function will add in any final bits of the message.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The HMAC context to update.
|
||||
* message_bits: [in]
|
||||
* The final bits of the message, in the upper portion of the
|
||||
* byte. (Use 0b###00000 instead of 0b00000### to input the
|
||||
* three bits ###.)
|
||||
* length: [in]
|
||||
* The number of bits in message_bits, between 1 and 7.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*/
|
||||
int hmacFinalBits(HMACContext *context,
|
||||
uint8_t bits, unsigned int bit_count)
|
||||
{
|
||||
if (!context) return shaNull;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
if (context->Computed) return context->Corrupted = shaStateError;
|
||||
/* then final bits of datagram */
|
||||
return context->Corrupted =
|
||||
USHAFinalBits(&context->shaContext, bits, bit_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* hmacResult
|
||||
*
|
||||
* Description:
|
||||
* This function will return the N-byte message digest into the
|
||||
* Message_Digest array provided by the caller.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to use to calculate the HMAC hash.
|
||||
* digest[ ]: [out]
|
||||
* Where the digest is returned.
|
||||
* NOTE 2: The length of the hash is determined by the value of
|
||||
* whichSha that was passed to hmacReset().
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int hmacResult(HMACContext *context, uint8_t *digest)
|
||||
{
|
||||
int ret;
|
||||
if (!context) return shaNull;
|
||||
if (context->Corrupted) return context->Corrupted;
|
||||
if (context->Computed) return context->Corrupted = shaStateError;
|
||||
|
||||
/* finish up 1st pass */
|
||||
/* (Use digest here as a temporary buffer.) */
|
||||
ret =
|
||||
USHAResult(&context->shaContext, digest) ||
|
||||
|
||||
/* perform outer SHA */
|
||||
/* init context for 2nd pass */
|
||||
USHAReset(&context->shaContext, context->whichSha) ||
|
||||
|
||||
/* start with outer pad */
|
||||
USHAInput(&context->shaContext, context->k_opad,
|
||||
context->blockSize) ||
|
||||
|
||||
/* then results of 1st hash */
|
||||
USHAInput(&context->shaContext, digest, context->hashSize) ||
|
||||
/* finish up 2nd pass */
|
||||
USHAResult(&context->shaContext, digest);
|
||||
|
||||
context->Computed = 1;
|
||||
return context->Corrupted = ret;
|
||||
}
|
||||
|
|
@ -1,471 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2010 Serge Zaitsev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef JSMN_H
|
||||
#define JSMN_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef JSMN_STATIC
|
||||
#define JSMN_API static
|
||||
#else
|
||||
#define JSMN_API extern
|
||||
#endif
|
||||
|
||||
/**
|
||||
* JSON type identifier. Basic types are:
|
||||
* o Object
|
||||
* o Array
|
||||
* o String
|
||||
* o Other primitive: number, boolean (true/false) or null
|
||||
*/
|
||||
typedef enum {
|
||||
JSMN_UNDEFINED = 0,
|
||||
JSMN_OBJECT = 1,
|
||||
JSMN_ARRAY = 2,
|
||||
JSMN_STRING = 3,
|
||||
JSMN_PRIMITIVE = 4
|
||||
} jsmntype_t;
|
||||
|
||||
enum jsmnerr {
|
||||
/* Not enough tokens were provided */
|
||||
JSMN_ERROR_NOMEM = -1,
|
||||
/* Invalid character inside JSON string */
|
||||
JSMN_ERROR_INVAL = -2,
|
||||
/* The string is not a full JSON packet, more bytes expected */
|
||||
JSMN_ERROR_PART = -3
|
||||
};
|
||||
|
||||
/**
|
||||
* JSON token description.
|
||||
* type type (object, array, string etc.)
|
||||
* start start position in JSON data string
|
||||
* end end position in JSON data string
|
||||
*/
|
||||
typedef struct jsmntok {
|
||||
jsmntype_t type;
|
||||
int start;
|
||||
int end;
|
||||
int size;
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
int parent;
|
||||
#endif
|
||||
} jsmntok_t;
|
||||
|
||||
/**
|
||||
* JSON parser. Contains an array of token blocks available. Also stores
|
||||
* the string being parsed now and current position in that string.
|
||||
*/
|
||||
typedef struct jsmn_parser {
|
||||
unsigned int pos; /* offset in the JSON string */
|
||||
unsigned int toknext; /* next token to allocate */
|
||||
int toksuper; /* superior token node, e.g. parent object or array */
|
||||
} jsmn_parser;
|
||||
|
||||
/**
|
||||
* Create JSON parser over an array of tokens
|
||||
*/
|
||||
JSMN_API void jsmn_init(jsmn_parser *parser);
|
||||
|
||||
/**
|
||||
* Run JSON parser. It parses a JSON data string into and array of tokens, each
|
||||
* describing
|
||||
* a single JSON object.
|
||||
*/
|
||||
JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
|
||||
jsmntok_t *tokens, const unsigned int num_tokens);
|
||||
|
||||
#ifndef JSMN_HEADER
|
||||
/**
|
||||
* Allocates a fresh unused token from the token pool.
|
||||
*/
|
||||
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
|
||||
const size_t num_tokens) {
|
||||
jsmntok_t *tok;
|
||||
if (parser->toknext >= num_tokens) {
|
||||
return NULL;
|
||||
}
|
||||
tok = &tokens[parser->toknext++];
|
||||
tok->start = tok->end = -1;
|
||||
tok->size = 0;
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
tok->parent = -1;
|
||||
#endif
|
||||
return tok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills token type and boundaries.
|
||||
*/
|
||||
static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
|
||||
const int start, const int end) {
|
||||
token->type = type;
|
||||
token->start = start;
|
||||
token->end = end;
|
||||
token->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills next available token with JSON primitive.
|
||||
*/
|
||||
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
||||
const size_t len, jsmntok_t *tokens,
|
||||
const size_t num_tokens) {
|
||||
jsmntok_t *token;
|
||||
int start;
|
||||
|
||||
start = parser->pos;
|
||||
|
||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
||||
switch (js[parser->pos]) {
|
||||
#ifndef JSMN_STRICT
|
||||
/* In strict mode primitive must be followed by "," or "}" or "]" */
|
||||
case ':':
|
||||
#endif
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case ' ':
|
||||
case ',':
|
||||
case ']':
|
||||
case '}':
|
||||
goto found;
|
||||
default:
|
||||
/* to quiet a warning from gcc*/
|
||||
break;
|
||||
}
|
||||
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
#ifdef JSMN_STRICT
|
||||
/* In strict mode primitive must be followed by a comma/object/array */
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_PART;
|
||||
#endif
|
||||
|
||||
found:
|
||||
if (tokens == NULL) {
|
||||
parser->pos--;
|
||||
return 0;
|
||||
}
|
||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||
if (token == NULL) {
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_NOMEM;
|
||||
}
|
||||
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
token->parent = parser->toksuper;
|
||||
#endif
|
||||
parser->pos--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills next token with JSON string.
|
||||
*/
|
||||
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
||||
const size_t len, jsmntok_t *tokens,
|
||||
const size_t num_tokens) {
|
||||
jsmntok_t *token;
|
||||
|
||||
int start = parser->pos;
|
||||
|
||||
parser->pos++;
|
||||
|
||||
/* Skip starting quote */
|
||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
||||
char c = js[parser->pos];
|
||||
|
||||
/* Quote: end of string */
|
||||
if (c == '\"') {
|
||||
if (tokens == NULL) {
|
||||
return 0;
|
||||
}
|
||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||
if (token == NULL) {
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_NOMEM;
|
||||
}
|
||||
jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
token->parent = parser->toksuper;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Backslash: Quoted symbol expected */
|
||||
if (c == '\\' && parser->pos + 1 < len) {
|
||||
int i;
|
||||
parser->pos++;
|
||||
switch (js[parser->pos]) {
|
||||
/* Allowed escaped symbols */
|
||||
case '\"':
|
||||
case '/':
|
||||
case '\\':
|
||||
case 'b':
|
||||
case 'f':
|
||||
case 'r':
|
||||
case 'n':
|
||||
case 't':
|
||||
break;
|
||||
/* Allows escaped symbol \uXXXX */
|
||||
case 'u':
|
||||
parser->pos++;
|
||||
for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
|
||||
i++) {
|
||||
/* If it isn't a hex character we have an error */
|
||||
if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
|
||||
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
|
||||
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
parser->pos++;
|
||||
}
|
||||
parser->pos--;
|
||||
break;
|
||||
/* Unexpected symbol */
|
||||
default:
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
parser->pos = start;
|
||||
return JSMN_ERROR_PART;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON string and fill tokens.
|
||||
*/
|
||||
JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
|
||||
jsmntok_t *tokens, const unsigned int num_tokens) {
|
||||
int r;
|
||||
int i;
|
||||
jsmntok_t *token;
|
||||
int count = parser->toknext;
|
||||
|
||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
||||
char c;
|
||||
jsmntype_t type;
|
||||
|
||||
c = js[parser->pos];
|
||||
switch (c) {
|
||||
case '{':
|
||||
case '[':
|
||||
count++;
|
||||
if (tokens == NULL) {
|
||||
break;
|
||||
}
|
||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||
if (token == NULL) {
|
||||
return JSMN_ERROR_NOMEM;
|
||||
}
|
||||
if (parser->toksuper != -1) {
|
||||
jsmntok_t *t = &tokens[parser->toksuper];
|
||||
#ifdef JSMN_STRICT
|
||||
/* In strict mode an object or array can't become a key */
|
||||
if (t->type == JSMN_OBJECT) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
#endif
|
||||
t->size++;
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
token->parent = parser->toksuper;
|
||||
#endif
|
||||
}
|
||||
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||
token->start = parser->pos;
|
||||
parser->toksuper = parser->toknext - 1;
|
||||
break;
|
||||
case '}':
|
||||
case ']':
|
||||
if (tokens == NULL) {
|
||||
break;
|
||||
}
|
||||
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
if (parser->toknext < 1) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
token = &tokens[parser->toknext - 1];
|
||||
for (;;) {
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
if (token->type != type) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
token->end = parser->pos + 1;
|
||||
parser->toksuper = token->parent;
|
||||
break;
|
||||
}
|
||||
if (token->parent == -1) {
|
||||
if (token->type != type || parser->toksuper == -1) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
token = &tokens[token->parent];
|
||||
}
|
||||
#else
|
||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
||||
token = &tokens[i];
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
if (token->type != type) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
parser->toksuper = -1;
|
||||
token->end = parser->pos + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Error if unmatched closing bracket */
|
||||
if (i == -1) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
for (; i >= 0; i--) {
|
||||
token = &tokens[i];
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
parser->toksuper = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case '\"':
|
||||
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
count++;
|
||||
if (parser->toksuper != -1 && tokens != NULL) {
|
||||
tokens[parser->toksuper].size++;
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case ' ':
|
||||
break;
|
||||
case ':':
|
||||
parser->toksuper = parser->toknext - 1;
|
||||
break;
|
||||
case ',':
|
||||
if (tokens != NULL && parser->toksuper != -1 &&
|
||||
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
||||
tokens[parser->toksuper].type != JSMN_OBJECT) {
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
parser->toksuper = tokens[parser->toksuper].parent;
|
||||
#else
|
||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
||||
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
|
||||
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
||||
parser->toksuper = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#ifdef JSMN_STRICT
|
||||
/* In strict mode primitives are: numbers and booleans */
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 't':
|
||||
case 'f':
|
||||
case 'n':
|
||||
/* And they must not be keys of the object */
|
||||
if (tokens != NULL && parser->toksuper != -1) {
|
||||
const jsmntok_t *t = &tokens[parser->toksuper];
|
||||
if (t->type == JSMN_OBJECT ||
|
||||
(t->type == JSMN_STRING && t->size != 0)) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* In non-strict mode every unquoted value is a primitive */
|
||||
default:
|
||||
#endif
|
||||
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
count++;
|
||||
if (parser->toksuper != -1 && tokens != NULL) {
|
||||
tokens[parser->toksuper].size++;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef JSMN_STRICT
|
||||
/* Unexpected char in strict mode */
|
||||
default:
|
||||
return JSMN_ERROR_INVAL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens != NULL) {
|
||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
||||
/* Unmatched opened object or array */
|
||||
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
||||
return JSMN_ERROR_PART;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new parser based over a given buffer with an array of tokens
|
||||
* available.
|
||||
*/
|
||||
JSMN_API void jsmn_init(jsmn_parser *parser) {
|
||||
parser->pos = 0;
|
||||
parser->toknext = 0;
|
||||
parser->toksuper = -1;
|
||||
}
|
||||
|
||||
#endif /* JSMN_HEADER */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* JSMN_H */
|
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>
|
||||
*
|
||||
* Licensed 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <json_generator.h>
|
||||
|
||||
#define MAX_INT_IN_STR 24
|
||||
#define MAX_FLOAT_IN_STR 30
|
||||
|
||||
static inline int json_gen_get_empty_len(json_gen_str_t *jstr)
|
||||
{
|
||||
return (jstr->buf_size - (jstr->free_ptr - jstr->buf) - 1);
|
||||
}
|
||||
|
||||
/* This will add the incoming string to the JSON string buffer
|
||||
* and flush it out if the buffer is full. Note that the data being
|
||||
* flushed out will always be equal to the size of the buffer unless
|
||||
* this is the last chunk being flushed out on json_gen_end_str()
|
||||
*/
|
||||
static int json_gen_add_to_str(json_gen_str_t *jstr, const char *str)
|
||||
{
|
||||
if (!str) {
|
||||
return 0;
|
||||
}
|
||||
int len = strlen(str);
|
||||
const char *cur_ptr = str;
|
||||
while (1) {
|
||||
int len_remaining = json_gen_get_empty_len(jstr);
|
||||
int copy_len = len_remaining > len ? len : len_remaining;
|
||||
memmove(jstr->free_ptr, cur_ptr, copy_len);
|
||||
cur_ptr += copy_len;
|
||||
jstr->free_ptr += copy_len;
|
||||
len -= copy_len;
|
||||
if (len) {
|
||||
*jstr->free_ptr = '\0';
|
||||
/* Report error if the buffer is full and no flush callback
|
||||
* is registered
|
||||
*/
|
||||
if (!jstr->flush_cb) {
|
||||
return -1;
|
||||
}
|
||||
jstr->flush_cb(jstr->buf, jstr->priv);
|
||||
jstr->free_ptr = jstr->buf;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void json_gen_str_start(json_gen_str_t *jstr, char *buf, int buf_size,
|
||||
json_gen_flush_cb_t flush_cb, void *priv)
|
||||
{
|
||||
memset(jstr, 0, sizeof(json_gen_str_t));
|
||||
jstr->buf = buf;
|
||||
jstr->buf_size = buf_size;
|
||||
jstr->flush_cb = flush_cb;
|
||||
jstr->free_ptr = buf;
|
||||
jstr->priv = priv;
|
||||
}
|
||||
|
||||
void json_gen_str_end(json_gen_str_t *jstr)
|
||||
{
|
||||
*jstr->free_ptr = '\0';
|
||||
if (jstr->flush_cb)
|
||||
jstr->flush_cb(jstr->buf, jstr->priv);
|
||||
memset(jstr, 0, sizeof(json_gen_str_t));
|
||||
}
|
||||
|
||||
static inline void json_gen_handle_comma(json_gen_str_t *jstr)
|
||||
{
|
||||
if (jstr->comma_req)
|
||||
json_gen_add_to_str(jstr, ",");
|
||||
}
|
||||
|
||||
|
||||
static int json_gen_handle_name(json_gen_str_t *jstr, const char *name)
|
||||
{
|
||||
json_gen_add_to_str(jstr, "\"");
|
||||
json_gen_add_to_str(jstr, name);
|
||||
return json_gen_add_to_str(jstr, "\":");
|
||||
}
|
||||
|
||||
|
||||
int json_gen_start_object(json_gen_str_t *jstr)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
jstr->comma_req = false;
|
||||
return json_gen_add_to_str(jstr, "{");
|
||||
}
|
||||
|
||||
int json_gen_end_object(json_gen_str_t *jstr)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
return json_gen_add_to_str(jstr, "}");
|
||||
}
|
||||
|
||||
|
||||
int json_gen_start_array(json_gen_str_t *jstr)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
jstr->comma_req = false;
|
||||
return json_gen_add_to_str(jstr, "[");
|
||||
}
|
||||
|
||||
int json_gen_end_array(json_gen_str_t *jstr)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
return json_gen_add_to_str(jstr, "]");
|
||||
}
|
||||
|
||||
int json_gen_push_object(json_gen_str_t *jstr, const char *name)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
jstr->comma_req = false;
|
||||
return json_gen_add_to_str(jstr, "{");
|
||||
}
|
||||
|
||||
int json_gen_pop_object(json_gen_str_t *jstr)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
return json_gen_add_to_str(jstr, "}");
|
||||
}
|
||||
|
||||
int json_gen_push_object_str(json_gen_str_t *jstr, const char *name, char *object_str)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
jstr->comma_req = true;
|
||||
return json_gen_add_to_str(jstr, object_str);
|
||||
}
|
||||
|
||||
int json_gen_push_array(json_gen_str_t *jstr, const char *name)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
jstr->comma_req = false;
|
||||
return json_gen_add_to_str(jstr, "[");
|
||||
}
|
||||
int json_gen_pop_array(json_gen_str_t *jstr)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
return json_gen_add_to_str(jstr, "]");
|
||||
}
|
||||
|
||||
int json_gen_push_array_str(json_gen_str_t *jstr, const char *name, char *array_str)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
jstr->comma_req = true;
|
||||
return json_gen_add_to_str(jstr, array_str);
|
||||
}
|
||||
|
||||
static int json_gen_set_bool(json_gen_str_t *jstr, bool val)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
if (val)
|
||||
return json_gen_add_to_str(jstr, "true");
|
||||
else
|
||||
return json_gen_add_to_str(jstr, "false");
|
||||
}
|
||||
int json_gen_obj_set_bool(json_gen_str_t *jstr, const char *name, bool val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
return json_gen_set_bool(jstr, val);
|
||||
}
|
||||
|
||||
int json_gen_arr_set_bool(json_gen_str_t *jstr, bool val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
return json_gen_set_bool(jstr, val);
|
||||
}
|
||||
|
||||
static int json_gen_set_int(json_gen_str_t *jstr, int val)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
char str[MAX_INT_IN_STR];
|
||||
snprintf(str, MAX_INT_IN_STR, "%d", val);
|
||||
return json_gen_add_to_str(jstr, str);
|
||||
}
|
||||
|
||||
int json_gen_obj_set_int(json_gen_str_t *jstr, const char *name, int val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
return json_gen_set_int(jstr, val);
|
||||
}
|
||||
|
||||
int json_gen_arr_set_int(json_gen_str_t *jstr, int val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
return json_gen_set_int(jstr, val);
|
||||
}
|
||||
|
||||
|
||||
static int json_gen_set_float(json_gen_str_t *jstr, float val)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
char str[MAX_FLOAT_IN_STR];
|
||||
snprintf(str, MAX_FLOAT_IN_STR, "%.*f", JSON_FLOAT_PRECISION, val);
|
||||
return json_gen_add_to_str(jstr, str);
|
||||
}
|
||||
int json_gen_obj_set_float(json_gen_str_t *jstr, const char *name, float val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
return json_gen_set_float(jstr, val);
|
||||
}
|
||||
int json_gen_arr_set_float(json_gen_str_t *jstr, float val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
return json_gen_set_float(jstr, val);
|
||||
}
|
||||
|
||||
static int json_gen_set_string(json_gen_str_t *jstr, const char *val)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
json_gen_add_to_str(jstr, "\"");
|
||||
json_gen_add_to_str(jstr, val);
|
||||
return json_gen_add_to_str(jstr, "\"");
|
||||
}
|
||||
|
||||
int json_gen_obj_set_string(json_gen_str_t *jstr, const char *name, const char *val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
return json_gen_set_string(jstr, val);
|
||||
}
|
||||
|
||||
int json_gen_arr_set_string(json_gen_str_t *jstr, const char *val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
return json_gen_set_string(jstr, val);
|
||||
}
|
||||
|
||||
static int json_gen_set_long_string(json_gen_str_t *jstr, const char *val)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
json_gen_add_to_str(jstr, "\"");
|
||||
return json_gen_add_to_str(jstr, val);
|
||||
}
|
||||
|
||||
int json_gen_obj_start_long_string(json_gen_str_t *jstr, const char *name, const char *val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
return json_gen_set_long_string(jstr, val);
|
||||
}
|
||||
|
||||
int json_gen_arr_start_long_string(json_gen_str_t *jstr, const char *val)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
return json_gen_set_long_string(jstr, val);
|
||||
}
|
||||
|
||||
int json_gen_add_to_long_string(json_gen_str_t *jstr, const char *val)
|
||||
{
|
||||
return json_gen_add_to_str(jstr, val);
|
||||
}
|
||||
|
||||
int json_gen_end_long_string(json_gen_str_t *jstr)
|
||||
{
|
||||
return json_gen_add_to_str(jstr, "\"");
|
||||
}
|
||||
static int json_gen_set_null(json_gen_str_t *jstr)
|
||||
{
|
||||
jstr->comma_req = true;
|
||||
return json_gen_add_to_str(jstr, "null");
|
||||
}
|
||||
int json_gen_obj_set_null(json_gen_str_t *jstr, const char *name)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
json_gen_handle_name(jstr, name);
|
||||
return json_gen_set_null(jstr);
|
||||
}
|
||||
|
||||
int json_gen_arr_set_null(json_gen_str_t *jstr)
|
||||
{
|
||||
json_gen_handle_comma(jstr);
|
||||
return json_gen_set_null(jstr);
|
||||
}
|
|
@ -1,507 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* JSON String Generator
|
||||
*
|
||||
* This module can be used to create JSON strings with a facility
|
||||
* to flush out data if the destination buffer is full. All commas
|
||||
* and colons as required are automatically added by the APIs
|
||||
*
|
||||
*/
|
||||
#ifndef _JSON_GENERATOR_H
|
||||
#define _JSON_GENERATOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** Float precision i.e. number of digits after decimal point */
|
||||
#ifndef JSON_FLOAT_PRECISION
|
||||
#define JSON_FLOAT_PRECISION 5
|
||||
#endif
|
||||
|
||||
/** JSON string flush callback prototype
|
||||
*
|
||||
* This is a prototype of the function that needs to be passed to
|
||||
* json_gen_str_start() and which will be invoked by the JSON generator
|
||||
* module either when the buffer is full or json_gen_str_end() ins invoked.
|
||||
*
|
||||
* \param[in] buf Pointer to a NULL terminated JSON string
|
||||
* \param[in] priv Private data to be passed to the flush callback. Will
|
||||
* be the same as the one passed to json_gen_str_start()
|
||||
*/
|
||||
typedef void (*json_gen_flush_cb_t) (char *buf, void *priv);
|
||||
|
||||
/** JSON String structure
|
||||
*
|
||||
* Please do not set/modify any elements.
|
||||
* Just define this structure and pass a pointer to it in the APIs below
|
||||
*/
|
||||
typedef struct {
|
||||
/** Pointer to the JSON buffer provided by the calling function */
|
||||
char *buf;
|
||||
/** Size of the above buffer */
|
||||
int buf_size;
|
||||
/** (Optional) callback function to invoke when the buffer gets full */
|
||||
json_gen_flush_cb_t flush_cb;
|
||||
/** (Optional) Private data to pass to the callback function */
|
||||
void *priv;
|
||||
/** (For Internal use only) */
|
||||
bool comma_req;
|
||||
/** (For Internal use only) */
|
||||
char *free_ptr;
|
||||
} json_gen_str_t;
|
||||
|
||||
/** Start a JSON String
|
||||
*
|
||||
* This is the first function to be called for creating a JSON string.
|
||||
* It initializes the internal data structures. After the JSON string
|
||||
* generation is over, the json_gen_str_end() function should be called.
|
||||
*
|
||||
* \param[out] jstr Pointer to an allocated \ref json_gen_str_t structure.
|
||||
* This will be initialised internally and needs to be passed to all
|
||||
* subsequent function calls
|
||||
* \param[out] buf Pointer to an allocated buffer into which the JSON
|
||||
* string will be written
|
||||
* \param[in] buf_size Size of the buffer
|
||||
* \param[in] flush_cb Pointer to the flushing function of type \ref json_gen_flush_cb_t
|
||||
* which will be invoked either when the buffer is full or when json_gen_str_end()
|
||||
* is invoked. Can be left NULL.
|
||||
* \param[in] priv Private data to be passed to the flushing function callback.
|
||||
* Can be something like a session identifier (Eg. socket). Can be left NULL.
|
||||
*/
|
||||
void json_gen_str_start(json_gen_str_t *jstr, char *buf, int buf_size,
|
||||
json_gen_flush_cb_t flush_cb, void *priv);
|
||||
|
||||
/** End JSON string
|
||||
*
|
||||
* This should be the last function to be called after the entire JSON string
|
||||
* has been generated.
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
*/
|
||||
void json_gen_str_end(json_gen_str_t *jstr);
|
||||
|
||||
/** Start a JSON object
|
||||
*
|
||||
* This starts a JSON object by adding a '{'
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_start_object(json_gen_str_t *jstr);
|
||||
|
||||
/** End a JSON object
|
||||
*
|
||||
* This ends a JSON object by adding a '}'
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_end_object(json_gen_str_t *jstr);
|
||||
|
||||
/** Start a JSON array
|
||||
*
|
||||
* This starts a JSON object by adding a '['
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_start_array(json_gen_str_t *jstr);
|
||||
|
||||
/** End a JSON object
|
||||
*
|
||||
* This ends a JSON object by adding a ']'
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_end_array(json_gen_str_t *jstr);
|
||||
|
||||
/** Push a named JSON object
|
||||
*
|
||||
* This adds a JSON object like "name":{
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the object
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_push_object(json_gen_str_t *jstr, const char *name);
|
||||
|
||||
/** Pop a named JSON object
|
||||
*
|
||||
* This ends a JSON object by adding a '}'. This is basically same as
|
||||
* json_gen_end_object() but included so as to complement json_gen_push_object()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_pop_object(json_gen_str_t *jstr);
|
||||
|
||||
/** Push a JSON object string
|
||||
*
|
||||
* This adds a complete pre-formatted JSON object string to the JSON object.
|
||||
*
|
||||
* Eg. json_gen_push_object_str(jstr, "pre-formatted", "{\"a\":1,\"b\":2}");
|
||||
* This will add "pre-formatted":{"a":1,"b":2}
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the JSON object string
|
||||
* \param[in] object_str The pre-formatted JSON object string
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that.
|
||||
*/
|
||||
int json_gen_push_object_str(json_gen_str_t *jstr, const char *name, char *object_str);
|
||||
|
||||
/** Push a named JSON array
|
||||
*
|
||||
* This adds a JSON array like "name":[
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the array
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_push_array(json_gen_str_t *jstr, const char *name);
|
||||
|
||||
/** Pop a named JSON array
|
||||
*
|
||||
* This ends a JSON array by adding a ']'. This is basically same as
|
||||
* json_gen_end_array() but included so as to complement json_gen_push_array()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_pop_array(json_gen_str_t *jstr);
|
||||
|
||||
/** Push a JSON array string
|
||||
*
|
||||
* This adds a complete pre-formatted JSON array string to the JSON object.
|
||||
*
|
||||
* Eg. json_gen_push_object_str(jstr, "pre-formatted", "[1,2,3]");
|
||||
* This will add "pre-formatted":[1,2,3]
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the JSON array string
|
||||
* \param[in] array_str The pre-formatted JSON array string
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that.
|
||||
*/
|
||||
int json_gen_push_array_str(json_gen_str_t *jstr, const char *name, char *array_str);
|
||||
|
||||
/** Add a boolean element to an object
|
||||
*
|
||||
* This adds a boolean element to an object. Eg. "bool_val":true
|
||||
*
|
||||
* \note This must be called between json_gen_start_object()/json_gen_push_object()
|
||||
* and json_gen_end_object()/json_gen_pop_object()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the element
|
||||
* \param[in] val Boolean value of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_obj_set_bool(json_gen_str_t *jstr, const char *name, bool val);
|
||||
|
||||
/** Add an integer element to an object
|
||||
*
|
||||
* This adds an integer element to an object. Eg. "int_val":28
|
||||
*
|
||||
* \note This must be called between json_gen_start_object()/json_gen_push_object()
|
||||
* and json_gen_end_object()/json_gen_pop_object()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the element
|
||||
* \param[in] val Integer value of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_obj_set_int(json_gen_str_t *jstr, const char *name, int val);
|
||||
|
||||
/** Add a float element to an object
|
||||
*
|
||||
* This adds a float element to an object. Eg. "float_val":23.8
|
||||
*
|
||||
* \note This must be called between json_gen_start_object()/json_gen_push_object()
|
||||
* and json_gen_end_object()/json_gen_pop_object()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the element
|
||||
* \param[in] val Float value of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_obj_set_float(json_gen_str_t *jstr, const char *name, float val);
|
||||
|
||||
/** Add a string element to an object
|
||||
*
|
||||
* This adds a string element to an object. Eg. "string_val":"my_string"
|
||||
*
|
||||
* \note This must be called between json_gen_start_object()/json_gen_push_object()
|
||||
* and json_gen_end_object()/json_gen_pop_object()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the element
|
||||
* \param[in] val Null terminated string value of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_obj_set_string(json_gen_str_t *jstr, const char *name, const char *val);
|
||||
|
||||
/** Add a NULL element to an object
|
||||
*
|
||||
* This adds a NULL element to an object. Eg. "null_val":null
|
||||
*
|
||||
* \note This must be called between json_gen_start_object()/json_gen_push_object()
|
||||
* and json_gen_end_object()/json_gen_pop_object()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_obj_set_null(json_gen_str_t *jstr, const char *name);
|
||||
|
||||
/** Add a boolean element to an array
|
||||
*
|
||||
* \note This must be called between json_gen_start_array()/json_gen_push_array()
|
||||
* and json_gen_end_array()/json_gen_pop_array()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] val Boolean value of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_arr_set_bool(json_gen_str_t *jstr, bool val);
|
||||
|
||||
/** Add an integer element to an array
|
||||
*
|
||||
* \note This must be called between json_gen_start_array()/json_gen_push_array()
|
||||
* and json_gen_end_array()/json_gen_pop_array()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] val Integer value of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_arr_set_int(json_gen_str_t *jstr, int val);
|
||||
|
||||
/** Add a float element to an array
|
||||
*
|
||||
* \note This must be called between json_gen_start_array()/json_gen_push_array()
|
||||
* and json_gen_end_array()/json_gen_pop_array()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] val Float value of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_arr_set_float(json_gen_str_t *jstr, float val);
|
||||
|
||||
/** Add a string element to an array
|
||||
*
|
||||
* \note This must be called between json_gen_start_array()/json_gen_push_array()
|
||||
* and json_gen_end_array()/json_gen_pop_array()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] val Null terminated string value of the element
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_arr_set_string(json_gen_str_t *jstr, const char *val);
|
||||
|
||||
/** Add a NULL element to an array
|
||||
*
|
||||
* \note This must be called between json_gen_start_array()/json_gen_push_array()
|
||||
* and json_gen_end_array()/json_gen_pop_array()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_arr_set_null(json_gen_str_t *jstr);
|
||||
|
||||
/** Start a Long string in an object
|
||||
*
|
||||
* This starts a string in an object, but does not end it (i.e., does not add the
|
||||
* terminating quotes. This is useful for long strings. Eg. "string_val":"my_string.
|
||||
* The API json_gen_add_to_long_string() must be used to add to this string and the API
|
||||
* json_gen_end_long_string() must be used to terminate it (i.e. add the ending quotes).
|
||||
*
|
||||
* \note This must be called between json_gen_start_object()/json_gen_push_object()
|
||||
* and json_gen_end_object()/json_gen_pop_object()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] name Name of the element
|
||||
* \param[in] val Null terminated initial part of the string value. It can also be NULL
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_obj_start_long_string(json_gen_str_t *jstr, const char *name, const char *val);
|
||||
|
||||
/** Start a Long string in an array
|
||||
*
|
||||
* This starts a string in an arrayt, but does not end it (i.e., does not add the
|
||||
* terminating quotes. This is useful for long strings.
|
||||
* The API json_gen_add_to_long_string() must be used to add to this string and the API
|
||||
* json_gen_end_long_string() must be used to terminate it (i.e. add the ending quotes).
|
||||
*
|
||||
* \note This must be called between json_gen_start_array()/json_gen_push_array()
|
||||
* and json_gen_end_array()/json_gen_pop_array()
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by
|
||||
* json_gen_str_start()
|
||||
* \param[in] val Null terminated initial part of the string value. It can also be NULL
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_arr_start_long_string(json_gen_str_t *jstr, const char *val);
|
||||
|
||||
/** Add to a JSON Long string
|
||||
*
|
||||
* This extends the string initialised by json_gen_obj_start_long_string() or
|
||||
* json_gen_arr_start_long_string(). After the entire string is created, it should be terminated
|
||||
* with json_gen_end_long_string().
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by json_gen_str_start()
|
||||
* \param[in] val Null terminated extending part of the string value.
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_add_to_long_string(json_gen_str_t *jstr, const char *val);
|
||||
|
||||
/** End a JSON Long string
|
||||
*
|
||||
* This ends the string initialised by json_gen_obj_start_long_string() or
|
||||
* json_gen_arr_start_long_string() by adding the ending quotes.
|
||||
*
|
||||
* \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by json_gen_str_start()
|
||||
*
|
||||
*
|
||||
* \return 0 on Success
|
||||
* \return -1 if buffer is out of space (possible only if no callback function
|
||||
* is passed to json_gen_str_start(). Else, buffer will be flushed out and new data
|
||||
* added after that
|
||||
*/
|
||||
int json_gen_end_long_string(json_gen_str_t *jstr);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,398 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>
|
||||
*
|
||||
* Licensed 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#define JSMN_PARENT_LINKS
|
||||
#define JSMN_STRICT
|
||||
#define JSMN_STATIC
|
||||
#include <jsmn/jsmn.h>
|
||||
#include <json_parser.h>
|
||||
|
||||
static bool token_matches_str(jparse_ctx_t *ctx, json_tok_t *tok, const char *str)
|
||||
{
|
||||
char *js = ctx->js;
|
||||
return ((strncmp(js + tok->start, str, strlen(str)) == 0)
|
||||
&& (strlen(str) == (size_t) (tok->end - tok->start)));
|
||||
}
|
||||
|
||||
static json_tok_t *json_skip_elem(json_tok_t *token)
|
||||
{
|
||||
json_tok_t *cur = token;
|
||||
int cnt = cur->size;
|
||||
while (cnt--) {
|
||||
cur++;
|
||||
cur = json_skip_elem(cur);
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
static int json_tok_to_bool(jparse_ctx_t *jctx, json_tok_t *tok, bool *val)
|
||||
{
|
||||
if (token_matches_str(jctx, tok, "true") || token_matches_str(jctx, tok, "1")) {
|
||||
*val = true;
|
||||
} else if (token_matches_str(jctx, tok, "false") || token_matches_str(jctx, tok, "0")) {
|
||||
*val = false;
|
||||
} else
|
||||
return -OS_FAIL;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
static int json_tok_to_int(jparse_ctx_t *jctx, json_tok_t *tok, int *val)
|
||||
{
|
||||
char *tok_start = &jctx->js[tok->start];
|
||||
char *tok_end = &jctx->js[tok->end];
|
||||
char *endptr;
|
||||
int i = strtoul(tok_start, &endptr, 10);
|
||||
if (endptr == tok_end) {
|
||||
*val = i;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
return -OS_FAIL;
|
||||
}
|
||||
|
||||
static int json_tok_to_int64(jparse_ctx_t *jctx, json_tok_t *tok, int64_t *val)
|
||||
{
|
||||
char *tok_start = &jctx->js[tok->start];
|
||||
char *tok_end = &jctx->js[tok->end];
|
||||
char *endptr;
|
||||
int64_t i64 = strtoull(tok_start, &endptr, 10);
|
||||
if (endptr == tok_end) {
|
||||
*val = i64;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
return -OS_FAIL;
|
||||
}
|
||||
|
||||
static int json_tok_to_float(jparse_ctx_t *jctx, json_tok_t *tok, float *val)
|
||||
{
|
||||
char *tok_start = &jctx->js[tok->start];
|
||||
char *tok_end = &jctx->js[tok->end];
|
||||
char *endptr;
|
||||
float f = strtof(tok_start, &endptr);
|
||||
if (endptr == tok_end) {
|
||||
*val = f;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
return -OS_FAIL;
|
||||
}
|
||||
|
||||
static int json_tok_to_string(jparse_ctx_t *jctx, json_tok_t *tok, char *val, int size)
|
||||
{
|
||||
if ((tok->end - tok->start) > (size - 1))
|
||||
return -OS_FAIL;
|
||||
strncpy(val, jctx->js + tok->start, tok->end - tok->start);
|
||||
val[tok->end - tok->start] = 0;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
static json_tok_t *json_obj_search(jparse_ctx_t *jctx, const char *key)
|
||||
{
|
||||
json_tok_t *tok = jctx->cur;
|
||||
int size = tok->size;
|
||||
if (size <= 0)
|
||||
return NULL;
|
||||
if (tok->type != JSMN_OBJECT)
|
||||
return NULL;
|
||||
|
||||
while (size--) {
|
||||
tok++;
|
||||
if (token_matches_str(jctx, tok, key))
|
||||
return tok;
|
||||
tok = json_skip_elem(tok);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static json_tok_t *json_obj_get_val_tok(jparse_ctx_t *jctx, const char *name, jsmntype_t type)
|
||||
{
|
||||
json_tok_t *tok = json_obj_search(jctx, name);
|
||||
if (!tok)
|
||||
return NULL;
|
||||
tok++;
|
||||
if (tok->type != type)
|
||||
return NULL;
|
||||
return tok;
|
||||
}
|
||||
|
||||
int json_obj_get_array(jparse_ctx_t *jctx, const char *name, int *num_elem)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = tok;
|
||||
*num_elem = tok->size;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_obj_leave_array(jparse_ctx_t *jctx)
|
||||
{
|
||||
/* The array's parent will be the key */
|
||||
if (jctx->cur->parent < 0)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = &jctx->tokens[jctx->cur->parent];
|
||||
|
||||
/* The key's parent will be the actual parent object */
|
||||
if (jctx->cur->parent < 0)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = &jctx->tokens[jctx->cur->parent];
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_obj_get_object(jparse_ctx_t *jctx, const char *name)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = tok;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_obj_leave_object(jparse_ctx_t *jctx)
|
||||
{
|
||||
/* The objects's parent will be the key */
|
||||
if (jctx->cur->parent < 0)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = &jctx->tokens[jctx->cur->parent];
|
||||
|
||||
/* The key's parent will be the actual parent object */
|
||||
if (jctx->cur->parent < 0)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = &jctx->tokens[jctx->cur->parent];
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_obj_get_bool(jparse_ctx_t *jctx, const char *name, bool *val)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_bool(jctx, tok, val);
|
||||
}
|
||||
|
||||
int json_obj_get_int(jparse_ctx_t *jctx, const char *name, int *val)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_int(jctx, tok, val);
|
||||
}
|
||||
|
||||
int json_obj_get_int64(jparse_ctx_t *jctx, const char *name, int64_t *val)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_int64(jctx, tok, val);
|
||||
}
|
||||
|
||||
int json_obj_get_float(jparse_ctx_t *jctx, const char *name, float *val)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_float(jctx, tok, val);
|
||||
}
|
||||
|
||||
int json_obj_get_string(jparse_ctx_t *jctx, const char *name, char *val, int size)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_STRING);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_string(jctx, tok, val, size);
|
||||
}
|
||||
|
||||
int json_obj_get_strlen(jparse_ctx_t *jctx, const char *name, int *strlen)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_STRING);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
*strlen = tok->end - tok->start;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_obj_get_object_str(jparse_ctx_t *jctx, const char *name, char *val, int size)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_string(jctx, tok, val, size);
|
||||
}
|
||||
|
||||
int json_obj_get_object_strlen(jparse_ctx_t *jctx, const char *name, int *strlen)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
*strlen = tok->end - tok->start;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
int json_obj_get_array_str(jparse_ctx_t *jctx, const char *name, char *val, int size)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_string(jctx, tok, val, size);
|
||||
}
|
||||
|
||||
int json_obj_get_array_strlen(jparse_ctx_t *jctx, const char *name, int *strlen)
|
||||
{
|
||||
json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
*strlen = tok->end - tok->start;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
static json_tok_t *json_arr_search(jparse_ctx_t *ctx, uint32_t index)
|
||||
{
|
||||
json_tok_t *tok = ctx->cur;
|
||||
if ((tok->type != JSMN_ARRAY) || (tok->size <= 0))
|
||||
return NULL;
|
||||
if (index > (uint32_t)(tok->size - 1))
|
||||
return NULL;
|
||||
/* Increment by 1, so that token points to index 0 */
|
||||
tok++;
|
||||
while (index--) {
|
||||
tok = json_skip_elem(tok);
|
||||
tok++;
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
static json_tok_t *json_arr_get_val_tok(jparse_ctx_t *jctx, uint32_t index, jsmntype_t type)
|
||||
{
|
||||
json_tok_t *tok = json_arr_search(jctx, index);
|
||||
if (!tok)
|
||||
return NULL;
|
||||
if (tok->type != type)
|
||||
return NULL;
|
||||
return tok;
|
||||
}
|
||||
|
||||
int json_arr_get_array(jparse_ctx_t *jctx, uint32_t index)
|
||||
{
|
||||
json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_ARRAY);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = tok;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_arr_leave_array(jparse_ctx_t *jctx)
|
||||
{
|
||||
if (jctx->cur->parent < 0)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = &jctx->tokens[jctx->cur->parent];
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_arr_get_object(jparse_ctx_t *jctx, uint32_t index)
|
||||
{
|
||||
json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_OBJECT);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = tok;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_arr_leave_object(jparse_ctx_t *jctx)
|
||||
{
|
||||
if (jctx->cur->parent < 0)
|
||||
return -OS_FAIL;
|
||||
jctx->cur = &jctx->tokens[jctx->cur->parent];
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_arr_get_bool(jparse_ctx_t *jctx, uint32_t index, bool *val)
|
||||
{
|
||||
json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_bool(jctx, tok, val);
|
||||
}
|
||||
|
||||
int json_arr_get_int(jparse_ctx_t *jctx, uint32_t index, int *val)
|
||||
{
|
||||
json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_int(jctx, tok, val);
|
||||
}
|
||||
|
||||
int json_arr_get_int64(jparse_ctx_t *jctx, uint32_t index, int64_t *val)
|
||||
{
|
||||
json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_int64(jctx, tok, val);
|
||||
}
|
||||
|
||||
int json_arr_get_float(jparse_ctx_t *jctx, uint32_t index, float *val)
|
||||
{
|
||||
json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_float(jctx, tok, val);
|
||||
}
|
||||
|
||||
int json_arr_get_string(jparse_ctx_t *jctx, uint32_t index, char *val, int size)
|
||||
{
|
||||
json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_STRING);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
return json_tok_to_string(jctx, tok, val, size);
|
||||
}
|
||||
|
||||
int json_arr_get_strlen(jparse_ctx_t *jctx, uint32_t index, int *strlen)
|
||||
{
|
||||
json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_STRING);
|
||||
if (!tok)
|
||||
return -OS_FAIL;
|
||||
*strlen = tok->end - tok->start;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_parse_start(jparse_ctx_t *jctx, char *js, int len)
|
||||
{
|
||||
memset(jctx, 0, sizeof(jparse_ctx_t));
|
||||
jsmn_init(&jctx->parser);
|
||||
int num_tokens = jsmn_parse(&jctx->parser, js, len, NULL, 0);
|
||||
if (num_tokens <= 0)
|
||||
return -OS_FAIL;
|
||||
jctx->num_tokens = num_tokens;
|
||||
jctx->tokens = calloc(num_tokens, sizeof(json_tok_t));
|
||||
if (!jctx->tokens)
|
||||
return -OS_FAIL;
|
||||
jctx->js = js;
|
||||
jsmn_init(&jctx->parser);
|
||||
int ret = jsmn_parse(&jctx->parser, js, len, jctx->tokens, jctx->num_tokens);
|
||||
if (ret <= 0) {
|
||||
free(jctx->tokens);
|
||||
memset(jctx, 0, sizeof(jparse_ctx_t));
|
||||
return -OS_FAIL;
|
||||
}
|
||||
jctx->cur = jctx->tokens;
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
|
||||
int json_parse_end(jparse_ctx_t *jctx)
|
||||
{
|
||||
if (jctx->tokens)
|
||||
free(jctx->tokens);
|
||||
memset(jctx, 0, sizeof(jparse_ctx_t));
|
||||
return OS_SUCCESS;
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>
|
||||
*
|
||||
* Licensed 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 _JSON_PARSER_H_
|
||||
#define _JSON_PARSER_H_
|
||||
|
||||
#define JSMN_HEADER
|
||||
#include <jsmn/jsmn.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define OS_SUCCESS 0
|
||||
#define OS_FAIL -1
|
||||
|
||||
typedef jsmn_parser json_parser_t;
|
||||
typedef jsmntok_t json_tok_t;
|
||||
|
||||
typedef struct {
|
||||
json_parser_t parser;
|
||||
char *js;
|
||||
json_tok_t *tokens;
|
||||
json_tok_t *cur;
|
||||
int num_tokens;
|
||||
} jparse_ctx_t;
|
||||
|
||||
int json_parse_start(jparse_ctx_t *jctx, char *js, int len);
|
||||
int json_parse_end(jparse_ctx_t *jctx);
|
||||
|
||||
int json_obj_get_array(jparse_ctx_t *jctx, const char *name, int *num_elem);
|
||||
int json_obj_leave_array(jparse_ctx_t *jctx);
|
||||
int json_obj_get_object(jparse_ctx_t *jctx, const char *name);
|
||||
int json_obj_leave_object(jparse_ctx_t *jctx);
|
||||
int json_obj_get_bool(jparse_ctx_t *jctx, const char *name, bool *val);
|
||||
int json_obj_get_int(jparse_ctx_t *jctx, const char *name, int *val);
|
||||
int json_obj_get_int64(jparse_ctx_t *jctx, const char *name, int64_t *val);
|
||||
int json_obj_get_float(jparse_ctx_t *jctx, const char *name, float *val);
|
||||
int json_obj_get_string(jparse_ctx_t *jctx, const char *name, char *val, int size);
|
||||
int json_obj_get_strlen(jparse_ctx_t *jctx, const char *name, int *strlen);
|
||||
int json_obj_get_object_str(jparse_ctx_t *jctx, const char *name, char *val, int size);
|
||||
int json_obj_get_object_strlen(jparse_ctx_t *jctx, const char *name, int *strlen);
|
||||
int json_obj_get_array_str(jparse_ctx_t *jctx, const char *name, char *val, int size);
|
||||
int json_obj_get_array_strlen(jparse_ctx_t *jctx, const char *name, int *strlen);
|
||||
|
||||
int json_arr_get_array(jparse_ctx_t *jctx, uint32_t index);
|
||||
int json_arr_leave_array(jparse_ctx_t *jctx);
|
||||
int json_arr_get_object(jparse_ctx_t *jctx, uint32_t index);
|
||||
int json_arr_leave_object(jparse_ctx_t *jctx);
|
||||
int json_arr_get_bool(jparse_ctx_t *jctx, uint32_t index, bool *val);
|
||||
int json_arr_get_int(jparse_ctx_t *jctx, uint32_t index, int *val);
|
||||
int json_arr_get_int64(jparse_ctx_t *jctx, uint32_t index, int64_t *val);
|
||||
int json_arr_get_float(jparse_ctx_t *jctx, uint32_t index, float *val);
|
||||
int json_arr_get_string(jparse_ctx_t *jctx, uint32_t index, char *val, int size);
|
||||
int json_arr_get_strlen(jparse_ctx_t *jctx, uint32_t index, int *strlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _JSON_PARSER_H_ */
|
|
@ -1,232 +0,0 @@
|
|||
#ifndef _MU_BIGNUM_H_
|
||||
#define _MU_BIGNUM_H_
|
||||
|
||||
#define BIGNUM_MBEDTLS
|
||||
|
||||
#ifdef BIGNUM_OPENSSL
|
||||
#include <openssl/bn.h>
|
||||
|
||||
|
||||
typedef BIGNUM mu_bn_t;
|
||||
typedef BN_CTX mu_bn_ctx_t;
|
||||
|
||||
|
||||
static inline mu_bn_t *mu_bn_new_from_hex(const char *hex)
|
||||
{
|
||||
mu_bn_t *a = BN_new();
|
||||
if (a)
|
||||
BN_hex2bn(&a, hex);
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline mu_bn_t *mu_bn_new_from_bin(const char *str, int str_len)
|
||||
{
|
||||
return BN_bin2bn((unsigned char *)str, str_len, NULL);
|
||||
}
|
||||
|
||||
static inline mu_bn_t *mu_bn_new()
|
||||
{
|
||||
return BN_new();
|
||||
}
|
||||
|
||||
static inline void mu_bn_free(mu_bn_t *bn)
|
||||
{
|
||||
return BN_free(bn);
|
||||
}
|
||||
|
||||
static inline mu_bn_ctx_t *mu_bn_ctx_new()
|
||||
{
|
||||
return BN_CTX_new();
|
||||
}
|
||||
|
||||
static inline void mu_bn_ctx_free(mu_bn_ctx_t *ctx)
|
||||
{
|
||||
return BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static inline unsigned int mu_bn_sizeof(mu_bn_t *bn)
|
||||
{
|
||||
return BN_num_bytes(bn);
|
||||
}
|
||||
|
||||
|
||||
static inline char *mu_bn_to_bin(mu_bn_t *bn, int *len)
|
||||
{
|
||||
*len = mu_bn_sizeof(bn);
|
||||
char *p = malloc(*len);
|
||||
if (p) {
|
||||
BN_bn2bin(bn, (unsigned char *)p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline int mu_bn_get_rand(mu_bn_t *bn, int bits, int top, int bottom)
|
||||
{
|
||||
return BN_rand(bn, bits, top, bottom);
|
||||
}
|
||||
|
||||
static inline int mu_bn_a_exp_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx)
|
||||
{
|
||||
return BN_mod_exp(result, a, b, c, ctx);
|
||||
}
|
||||
|
||||
static inline int mu_bn_a_mul_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx)
|
||||
{
|
||||
return BN_mod_mul(result, a, b, c, ctx);
|
||||
}
|
||||
|
||||
static inline int mu_bn_a_add_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx)
|
||||
{
|
||||
if (BN_add(result, a, b) != 1)
|
||||
return 1;
|
||||
return BN_mod(result, result, c, ctx);
|
||||
}
|
||||
#endif /* BIGNUM_OPENSSL */
|
||||
|
||||
|
||||
#ifdef BIGNUM_MBEDTLS
|
||||
#include <mbedtls/bignum.h>
|
||||
#include <esp_system.h>
|
||||
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
#include <driver/rtc.h>
|
||||
#endif
|
||||
typedef mbedtls_mpi mu_bn_t;
|
||||
typedef mu_bn_t mu_bn_ctx_t;
|
||||
|
||||
static inline mu_bn_t *mu_bn_new()
|
||||
{
|
||||
mu_bn_t *a = malloc(sizeof (mu_bn_t));
|
||||
if (!a)
|
||||
return NULL;
|
||||
mbedtls_mpi_init(a);
|
||||
return a;
|
||||
}
|
||||
static inline mu_bn_t *mu_bn_new_from_hex(const char *hex)
|
||||
{
|
||||
mu_bn_t *a = mu_bn_new();
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
||||
mbedtls_mpi_read_string(a, 16, hex);
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline mu_bn_t *mu_bn_new_from_bin(const char *str, int str_len)
|
||||
{
|
||||
|
||||
mu_bn_t *a = mu_bn_new();
|
||||
if (!a) {
|
||||
return NULL;
|
||||
}
|
||||
mbedtls_mpi_read_binary(a, (unsigned char *)str, str_len);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
static inline void mu_bn_free(mu_bn_t *bn)
|
||||
{
|
||||
if (bn) {
|
||||
mbedtls_mpi_free(bn);
|
||||
free(bn);
|
||||
}
|
||||
}
|
||||
|
||||
static inline mu_bn_ctx_t *mu_bn_ctx_new()
|
||||
{
|
||||
mu_bn_t *bn = mu_bn_new();
|
||||
return ( mu_bn_ctx_t *)bn;
|
||||
}
|
||||
|
||||
static inline void mu_bn_ctx_free(mu_bn_ctx_t *ctx)
|
||||
{
|
||||
mu_bn_free((mu_bn_t *)ctx);
|
||||
}
|
||||
|
||||
static inline unsigned int mu_bn_sizeof(mu_bn_t *bn)
|
||||
{
|
||||
return mbedtls_mpi_size(bn);
|
||||
}
|
||||
|
||||
|
||||
static inline char *mu_bn_to_bin(mu_bn_t *bn, int *len)
|
||||
{
|
||||
*len = mu_bn_sizeof(bn);
|
||||
char *p = malloc(*len);
|
||||
if (p) {
|
||||
mbedtls_mpi_write_binary(bn, (unsigned char *)p, *len);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline int mu_get_random(void *ctx, unsigned char *data, size_t len)
|
||||
{
|
||||
esp_fill_random(data, len);
|
||||
return 0;
|
||||
}
|
||||
static inline int mu_bn_get_rand(mu_bn_t *bn, int bits, int top, int bottom)
|
||||
{
|
||||
|
||||
return mbedtls_mpi_fill_random(bn, bits / 8, mu_get_random, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
static inline int mu_bn_a_exp_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx)
|
||||
{
|
||||
int ret;
|
||||
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M);
|
||||
ret = mbedtls_mpi_exp_mod(result, a, b, c, (mu_bn_t *) ctx);
|
||||
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M);
|
||||
return ret;
|
||||
}
|
||||
static inline int mu_bn_a_mul_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx)
|
||||
{
|
||||
mbedtls_mpi tmp_result;
|
||||
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M);
|
||||
mbedtls_mpi_init(&tmp_result);
|
||||
mbedtls_mpi_mul_mpi(&tmp_result, a, b);
|
||||
mbedtls_mpi_mod_mpi(result, &tmp_result, c);
|
||||
mbedtls_mpi_free(&tmp_result);
|
||||
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
#include "port/bignum.h"
|
||||
#include "port/bignum_impl.h"
|
||||
|
||||
static inline int mu_bn_a_exp_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx)
|
||||
{
|
||||
//return mbedtls_mpi_exp_mod(result, a, b, c, (mu_bn_t *) ctx);
|
||||
// wangbin changed
|
||||
printf("esp_mpi_exp_mod\n");
|
||||
return esp_mpi_exp_mod(result, a, b, c, (mu_bn_t *) ctx);
|
||||
}
|
||||
|
||||
|
||||
static inline int mu_bn_a_mul_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx)
|
||||
{
|
||||
printf("esp_mpi_mul_mpi_mod\n");
|
||||
return esp_mpi_mul_mpi_mod(result, a, b, c);
|
||||
}
|
||||
#endif /* !CONFIG_IDF_TARGET_ESP8266 */
|
||||
|
||||
static inline int mu_bn_a_add_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx)
|
||||
{
|
||||
int res;
|
||||
mbedtls_mpi t;
|
||||
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M);
|
||||
#endif
|
||||
mbedtls_mpi_init(&t);
|
||||
res = mbedtls_mpi_add_mpi(&t, a, b);
|
||||
if (res == 0) {
|
||||
res = mbedtls_mpi_mod_mpi(result, &t, c);
|
||||
}
|
||||
mbedtls_mpi_free(&t);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
#endif /* BIGNUM_MBEDTLS */
|
||||
#endif /* ! _MU_BIGNUM_H_ */
|
|
@ -1,489 +0,0 @@
|
|||
#include <string.h>
|
||||
#include "hkdf-sha.h"
|
||||
#include "mu_bignum.h"
|
||||
#include "mu_srp.h"
|
||||
|
||||
#ifdef SRP_DEBUG
|
||||
#include <stdio.h>
|
||||
#define srp_print printf
|
||||
static void hex_dbg(char *name, void *buf, int buf_len)
|
||||
{
|
||||
char *p = (char *)buf;
|
||||
int i;
|
||||
srp_print("%s (%d): ", name, buf_len);
|
||||
for (i = 0; i < buf_len; i++) {
|
||||
if (i % 16 == 0)
|
||||
srp_print("\r\n");
|
||||
srp_print("%02x ", (unsigned)(unsigned char)p[i]);
|
||||
}
|
||||
srp_print("\r\n");
|
||||
}
|
||||
|
||||
static void hex_dbg_bn(char *name, mu_bn_t *bn)
|
||||
{
|
||||
int len;
|
||||
char *str = mu_bn_to_bin(bn, &len);
|
||||
if (str) {
|
||||
hex_dbg(name, str, len);
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define srp_print(...)
|
||||
#define hex_dbg(...)
|
||||
#define hex_dbg_bn(...)
|
||||
#endif
|
||||
|
||||
static inline void SHA512_hash(const uint8_t *bytes, unsigned int byte_count,
|
||||
uint8_t digest[SHA512HashSize])
|
||||
{
|
||||
SHA512Context ctx;
|
||||
SHA512Reset(&ctx);
|
||||
SHA512Input(&ctx, bytes, byte_count);
|
||||
SHA512Result(&ctx, digest);
|
||||
}
|
||||
|
||||
/************************* SRP Stuff */
|
||||
char N_3072[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2,
|
||||
0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67,
|
||||
0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E,
|
||||
0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
|
||||
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5,
|
||||
0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF,
|
||||
0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE,
|
||||
0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
|
||||
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3,
|
||||
0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3,
|
||||
0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70,
|
||||
0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
|
||||
0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77,
|
||||
0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5,
|
||||
0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39,
|
||||
0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A,
|
||||
0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB,
|
||||
0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6,
|
||||
0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0,
|
||||
0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA,
|
||||
0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F,
|
||||
0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77,
|
||||
0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
|
||||
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2,
|
||||
0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
char g_3072[] = { 5 };
|
||||
|
||||
|
||||
int mu_srp_init(mu_srp_handle_t *hd, mu_ng_type_t ng)
|
||||
{
|
||||
if (hd->allocated)
|
||||
mu_srp_free(hd);
|
||||
|
||||
memset(hd, 0, sizeof(*hd));
|
||||
hd->allocated = 1;
|
||||
|
||||
hd->ctx = mu_bn_ctx_new();
|
||||
if (! hd->ctx)
|
||||
goto error;
|
||||
if (ng != MU_NG_3072)
|
||||
goto error;
|
||||
|
||||
hd->n = mu_bn_new_from_bin(N_3072, sizeof(N_3072));
|
||||
hd->bytes_n = N_3072;
|
||||
hd->len_n = sizeof(N_3072);
|
||||
if (! hd->n)
|
||||
goto error;
|
||||
|
||||
hd->g = mu_bn_new_from_bin(g_3072, sizeof(g_3072));
|
||||
hd->bytes_g = g_3072;
|
||||
hd->len_g = sizeof(g_3072);
|
||||
if (! hd->g)
|
||||
goto error;
|
||||
hd->type = ng;
|
||||
return 0;
|
||||
error:
|
||||
mu_srp_free(hd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void mu_srp_free(mu_srp_handle_t *hd)
|
||||
{
|
||||
if (hd->allocated != 1)
|
||||
return;
|
||||
|
||||
if (hd->ctx)
|
||||
mu_bn_ctx_free(hd->ctx);
|
||||
if (hd->n)
|
||||
mu_bn_free(hd->n);
|
||||
if (hd->g)
|
||||
mu_bn_free(hd->g);
|
||||
if (hd->s)
|
||||
mu_bn_free(hd->s);
|
||||
if (hd->bytes_s)
|
||||
free(hd->bytes_s);
|
||||
if (hd->v)
|
||||
mu_bn_free(hd->v);
|
||||
if (hd->B)
|
||||
mu_bn_free(hd->B);
|
||||
if (hd->bytes_B)
|
||||
free(hd->bytes_B);
|
||||
if (hd->b)
|
||||
mu_bn_free(hd->b);
|
||||
if (hd->A)
|
||||
mu_bn_free(hd->A);
|
||||
if (hd->bytes_A)
|
||||
free(hd->bytes_A);
|
||||
if (hd->session_key)
|
||||
free(hd->session_key);
|
||||
memset(hd, 0, sizeof(*hd));
|
||||
}
|
||||
|
||||
static mu_bn_t *calculate_x(char *bytes_salt, int salt_len, const char *username, const char *pass, int pass_len)
|
||||
{
|
||||
unsigned char digest[SHA512HashSize];
|
||||
SHA512Context ctx;
|
||||
srp_print("username:%s:\npass:%s:\npass_len:%d:\n", username, pass, pass_len);
|
||||
hex_dbg("salt", bytes_salt, salt_len);
|
||||
SHA512Reset(&ctx);
|
||||
SHA512Input(&ctx, (unsigned char *)username, strlen(username));
|
||||
SHA512Input(&ctx, (unsigned char *)":", 1);
|
||||
SHA512Input(&ctx, (unsigned char *)pass, pass_len);
|
||||
SHA512Result(&ctx, digest);
|
||||
|
||||
SHA512Reset(&ctx);
|
||||
SHA512Input(&ctx, (unsigned char *)bytes_salt, salt_len);
|
||||
SHA512Input(&ctx, digest, sizeof(digest));
|
||||
SHA512Result(&ctx, digest);
|
||||
|
||||
hex_dbg("Digest", digest, sizeof(digest));
|
||||
return mu_bn_new_from_bin((char *)digest, sizeof(digest));
|
||||
}
|
||||
|
||||
static mu_bn_t *calculate_padded_hash(mu_srp_handle_t *hd, char *a, int len_a, char *b, int len_b)
|
||||
{
|
||||
unsigned char digest[SHA512HashSize];
|
||||
SHA512Context ctx;
|
||||
int pad_len;
|
||||
char *s = NULL;
|
||||
|
||||
if (len_a > len_b) {
|
||||
pad_len = hd->len_n - len_b;
|
||||
} else {
|
||||
pad_len = hd->len_n - len_a;
|
||||
}
|
||||
|
||||
if (pad_len) {
|
||||
s = malloc(pad_len);
|
||||
if (s) {
|
||||
memset(s, 0, pad_len);
|
||||
}
|
||||
}
|
||||
|
||||
SHA512Reset(&ctx);
|
||||
/* PAD (a) */
|
||||
if (s && (len_a != hd->len_n)) {
|
||||
SHA512Input(&ctx, (unsigned char *)s, hd->len_n - len_a);
|
||||
}
|
||||
|
||||
SHA512Input(&ctx, (unsigned char *)a, len_a);
|
||||
|
||||
/* PAD (b) */
|
||||
if (s && (len_b != hd->len_n)) {
|
||||
SHA512Input(&ctx, (unsigned char *)s, hd->len_n - len_b);
|
||||
}
|
||||
|
||||
SHA512Input(&ctx, (unsigned char *)b, len_b);
|
||||
|
||||
SHA512Result(&ctx, digest);
|
||||
|
||||
if (s) {
|
||||
free(s);
|
||||
}
|
||||
|
||||
hex_dbg("value", digest, sizeof(digest));
|
||||
return mu_bn_new_from_bin((char *)digest, sizeof(digest));
|
||||
}
|
||||
|
||||
/* k = SHA (N, PAD(g))
|
||||
*
|
||||
* https://tools.ietf.org/html/draft-ietf-tls-srp-08
|
||||
*/
|
||||
static mu_bn_t *calculate_k(mu_srp_handle_t *hd)
|
||||
{
|
||||
srp_print("k-->");
|
||||
return calculate_padded_hash(hd, hd->bytes_n, hd->len_n, hd->bytes_g, hd->len_g);
|
||||
}
|
||||
|
||||
static mu_bn_t *calculate_u(mu_srp_handle_t *hd, char *A, int len_A)
|
||||
{
|
||||
srp_print("u-->");
|
||||
return calculate_padded_hash(hd, A, len_A, hd->bytes_B, hd->len_B);
|
||||
}
|
||||
|
||||
int __mu_srp_srv_pubkey(mu_srp_handle_t *hd, char **bytes_B, int *len_B)
|
||||
{
|
||||
mu_bn_t *k = calculate_k(hd);
|
||||
mu_bn_t *kv = NULL;
|
||||
mu_bn_t *gb = NULL;
|
||||
if (!k)
|
||||
goto error;
|
||||
|
||||
hd->b = mu_bn_new();
|
||||
if (!hd->b)
|
||||
goto error;
|
||||
mu_bn_get_rand(hd->b, 256, -1, 0);
|
||||
hex_dbg_bn("b", hd->b);
|
||||
|
||||
/* B = kv + g^b */
|
||||
kv = mu_bn_new();
|
||||
gb = mu_bn_new();
|
||||
hd->B = mu_bn_new();
|
||||
if (!kv || !gb || ! hd->B)
|
||||
goto error;
|
||||
mu_bn_a_mul_b_mod_c(kv, k, hd->v, hd->n, hd->ctx);
|
||||
mu_bn_a_exp_b_mod_c(gb, hd->g, hd->b, hd->n, hd->ctx);
|
||||
mu_bn_a_add_b_mod_c(hd->B, kv, gb, hd->n, hd->ctx);
|
||||
hd->bytes_B = mu_bn_to_bin(hd->B, len_B);
|
||||
hd->len_B = *len_B;
|
||||
*bytes_B = hd->bytes_B;
|
||||
|
||||
mu_bn_free(k);
|
||||
mu_bn_free(kv);
|
||||
mu_bn_free(gb);
|
||||
return 0;
|
||||
error:
|
||||
if (k)
|
||||
mu_bn_free(k);
|
||||
if (kv)
|
||||
mu_bn_free(kv);
|
||||
if (gb)
|
||||
mu_bn_free(gb);
|
||||
if (hd->B) {
|
||||
mu_bn_free(hd->B);
|
||||
hd->B = NULL;
|
||||
}
|
||||
if (hd->b) {
|
||||
mu_bn_free(hd->b);
|
||||
hd->b = NULL;
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mu_srp_srv_pubkey(mu_srp_handle_t *hd, const char *username, const char *pass, int pass_len, int salt_len,
|
||||
char **bytes_B, int *len_B, char **bytes_salt)
|
||||
{
|
||||
/* Get Salt */
|
||||
int str_salt_len;
|
||||
mu_bn_t *x = NULL;
|
||||
hd->s = mu_bn_new();
|
||||
if (! hd->s)
|
||||
goto error;
|
||||
mu_bn_get_rand(hd->s, 8 * salt_len, -1, 0);
|
||||
*bytes_salt = mu_bn_to_bin(hd->s, &str_salt_len);
|
||||
if (! *bytes_salt)
|
||||
goto error;
|
||||
hd->bytes_s = *bytes_salt;
|
||||
hd->len_s = salt_len;
|
||||
hex_dbg("Salt", *bytes_salt, str_salt_len);
|
||||
|
||||
/* Calculate X which is simply a hash for all these things */
|
||||
x = calculate_x(*bytes_salt, str_salt_len, username, pass, pass_len);
|
||||
if (! x)
|
||||
goto error;
|
||||
hex_dbg_bn("x", x);
|
||||
|
||||
/* v = g^x % N */
|
||||
hd->v = mu_bn_new();
|
||||
if (! hd->v)
|
||||
goto error;
|
||||
mu_bn_a_exp_b_mod_c(hd->v, hd->g, x, hd->n, hd->ctx);
|
||||
hex_dbg_bn("Verifier", hd->v);
|
||||
|
||||
if (__mu_srp_srv_pubkey(hd, bytes_B, len_B) < 0 )
|
||||
goto error;
|
||||
|
||||
mu_bn_free(x);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (hd->s) {
|
||||
mu_bn_free(hd->s);
|
||||
hd->s = NULL;
|
||||
}
|
||||
if (*bytes_salt) {
|
||||
free(*bytes_salt);
|
||||
*bytes_salt = NULL;
|
||||
hd->bytes_s = NULL;
|
||||
hd->len_s = 0;
|
||||
}
|
||||
if (x) {
|
||||
mu_bn_free(x);
|
||||
x = NULL;
|
||||
}
|
||||
if (hd->v) {
|
||||
mu_bn_free(hd->v);
|
||||
hd->v = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mu_srp_srv_pubkey_from_salt_verifier(mu_srp_handle_t *hd, char **bytes_B, int *len_B)
|
||||
{
|
||||
return __mu_srp_srv_pubkey(hd, bytes_B, len_B);
|
||||
}
|
||||
|
||||
int mu_srp_set_salt_verifier(mu_srp_handle_t *hd, const char *salt, int salt_len,
|
||||
const char *verifier, int verifier_len)
|
||||
{
|
||||
hd->bytes_s = malloc(salt_len);
|
||||
if (!hd->bytes_s) {
|
||||
goto error;
|
||||
}
|
||||
memcpy(hd->bytes_s, salt, salt_len);
|
||||
hd->len_s = salt_len;
|
||||
|
||||
hd->s = mu_bn_new_from_bin(salt, salt_len);
|
||||
if (!hd->s) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
hd->v = mu_bn_new_from_bin(verifier, verifier_len);
|
||||
if (!hd->v) {
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (hd->bytes_s) {
|
||||
free(hd->bytes_s);
|
||||
hd->bytes_s = NULL;
|
||||
hd->len_s = 0;
|
||||
}
|
||||
if (hd->s) {
|
||||
mu_bn_free(hd->s);
|
||||
hd->s = NULL;
|
||||
}
|
||||
if (hd->v) {
|
||||
mu_bn_free(hd->v);
|
||||
hd->v = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mu_srp_get_session_key(mu_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, int *len_key)
|
||||
{
|
||||
mu_bn_t *u, *vu, *avu, *S;
|
||||
char *bytes_S;
|
||||
int len_S;
|
||||
|
||||
u = vu = avu = S = NULL;
|
||||
bytes_S = NULL;
|
||||
|
||||
hd->bytes_A = malloc(len_A);
|
||||
if (! hd->bytes_A)
|
||||
goto error;
|
||||
memcpy(hd->bytes_A, bytes_A, len_A);
|
||||
hd->len_A = len_A;
|
||||
|
||||
hd->A = mu_bn_new_from_bin(bytes_A, len_A);
|
||||
if (! hd->A)
|
||||
goto error;
|
||||
u = calculate_u(hd, bytes_A, len_A);
|
||||
if (! u)
|
||||
goto error;
|
||||
|
||||
/* S = (A v^u)^b */
|
||||
vu = mu_bn_new();
|
||||
avu = mu_bn_new();
|
||||
S = mu_bn_new();
|
||||
if (!vu || !avu || !S )
|
||||
goto error;
|
||||
|
||||
mu_bn_a_exp_b_mod_c(vu, hd->v, u, hd->n, hd->ctx);
|
||||
mu_bn_a_mul_b_mod_c(avu, hd->A, vu, hd->n, hd->ctx);
|
||||
mu_bn_a_exp_b_mod_c(S, avu, hd->b, hd->n, hd->ctx);
|
||||
hex_dbg_bn("S", S);
|
||||
|
||||
bytes_S = mu_bn_to_bin(S, &len_S);
|
||||
hd->session_key = malloc(SHA512HashSize);
|
||||
if (!hd->session_key || ! bytes_S)
|
||||
goto error;
|
||||
|
||||
SHA512_hash((unsigned char *)bytes_S, len_S, (unsigned char *)hd->session_key);
|
||||
*bytes_key = hd->session_key;
|
||||
*len_key = SHA512HashSize;
|
||||
|
||||
free(bytes_S);
|
||||
mu_bn_free(vu);
|
||||
mu_bn_free(avu);
|
||||
mu_bn_free(S);
|
||||
mu_bn_free(u);
|
||||
return 0;
|
||||
error:
|
||||
if (bytes_S)
|
||||
free(bytes_S);
|
||||
if (vu)
|
||||
mu_bn_free(vu);
|
||||
if (avu)
|
||||
mu_bn_free(avu);
|
||||
if (S)
|
||||
mu_bn_free(S);
|
||||
if (u)
|
||||
mu_bn_free(u);
|
||||
if (hd->session_key) {
|
||||
free(hd->session_key);
|
||||
hd->session_key = NULL;
|
||||
}
|
||||
if (hd->A) {
|
||||
mu_bn_free(hd->A);
|
||||
hd->A = NULL;
|
||||
}
|
||||
if (hd->bytes_A) {
|
||||
free(hd->bytes_A);
|
||||
hd->bytes_A = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mu_srp_exchange_proofs(mu_srp_handle_t *hd, const char *username, char *bytes_user_proof, char *bytes_host_proof)
|
||||
{
|
||||
/* First calculate M */
|
||||
unsigned char hash_n[SHA512HashSize];
|
||||
unsigned char hash_g[SHA512HashSize];
|
||||
unsigned char hash_n_xor_g[SHA512HashSize];
|
||||
int i;
|
||||
SHA512_hash((unsigned char *)hd->bytes_n, hd->len_n, (unsigned char *)hash_n);
|
||||
SHA512_hash((unsigned char *)hd->bytes_g, hd->len_g, (unsigned char *)hash_g);
|
||||
for (i = 0; i < SHA512HashSize; i++)
|
||||
hash_n_xor_g[i] = hash_n[i] ^ hash_g[i];
|
||||
|
||||
unsigned char hash_I[SHA512HashSize];
|
||||
SHA512_hash((unsigned char *)username, strlen(username), (unsigned char *)hash_I);
|
||||
|
||||
SHA512Context ctx;
|
||||
unsigned char digest[SHA512HashSize];
|
||||
SHA512Reset(&ctx);
|
||||
SHA512Input(&ctx, hash_n_xor_g, SHA512HashSize);
|
||||
SHA512Input(&ctx, hash_I, SHA512HashSize);
|
||||
SHA512Input(&ctx, (unsigned char *)hd->bytes_s, hd->len_s);
|
||||
SHA512Input(&ctx, (unsigned char *)hd->bytes_A, hd->len_A);
|
||||
SHA512Input(&ctx, (unsigned char *)hd->bytes_B, hd->len_B);
|
||||
SHA512Input(&ctx, (unsigned char *)hd->session_key, SHA512HashSize);
|
||||
SHA512Result(&ctx, digest);
|
||||
|
||||
hex_dbg("M", digest, sizeof(digest));
|
||||
if (memcmp(bytes_user_proof, digest, SHA512HashSize) != 0)
|
||||
return false;
|
||||
/* M is now validated, let's proceed to H(AMK) */
|
||||
SHA512Reset(&ctx);
|
||||
SHA512Input(&ctx, (unsigned char *)hd->bytes_A, hd->len_A);
|
||||
SHA512Input(&ctx, digest, SHA512HashSize);
|
||||
SHA512Input(&ctx, (unsigned char *)hd->session_key, SHA512HashSize);
|
||||
SHA512Result(&ctx, (unsigned char *)bytes_host_proof);
|
||||
hex_dbg("AMK", bytes_host_proof, SHA512HashSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
/************************* SRP Stuff Ends */
|
|
@ -1,91 +0,0 @@
|
|||
#ifndef _MU_SRP_H_
|
||||
#define _MU_SRP_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "mu_bignum.h"
|
||||
|
||||
typedef enum {
|
||||
MU_NG_3072 = 0,
|
||||
} mu_ng_type_t;
|
||||
|
||||
typedef struct mu_srp_handle {
|
||||
int allocated;
|
||||
mu_ng_type_t type;
|
||||
mu_bn_ctx_t *ctx;
|
||||
|
||||
/* N
|
||||
* the bytes_n simply points to the static array
|
||||
*/
|
||||
mu_bn_t *n;
|
||||
char *bytes_n;
|
||||
int len_n;
|
||||
|
||||
/* g
|
||||
* the bytes_g simply points to the static array
|
||||
*/
|
||||
mu_bn_t *g;
|
||||
char *bytes_g;
|
||||
int len_g;
|
||||
|
||||
/* Salt */
|
||||
mu_bn_t *s;
|
||||
char *bytes_s;
|
||||
int len_s;
|
||||
/* Verifier */
|
||||
mu_bn_t *v;
|
||||
/* B */
|
||||
mu_bn_t *B;
|
||||
char *bytes_B;
|
||||
int len_B;
|
||||
/* b */
|
||||
mu_bn_t *b;
|
||||
/* A */
|
||||
mu_bn_t *A;
|
||||
char *bytes_A;
|
||||
int len_A;
|
||||
/* K - session key*/
|
||||
char *session_key;
|
||||
} mu_srp_handle_t;
|
||||
|
||||
int mu_srp_init(mu_srp_handle_t *hd, mu_ng_type_t ng);
|
||||
|
||||
void mu_srp_free(mu_srp_handle_t *hd);
|
||||
/* Returns B (pub key) and salt
|
||||
*
|
||||
* *bytes_B MUST NOT BE FREED BY THE CALLER
|
||||
* *bytes_salt MUST NOT BE FREE BY THE CALLER
|
||||
*
|
||||
*/
|
||||
int mu_srp_srv_pubkey(mu_srp_handle_t *hd, const char *username, const char *pass, int pass_len, int salt_len,
|
||||
char **bytes_B, int *len_B, char **bytes_salt);
|
||||
|
||||
/* Set the Salt and Verifier pre-generated for a given password.
|
||||
* This should be used only if the actual password is not available.
|
||||
* The public key can then be generated using mu_srp_srv_pubkey_from_salt_verifier()
|
||||
* and not mu_srp_srv_pubkey()
|
||||
*/
|
||||
int mu_srp_set_salt_verifier(mu_srp_handle_t *hd, const char *salt, int salt_len,
|
||||
const char *verifier, int verifier_len);
|
||||
|
||||
/* Returns B (pub key) when the salt and verifier are set using mu_srp_set_salt_verifier()
|
||||
*
|
||||
* *bytes_B MUST NOT BE FREED BY THE CALLER
|
||||
*/
|
||||
int mu_srp_srv_pubkey_from_salt_verifier(mu_srp_handle_t *hd, char **bytes_B, int *len_B);
|
||||
|
||||
/* Returns bytes_key
|
||||
* *bytes_key MUST NOT BE FREED BY THE CALLER
|
||||
*/
|
||||
int mu_srp_get_session_key(mu_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, int *len_key);
|
||||
|
||||
/* Exchange proofs
|
||||
* Returns 1 if user's proof is ok. Also 1 when is returned, bytes_host_proof contains our proof.
|
||||
*
|
||||
* bytes_user_proof is parameter in
|
||||
* bytes_host_proof is parameter out (should be SHA512_DIGEST_LENGTH) bytes in size
|
||||
*/
|
||||
int mu_srp_exchange_proofs(mu_srp_handle_t *hd, const char *username, char *bytes_user_proof, char *bytes_host_proof);
|
||||
|
||||
|
||||
|
||||
#endif /* ! _MU_SRP_H_ */
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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.
|
||||
#pragma once
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "bignum_ESP32.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "bignum_ESP32_C3.h"
|
||||
#endif
|
|
@ -1,297 +0,0 @@
|
|||
/**
|
||||
* \brief Multi-precision integer library, ESP-IDF hardware accelerated parts
|
||||
*
|
||||
* based on mbedTLS implementation
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#if __has_include("esp_idf_version.h")
|
||||
#include "esp_idf_version.h"
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
// #warning("IDF is 4 or later")
|
||||
#include "soc/hwcrypto_periph.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "soc/hwcrypto_reg.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include <mbedtls/bignum.h>
|
||||
#include "bignum_impl.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/lock.h>
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/dport_access.h"
|
||||
#endif
|
||||
#if CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "esp32c6/dport_access.h"
|
||||
#endif
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/dport_access.h"
|
||||
#endif
|
||||
|
||||
static _lock_t mpi_lock;
|
||||
|
||||
/* Round up number of words to nearest
|
||||
512 bit (16 word) block count.
|
||||
*/
|
||||
size_t esp_mpi_hardware_words(size_t words)
|
||||
{
|
||||
return (words + 0xF) & ~0xF;
|
||||
}
|
||||
|
||||
void esp_mpi_enable_hardware_hw_op( void )
|
||||
{
|
||||
/* newlib locks lazy initialize on ESP-IDF */
|
||||
_lock_acquire(&mpi_lock);
|
||||
|
||||
/* Enable RSA hardware */
|
||||
periph_module_enable(PERIPH_RSA_MODULE);
|
||||
DPORT_REG_CLR_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD);
|
||||
|
||||
while (DPORT_REG_READ(RSA_CLEAN_REG) != 1)
|
||||
{ }
|
||||
// Note: from enabling RSA clock to here takes about 1.3us
|
||||
}
|
||||
|
||||
void esp_mpi_disable_hardware_hw_op( void )
|
||||
{
|
||||
DPORT_REG_SET_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD);
|
||||
|
||||
/* Disable RSA hardware */
|
||||
periph_module_disable(PERIPH_RSA_MODULE);
|
||||
|
||||
_lock_release(&mpi_lock);
|
||||
}
|
||||
|
||||
|
||||
/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'.
|
||||
|
||||
If hw_words is higher than the number of words in the bignum then
|
||||
these additional words will be zeroed in the memory buffer.
|
||||
|
||||
*/
|
||||
static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t hw_words)
|
||||
{
|
||||
uint32_t *pbase = (uint32_t *)mem_base;
|
||||
uint32_t copy_words = MIN(hw_words, mpi->n);
|
||||
|
||||
/* Copy MPI data to memory block registers */
|
||||
for (int i = 0; i < copy_words; i++) {
|
||||
pbase[i] = mpi->p[i];
|
||||
}
|
||||
|
||||
/* Zero any remaining memory block data */
|
||||
for (int i = copy_words; i < hw_words; i++) {
|
||||
pbase[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read mbedTLS MPI bignum back from hardware memory block.
|
||||
|
||||
Reads num_words words from block.
|
||||
|
||||
Bignum 'x' should already be grown to at least num_words by caller (can be done while
|
||||
calculation is in progress, to save some cycles)
|
||||
*/
|
||||
static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words)
|
||||
{
|
||||
assert(x->n >= num_words);
|
||||
|
||||
/* Copy data from memory block registers */
|
||||
esp_dport_access_read_buffer(x->p, mem_base, num_words);
|
||||
|
||||
/* Zero any remaining limbs in the bignum, if the buffer is bigger
|
||||
than num_words */
|
||||
for (size_t i = num_words; i < x->n; i++) {
|
||||
x->p[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Begin an RSA operation. op_reg specifies which 'START' register
|
||||
to write to.
|
||||
*/
|
||||
static inline void start_op(uint32_t op_reg)
|
||||
{
|
||||
/* Clear interrupt status */
|
||||
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
|
||||
|
||||
/* Note: above REG_WRITE includes a memw, so we know any writes
|
||||
to the memory blocks are also complete. */
|
||||
|
||||
DPORT_REG_WRITE(op_reg, 1);
|
||||
}
|
||||
|
||||
/* Wait for an RSA operation to complete.
|
||||
*/
|
||||
static inline void wait_op_complete(void)
|
||||
{
|
||||
while (DPORT_REG_READ(RSA_INTERRUPT_REG) != 1)
|
||||
{ }
|
||||
|
||||
/* clear the interrupt */
|
||||
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
|
||||
}
|
||||
|
||||
/* Read result from last MPI operation */
|
||||
void esp_mpi_read_result_hw_op(mbedtls_mpi *Z, size_t z_words)
|
||||
{
|
||||
wait_op_complete();
|
||||
mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, z_words);
|
||||
}
|
||||
|
||||
/* Z = (X * Y) mod M */
|
||||
void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words)
|
||||
{
|
||||
/* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */
|
||||
mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, hw_words);
|
||||
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words);
|
||||
mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Rinv, hw_words);
|
||||
DPORT_REG_WRITE(RSA_M_DASH_REG, (uint32_t)Mprime);
|
||||
|
||||
/* "mode" register loaded with number of 512-bit blocks, minus 1 */
|
||||
DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hw_words / 16) - 1);
|
||||
|
||||
/* Execute first stage montgomery multiplication */
|
||||
start_op(RSA_MULT_START_REG);
|
||||
|
||||
wait_op_complete();
|
||||
|
||||
/* execute second stage */
|
||||
/* Load Y to X input memory block, rerun */
|
||||
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, hw_words);
|
||||
|
||||
start_op(RSA_MULT_START_REG);
|
||||
}
|
||||
|
||||
/* Z = X * Y */
|
||||
void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t hw_words)
|
||||
{
|
||||
/* Copy X (right-extended) & Y (left-extended) to memory block */
|
||||
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words);
|
||||
mpi_to_mem_block(RSA_MEM_Z_BLOCK_BASE + hw_words * 4, Y, hw_words);
|
||||
/* NB: as Y is left-extended, we don't zero the bottom words_mult words of Y block.
|
||||
This is OK for now because zeroing is done by hardware when we do esp_mpi_acquire_hardware().
|
||||
*/
|
||||
|
||||
DPORT_REG_WRITE(RSA_M_DASH_REG, 0);
|
||||
|
||||
/* "mode" register loaded with number of 512-bit blocks in result,
|
||||
plus 7 (for range 9-12). (this is ((N~ / 32) - 1) + 8))
|
||||
*/
|
||||
DPORT_REG_WRITE(RSA_MULT_MODE_REG, ((hw_words * 2) / 16) + 7);
|
||||
|
||||
start_op(RSA_MULT_START_REG);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int esp_mont_hw_op(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M,
|
||||
mbedtls_mpi_uint Mprime,
|
||||
size_t hw_words,
|
||||
bool again)
|
||||
{
|
||||
// Note Z may be the same pointer as X or Y
|
||||
int ret = 0;
|
||||
|
||||
// montgomery mult prepare
|
||||
if (again == false) {
|
||||
mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, hw_words);
|
||||
DPORT_REG_WRITE(RSA_M_DASH_REG, Mprime);
|
||||
DPORT_REG_WRITE(RSA_MULT_MODE_REG, hw_words / 16 - 1);
|
||||
}
|
||||
|
||||
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words);
|
||||
mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Y, hw_words);
|
||||
|
||||
start_op(RSA_MULT_START_REG);
|
||||
Z->s = 1; // The sign of Z will be = M->s (but M->s is always 1)
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, hw_words) );
|
||||
|
||||
wait_op_complete();
|
||||
|
||||
/* Read back the result */
|
||||
mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, hw_words);
|
||||
|
||||
|
||||
/* from HAC 14.36 - 3. If Z >= M then Z = Z - M */
|
||||
if (mbedtls_mpi_cmp_mpi(Z, M) >= 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(Z, Z, M));
|
||||
}
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Special-case of mbedtls_mpi_mult_mpi(), where we use hardware montgomery mod
|
||||
multiplication to calculate an mbedtls_mpi_mult_mpi result where either
|
||||
A or B are >2048 bits so can't use the standard multiplication method.
|
||||
|
||||
Result (z_words, based on A bits + B bits) must still be less than 4096 bits.
|
||||
|
||||
This case is simpler than the general case modulo multiply of
|
||||
esp_mpi_mul_mpi_mod() because we can control the other arguments:
|
||||
|
||||
* Modulus is chosen with M=(2^num_bits - 1) (ie M=R-1), so output
|
||||
isn't actually modulo anything.
|
||||
* Mprime and Rinv are therefore predictable as follows:
|
||||
Mprime = 1
|
||||
Rinv = 1
|
||||
|
||||
(See RSA Accelerator section in Technical Reference for more about Mprime, Rinv)
|
||||
*/
|
||||
void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words)
|
||||
{
|
||||
size_t hw_words = num_words;
|
||||
|
||||
/* M = 2^num_words - 1, so block is entirely FF */
|
||||
for (int i = 0; i < hw_words; i++) {
|
||||
DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, UINT32_MAX);
|
||||
}
|
||||
/* Mprime = 1 */
|
||||
DPORT_REG_WRITE(RSA_M_DASH_REG, 1);
|
||||
|
||||
/* "mode" register loaded with number of 512-bit blocks, minus 1 */
|
||||
DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hw_words / 16) - 1);
|
||||
|
||||
/* Load X */
|
||||
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words);
|
||||
|
||||
/* Rinv = 1, write first word */
|
||||
DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE, 1);
|
||||
|
||||
/* Zero out rest of the Rinv words */
|
||||
for (int i = 1; i < hw_words; i++) {
|
||||
DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0);
|
||||
}
|
||||
|
||||
start_op(RSA_MULT_START_REG);
|
||||
|
||||
wait_op_complete();
|
||||
|
||||
/* finish the modular multiplication */
|
||||
/* Load Y to X input memory block, rerun */
|
||||
mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, hw_words);
|
||||
|
||||
start_op(RSA_MULT_START_REG);
|
||||
|
||||
}
|
||||
#endif //CONFIG_IDF_TARGET_ESP32
|
|
@ -1,82 +0,0 @@
|
|||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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.
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#pragma once
|
||||
|
||||
#include_next "mbedtls/bignum.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**
|
||||
* This is a wrapper for the main mbedtls/bignum.h. This wrapper
|
||||
* provides a few additional ESP32-only functions.
|
||||
*
|
||||
* This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we
|
||||
* do for AES, SHA, etc. Because we still use most of the bignum.h
|
||||
* implementation and just replace a few hardware accelerated
|
||||
* functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in
|
||||
* esp_config.h).
|
||||
*
|
||||
* @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no
|
||||
* generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this
|
||||
* is that all of the function implementations depend strongly upon the mbedTLS MPI implementation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Lock access to RSA Accelerator (MPI/bignum operations)
|
||||
*
|
||||
* RSA Accelerator hardware unit can only be used by one
|
||||
* consumer at a time.
|
||||
*
|
||||
* @note This function is non-recursive (do not call it twice from the
|
||||
* same task.)
|
||||
*
|
||||
* @note You do not need to call this if you are using the mbedTLS bignum.h
|
||||
* API or esp_mpi_xxx functions. This function is only needed if you
|
||||
* want to call ROM RSA functions or access the registers directly.
|
||||
*
|
||||
*/
|
||||
void esp_mpi_acquire_hardware(void);
|
||||
|
||||
/**
|
||||
* @brief Unlock access to RSA Accelerator (MPI/bignum operations)
|
||||
*
|
||||
* Has to be called once for each call to esp_mpi_acquire_hardware().
|
||||
*
|
||||
* @note You do not need to call this if you are using the mbedTLS bignum.h
|
||||
* API or esp_mpi_xxx functions. This function is only needed if you
|
||||
* want to call ROM RSA functions or access the registers directly.
|
||||
*/
|
||||
void esp_mpi_release_hardware(void);
|
||||
|
||||
//#if CONFIG_MBEDTLS_HARDWARE_MPI
|
||||
|
||||
/* @brief MPI modular mupltiplication function
|
||||
*
|
||||
* Calculates Z = (X * Y) mod M using MPI hardware acceleration.
|
||||
*
|
||||
* This is not part of the standard mbedTLS bignum API.
|
||||
*
|
||||
* @note All of X, Y & Z should be less than 4096 bit long or an error is returned.
|
||||
*
|
||||
* @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init().
|
||||
* @param X First multiplication argument.
|
||||
* @param Y Second multiplication argument.
|
||||
* @param M Modulus value for result.
|
||||
*
|
||||
* @return 0 on success, mbedTLS MPI error codes on failure.
|
||||
*/
|
||||
int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M);
|
||||
|
||||
//#endif // CONFIG_MBEDTLS_HARDWARE_MPI
|
||||
#endif //CONFIG_IDF_TARGET_ESP32
|
|
@ -1,108 +0,0 @@
|
|||
/**
|
||||
* \brief Multi-precision integer library, ESP-IDF hardware accelerated parts
|
||||
*
|
||||
* based on mbedTLS implementation
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#if __has_include("esp_idf_version.h")
|
||||
#include "esp_idf_version.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "soc/hwcrypto_periph.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "mbedtls/bignum.h"
|
||||
#include "bignum_impl.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "esp_crypto_lock.h"
|
||||
|
||||
/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'.
|
||||
|
||||
If hw_words is higher than the number of words in the bignum then
|
||||
these additional words will be zeroed in the memory buffer.
|
||||
|
||||
*/
|
||||
static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words)
|
||||
{
|
||||
uint32_t *pbase = (uint32_t *)mem_base;
|
||||
uint32_t copy_words = MIN(num_words, mpi->n);
|
||||
|
||||
/* Copy MPI data to memory block registers */
|
||||
for (int i = 0; i < copy_words; i++) {
|
||||
pbase[i] = mpi->p[i];
|
||||
}
|
||||
|
||||
/* Zero any remaining memory block data */
|
||||
for (int i = copy_words; i < num_words; i++) {
|
||||
pbase[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read mbedTLS MPI bignum back from hardware memory block.
|
||||
|
||||
Reads num_words words from block.
|
||||
|
||||
Bignum 'x' should already be grown to at least num_words by caller (can be done while
|
||||
calculation is in progress, to save some cycles)
|
||||
*/
|
||||
static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words)
|
||||
{
|
||||
|
||||
/* Copy data from memory block registers */
|
||||
const size_t REG_WIDTH = sizeof(uint32_t);
|
||||
for (size_t i = 0; i < num_words; i++) {
|
||||
x->p[i] = REG_READ(mem_base + (i * REG_WIDTH));
|
||||
}
|
||||
/* Zero any remaining limbs in the bignum, if the buffer is bigger
|
||||
than num_words */
|
||||
for (size_t i = num_words; i < x->n; i++) {
|
||||
x->p[i] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Begin an RSA operation. op_reg specifies which 'START' register
|
||||
to write to.
|
||||
*/
|
||||
static inline void start_op(uint32_t op_reg)
|
||||
{
|
||||
/* Clear interrupt status */
|
||||
REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1);
|
||||
|
||||
/* Note: above REG_WRITE includes a memw, so we know any writes
|
||||
to the memory blocks are also complete. */
|
||||
|
||||
REG_WRITE(op_reg, 1);
|
||||
}
|
||||
|
||||
/* Wait for an RSA operation to complete.
|
||||
*/
|
||||
static inline void wait_op_complete(void)
|
||||
{
|
||||
while (REG_READ(RSA_QUERY_INTERRUPT_REG) != 1)
|
||||
{ }
|
||||
|
||||
/* clear the interrupt */
|
||||
REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1);
|
||||
}
|
||||
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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.
|
||||
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#pragma once
|
||||
|
||||
#include_next "mbedtls/bignum.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**
|
||||
* This is a wrapper for the main mbedtls/bignum.h. This wrapper
|
||||
* provides a few additional ESP32-only functions.
|
||||
*
|
||||
* This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we
|
||||
* do for AES, SHA, etc. Because we still use most of the bignum.h
|
||||
* implementation and just replace a few hardware accelerated
|
||||
* functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in
|
||||
* esp_config.h).
|
||||
*
|
||||
* @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no
|
||||
* generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this
|
||||
* is that all of the function implementations depend strongly upon the mbedTLS MPI implementation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Lock access to RSA Accelerator (MPI/bignum operations)
|
||||
*
|
||||
* RSA Accelerator hardware unit can only be used by one
|
||||
* consumer at a time.
|
||||
*
|
||||
* @note This function is non-recursive (do not call it twice from the
|
||||
* same task.)
|
||||
*
|
||||
* @note You do not need to call this if you are using the mbedTLS bignum.h
|
||||
* API or esp_mpi_xxx functions. This function is only needed if you
|
||||
* want to call ROM RSA functions or access the registers directly.
|
||||
*
|
||||
*/
|
||||
void esp_mpi_acquire_hardware(void);
|
||||
|
||||
/**
|
||||
* @brief Unlock access to RSA Accelerator (MPI/bignum operations)
|
||||
*
|
||||
* Has to be called once for each call to esp_mpi_acquire_hardware().
|
||||
*
|
||||
* @note You do not need to call this if you are using the mbedTLS bignum.h
|
||||
* API or esp_mpi_xxx functions. This function is only needed if you
|
||||
* want to call ROM RSA functions or access the registers directly.
|
||||
*/
|
||||
void esp_mpi_release_hardware(void);
|
||||
|
||||
//#if CONFIG_MBEDTLS_HARDWARE_MPI
|
||||
|
||||
/* @brief MPI modular mupltiplication function
|
||||
*
|
||||
* Calculates Z = (X * Y) mod M using MPI hardware acceleration.
|
||||
*
|
||||
* This is not part of the standard mbedTLS bignum API.
|
||||
*
|
||||
* @note All of X, Y & Z should be less than 4096 bit long or an error is returned.
|
||||
*
|
||||
* @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init().
|
||||
* @param X First multiplication argument.
|
||||
* @param Y Second multiplication argument.
|
||||
* @param M Modulus value for result.
|
||||
*
|
||||
* @return 0 on success, mbedTLS MPI error codes on failure.
|
||||
*/
|
||||
int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M);
|
||||
|
||||
void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words);
|
||||
static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words);
|
||||
void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words);
|
||||
|
||||
|
||||
//#endif // CONFIG_MBEDTLS_HARDWARE_MPI
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6|| CONFIG_IDF_TARGET_ESP32S3
|
|
@ -1,102 +0,0 @@
|
|||
#ifndef _ESP_BIGNUM_H_
|
||||
#define _ESP_BIGNUM_H_
|
||||
|
||||
#include <mbedtls/bignum.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Use montgomery exponentiation (HAC 14.94) for calculating X ^ Y mod M,
|
||||
this may be faster for some targets. The hardware acceleration support for modular
|
||||
exponentiation on the ESP32 is slow for public key operations, so use montgomery
|
||||
exponentiation instead.
|
||||
*/
|
||||
|
||||
// #define CONFIG_IDF_TARGET_ESP32 1
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define ESP_MPI_USE_MONT_EXP
|
||||
|
||||
#define MBEDTLS_MPI_EXP_MOD_ALT
|
||||
//#define MBEDTLS_MPI_MUL_MPI_ALT
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv );
|
||||
|
||||
/**
|
||||
* @brief Enable the MPI hardware and acquire the lock
|
||||
*
|
||||
*/
|
||||
void esp_mpi_enable_hardware_hw_op( void );
|
||||
|
||||
/**
|
||||
* @brief Disable the MPI hardware and release the lock
|
||||
*
|
||||
*/
|
||||
void esp_mpi_disable_hardware_hw_op( void );
|
||||
|
||||
/**
|
||||
* @brief Calculate the number of words needed to represent the input word in hardware
|
||||
*
|
||||
* @param words The number of words to be represented
|
||||
*
|
||||
* @return size_t Number of words required
|
||||
*/
|
||||
size_t esp_mpi_hardware_words(size_t words);
|
||||
|
||||
/**
|
||||
* @brief Starts a (X * Y) Mod M calculation in hardware. Rinv and M_prime needs to be precalculated in software.
|
||||
*
|
||||
*/
|
||||
void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words);
|
||||
|
||||
/**
|
||||
* @brief Starts a (X * Y) calculation in hardware.
|
||||
*
|
||||
*/
|
||||
void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words);
|
||||
|
||||
/**
|
||||
* @brief Special-case of (X * Y), where we use hardware montgomery mod
|
||||
multiplication to calculate result where either A or B are >2048 bits so
|
||||
can't use the standard multiplication method.
|
||||
*
|
||||
*/
|
||||
void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words);
|
||||
|
||||
/**
|
||||
* @brief Read out the result from the previous calculation.
|
||||
*
|
||||
*/
|
||||
void esp_mpi_read_result_hw_op(mbedtls_mpi *Z, size_t z_words);
|
||||
|
||||
#ifdef ESP_MPI_USE_MONT_EXP
|
||||
/**
|
||||
* @brief Starts a montgomery multiplication calculation in hardware
|
||||
*
|
||||
*/
|
||||
int esp_mont_hw_op(mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi* Y, const mbedtls_mpi* M,
|
||||
mbedtls_mpi_uint Mprime,
|
||||
size_t hw_words,
|
||||
bool again);
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* @brief Starts a (X ^ Y) Mod M calculation in hardware. Rinv and M_prime needs to be precalculated in software.
|
||||
*
|
||||
*/
|
||||
void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words);
|
||||
#endif //CONFIG_IDF_TARGET_ESP32
|
||||
#endif //ESP_MPI_USE_MONT_EXP
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3
|
||||
void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words);
|
||||
extern int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv );
|
||||
extern size_t esp_mpi_hardware_words(size_t words);
|
||||
extern void esp_mpi_enable_hardware_hw_op( void );
|
||||
extern void esp_mpi_disable_hardware_hw_op( void );
|
||||
extern void esp_mpi_read_result_hw_op(mbedtls_mpi *Z, size_t z_words);
|
||||
extern void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words);
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3
|
||||
|
||||
#endif
|
|
@ -1,628 +0,0 @@
|
|||
/**
|
||||
* \brief Multi-precision integer library, ESP32 hardware accelerated parts
|
||||
*
|
||||
* based on mbedTLS implementation
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed 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.
|
||||
*
|
||||
*/
|
||||
#if __has_include("esp_idf_version.h")
|
||||
#include "esp_idf_version.h"
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
// #warning("IDF is 4 or later")
|
||||
#include "soc/hwcrypto_periph.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "bignum_impl.h"
|
||||
//#include "soc/soc_caps.h"
|
||||
|
||||
#include <mbedtls/bignum.h>
|
||||
|
||||
// wangbin added
|
||||
#if !defined(SOC_RSA_MAX_BIT_LEN)
|
||||
#define SOC_RSA_MAX_BIT_LEN (4096)
|
||||
#endif
|
||||
|
||||
|
||||
/* Some implementation notes:
|
||||
*
|
||||
* - Naming convention x_words, y_words, z_words for number of words (limbs) used in a particular
|
||||
* bignum. This number may be less than the size of the bignum
|
||||
*
|
||||
* - Naming convention hw_words for the hardware length of the operation. This number maybe be rounded up
|
||||
* for targets that requres this (e.g. ESP32), and may be larger than any of the numbers
|
||||
* involved in the calculation.
|
||||
*
|
||||
* - Timing behaviour of these functions will depend on the length of the inputs. This is fundamentally
|
||||
* the same constraint as the software mbedTLS implementations, and relies on the same
|
||||
* countermeasures (exponent blinding, etc) which are used in mbedTLS.
|
||||
*/
|
||||
|
||||
static const __attribute__((unused)) char *TAG = "bignum";
|
||||
|
||||
#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */
|
||||
#define biL (ciL << 3) /* bits in limb */
|
||||
|
||||
|
||||
/* Convert bit count to word count
|
||||
*/
|
||||
static inline size_t bits_to_words(size_t bits)
|
||||
{
|
||||
return (bits + 31) / 32;
|
||||
}
|
||||
|
||||
/* Return the number of words actually used to represent an mpi
|
||||
number.
|
||||
*/
|
||||
#if defined(MBEDTLS_MPI_EXP_MOD_ALT) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
static size_t mpi_words(const mbedtls_mpi *mpi)
|
||||
{
|
||||
for (size_t i = mpi->n; i > 0; i--) {
|
||||
if (mpi->p[i - 1] != 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif //MBEDTLS_MPI_EXP_MOD_ALT
|
||||
|
||||
/**
|
||||
*
|
||||
* There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1,
|
||||
* where B^-1(B-1) mod N=1. Actually, only the least significant part of
|
||||
* N' is needed, hence the definition N0'=N' mod b. We reproduce below the
|
||||
* simple algorithm from an article by Dusse and Kaliski to efficiently
|
||||
* find N0' from N0 and b
|
||||
*/
|
||||
static mbedtls_mpi_uint modular_inverse(const mbedtls_mpi *M)
|
||||
{
|
||||
int i;
|
||||
uint64_t t = 1;
|
||||
uint64_t two_2_i_minus_1 = 2; /* 2^(i-1) */
|
||||
uint64_t two_2_i = 4; /* 2^i */
|
||||
uint64_t N = M->p[0];
|
||||
|
||||
for (i = 2; i <= 32; i++) {
|
||||
if ((mbedtls_mpi_uint) N * t % two_2_i >= two_2_i_minus_1) {
|
||||
t += two_2_i_minus_1;
|
||||
}
|
||||
|
||||
two_2_i_minus_1 <<= 1;
|
||||
two_2_i <<= 1;
|
||||
}
|
||||
|
||||
return (mbedtls_mpi_uint)(UINT32_MAX - t + 1);
|
||||
}
|
||||
|
||||
/* Calculate Rinv = RR^2 mod M, where:
|
||||
*
|
||||
* R = b^n where b = 2^32, n=num_words,
|
||||
* R = 2^N (where N=num_bits)
|
||||
* RR = R^2 = 2^(2*N) (where N=num_bits=num_words*32)
|
||||
*
|
||||
* This calculation is computationally expensive (mbedtls_mpi_mod_mpi)
|
||||
* so caller should cache the result where possible.
|
||||
*
|
||||
* DO NOT call this function while holding esp_mpi_enable_hardware_hw_op().
|
||||
*
|
||||
*/
|
||||
static int calculate_rinv(mbedtls_mpi *Rinv, const mbedtls_mpi *M, int num_words)
|
||||
{
|
||||
int ret;
|
||||
size_t num_bits = num_words * 32;
|
||||
mbedtls_mpi RR;
|
||||
mbedtls_mpi_init(&RR);
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&RR, num_bits * 2, 1));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(Rinv, &RR, M));
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&RR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
/* Z = (X * Y) mod M
|
||||
|
||||
Not an mbedTLS function
|
||||
*/
|
||||
int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
size_t x_bits = mbedtls_mpi_bitlen(X);
|
||||
size_t y_bits = mbedtls_mpi_bitlen(Y);
|
||||
size_t m_bits = mbedtls_mpi_bitlen(M);
|
||||
size_t z_bits = MIN(m_bits, x_bits + y_bits);
|
||||
size_t x_words = bits_to_words(x_bits);
|
||||
size_t y_words = bits_to_words(y_bits);
|
||||
size_t m_words = bits_to_words(m_bits);
|
||||
size_t z_words = bits_to_words(z_bits);
|
||||
size_t hw_words = esp_mpi_hardware_words(MAX(x_words, MAX(y_words, m_words))); /* longest operand */
|
||||
mbedtls_mpi Rinv;
|
||||
mbedtls_mpi_uint Mprime;
|
||||
|
||||
/* Calculate and load the first stage montgomery multiplication */
|
||||
mbedtls_mpi_init(&Rinv);
|
||||
MBEDTLS_MPI_CHK(calculate_rinv(&Rinv, M, hw_words));
|
||||
Mprime = modular_inverse(M);
|
||||
|
||||
esp_mpi_enable_hardware_hw_op();
|
||||
/* Load and start a (X * Y) mod M calculation */
|
||||
esp_mpi_mul_mpi_mod_hw_op(X, Y, M, &Rinv, Mprime, hw_words);
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Z, z_words));
|
||||
|
||||
esp_mpi_read_result_hw_op(Z, z_words);
|
||||
Z->s = X->s * Y->s;
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&Rinv);
|
||||
esp_mpi_disable_hardware_hw_op();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
|
||||
#if defined(MBEDTLS_MPI_EXP_MOD_ALT)
|
||||
|
||||
#ifdef ESP_MPI_USE_MONT_EXP
|
||||
/*
|
||||
* Return the most significant one-bit.
|
||||
*/
|
||||
static size_t mbedtls_mpi_msb( const mbedtls_mpi *X )
|
||||
{
|
||||
int i, j;
|
||||
if (X != NULL && X->n != 0) {
|
||||
for (i = X->n - 1; i >= 0; i--) {
|
||||
if (X->p[i] != 0) {
|
||||
for (j = biL - 1; j >= 0; j--) {
|
||||
if ((X->p[i] & (1 << j)) != 0) {
|
||||
return (i * biL) + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Montgomery exponentiation: Z = X ^ Y mod M (HAC 14.94)
|
||||
*/
|
||||
static int mpi_montgomery_exp_calc( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M,
|
||||
mbedtls_mpi *Rinv,
|
||||
size_t hw_words,
|
||||
mbedtls_mpi_uint Mprime )
|
||||
{
|
||||
int ret = 0;
|
||||
mbedtls_mpi X_, one;
|
||||
|
||||
mbedtls_mpi_init(&X_);
|
||||
mbedtls_mpi_init(&one);
|
||||
if ( ( ( ret = mbedtls_mpi_grow(&one, hw_words) ) != 0 ) ||
|
||||
( ( ret = mbedtls_mpi_set_bit(&one, 0, 1) ) != 0 ) ) {
|
||||
goto cleanup2;
|
||||
}
|
||||
|
||||
// Algorithm from HAC 14.94
|
||||
{
|
||||
// 0 determine t (highest bit set in y)
|
||||
int t = mbedtls_mpi_msb(Y);
|
||||
|
||||
esp_mpi_enable_hardware_hw_op();
|
||||
|
||||
// 1.1 x_ = mont(x, R^2 mod m)
|
||||
// = mont(x, rb)
|
||||
MBEDTLS_MPI_CHK( esp_mont_hw_op(&X_, X, Rinv, M, Mprime, hw_words, false) );
|
||||
|
||||
// 1.2 z = R mod m
|
||||
// now z = R mod m = Mont (R^2 mod m, 1) mod M (as Mont(x) = X&R^-1 mod M)
|
||||
MBEDTLS_MPI_CHK( esp_mont_hw_op(Z, Rinv, &one, M, Mprime, hw_words, true) );
|
||||
|
||||
// 2 for i from t down to 0
|
||||
for (int i = t; i >= 0; i--) {
|
||||
// 2.1 z = mont(z,z)
|
||||
if (i != t) { // skip on the first iteration as is still unity
|
||||
MBEDTLS_MPI_CHK( esp_mont_hw_op(Z, Z, Z, M, Mprime, hw_words, true) );
|
||||
}
|
||||
|
||||
// 2.2 if y[i] = 1 then z = mont(A, x_)
|
||||
if (mbedtls_mpi_get_bit(Y, i)) {
|
||||
MBEDTLS_MPI_CHK( esp_mont_hw_op(Z, Z, &X_, M, Mprime, hw_words, true) );
|
||||
}
|
||||
}
|
||||
|
||||
// 3 z = Mont(z, 1)
|
||||
MBEDTLS_MPI_CHK( esp_mont_hw_op(Z, Z, &one, M, Mprime, hw_words, true) );
|
||||
}
|
||||
|
||||
cleanup:
|
||||
esp_mpi_disable_hardware_hw_op();
|
||||
|
||||
cleanup2:
|
||||
mbedtls_mpi_free(&X_);
|
||||
mbedtls_mpi_free(&one);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif //USE_MONT_EXPONENATIATION
|
||||
|
||||
/*
|
||||
* Z = X ^ Y mod M
|
||||
*
|
||||
* _Rinv is optional pre-calculated version of Rinv (via calculate_rinv()).
|
||||
*
|
||||
* (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv)
|
||||
*
|
||||
*/
|
||||
// wangbin changed mbedtls_mpi_exp_mod -> esp_mpi_exp_mod
|
||||
int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv )
|
||||
{
|
||||
int ret = 0;
|
||||
size_t x_words = mpi_words(X);
|
||||
size_t y_words = mpi_words(Y);
|
||||
size_t m_words = mpi_words(M);
|
||||
|
||||
|
||||
/* "all numbers must be the same length", so choose longest number
|
||||
as cardinal length of operation...
|
||||
*/
|
||||
size_t num_words = esp_mpi_hardware_words(MAX(m_words, MAX(x_words, y_words)));
|
||||
|
||||
mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */
|
||||
mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */
|
||||
mbedtls_mpi_uint Mprime;
|
||||
|
||||
if (mbedtls_mpi_cmp_int(M, 0) <= 0 || (M->p[0] & 1) == 0) {
|
||||
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_int(Y, 0) < 0) {
|
||||
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_int(Y, 0) == 0) {
|
||||
return mbedtls_mpi_lset(Z, 1);
|
||||
}
|
||||
|
||||
if (num_words * 32 > SOC_RSA_MAX_BIT_LEN) {
|
||||
return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
|
||||
}
|
||||
|
||||
/* Determine RR pointer, either _RR for cached value
|
||||
or local RR_new */
|
||||
if (_Rinv == NULL) {
|
||||
mbedtls_mpi_init(&Rinv_new);
|
||||
Rinv = &Rinv_new;
|
||||
} else {
|
||||
Rinv = _Rinv;
|
||||
}
|
||||
if (Rinv->p == NULL) {
|
||||
MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words));
|
||||
}
|
||||
|
||||
Mprime = modular_inverse(M);
|
||||
|
||||
// Montgomery exponentiation: Z = X ^ Y mod M (HAC 14.94)
|
||||
#ifdef ESP_MPI_USE_MONT_EXP
|
||||
ret = mpi_montgomery_exp_calc(Z, X, Y, M, Rinv, num_words, Mprime) ;
|
||||
MBEDTLS_MPI_CHK(ret);
|
||||
#else
|
||||
esp_mpi_enable_hardware_hw_op();
|
||||
|
||||
esp_mpi_exp_mpi_mod_hw_op(X, Y, M, Rinv, Mprime, num_words);
|
||||
ret = mbedtls_mpi_grow(Z, m_words);
|
||||
if (ret != 0) {
|
||||
esp_mpi_disable_hardware_hw_op();
|
||||
goto cleanup;
|
||||
}
|
||||
esp_mpi_read_result_hw_op(Z, m_words);
|
||||
esp_mpi_disable_hardware_hw_op();
|
||||
#endif
|
||||
|
||||
// Compensate for negative X
|
||||
if (X->s == -1 && (Y->p[0] & 1) != 0) {
|
||||
Z->s = -1;
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(Z, M, Z));
|
||||
} else {
|
||||
Z->s = 1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (_Rinv == NULL) {
|
||||
mbedtls_mpi_free(&Rinv_new);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_MPI_EXP_MOD_ALT */
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
|
||||
int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv )
|
||||
{
|
||||
int ret = 0;
|
||||
size_t x_words = mpi_words(X);
|
||||
size_t y_words = mpi_words(Y);
|
||||
size_t m_words = mpi_words(M);
|
||||
|
||||
|
||||
/* "all numbers must be the same length", so choose longest number
|
||||
as cardinal length of operation...
|
||||
*/
|
||||
size_t num_words = esp_mpi_hardware_words(MAX(m_words, MAX(x_words, y_words)));
|
||||
|
||||
mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */
|
||||
mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */
|
||||
mbedtls_mpi_uint Mprime;
|
||||
|
||||
if (mbedtls_mpi_cmp_int(M, 0) <= 0 || (M->p[0] & 1) == 0) {
|
||||
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_int(Y, 0) < 0) {
|
||||
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_int(Y, 0) == 0) {
|
||||
return mbedtls_mpi_lset(Z, 1);
|
||||
}
|
||||
|
||||
if (num_words * 32 > SOC_RSA_MAX_BIT_LEN) {
|
||||
return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
|
||||
}
|
||||
|
||||
/* Determine RR pointer, either _RR for cached value
|
||||
or local RR_new */
|
||||
if (_Rinv == NULL) {
|
||||
mbedtls_mpi_init(&Rinv_new);
|
||||
Rinv = &Rinv_new;
|
||||
} else {
|
||||
Rinv = _Rinv;
|
||||
}
|
||||
if (Rinv->p == NULL) {
|
||||
MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words));
|
||||
}
|
||||
|
||||
Mprime = modular_inverse(M);
|
||||
|
||||
// Montgomery exponentiation: Z = X ^ Y mod M (HAC 14.94)
|
||||
#ifdef ESP_MPI_USE_MONT_EXP
|
||||
ret = mpi_montgomery_exp_calc(Z, X, Y, M, Rinv, num_words, Mprime) ;
|
||||
MBEDTLS_MPI_CHK(ret);
|
||||
#else
|
||||
esp_mpi_enable_hardware_hw_op();
|
||||
|
||||
esp_mpi_exp_mpi_mod_hw_op(X, Y, M, Rinv, Mprime, num_words);
|
||||
ret = mbedtls_mpi_grow(Z, m_words);
|
||||
if (ret != 0) {
|
||||
esp_mpi_disable_hardware_hw_op();
|
||||
goto cleanup;
|
||||
}
|
||||
esp_mpi_read_result_hw_op(Z, m_words);
|
||||
esp_mpi_disable_hardware_hw_op();
|
||||
#endif
|
||||
|
||||
// Compensate for negative X
|
||||
if (X->s == -1 && (Y->p[0] & 1) != 0) {
|
||||
Z->s = -1;
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(Z, M, Z));
|
||||
} else {
|
||||
Z->s = 1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (_Rinv == NULL) {
|
||||
mbedtls_mpi_free(&Rinv_new);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif //CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
|
||||
|
||||
#if defined(MBEDTLS_MPI_MUL_MPI_ALT) /* MBEDTLS_MPI_MUL_MPI_ALT */
|
||||
|
||||
static int mpi_mult_mpi_failover_mod_mult( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t z_words);
|
||||
static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t y_words, size_t z_words);
|
||||
|
||||
#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
/* Z = X * Y */
|
||||
int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y )
|
||||
{
|
||||
int ret = 0;
|
||||
size_t x_bits = mbedtls_mpi_bitlen(X);
|
||||
size_t y_bits = mbedtls_mpi_bitlen(Y);
|
||||
size_t x_words = bits_to_words(x_bits);
|
||||
size_t y_words = bits_to_words(y_bits);
|
||||
size_t z_words = bits_to_words(x_bits + y_bits);
|
||||
size_t hw_words = esp_mpi_hardware_words(MAX(x_words, y_words)); // length of one operand in hardware
|
||||
|
||||
/* Short-circuit eval if either argument is 0 or 1.
|
||||
|
||||
This is needed as the mpi modular division
|
||||
argument will sometimes call in here when one
|
||||
argument is too large for the hardware unit, but the other
|
||||
argument is zero or one.
|
||||
*/
|
||||
if (x_bits == 0 || y_bits == 0) {
|
||||
mbedtls_mpi_lset(Z, 0);
|
||||
return 0;
|
||||
}
|
||||
if (x_bits == 1) {
|
||||
ret = mbedtls_mpi_copy(Z, Y);
|
||||
Z->s *= X->s;
|
||||
return ret;
|
||||
}
|
||||
if (y_bits == 1) {
|
||||
ret = mbedtls_mpi_copy(Z, X);
|
||||
Z->s *= Y->s;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Grow Z to result size early, avoid interim allocations */
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, z_words) );
|
||||
|
||||
/* If either factor is over 2048 bits, we can't use the standard hardware multiplier
|
||||
(it assumes result is double longest factor, and result is max 4096 bits.)
|
||||
|
||||
However, we can fail over to mod_mult for up to 4096 bits of result (modulo
|
||||
multiplication doesn't have the same restriction, so result is simply the
|
||||
number of bits in X plus number of bits in in Y.)
|
||||
*/
|
||||
if (hw_words * 32 > SOC_RSA_MAX_BIT_LEN/2) {
|
||||
if (z_words * 32 <= SOC_RSA_MAX_BIT_LEN) {
|
||||
/* Note: it's possible to use mpi_mult_mpi_overlong
|
||||
for this case as well, but it's very slightly
|
||||
slower and requires a memory allocation.
|
||||
*/
|
||||
return mpi_mult_mpi_failover_mod_mult(Z, X, Y, z_words);
|
||||
} else {
|
||||
/* Still too long for the hardware unit... */
|
||||
if (y_words > x_words) {
|
||||
return mpi_mult_mpi_overlong(Z, X, Y, y_words, z_words);
|
||||
} else {
|
||||
return mpi_mult_mpi_overlong(Z, Y, X, x_words, z_words);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, we can use the (faster) multiply hardware unit */
|
||||
esp_mpi_enable_hardware_hw_op();
|
||||
|
||||
esp_mpi_mul_mpi_hw_op(X, Y, hw_words);
|
||||
esp_mpi_read_result_hw_op(Z, z_words);
|
||||
|
||||
esp_mpi_disable_hardware_hw_op();
|
||||
|
||||
Z->s = X->s * Y->s;
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
#endif //ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
|
||||
|
||||
|
||||
/* Deal with the case when X & Y are too long for the hardware unit, by splitting one operand
|
||||
into two halves.
|
||||
|
||||
Y must be the longer operand
|
||||
|
||||
Slice Y into Yp, Ypp such that:
|
||||
Yp = lower 'b' bits of Y
|
||||
Ypp = upper 'b' bits of Y (right shifted)
|
||||
|
||||
Such that
|
||||
Z = X * Y
|
||||
Z = X * (Yp + Ypp<<b)
|
||||
Z = (X * Yp) + (X * Ypp<<b)
|
||||
|
||||
Note that this function may recurse multiple times, if both X & Y
|
||||
are too long for the hardware multiplication unit.
|
||||
*/
|
||||
static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t y_words, size_t z_words)
|
||||
{
|
||||
int ret = 0;
|
||||
mbedtls_mpi Ztemp;
|
||||
/* Rather than slicing in two on bits we slice on limbs (32 bit words) */
|
||||
const size_t words_slice = y_words / 2;
|
||||
/* Yp holds lower bits of Y (declared to reuse Y's array contents to save on copying) */
|
||||
const mbedtls_mpi Yp = {
|
||||
.p = Y->p,
|
||||
.n = words_slice,
|
||||
.s = Y->s
|
||||
};
|
||||
/* Ypp holds upper bits of Y, right shifted (also reuses Y's array contents) */
|
||||
const mbedtls_mpi Ypp = {
|
||||
.p = Y->p + words_slice,
|
||||
.n = y_words - words_slice,
|
||||
.s = Y->s
|
||||
};
|
||||
mbedtls_mpi_init(&Ztemp);
|
||||
|
||||
/* Get result Ztemp = Yp * X (need temporary variable Ztemp) */
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(&Ztemp, X, &Yp) );
|
||||
|
||||
/* Z = Ypp * Y */
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(Z, X, &Ypp) );
|
||||
|
||||
/* Z = Z << b */
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(Z, words_slice * 32) );
|
||||
|
||||
/* Z += Ztemp */
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi(Z, Z, &Ztemp) );
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&Ztemp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Special-case of mbedtls_mpi_mult_mpi(), where we use hardware montgomery mod
|
||||
multiplication to calculate an mbedtls_mpi_mult_mpi result where either
|
||||
A or B are >2048 bits so can't use the standard multiplication method.
|
||||
|
||||
Result (number of words, based on A bits + B bits) must still be less than 4096 bits.
|
||||
|
||||
This case is simpler than the general case modulo multiply of
|
||||
esp_mpi_mul_mpi_mod() because we can control the other arguments:
|
||||
|
||||
* Modulus is chosen with M=(2^num_bits - 1) (ie M=R-1), so output
|
||||
* Mprime and Rinv are therefore predictable as follows:
|
||||
isn't actually modulo anything.
|
||||
Mprime 1
|
||||
Rinv 1
|
||||
|
||||
(See RSA Accelerator section in Technical Reference for more about Mprime, Rinv)
|
||||
*/
|
||||
|
||||
static int mpi_mult_mpi_failover_mod_mult( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t z_words)
|
||||
{
|
||||
int ret;
|
||||
size_t hw_words = esp_mpi_hardware_words(z_words);
|
||||
|
||||
esp_mpi_enable_hardware_hw_op();
|
||||
|
||||
esp_mpi_mult_mpi_failover_mod_mult_hw_op(X, Y, hw_words );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, hw_words) );
|
||||
esp_mpi_read_result_hw_op(Z, hw_words);
|
||||
|
||||
Z->s = X->s * Y->s;
|
||||
cleanup:
|
||||
esp_mpi_disable_hardware_hw_op();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_MPI_MUL_MPI_ALT */
|
|
@ -1,29 +0,0 @@
|
|||
/************************ sha-private.h ************************/
|
||||
/***************** See RFC 6234 for details. *******************/
|
||||
#ifndef _SHA_PRIVATE__H
|
||||
#define _SHA_PRIVATE__H
|
||||
/*
|
||||
* These definitions are defined in FIPS 180-3, section 4.1.
|
||||
* Ch() and Maj() are defined identically in sections 4.1.1,
|
||||
* 4.1.2, and 4.1.3.
|
||||
*
|
||||
* The definitions used in FIPS 180-3 are as follows:
|
||||
*/
|
||||
|
||||
#ifndef USE_MODIFIED_MACROS
|
||||
#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
|
||||
#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#else /* USE_MODIFIED_MACROS */
|
||||
/*
|
||||
* The following definitions are equivalent and potentially faster.
|
||||
*/
|
||||
|
||||
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
|
||||
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
|
||||
|
||||
#endif /* USE_MODIFIED_MACROS */
|
||||
|
||||
#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))
|
||||
|
||||
#endif /* _SHA_PRIVATE__H */
|
||||
|
|
@ -1,358 +0,0 @@
|
|||
/**************************** sha.h ****************************/
|
||||
/***************** See RFC 6234 for details. *******************/
|
||||
/*
|
||||
Copyright (c) 2011 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and
|
||||
the following disclaimer.
|
||||
|
||||
- Redistributions in binary form 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.
|
||||
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor
|
||||
the names of specific contributors, may be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
#ifndef _SHA_H_
|
||||
#define _SHA_H_
|
||||
|
||||
/*
|
||||
* Description:
|
||||
* This file implements the Secure Hash Algorithms
|
||||
* as defined in the U.S. National Institute of Standards
|
||||
* and Technology Federal Information Processing Standards
|
||||
* Publication (FIPS PUB) 180-3 published in October 2008
|
||||
* and formerly defined in its predecessors, FIPS PUB 180-1
|
||||
* and FIP PUB 180-2.
|
||||
*
|
||||
* A combined document showing all algorithms is available at
|
||||
* http://csrc.nist.gov/publications/fips/
|
||||
* fips180-3/fips180-3_final.pdf
|
||||
*
|
||||
* The five hashes are defined in these sizes:
|
||||
* SHA-1 20 byte / 160 bit
|
||||
* SHA-224 28 byte / 224 bit
|
||||
* SHA-256 32 byte / 256 bit
|
||||
* SHA-384 48 byte / 384 bit
|
||||
* SHA-512 64 byte / 512 bit
|
||||
*
|
||||
* Compilation Note:
|
||||
* These files may be compiled with two options:
|
||||
* USE_32BIT_ONLY - use 32-bit arithmetic only, for systems
|
||||
* without 64-bit integers
|
||||
*
|
||||
* USE_MODIFIED_MACROS - use alternate form of the SHA_Ch()
|
||||
* and SHA_Maj() macros that are equivalent
|
||||
* and potentially faster on many systems
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
/*
|
||||
* If you do not have the ISO standard stdint.h header file, then you
|
||||
* must typedef the following:
|
||||
* name meaning
|
||||
* uint64_t unsigned 64-bit integer
|
||||
* uint32_t unsigned 32-bit integer
|
||||
* uint8_t unsigned 8-bit integer (i.e., unsigned char)
|
||||
* int_least16_t integer of >= 16 bits
|
||||
*
|
||||
* See stdint-example.h
|
||||
*/
|
||||
|
||||
#ifndef _SHA_enum_
|
||||
#define _SHA_enum_
|
||||
/*
|
||||
* All SHA functions return one of these values.
|
||||
*/
|
||||
enum {
|
||||
shaSuccess = 0,
|
||||
shaNull, /* Null pointer parameter */
|
||||
shaInputTooLong, /* input data too long */
|
||||
shaStateError, /* called Input after FinalBits or Result */
|
||||
shaBadParam /* passed a bad parameter */
|
||||
};
|
||||
#endif /* _SHA_enum_ */
|
||||
|
||||
/*
|
||||
* These constants hold size information for each of the SHA
|
||||
* hashing operations
|
||||
*/
|
||||
enum {
|
||||
SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64,
|
||||
SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128,
|
||||
SHA512_Message_Block_Size = 128,
|
||||
USHA_Max_Message_Block_Size = SHA512_Message_Block_Size,
|
||||
|
||||
SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32,
|
||||
SHA384HashSize = 48, SHA512HashSize = 64,
|
||||
USHAMaxHashSize = SHA512HashSize,
|
||||
|
||||
SHA1HashSizeBits = 160, SHA224HashSizeBits = 224,
|
||||
SHA256HashSizeBits = 256, SHA384HashSizeBits = 384,
|
||||
SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits
|
||||
};
|
||||
|
||||
/*
|
||||
* These constants are used in the USHA (Unified SHA) functions.
|
||||
*/
|
||||
typedef enum SHAversion {
|
||||
SHA1, SHA224, SHA256, SHA384, SHA512
|
||||
} SHAversion;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-1
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA1Context {
|
||||
uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
|
||||
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 512-bit message blocks */
|
||||
uint8_t Message_Block[SHA1_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA1Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-256
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA256Context {
|
||||
uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */
|
||||
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 512-bit message blocks */
|
||||
uint8_t Message_Block[SHA256_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA256Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-512
|
||||
* hashing operation.
|
||||
*/
|
||||
typedef struct SHA512Context {
|
||||
#ifdef USE_32BIT_ONLY
|
||||
uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */
|
||||
uint32_t Length[4]; /* Message length in bits */
|
||||
#else /* !USE_32BIT_ONLY */
|
||||
uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */
|
||||
uint64_t Length_High, Length_Low; /* Message length in bits */
|
||||
#endif /* USE_32BIT_ONLY */
|
||||
|
||||
int_least16_t Message_Block_Index; /* Message_Block array index */
|
||||
/* 1024-bit message blocks */
|
||||
uint8_t Message_Block[SHA512_Message_Block_Size];
|
||||
|
||||
int Computed; /* Is the hash computed?*/
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} SHA512Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-224
|
||||
* hashing operation. It uses the SHA-256 structure for computation.
|
||||
*/
|
||||
typedef struct SHA256Context SHA224Context;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-384
|
||||
* hashing operation. It uses the SHA-512 structure for computation.
|
||||
*/
|
||||
typedef struct SHA512Context SHA384Context;
|
||||
|
||||
/*
|
||||
* This structure holds context information for all SHA
|
||||
* hashing operations.
|
||||
*/
|
||||
typedef struct USHAContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
union {
|
||||
SHA1Context sha1Context;
|
||||
SHA224Context sha224Context; SHA256Context sha256Context;
|
||||
SHA384Context sha384Context; SHA512Context sha512Context;
|
||||
} ctx;
|
||||
|
||||
} USHAContext;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the HMAC
|
||||
* keyed-hashing operation.
|
||||
*/
|
||||
typedef struct HMACContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
int hashSize; /* hash size of SHA being used */
|
||||
int blockSize; /* block size of SHA being used */
|
||||
USHAContext shaContext; /* SHA context */
|
||||
unsigned char k_opad[USHA_Max_Message_Block_Size];
|
||||
/* outer padding - key XORd with opad */
|
||||
int Computed; /* Is the MAC computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
|
||||
} HMACContext;
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the HKDF
|
||||
* extract-and-expand Key Derivation Functions.
|
||||
*/
|
||||
typedef struct HKDFContext {
|
||||
int whichSha; /* which SHA is being used */
|
||||
HMACContext hmacContext;
|
||||
int hashSize; /* hash size of SHA being used */
|
||||
unsigned char prk[USHAMaxHashSize];
|
||||
/* pseudo-random key - output of hkdfInput */
|
||||
int Computed; /* Is the key material computed? */
|
||||
int Corrupted; /* Cumulative corruption code */
|
||||
} HKDFContext;
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
|
||||
/* SHA-1 */
|
||||
extern int SHA1Reset(SHA1Context *);
|
||||
extern int SHA1Input(SHA1Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA1FinalBits(SHA1Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA1Result(SHA1Context *,
|
||||
uint8_t Message_Digest[SHA1HashSize]);
|
||||
|
||||
/* SHA-224 */
|
||||
extern int SHA224Reset(SHA224Context *);
|
||||
extern int SHA224Input(SHA224Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA224FinalBits(SHA224Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA224Result(SHA224Context *,
|
||||
uint8_t Message_Digest[SHA224HashSize]);
|
||||
|
||||
/* SHA-256 */
|
||||
extern int SHA256Reset(SHA256Context *);
|
||||
extern int SHA256Input(SHA256Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA256FinalBits(SHA256Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA256Result(SHA256Context *,
|
||||
uint8_t Message_Digest[SHA256HashSize]);
|
||||
|
||||
/* SHA-384 */
|
||||
extern int SHA384Reset(SHA384Context *);
|
||||
extern int SHA384Input(SHA384Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA384FinalBits(SHA384Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA384Result(SHA384Context *,
|
||||
uint8_t Message_Digest[SHA384HashSize]);
|
||||
|
||||
/* SHA-512 */
|
||||
extern int SHA512Reset(SHA512Context *);
|
||||
extern int SHA512Input(SHA512Context *, const uint8_t *bytes,
|
||||
unsigned int bytecount);
|
||||
extern int SHA512FinalBits(SHA512Context *, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int SHA512Result(SHA512Context *,
|
||||
uint8_t Message_Digest[SHA512HashSize]);
|
||||
|
||||
/* Unified SHA functions, chosen by whichSha */
|
||||
extern int USHAReset(USHAContext *context, SHAversion whichSha);
|
||||
extern int USHAInput(USHAContext *context,
|
||||
const uint8_t *bytes, unsigned int bytecount);
|
||||
extern int USHAFinalBits(USHAContext *context,
|
||||
uint8_t bits, unsigned int bit_count);
|
||||
extern int USHAResult(USHAContext *context,
|
||||
uint8_t Message_Digest[USHAMaxHashSize]);
|
||||
extern int USHABlockSize(enum SHAversion whichSha);
|
||||
extern int USHAHashSize(enum SHAversion whichSha);
|
||||
extern int USHAHashSizeBits(enum SHAversion whichSha);
|
||||
extern const char *USHAHashName(enum SHAversion whichSha);
|
||||
|
||||
/*
|
||||
* HMAC Keyed-Hashing for Message Authentication, RFC 2104,
|
||||
* for all SHAs.
|
||||
* This interface allows a fixed-length text input to be used.
|
||||
*/
|
||||
extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */
|
||||
const unsigned char *text, /* pointer to data stream */
|
||||
int text_len, /* length of data stream */
|
||||
const unsigned char *key, /* pointer to authentication key */
|
||||
int key_len, /* length of authentication key */
|
||||
uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
|
||||
|
||||
/*
|
||||
* HMAC Keyed-Hashing for Message Authentication, RFC 2104,
|
||||
* for all SHAs.
|
||||
* This interface allows any length of text input to be used.
|
||||
*/
|
||||
extern int hmacReset(HMACContext *context, enum SHAversion whichSha,
|
||||
const unsigned char *key, int key_len);
|
||||
extern int hmacInput(HMACContext *context, const unsigned char *text,
|
||||
int text_len);
|
||||
extern int hmacFinalBits(HMACContext *context, uint8_t bits,
|
||||
unsigned int bit_count);
|
||||
extern int hmacResult(HMACContext *context,
|
||||
uint8_t digest[USHAMaxHashSize]);
|
||||
|
||||
/*
|
||||
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
|
||||
* RFC 5869, for all SHAs.
|
||||
*/
|
||||
extern int hkdf(SHAversion whichSha, const unsigned char *salt,
|
||||
int salt_len, const unsigned char *ikm, int ikm_len,
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[ ], int okm_len);
|
||||
extern int hkdfExtract(SHAversion whichSha, const unsigned char *salt,
|
||||
int salt_len, const unsigned char *ikm,
|
||||
int ikm_len, uint8_t prk[USHAMaxHashSize]);
|
||||
extern int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
|
||||
int prk_len, const unsigned char *info,
|
||||
int info_len, uint8_t okm[ ], int okm_len);
|
||||
|
||||
/*
|
||||
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
|
||||
* RFC 5869, for all SHAs.
|
||||
* This interface allows any length of text input to be used.
|
||||
*/
|
||||
extern int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
|
||||
const unsigned char *salt, int salt_len);
|
||||
extern int hkdfInput(HKDFContext *context, const unsigned char *ikm,
|
||||
int ikm_len);
|
||||
extern int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
|
||||
unsigned int ikm_bit_count);
|
||||
extern int hkdfResult(HKDFContext *context,
|
||||
uint8_t prk[USHAMaxHashSize],
|
||||
const unsigned char *info, int info_len,
|
||||
uint8_t okm[USHAMaxHashSize], int okm_len);
|
||||
#endif /* _SHA_H_ */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue