Generate device EUI from MAC

This commit is contained in:
Manuel Bleichenbacher 2018-09-17 22:50:15 +02:00
parent 5cd2c7bac4
commit 302509d096
8 changed files with 184 additions and 4 deletions

View File

@ -4,6 +4,8 @@
"config.h": "c",
"sdkconfig.h": "c",
"oslmic.h": "c",
"hal_esp32.h": "c"
"hal_esp32.h": "c",
"esp_log.h": "c",
"nvs_flash.h": "c"
}
}

View File

@ -0,0 +1,3 @@
PROJECT_NAME := mac_address
include $(IDF_PATH)/make/project.mk

View File

View File

@ -0,0 +1,96 @@
/*******************************************************************************
*
* ttn-esp32 - The Things Network device library for ESP-IDF / SX127x
*
* Copyright (c) 2018 Manuel Bleichenbacher
*
* Licensed under MIT License
* https://opensource.org/licenses/MIT
*
* Sample program showing how to provision the keys from the built-in MAC.
*******************************************************************************/
#include "freertos/FreeRTOS.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "TheThingsNetwork.h"
// NOTE:
// The LoRaWAN frequency and the radio chip must be configured by running 'make menuconfig'.
// Go to Components / The Things Network, select the appropriate values and save.
// Copy the below two lines from the bottom
// of your device's overview page in the TTN console.
const char *appEui = "????????????????";
const char *appKey = "????????????????????????????????";
// Pins and other resources
#define TTN_SPI_HOST HSPI_HOST
#define TTN_SPI_DMA_CHAN 1
#define TTN_PIN_SPI_SCLK 5
#define TTN_PIN_SPI_MOSI 27
#define TTN_PIN_SPI_MISO 19
#define TTN_PIN_NSS 18
#define TTN_PIN_RXTX TTN_NOT_CONNECTED
#define TTN_PIN_RST TTN_NOT_CONNECTED
#define TTN_PIN_DIO0 26
#define TTN_PIN_DIO1 33
static TheThingsNetwork ttn;
const unsigned TX_INTERVAL = 30;
static uint8_t msgData[] = "Hello, world";
void sendMessages(void* pvParameter)
{
while (1) {
printf("Sending message...\n");
TTNResponseCode res = ttn.transmitMessage(msgData, sizeof(msgData) - 1);
printf(res == kTTNSuccessfulTransmission ? "Message sent.\n" : "Transmission failed.\n");
vTaskDelay(TX_INTERVAL * 1000 / portTICK_PERIOD_MS);
}
}
extern "C" void app_main(void)
{
esp_err_t err;
// Initialize the GPIO ISR handler service
err = gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
ESP_ERROR_CHECK(err);
// Initialize the NVS (non-volatile storage) for saving and restoring the keys
err = nvs_flash_init();
ESP_ERROR_CHECK(err);
// Initialize SPI bus
spi_bus_config_t spi_bus_config;
spi_bus_config.miso_io_num = TTN_PIN_SPI_MISO;
spi_bus_config.mosi_io_num = TTN_PIN_SPI_MOSI;
spi_bus_config.sclk_io_num = TTN_PIN_SPI_SCLK;
spi_bus_config.quadwp_io_num = -1;
spi_bus_config.quadhd_io_num = -1;
spi_bus_config.max_transfer_sz = 0;
err = spi_bus_initialize(TTN_SPI_HOST, &spi_bus_config, TTN_SPI_DMA_CHAN);
ESP_ERROR_CHECK(err);
// Configure the SX127x pins
ttn.configurePins(TTN_SPI_HOST, TTN_PIN_NSS, TTN_PIN_RXTX, TTN_PIN_RST, TTN_PIN_DIO0, TTN_PIN_DIO1);
ttn.provisionWithMAC(appEui, appKey);
ttn.startProvisioningTask();
printf("Joining...\n");
if (ttn.join())
{
printf("Joined.\n");
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, NULL);
}
else
{
printf("Join failed. Goodbye\n");
}
}

View File

@ -104,6 +104,32 @@ public:
*/
bool provision(const char *devEui, const char *appEui, const char *appKey);
/**
* @brief Sets the information needed to activate the device via OTAA, using the MAC to generate the device EUI
* and without actually activating.
*
* The generated device EUI and the provided app EUI and app key are saved in non-volatile memory. Before
* this function is called, 'nvs_flash_init' must have been called once.
*
* The device EUI is generated by retrieving the ESP32's WiFi MAC address and expanding it into a device EUI
* by adding FFFE in the middle. So the MAC address A0:B1:C2:01:02:03 becomes the EUI A0:B1:C2:FF:FE:01:02:03.
* The TTN console requires the device EUI in MSB format, so it has to be reversed and entered as
* "03 02 01 FE FF C2 B1 A0".
*
* Generating the device EUI from the MAC address allows to flash the same app EUI and app key to a batch of
* devices. However, using the same app key for multiple devices is insecure. Only use this approach if
* it is okay for that the LoRa communication of your application can easily be intercepted and that
* forged data can be injected.
*
* Call join() without arguments to activate.
*
* @param appEui Application EUI of the device (16 character string with hexadecimal data)
* @param appKey App Key of the device (32 character string with hexadecimal data)
* @return true if the provisioning was successful
* @return false if the provisioning failed
*/
bool provisionWithMAC(const char *appEui, const char *appKey);
/**
* @brief Start task that listens on configured UART for provisioning commands.
*

View File

@ -86,6 +86,14 @@ bool TheThingsNetwork::provision(const char *devEui, const char *appEui, const c
return provisioning_save_keys();
}
bool TheThingsNetwork::provisionWithMAC(const char *appEui, const char *appKey)
{
if (!provisioning_from_mac(appEui, appKey))
return false;
return provisioning_save_keys();
}
void TheThingsNetwork::startProvisioningTask()
{
#if !defined(CONFIG_TTN_PROVISION_UART_NONE)

View File

@ -14,6 +14,7 @@
#include "driver/uart.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "provisioning.h"
#include "lmic.h"
@ -28,6 +29,7 @@ static const char *NVS_FLASH_KEY_DEV_EUI = "devEui";
static const char *NVS_FLASH_KEY_APP_EUI = "appEui";
static const char *NVS_FLASH_KEY_APP_KEY = "appKey";
static bool provisioning_decode(bool incl_dev_eui, const char *dev_eui, const char *app_eui, const char *app_key);
static void provisioning_task(void* pvParameter);
static void provisioning_add_line_data(int numBytes);
static void provisioning_detect_line_end(int start_at);
@ -195,6 +197,7 @@ void provisioning_process_line()
// Expected format:
// AT+PROV?
// AT+PROV=hex16-hex16-hex32
// AT+MAC?
if (strcmp(line_buf, "AT+PROV?") == 0)
{
uint8_t binbuf[8];
@ -233,6 +236,22 @@ void provisioning_process_line()
is_ok = false;
}
}
else if (strcmp(line_buf, "AT+MAC?") == 0)
{
uint8_t mac[6];
char hexbuf[12];
esp_err_t err = esp_efuse_mac_get_default(mac);
ESP_ERROR_CHECK(err);
bin_to_hex_str(mac, 6, hexbuf);
for (int i = 0; i < 12; i += 2) {
if (i > 0)
uart_write_bytes(UART_NUM, ":", 1);
uart_write_bytes(UART_NUM, hexbuf + i, 2);
}
uart_write_bytes(UART_NUM, "\r\n", 2);
}
else if (strcmp(line_buf, "AT+PROVQ") == 0)
{
quit_task = true;
@ -276,17 +295,41 @@ bool provisioning_have_keys()
}
bool provisioning_decode_keys(const char *dev_eui, const char *app_eui, const char *app_key)
{
return provisioning_decode(true, dev_eui, app_eui, app_key);
}
bool provisioning_from_mac(const char *app_eui, const char *app_key)
{
uint8_t mac[6];
esp_err_t err = esp_efuse_mac_get_default(mac);
ESP_ERROR_CHECK(err);
global_dev_eui[0] = mac[0];
global_dev_eui[1] = mac[1];
global_dev_eui[2] = mac[2];
global_dev_eui[3] = 0xff;
global_dev_eui[4] = 0xfe;
global_dev_eui[5] = mac[3];
global_dev_eui[6] = mac[4];
global_dev_eui[7] = mac[5];
return provisioning_decode(false, NULL, app_eui, app_key);
}
bool provisioning_decode(bool incl_dev_eui, const char *dev_eui, const char *app_eui, const char *app_key)
{
uint8_t buf_dev_eui[8];
uint8_t buf_app_eui[8];
uint8_t buf_app_key[16];
if (strlen(dev_eui) != 16 || !hex_str_to_bin(dev_eui, buf_dev_eui, 8))
if (incl_dev_eui && (strlen(dev_eui) != 16 || !hex_str_to_bin(dev_eui, buf_dev_eui, 8)))
{
ESP_LOGW(TAG, "Invalid device EUI: %s", dev_eui);
return false;
}
if (incl_dev_eui)
swap_bytes(buf_dev_eui, 8);
if (strlen(app_eui) != 16 || !hex_str_to_bin(app_eui, buf_app_eui, 8))
@ -303,6 +346,7 @@ bool provisioning_decode_keys(const char *dev_eui, const char *app_eui, const ch
return false;
}
if (incl_dev_eui)
memcpy(global_dev_eui, buf_dev_eui, sizeof(global_dev_eui));
memcpy(global_app_eui, buf_app_eui, sizeof(global_app_eui));
memcpy(global_app_key, buf_app_key, sizeof(global_app_key));

View File

@ -24,6 +24,7 @@ extern "C" {
void provisioning_start_task();
bool provisioning_have_keys();
bool provisioning_decode_keys(const char *dev_eui, const char *app_eui, const char *app_key);
bool provisioning_from_mac(const char *app_eui, const char *app_key);
bool provisioning_save_keys();
bool provisioning_restore_keys(bool silent);