manuelbl / ttn-esp32

The Things Network device library for ESP32 (ESP-IDF) and SX127x based devices
MIT License
303 stars 64 forks source link

Feature request: AT+MAC? #3

Closed jpmeijers closed 5 years ago

jpmeijers commented 5 years ago

The ESP32 has a unique hardware wifi MAC address. It would be useful to use this MAC as the basis for a self-generated Dev-EUI. We are doing a similar thing with Raspberry Pi base LoRaWAN gateway - take the ethernet MAC, split it in half, and add FFFF or FFFE in the middle. The result is a valid self-assigned EUI.

My request is two-fold:

  1. Make is possible to use the MAC-based EUI as default, so that the same App EUI and App Key can be programmed to all devices.
  2. Add the ability to read out the device MAC address via AT commands. This can be used to make a spreadsheet of MAC, Dev EUI, App EUI, App Key values. The MAC could also be used to generate a MAC-based EUI that is then registered on TTN.
manuelbl commented 5 years ago

That's an interesting idea. I will investigate it.

cyberman54 commented 5 years ago

You may look here how to do it:

https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/lorawan.cpp

jpmeijers commented 5 years ago

Watch out. That repo is doing it incorrectly. They are prefixing the MAC with FFFE, while in fact it should be inserted in the middle: https://community.cisco.com/t5/network-architecture-documents/understanding-ipv6-eui-64-bit-address/ta-p/3116953

manuelbl commented 5 years ago

Using the MAC to generate the device EUI only makes sense if the same app EUI and app key are used on a batch of devices. However, using the same app key on several devices is insecure as it allows certain attacks. As an example: if you have access to one device of a batch, you can easily intercept and inject LoRa traffic of other devices if they have WiFi turn on.

Would you agree that the feature requires a security warning?

jpmeijers commented 5 years ago

Using the same App EUI and App Key on all devices definitely needs a security warning.

I however will still follow the normal registration procedure to get a unique App Key for the device, but I won't use the Dev EUI TTN generated, but rather the one we generated ourselves based on the MAC. This helps identifying a device when it is out there in the field.

manuelbl commented 5 years ago

An initial implementation of the feature can be found in the mac_as_deveui branch. The sample application is in examples/mac_address.

The command for displaying the MAC address (AT+MAC?) is certainly ok. But I'm less sure about the generated device EUI. Is it a good use case? Is there a demand for it?

The device EUI is generated like so:

  1. The MAC address is retrieved, e.g. A0:B1:C2:01:02:03.
  2. FFFE is inserted in the middle. So the EUI becomes A0:B1:C2:FF:FE:01:02:03.

The MAC address and EUI are in the usual LSB order (least significant bit and byte first). However, in the TTN console, it must be entered using most significant byte first, i.e. as 03 02 01 FE FF C2 B1 A0. It's quite confusing. I never understood why TTN uses MSB.

Have a look at it and give me feedback.

jpmeijers commented 5 years ago

I think we might have the LSB/MSB thing the wrong way around.

Example

My ESP32's MAC: D8:A0:1D:40:4E:54 The Espressif OUI: D8:A0:1D According to here we should insert FF:FE between the OUI and NIC specific parts: D8:A0:1D:FF:FE:40:4E:54

So on TTN we should type in D8 A0 1D FF FE 40 4E 54, which is the normal MSB representation. LMIC wants the EUI in LSB, which according to me is the non-standard form. LMIC therefore gets: 54 4E 40 FE FF 1D A0 D8.

So to do this correctly, I would suggest we change the provisioning_from_mac function to be like this:

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[7] = mac[0];
    global_dev_eui[6] = mac[1];
    global_dev_eui[5] = mac[2];
    global_dev_eui[4] = 0xff;
    global_dev_eui[3] = 0xfe;
    global_dev_eui[2] = mac[3];
    global_dev_eui[1] = mac[4];
    global_dev_eui[0] = mac[5];
     return provisioning_decode(false, NULL, app_eui, app_key);
}

I am not sure if we should invert the "locally administered bit". Nobody else does this, but if we want to, it as easy as changing one line to: global_dev_eui[7] = mac[0] ^ 0x02;

jpmeijers commented 5 years ago

Filed #4 to fix this and add a few features.

manuelbl commented 5 years ago

Are you sure about the LSB/MSB mix-up? LMIC treats the EUIs neither as LSB nor as MSB but more like a string. It copies them byte by byte in the given order into the join request.

And I can't find any reference where it says the EUI is to be treated as a 64 bit number. Whatever I found only describes an array of 8 octets (bytes).

I think a MAC address like D8:A0:1D:40:4E:54 should become the EUI D8:A0:1D:FF:FE:40:4E:54 and then be copied into the join request byte by byte in this order. That's what my code currently does.

But then again: I don't fully understand all the details of LoRA. So I'm open for input.

jpmeijers commented 5 years ago

If I recall correctly it is LoRaWAN that wants the EUIs in lsb (reversed) order in the LoRa payload. The most modules does this reversing in firmware. This is also how the most things work: MSB in memory and code, but LSB on the wire (air).

On Sun, 30 Sep 2018, 11:38 AM Manuel Bl., notifications@github.com wrote:

Are you sure about the LSB/MSB mix-up? LMIC treats the EUIs neither as LSB nor as MSB but more like a string. It copies them byte by byte in the given order into the join request.

And I can't find any reference where it says the EUI is to be treated as a 64 bit number. Whatever I found only describes an array of 8 octets (bytes).

I think a MAC address like D8:A0:1D:40:4E:54 should become the EUI D8:A0:1D:FF:FE:40:4E:54 and then be copied into the join request byte by byte in this order. That's what my code currently does.

But then again: I don't fully understand all the details of LoRA. So I'm open for input.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/manuelbl/ttn-esp32/issues/3#issuecomment-425707973, or mute the thread https://github.com/notifications/unsubscribe-auth/AA54NpRbJ_9IGNH--wXmQrWhtA52ksJhks5ugJEcgaJpZM4WrBMH .

manuelbl commented 5 years ago

The LoRaWAN specification says:

EUI are 8 bytes multi-octet fields and are transmitted as little endian.

That's a bit confusing for me as EUIs are octet sequence and therefore have no least or most significant byte. I assume it means that the left most byte is transmitted first (i.e. the byte sequence is reversed).

So I'll proceed as you have proposed.

manuelbl commented 5 years ago

I've merged the push request into the mac_as_deveui branch. For the provisioning using the hardware EUI, I've introduced a separate command: AT+PROVM=xxx-xxxxxx. The parameter overloading seemed too complex to explain and use.

Please check it out and let me know if it works for you. Then I'll merge it into the master branch and update the documentation.

jpmeijers commented 5 years ago

Ok, I've tested the latest mac_as_deveui branch. Everything works as expected, including AT+HWEUI? and AT+PROVM=.... You're welcome to merge.

manuelbl commented 5 years ago

Merged, and documentation updated.