1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

gnrc/lorawan: add support for GNRC LoRaWAN 1.1

This commit is contained in:
Ollrogge 2022-09-29 11:25:56 +02:00
parent 3f8f6e929d
commit 12a4e1c1ec
19 changed files with 1633 additions and 460 deletions

View File

@ -14,6 +14,8 @@ USEMODULE += auto_init_gnrc_netif
# Add support for GNRC LoRaWAN
USEMODULE += gnrc_lorawan
# Add support for GNRC LoRaWAN 1.1
# USEMODULE += gnrc_lorawan_1_1
# Use GNRC pktdump to print downlink messages
USEMODULE += gnrc_pktdump
@ -55,7 +57,9 @@ ifndef CONFIG_KCONFIG_USEMODULE_LORAWAN
CFLAGS += -DCONFIG_GNRC_NETIF_LORAWAN_NETIF_HDR
CFLAGS += -DCONFIG_LORAMAC_APP_KEY_DEFAULT=\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"
CFLAGS += -DCONFIG_LORAMAC_NWK_KEY_DEFAULT=\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"
CFLAGS += -DCONFIG_LORAMAC_APP_EUI_DEFAULT=\"BBBBBBBBBBBBBBBB\"
CFLAGS += -DCONFIG_LORAMAC_JOIN_EUI_DEFAULT=\"BBBBBBBBBBBBBBBB\"
CFLAGS += -DCONFIG_LORAMAC_DEV_EUI_DEFAULT=\"CCCCCCCCCCCCCCCC\"
# For TTN, It's necessary to set the RX2 DR to 3 in EU_868 region

View File

@ -89,6 +89,7 @@ PSEUDOMODULES += gnrc_ipv6_nib_dns
PSEUDOMODULES += gnrc_ipv6_nib_rio
PSEUDOMODULES += gnrc_ipv6_nib_router
PSEUDOMODULES += gnrc_ipv6_nib_rtr_adv_pio_cb
PSEUDOMODULES += gnrc_lorawan_1_1
PSEUDOMODULES += gnrc_netdev_default
PSEUDOMODULES += gnrc_neterr
PSEUDOMODULES += gnrc_netapi_callbacks

View File

@ -199,10 +199,10 @@ void gnrc_lorawan_timeout_cb(gnrc_lorawan_t *mac);
* @brief Init GNRC LoRaWAN
*
* @param[in] mac pointer to the MAC descriptor
* @param[in] nwkskey buffer to store the NwkSKey. Should be at least 16 bytes long
* @param[in] appskey buffer to store the AppsKey. Should be at least 16 bytes long
* @param[in] joineui pointer to Join EUI
* @param[in] ctx pointer to LoRaWAN context
*/
void gnrc_lorawan_init(gnrc_lorawan_t *mac, uint8_t *nwkskey, uint8_t *appskey);
void gnrc_lorawan_init(gnrc_lorawan_t *mac, uint8_t *joineui, const gnrc_lorawan_key_ctx_t *ctx);
/**
* @brief Perform a MLME request

View File

@ -50,23 +50,133 @@ extern "C" {
* @brief GNRC LoRaWAN interface descriptor
*/
typedef struct {
uint8_t nwkskey[LORAMAC_NWKSKEY_LEN]; /**< network SKey buffer */
uint8_t appskey[LORAMAC_APPSKEY_LEN]; /**< App SKey buffer */
uint8_t appkey[LORAMAC_APPKEY_LEN]; /**< App Key buffer */
uint8_t deveui[LORAMAC_DEVEUI_LEN]; /**< Device EUI buffer */
uint8_t appeui[LORAMAC_APPEUI_LEN]; /**< App EUI buffer */
gnrc_lorawan_t mac; /**< gnrc lorawan mac descriptor */
ztimer_t timer; /**< General purpose timer */
ztimer_t backoff_timer; /**< Backoff timer */
uint8_t flags; /**< flags for the LoRaWAN interface */
uint8_t demod_margin; /**< value of last demodulation margin */
uint8_t num_gateways; /**< number of gateways of last link check */
uint8_t datarate; /**< LoRaWAN datarate for the next transmission */
uint8_t port; /**< LoRaWAN port for the next transmission */
uint8_t ack_req; /**< Request ACK in the next transmission */
uint8_t otaa; /**< whether the next transmission is OTAA or not */
uint8_t appskey[LORAMAC_APPSKEY_LEN]; /**< App SKey buffer */
uint8_t fnwksintkey[LORAMAC_FNWKSINTKEY_LEN]; /**< Forwarding Network session integrity key buffer */
uint8_t nwkkey[LORAMAC_NWKKEY_LEN]; /**< Network key buffer. Mapped to AppKey if LoRaWAN 1.0x */
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
uint8_t appkey[LORAMAC_APPKEY_LEN]; /**< App Key buffer. The AppKey used in LoRaWAN 1.0x has been mapped to the nwkkey in LoRaWAN 1.1x */
uint8_t snwksintkey[LORAMAC_SNWKSINTKEY_LEN]; /**< Serving Network session integrity key buffer */
uint8_t nwksenckey[LORAMAC_NWKSENCKEY_LEN]; /**< Network session encryption key buffer */
uint8_t jsintkey[LORAMAC_JSINTKEY_LEN]; /**< Join session integrity key buffer */
uint8_t jsenckey[LORAMAC_JSENCKEY_LEN]; /**< Join session encryption key buffer */
#endif
uint8_t deveui[LORAMAC_DEVEUI_LEN]; /**< Device EUI buffer */
uint8_t joineui[LORAMAC_JOINEUI_LEN]; /**< Join EUI buffer */
gnrc_lorawan_t mac; /**< gnrc lorawan mac descriptor */
ztimer_t timer; /**< General purpose timer */
ztimer_t backoff_timer; /**< Backoff timer */
uint8_t flags; /**< flags for the LoRaWAN interface */
uint8_t demod_margin; /**< value of last demodulation margin */
uint8_t num_gateways; /**< number of gateways of last link check */
uint8_t datarate; /**< LoRaWAN datarate for the next transmission */
uint8_t port; /**< LoRaWAN port for the next transmission */
uint8_t ack_req; /**< Request ACK in the next transmission */
uint8_t otaa; /**< whether the next transmission is OTAA or not */
} gnrc_netif_lorawan_t;
/**
* @brief Set the app key in the interface descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] lw_netif pointer to the interface descriptor
* @param[in] key pointer to the app key
* @param[in] len length of the app key
* @return 0 on success
* @return <0 on failure
*/
static inline int gnrc_netif_lorawan_set_appkey(gnrc_netif_lorawan_t *lw_netif, const uint8_t *key,
size_t len)
{
(void)lw_netif;
(void)key;
(void)len;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
if (sizeof(lw_netif->appkey) < len) {
return -1;
}
memcpy(lw_netif->appkey, key, len);
#endif
return 0;
}
/**
* @brief Get the app key from the interface descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] lw_netif pointer to the interface descriptor
* @return pointer to the app key
*/
static inline uint8_t * gnrc_netif_lorawan_get_appkey(gnrc_netif_lorawan_t *lw_netif)
{
(void)lw_netif;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
return lw_netif->appkey;
#endif
return NULL; /* NO-OP */
}
/**
* @brief Set the serving network session integrity key in the interface descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] lw_netif pointer to the interface descriptor
* @param[in] key pointer to the serving network session integrity key
* @param[in] len length of serving network session integrity key
* @return 0 on success
* @return <0 on failure
*/
static inline int gnrc_netif_lorawan_set_snwksintkey(gnrc_netif_lorawan_t *lw_netif,
const uint8_t *key, size_t len)
{
(void)lw_netif;
(void)key;
(void)len;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
if (sizeof(lw_netif->snwksintkey) < len) {
return -1;
}
memcpy(lw_netif->snwksintkey, key, len);
#endif
return 0;
}
/**
* @brief Set the network session encryption key in the interface descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] lw_netif pointer to the interface descriptor
* @param[in] key pointer to the network session encryption key
* @param[in] len length of network session encryption key
* @return 0 on success
* @return <0 on failure
*/
static inline int gnrc_netif_lorawan_set_nwksenckey(gnrc_netif_lorawan_t *lw_netif,
const uint8_t *key, size_t len)
{
(void)lw_netif;
(void)key;
(void)len;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
if (sizeof(lw_netif->nwksenckey) < len) {
return -1;
}
memcpy(lw_netif->nwksenckey, key, len);
#endif
return 0;
}
#ifdef __cplusplus
}
#endif

View File

@ -46,6 +46,15 @@ extern "C" {
#define CONFIG_LORAMAC_DEV_EUI_DEFAULT "0000000000000000"
#endif
/**
* @brief Default join EUI
*
* 8 bytes key, required for join procedure
*/
#ifndef CONFIG_LORAMAC_JOIN_EUI_DEFAULT
#define CONFIG_LORAMAC_JOIN_EUI_DEFAULT "0000000000000000"
#endif
/**
* @brief Default application EUI
*
@ -64,6 +73,15 @@ extern "C" {
#define CONFIG_LORAMAC_APP_KEY_DEFAULT "00000000000000000000000000000000"
#endif
/**
* @brief Default network key
*
* 16 bytes key, required for join procedure
*/
#ifndef CONFIG_LORAMAC_NWK_KEY_DEFAULT
#define CONFIG_LORAMAC_NWK_KEY_DEFAULT "00000000000000000000000000000000"
#endif
/**
* @brief Default application session key
*
@ -82,6 +100,33 @@ extern "C" {
#define CONFIG_LORAMAC_NWK_SKEY_DEFAULT "00000000000000000000000000000000"
#endif
/**
* @brief Default network session integrity key
*
* 16 bytes key, required for join procedure
*/
#ifndef CONFIG_LORAMAC_FNWKSINT_KEY_DEFAULT
#define CONFIG_LORAMAC_FNWKSINT_KEY_DEFAULT "00000000000000000000000000000000"
#endif
/**
* @brief Default serving network session integrity key
*
* 16 bytes key, required for join procedure
*/
#ifndef CONFIG_LORAMAC_SNWKSINT_KEY_DEFAULT
#define CONFIG_LORAMAC_SNWKSINT_KEY_DEFAULT "00000000000000000000000000000000"
#endif
/**
* @brief Default network session encryption key
*
* 16 bytes key, required for join procedure
*/
#ifndef CONFIG_LORAMAC_NWKSENC_KEY_DEFAULT
#define CONFIG_LORAMAC_NWKSENC_KEY_DEFAULT "00000000000000000000000000000000"
#endif
/**
* @brief Default device address
*/
@ -514,11 +559,21 @@ extern "C" {
*/
#define LORAMAC_APPEUI_LEN (8U)
/**
* @brief Join EUI length in bytes
*/
#define LORAMAC_JOINEUI_LEN (8U)
/**
* @brief Application key length in bytes
*/
#define LORAMAC_APPKEY_LEN (16U)
/**
* @brief Network key length in bytes
*/
#define LORAMAC_NWKKEY_LEN (16U)
/**
* @brief Application session key length in bytes
*/
@ -529,6 +584,36 @@ extern "C" {
*/
#define LORAMAC_NWKSKEY_LEN (16U)
/**
* @brief Forwarding Network session integrity key length in bytes
*/
#define LORAMAC_FNWKSINTKEY_LEN (16U)
/**
* @brief Serving Network session integrity key length in bytes
*/
#define LORAMAC_SNWKSINTKEY_LEN (16U)
/**
* @brief Network session encryption key length in bytes
*/
#define LORAMAC_NWKSENCKEY_LEN (16U)
/**
* @brief Join session integrity key length in bytes
*/
#define LORAMAC_JSINTKEY_LEN (16U)
/**
* @brief Join session encryption key length in bytes
*/
#define LORAMAC_JSENCKEY_LEN (16U)
/**
* @brief Network session encryption key length in bytes
*/
#define LORAMAC_JSINTKEY_LEN (16U)
/**
* @brief Minimum port value
*/
@ -544,6 +629,11 @@ extern "C" {
*/
#define LORAMAC_APP_NONCE_LEN (3U)
/**
* @brief Join nonce length in bytes
*/
#define LORAMAC_JOIN_NONCE_LEN (3U)
/**
* @brief Network ID length in bytes
*/

View File

@ -44,6 +44,9 @@
#define LORAWAN_HDR_FOPTS_LEN_MASK (0x0F) /**< Frame options mask */
#define LORAWAN_HDR_FOPTS_LEN_POS (0U) /**< Frame options position */
#define LORAWAN_JA_HDR_OPTNEG_MASK (0x80) /**< OptNeg bit mask */
#define LORAWAN_JA_HDR_OPTNEG_POS (7U) /**< OptNeg bit position */
#ifdef __cplusplus
extern "C" {
#endif
@ -92,7 +95,7 @@ typedef struct __attribute__((packed)) {
*/
typedef struct __attribute__((packed)) {
uint8_t mt_maj; /**< mtype and major version holder */
le_uint64_t app_eui; /**< application EUI */
le_uint64_t join_eui; /**< join EUI. Mapped to app EUI if LoRaWAN 1.0x */
le_uint64_t dev_eui; /**< device EUI */
le_uint16_t dev_nonce; /**< device nonce */
le_uint32_t mic; /**< message integrity code */
@ -103,7 +106,7 @@ typedef struct __attribute__((packed)) {
*/
typedef struct __attribute__((packed)) {
uint8_t mt_maj; /**< mtype and major version holder */
uint8_t app_nonce[LORAMAC_APP_NONCE_LEN]; /**< application nonce */
uint8_t join_nonce[LORAMAC_JOIN_NONCE_LEN]; /**< join nonce. Mapped to application nonce if LoRaWAN 1.0x */
uint8_t net_id[LORAMAC_NETWORK_ID_LEN]; /**< network id */
uint8_t dev_addr[LORAMAC_DEVADDR_LEN]; /**< device address */
uint8_t dl_settings; /**< downlink settings */
@ -278,6 +281,18 @@ static inline uint8_t lorawan_hdr_get_frame_opts_len(lorawan_hdr_t *hdr)
return (hdr->fctrl & LORAWAN_HDR_FOPTS_LEN_MASK) >> LORAWAN_HDR_FOPTS_LEN_POS;
}
/**
* @brief Get LoRaWAN join accept message OptNeg bit
*
* @param[in] ja_hdr Join accept message header
*
* @return value of the OptNeg bit
*/
static inline bool lorawan_ja_hdr_get_optneg(lorawan_join_accept_t *ja_hdr)
{
return (ja_hdr->dl_settings & LORAWAN_JA_HDR_OPTNEG_MASK) >> LORAWAN_JA_HDR_OPTNEG_POS;
}
#ifdef __cplusplus
}
#endif

View File

@ -584,20 +584,52 @@ typedef enum {
*/
NETOPT_LORAWAN_APPEUI,
/**
* @brief (uint8_t*) LoRaWAN join EUI (8 bytes length)
*/
NETOPT_LORAWAN_JOINEUI,
/**
* @brief (uint8_t*) LoRaWAN application key (16 bytes length)
*/
NETOPT_LORAWAN_APPKEY,
/**
* @brief (uint8_t*) LoRaWAN network key (16 bytes length)
*/
NETOPT_LORAWAN_NWKKEY,
/**
* @brief (uint8_t*) LoRaWAN network session key (16 bytes length)
*/
NETOPT_LORAWAN_NWKSKEY,
/**
* @brief (uint8_t*) LoRaWAN application session key (16 bytes length)
*/
NETOPT_LORAWAN_APPSKEY,
/**
* @brief (uint8_t*) LoRaWAN forwarding network session integrity key (16 bytes length)
*
* This key is only valid when using LoRaWAN 1.1x.
*/
NETOPT_LORAWAN_FNWKSINTKEY,
/**
* @brief (uint8_t*) LoRaWAN serving network session integrity key (16 bytes length)
*
* This key is only valid when using LoRaWAN 1.1x.
*/
NETOPT_LORAWAN_SNWKSINTKEY,
/**
* @brief (uint8_t*) LoRaWAN network session encryption key buffer (16 bytes length)
*
* This key is only valid when using LoRaWAN 1.1x.
*/
NETOPT_LORAWAN_NWKSENCKEY,
/**
* @brief (uint8_t) LoRaWAN device class (A, B, C)
* - LoRaWAN: @ref loramac_class_t

View File

@ -94,9 +94,14 @@ static const char *_netopt_strmap[] = {
[NETOPT_CHECKSUM] = "NETOPT_CHECKSUM",
[NETOPT_PHY_BUSY] = "NETOPT_PHY_BUSY",
[NETOPT_LORAWAN_APPEUI] = "NETOPT_LORAWAN_APPEUI",
[NETOPT_LORAWAN_JOINEUI] = "NETOPT_LORAWAN_JOINEUI",
[NETOPT_LORAWAN_APPKEY] = "NETOPT_LORAWAN_APPKEY",
[NETOPT_LORAWAN_NWKKEY] = "NETOPT_LORAWAN_NWKKEY",
[NETOPT_LORAWAN_APPSKEY] = "NETOPT_LORAWAN_APPSKEY",
[NETOPT_LORAWAN_NWKSKEY] = "NETOPT_LORAWAN_NWKSKEY",
[NETOPT_LORAWAN_FNWKSINTKEY] = "NETOPT_LORAWAN_FNWKSINTKEY",
[NETOPT_LORAWAN_SNWKSINTKEY] = "NETOPT_LORAWAN_SNWKSINTKEY",
[NETOPT_LORAWAN_NWKSENCKEY] = "NETOPT_LORAWAN_NWKSENCKEY",
[NETOPT_LORAWAN_DEVICE_CLASS] = "NETOPT_LORAWAN_DEVICE_CLASS",
[NETOPT_LORAWAN_DR] = "NETOPT_LORAWAN_DR",
[NETOPT_LORAWAN_ADR] = "NETOPT_LORAWAN_ADR",

View File

@ -41,6 +41,11 @@ ifneq (,$(filter gnrc_lorawan,$(USEMODULE)))
USEMODULE += crypto_aes_128
endif
ifneq (,$(filter gnrc_lorawan_1_1,$(USEMODULE)))
USEMODULE += gnrc_lorawan
FEATURES_REQUIRED += periph_flashpage
endif
ifneq (,$(filter gnrc_netdev_default,$(USEMODULE)))
# enable default network devices on the platform
USEMODULE += netdev_default
@ -78,7 +83,7 @@ ifneq (,$(filter gnrc_uhcpc,$(USEMODULE)))
USEMODULE += fmt
endif
ifneq (,$(filter gnrc_%,$(filter-out gnrc_lorawan gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pkt%,$(USEMODULE))))
ifneq (,$(filter gnrc_%,$(filter-out gnrc_lorawan gnrc_lorawan_1_1 gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pkt%,$(USEMODULE))))
USEMODULE += gnrc
endif

View File

@ -29,6 +29,10 @@
#include "net/gnrc/lorawan/region.h"
#include "timex.h"
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
#include "periph/flashpage.h"
#endif
#define ENABLE_DEBUG 0
#include "debug.h"
@ -43,6 +47,7 @@ static inline void gnrc_lorawan_mlme_reset(gnrc_lorawan_t *mac)
mac->mlme.pending_mlme_opts = 0;
mac->rx_delay = (CONFIG_LORAMAC_DEFAULT_RX1_DELAY / MS_PER_SEC);
mac->mlme.nid = CONFIG_LORAMAC_DEFAULT_NETID;
memset(mac->mlme.dev_nonce, 0x00, sizeof(mac->mlme.dev_nonce));
}
static inline void gnrc_lorawan_mlme_backoff_init(gnrc_lorawan_t *mac)
@ -76,13 +81,43 @@ static void _sleep_radio(gnrc_lorawan_t *mac)
dev->driver->set(dev, NETOPT_STATE, &state, sizeof(state));
}
void gnrc_lorawan_init(gnrc_lorawan_t *mac, uint8_t *nwkskey, uint8_t *appskey)
static void _load_persistent_state(gnrc_lorawan_t *mac)
{
mac->nwkskey = nwkskey;
mac->appskey = appskey;
(void) mac;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
void *addr = flashpage_addr(GNRC_LORAWAN_STATE_FLASHPAGE_NUM);
gnrc_lorawan_persistent_state_t state = { 0 };
memcpy(&state, addr, sizeof(state));
if (state.initialized_marker != GNRC_LORAWAN_INITIALIZED_MARKER) {
memset(&state, 0x0, sizeof(state));
state.initialized_marker = GNRC_LORAWAN_INITIALIZED_MARKER;
flashpage_erase(GNRC_LORAWAN_STATE_FLASHPAGE_NUM);
/* ensure written length is multiple of FLASHPAGE_WRITE_BLOCK_SIZE */
flashpage_write(addr, &state, (sizeof(state) /
FLASHPAGE_WRITE_BLOCK_SIZE + 0x1) *
FLASHPAGE_WRITE_BLOCK_SIZE);
}
memcpy(mac->mlme.dev_nonce, state.dev_nonce, sizeof(mac->mlme.dev_nonce));
#endif
}
void gnrc_lorawan_init(gnrc_lorawan_t *mac, uint8_t *joineui, const gnrc_lorawan_key_ctx_t *ctx)
{
DEBUG("Lorawan init !\n");
mac->joineui = joineui;
memcpy(&mac->ctx, ctx, sizeof(gnrc_lorawan_key_ctx_t));
mac->busy = false;
gnrc_lorawan_mlme_backoff_init(mac);
gnrc_lorawan_reset(mac);
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
_load_persistent_state(mac);
}
}
void gnrc_lorawan_reset(gnrc_lorawan_t *mac)
@ -110,6 +145,24 @@ void gnrc_lorawan_reset(gnrc_lorawan_t *mac)
gnrc_lorawan_channels_init(mac);
}
void gnrc_lorawan_store_dev_nonce(uint8_t *dev_nonce)
{
(void) dev_nonce;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
void *addr = flashpage_addr(GNRC_LORAWAN_STATE_FLASHPAGE_NUM);
gnrc_lorawan_persistent_state_t state = { 0 };
memcpy(&state, addr, sizeof(state));
memcpy(state.dev_nonce, dev_nonce, sizeof(state.dev_nonce));
flashpage_erase(GNRC_LORAWAN_STATE_FLASHPAGE_NUM);
/* ensure written length is multiple of FLASHPAGE_WRITE_BLOCK_SIZE */
flashpage_write(addr, &state, (sizeof(state) /
FLASHPAGE_WRITE_BLOCK_SIZE + 0x1) *
FLASHPAGE_WRITE_BLOCK_SIZE);
#endif
}
static void _config_radio(gnrc_lorawan_t *mac, uint32_t channel_freq,
uint8_t dr, int rx)
{
@ -157,20 +210,20 @@ void gnrc_lorawan_open_rx_window(gnrc_lorawan_t *mac)
void gnrc_lorawan_timeout_cb(gnrc_lorawan_t *mac)
{
switch(mac->state) {
case LORAWAN_STATE_RX_1:
case LORAWAN_STATE_RX_2:
gnrc_lorawan_open_rx_window(mac);
break;
case LORAWAN_STATE_JOIN:
gnrc_lorawan_trigger_join(mac);
break;
case LORAWAN_STATE_IDLE:
gnrc_lorawan_event_retrans_timeout(mac);
break;
default:
assert(false);
break;
switch (mac->state) {
case LORAWAN_STATE_RX_1:
case LORAWAN_STATE_RX_2:
gnrc_lorawan_open_rx_window(mac);
break;
case LORAWAN_STATE_JOIN:
gnrc_lorawan_trigger_join(mac);
break;
case LORAWAN_STATE_IDLE:
gnrc_lorawan_event_retrans_timeout(mac);
break;
default:
assert(false);
break;
}
}
@ -200,33 +253,32 @@ void gnrc_lorawan_radio_rx_timeout_cb(gnrc_lorawan_t *mac)
{
(void)mac;
switch (mac->state) {
case LORAWAN_STATE_RX_1:
DEBUG("gnrc_lorawan: RX1 timeout.\n");
_configure_rx_window(mac, CONFIG_LORAMAC_DEFAULT_RX2_FREQ,
mac->dl_settings &
GNRC_LORAWAN_DL_RX2_DR_MASK);
mac->state = LORAWAN_STATE_RX_2;
break;
case LORAWAN_STATE_RX_2:
DEBUG("gnrc_lorawan: RX2 timeout.\n");
gnrc_lorawan_event_no_rx(mac);
mac->state = LORAWAN_STATE_IDLE;
break;
default:
assert(false);
break;
case LORAWAN_STATE_RX_1:
DEBUG("gnrc_lorawan: RX1 timeout.\n");
_configure_rx_window(mac, CONFIG_LORAMAC_DEFAULT_RX2_FREQ,
mac->dl_settings &
GNRC_LORAWAN_DL_RX2_DR_MASK);
mac->state = LORAWAN_STATE_RX_2;
break;
case LORAWAN_STATE_RX_2:
DEBUG("gnrc_lorawan: RX2 timeout.\n");
gnrc_lorawan_event_no_rx(mac);
mac->state = LORAWAN_STATE_IDLE;
break;
default:
assert(false);
break;
}
_sleep_radio(mac);
}
void gnrc_lorawan_send_pkt(gnrc_lorawan_t *mac, iolist_t *psdu, uint8_t dr)
void gnrc_lorawan_send_pkt(gnrc_lorawan_t *mac, iolist_t *psdu, uint8_t dr,
uint32_t chan)
{
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
mac->state = LORAWAN_STATE_TX;
uint32_t chan = gnrc_lorawan_pick_channel(mac);
DEBUG("gnrc_lorawan: Channel: %" PRIu32 "Hz \n", chan);
_config_radio(mac, chan, dr, false);
@ -254,14 +306,14 @@ void gnrc_lorawan_radio_rx_done_cb(gnrc_lorawan_t *mac, uint8_t *psdu,
uint8_t mtype = (*psdu & MTYPE_MASK) >> 5;
switch (mtype) {
case MTYPE_JOIN_ACCEPT:
gnrc_lorawan_mlme_process_join(mac, psdu, size);
break;
case MTYPE_CNF_DOWNLINK:
case MTYPE_UNCNF_DOWNLINK:
gnrc_lorawan_mcps_process_downlink(mac, psdu, size);
break;
default:
break;
case MTYPE_JOIN_ACCEPT:
gnrc_lorawan_mlme_process_join(mac, psdu, size);
break;
case MTYPE_CNF_DOWNLINK:
case MTYPE_UNCNF_DOWNLINK:
gnrc_lorawan_mcps_process_downlink(mac, psdu, size);
break;
default:
break;
}
}

View File

@ -23,13 +23,23 @@
#include "byteorder.h"
#include "net/lorawan/hdr.h"
#include "fmt.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define MIC_B0_START (0x49)
#define MIC_B1_START (0x49)
#define CRYPT_B0_START (0x01)
#define DIR_MASK (0x1)
#define SBIT_MASK (0xF)
#define APP_SKEY_B0_START (0x1)
#define NWK_SKEY_B0_START (0x2)
#define APP_SKEY_B0_START (0x2)
#define NWK_SKEY_B0_START (0x2)
#define FNWKSINT_KEY_B0_START (0x1)
#define SNWKSINT_KEY_B0_START (0x3)
#define NWKSENC_KEY_B0_START (0x4)
#define JSENC_KEY_B0_START (0x5)
#define JSINT_KEY_B0_START (0x6)
static aes128_cmac_context_t CmacContext;
static uint8_t digest[LORAMAC_APPKEY_LEN];
@ -37,16 +47,31 @@ static cipher_t AesContext;
typedef struct __attribute__((packed)) {
uint8_t fb;
uint32_t u8_pad;
union {
uint32_t u8_pad;
le_uint16_t conf_fcnt;
};
uint8_t dir;
le_uint32_t dev_addr;
le_uint32_t fcnt;
uint8_t u32_pad;
uint8_t len;
} lorawan_block_t;
} lorawan_block0_t;
void gnrc_lorawan_calculate_join_mic(const uint8_t *buf, size_t len,
const uint8_t *key, le_uint32_t *out)
typedef struct __attribute__((packed)) {
uint8_t fb;
le_uint16_t conf_fcnt;
uint8_t tx_dr;
uint8_t tx_ch;
uint8_t dir;
le_uint32_t dev_addr;
le_uint32_t fcnt;
uint8_t u32_pad;
uint8_t len;
} lorawan_block1_t;
void gnrc_lorawan_calculate_join_req_mic(const uint8_t *buf, size_t len,
uint8_t *key, le_uint32_t *out)
{
aes128_cmac_init(&CmacContext, key, LORAMAC_APPKEY_LEN);
aes128_cmac_update(&CmacContext, buf, len);
@ -55,25 +80,113 @@ void gnrc_lorawan_calculate_join_mic(const uint8_t *buf, size_t len,
memcpy(out, digest, sizeof(le_uint32_t));
}
void gnrc_lorawan_calculate_mic(const le_uint32_t *dev_addr, uint32_t fcnt,
uint8_t dir, iolist_t *frame,
const uint8_t *nwkskey, le_uint32_t *out)
void gnrc_lorawan_calculate_join_acpt_mic(const uint8_t *buf, size_t len,
gnrc_lorawan_t *mac, le_uint32_t *out)
{
lorawan_block_t block;
uint8_t *key;
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
key = gnrc_lorawan_get_jsintkey(mac);
}
else {
key = mac->ctx.nwksenckey;
}
aes128_cmac_init(&CmacContext, key, LORAMAC_JSINTKEY_LEN);
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
/**
* TODO: JoinReqType hardcoded for now. Will probably move into
* gnrc_lorawan_t struct once ReJoin requests are implemented.
*/
mlme_join_req_type_t type = JOIN_REQ;
aes128_cmac_update(&CmacContext, &type, 0x1);
aes128_cmac_update(&CmacContext, mac->joineui, LORAMAC_JOINEUI_LEN);
aes128_cmac_update(&CmacContext, mac->mlme.dev_nonce, GNRC_LORAWAN_DEV_NONCE_SIZE);
}
/* buf = HDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList */
aes128_cmac_update(&CmacContext, buf, len);
aes128_cmac_final(&CmacContext, digest);
memcpy(out, digest, sizeof(le_uint32_t));
}
void gnrc_lorawan_calculate_mic_uplink(iolist_t *frame, uint16_t conf_fcnt,
gnrc_lorawan_t *mac, le_uint32_t *out)
{
lorawan_block0_t block0 = { 0 };
block0.fb = MIC_B0_START;
block0.dir = 0x00;
memcpy(&block0.dev_addr, &mac->dev_addr, sizeof(le_uint32_t));
block0.fcnt = byteorder_htoll(mac->mcps.fcnt);
block0.len = iolist_size(frame);
/* cmacF = aes128_cmac(FNwkSIntKey, B0 | msg) */
aes128_cmac_init(&CmacContext, mac->ctx.fnwksintkey, LORAMAC_FNWKSINTKEY_LEN);
aes128_cmac_update(&CmacContext, &block0, sizeof(block0));
for (iolist_t *io = frame; io != NULL; io = io->iol_next) {
aes128_cmac_update(&CmacContext, io->iol_base, io->iol_len);
}
aes128_cmac_final(&CmacContext, digest);
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
/* cmacF[0..1] (MIC = cmacS[0..1] | cmacF[0..1]) */
memcpy((uint8_t *)out + 0x2, digest, 0x2);
}
else {
/* MIC = cmacF[0..3] */
memcpy(out, digest, sizeof(le_uint32_t));
}
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
lorawan_block1_t block1 = { 0 };
block1.fb = MIC_B1_START;
block1.conf_fcnt = byteorder_htols(conf_fcnt);
block1.tx_dr = mac->last_dr;
block1.tx_ch = mac->last_chan_idx;
block1.dir = 0x00;
memcpy(&block1.dev_addr, &mac->dev_addr, sizeof(le_uint32_t));
block1.fcnt = byteorder_htoll(mac->mcps.fcnt);
block1.len = iolist_size(frame);
/* cmacS = aes128_cmac(SNwkSIntKey, B1 | msg) */
aes128_cmac_init(&CmacContext, mac->ctx.snwksintkey, LORAMAC_SNWKSINTKEY_LEN);
aes128_cmac_update(&CmacContext, &block1, sizeof(block1));
for (iolist_t *io = frame; io != NULL; io = io->iol_next) {
aes128_cmac_update(&CmacContext, io->iol_base, io->iol_len);
}
aes128_cmac_final(&CmacContext, digest);
/* cmacS[0..1] (MIC = cmacS[0..1] | cmacF[0..1]) */
memcpy(out, digest, 0x2);
}
}
void gnrc_lorawan_calculate_mic_downlink(const le_uint32_t *dev_addr,
uint32_t fcnt, uint16_t conf_fcnt,
iolist_t *frame,
const uint8_t *snwksintkey,
le_uint32_t *out)
{
lorawan_block0_t block = { 0 };
block.fb = MIC_B0_START;
block.u8_pad = 0;
block.dir = dir & DIR_MASK;
block.conf_fcnt = byteorder_htols(conf_fcnt);
block.dir = 0x1;
memcpy(&block.dev_addr, dev_addr, sizeof(le_uint32_t));
block.fcnt = byteorder_htoll(fcnt);
block.u32_pad = 0;
block.len = iolist_size(frame);
aes128_cmac_init(&CmacContext, nwkskey, LORAMAC_APPKEY_LEN);
aes128_cmac_init(&CmacContext, snwksintkey, LORAMAC_SNWKSINTKEY_LEN);
aes128_cmac_update(&CmacContext, &block, sizeof(block));
for (iolist_t *io = frame; io != NULL; io = io->iol_next) {
aes128_cmac_update(&CmacContext, io->iol_base, io->iol_len);
@ -83,6 +196,41 @@ void gnrc_lorawan_calculate_mic(const le_uint32_t *dev_addr, uint32_t fcnt,
memcpy(out, digest, sizeof(le_uint32_t));
}
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
void gnrc_lorawan_encrypt_fopts(uint8_t *fopts, size_t len,
const le_uint32_t *dev_addr, uint32_t fcnt,
bool afcnt, uint8_t dir, const uint8_t *key)
{
uint8_t s_block[16] = { 0 };
uint8_t a_block[16] = { 0 };
lorawan_block0_t *block = (lorawan_block0_t *)a_block;
cipher_init(&AesContext, CIPHER_AES, key, LORAMAC_APPKEY_LEN);
block->fb = CRYPT_B0_START;
if (afcnt) {
a_block[0x4] = 0x02;
}
else {
a_block[0x4] = 0x01;
}
block->dir = dir & DIR_MASK;
block->dev_addr = *dev_addr;
block->fcnt = byteorder_htoll(fcnt);
block->len = 0x01;
cipher_encrypt(&AesContext, a_block, s_block);
for (size_t i = 0; i < len; i++) {
fopts[i] ^= s_block[i];
}
}
#endif /* IS_USED(MODULE_GNRC_LORAWAN_1_1) */
void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr,
uint32_t fcnt, uint8_t dir,
const uint8_t *appskey)
@ -93,7 +241,7 @@ void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr,
memset(s_block, 0, sizeof(s_block));
memset(a_block, 0, sizeof(a_block));
lorawan_block_t *block = (lorawan_block_t *)a_block;
lorawan_block0_t *block = (lorawan_block0_t *)a_block;
cipher_init(&AesContext, CIPHER_AES, appskey, LORAMAC_APPKEY_LEN);
@ -136,30 +284,82 @@ void gnrc_lorawan_decrypt_join_accept(const uint8_t *key, uint8_t *pkt,
}
}
void gnrc_lorawan_generate_session_keys(const uint8_t *app_nonce,
const uint8_t *dev_nonce,
const uint8_t *appkey, uint8_t *nwkskey,
uint8_t *appskey)
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
void gnrc_lorawan_generate_lifetime_session_keys(const uint8_t *deveui,
const uint8_t *nwkkey,
uint8_t *jsintkey,
uint8_t *jsenckey)
{
uint8_t buf[LORAMAC_APPSKEY_LEN];
uint8_t buf[LORAMAC_JSINTKEY_LEN] = { 0 };
memset(buf, 0, sizeof(buf));
cipher_init(&AesContext, CIPHER_AES, nwkkey, LORAMAC_NWKKEY_LEN);
cipher_init(&AesContext, CIPHER_AES, appkey, LORAMAC_APPSKEY_LEN);
memcpy(buf + 1, deveui, LORAMAC_DEVEUI_LEN);
/* net_id comes right after app_nonce */
memcpy(buf + 1, app_nonce,
GNRC_LORAWAN_APP_NONCE_SIZE + GNRC_LORAWAN_NET_ID_SIZE);
memcpy(buf + 1 + GNRC_LORAWAN_APP_NONCE_SIZE + GNRC_LORAWAN_NET_ID_SIZE,
dev_nonce, GNRC_LORAWAN_DEV_NONCE_SIZE);
buf[0] = JSENC_KEY_B0_START;
cipher_encrypt(&AesContext, buf, jsenckey);
/* Calculate Application Session Key */
buf[0] = APP_SKEY_B0_START;
cipher_encrypt(&AesContext, buf, nwkskey);
/* Calculate Network Session Key */
buf[0] = NWK_SKEY_B0_START;
cipher_encrypt(&AesContext, buf, appskey);
buf[0] = JSINT_KEY_B0_START;
cipher_encrypt(&AesContext, buf, jsintkey);
}
#endif /* IS_USED(MODULE_GNRC_LORAWAN_1_1) */
void gnrc_lorawan_generate_session_keys(const uint8_t *join_nonce,
const uint8_t *dev_nonce,
const uint8_t *joineui,
gnrc_lorawan_t *mac)
{
uint8_t buf[LORAMAC_APPSKEY_LEN] = { 0 };
uint8_t *nwkkey = mac->ctx.nwksenckey;
uint8_t *appkey = mac->ctx.appskey;
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
/* JoinNonce | JoinEUI | DevNonce */
memcpy(buf + 1, join_nonce, GNRC_LORAWAN_JOIN_NONCE_SIZE);
memcpy(buf + 1 + GNRC_LORAWAN_JOIN_NONCE_SIZE, joineui,
LORAMAC_JOINEUI_LEN);
memcpy(buf + 1 + GNRC_LORAWAN_JOIN_NONCE_SIZE + LORAMAC_JOINEUI_LEN,
dev_nonce, GNRC_LORAWAN_DEV_NONCE_SIZE);
}
else {
/* AppNonce | NetID | DevNonce */
/* net_id comes right after join_nonce */
memcpy(buf + 1, join_nonce,
GNRC_LORAWAN_APP_NONCE_SIZE + GNRC_LORAWAN_NET_ID_SIZE);
memcpy(buf + 1 + GNRC_LORAWAN_APP_NONCE_SIZE + GNRC_LORAWAN_NET_ID_SIZE,
dev_nonce, GNRC_LORAWAN_DEV_NONCE_SIZE);
}
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
cipher_init(&AesContext, CIPHER_AES, appkey, LORAMAC_APPKEY_LEN);
/* derive application session key */
buf[0] = APP_SKEY_B0_START;
cipher_encrypt(&AesContext, buf, mac->ctx.appskey);
}
cipher_init(&AesContext, CIPHER_AES, nwkkey, LORAMAC_NWKKEY_LEN);
/* derive forwarding Network session integrity key */
buf[0] = FNWKSINT_KEY_B0_START;
cipher_encrypt(&AesContext, buf, mac->ctx.fnwksintkey);
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
/* derive serving network session integrity key */
buf[0] = SNWKSINT_KEY_B0_START;
cipher_encrypt(&AesContext, buf, mac->ctx.snwksintkey);
/* derive Network session encryption key */
buf[0] = NWKSENC_KEY_B0_START;
cipher_encrypt(&AesContext, buf, mac->ctx.nwksenckey);
}
else {
/* derive application session key */
buf[0] = APP_SKEY_B0_START;
cipher_encrypt(&AesContext, buf, mac->ctx.appskey);
mac->ctx.snwksintkey = mac->ctx.fnwksintkey;
mac->ctx.nwksenckey = mac->ctx.fnwksintkey;
}
}
/** @} */

View File

@ -34,8 +34,10 @@
static void _end_of_tx(gnrc_lorawan_t *mac, int type, int status);
static int gnrc_lorawan_mic_is_valid(uint8_t *buf, size_t len, uint8_t *nwkskey)
static int gnrc_lorawan_mic_is_valid(uint8_t *buf, size_t len, uint8_t *key,
uint32_t fcnt_up, bool optneg)
{
(void)fcnt_up;
le_uint32_t calc_mic;
lorawan_hdr_t *lw_hdr = (lorawan_hdr_t *)buf;
@ -44,8 +46,25 @@ static int gnrc_lorawan_mic_is_valid(uint8_t *buf, size_t len, uint8_t *nwkskey)
iolist_t iol =
{ .iol_base = buf, .iol_len = len - MIC_SIZE, .iol_next = NULL };
gnrc_lorawan_calculate_mic(&lw_hdr->addr, fcnt, GNRC_LORAWAN_DIR_DOWNLINK,
&iol, nwkskey, &calc_mic);
/* for LoRaWAN 1.0 conf_fcnt is hardcoded to be 0 */
uint16_t conf_fnct = 0x00;
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && optneg) {
/**
* If the device is connected to a LoRaWAN 1.1 Network Server and the
* ACK bit of the downlink frame is set, meaning this frame is acknowledging
* an uplink confirmed frame,then ConfFCnt is the frame counter value
* modulo 2^16 of the confirmed uplink frame that is being acknowledged.
* In all other cases ConfFCnt = 0x0000.
*/
if (lorawan_hdr_get_ack(lw_hdr)) {
conf_fnct = fcnt_up;
}
}
gnrc_lorawan_calculate_mic_downlink(&lw_hdr->addr, fcnt, conf_fnct, &iol,
key, &calc_mic);
return calc_mic.u32 == ((le_uint32_t *)(buf + len - MIC_SIZE))->u32;
}
@ -91,17 +110,6 @@ int gnrc_lorawan_parse_dl(gnrc_lorawan_t *mac, uint8_t *buf, size_t len,
return -1;
}
uint32_t _fcnt =
gnrc_lorawan_fcnt_stol(mac->mcps.fcnt_down, _hdr->fcnt.u16);
if (mac->mcps.fcnt_down > _fcnt || mac->mcps.fcnt_down +
CONFIG_LORAMAC_DEFAULT_MAX_FCNT_GAP < _fcnt) {
DEBUG("gnrc_lorawan: wrong frame counter\n");
return -1;
}
pkt->fcnt_down = _fcnt;
int fopts_length = lorawan_hdr_get_frame_opts_len(_hdr);
if (fopts_length) {
@ -129,6 +137,22 @@ int gnrc_lorawan_parse_dl(gnrc_lorawan_t *mac, uint8_t *buf, size_t len,
}
}
uint32_t _fcnt =
gnrc_lorawan_fcnt_stol(mac->mcps.fcnt_down, _hdr->fcnt.u16);
uint32_t fcnt_down = mac->mcps.fcnt_down;
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && pkt->port) {
fcnt_down = gnrc_lorawan_get_afcnt_down(mac);
}
if (fcnt_down > _fcnt || fcnt_down + CONFIG_LORAMAC_DEFAULT_MAX_FCNT_GAP < _fcnt) {
DEBUG("gnrc_lorawan: wrong frame counter\n");
return -1;
}
pkt->fcnt_down = _fcnt;
pkt->ack_req = lorawan_hdr_get_mtype(_hdr) == MTYPE_CNF_DOWNLINK;
pkt->ack = lorawan_hdr_get_ack(_hdr);
pkt->frame_pending = lorawan_hdr_get_frame_pending(_hdr);
@ -142,7 +166,8 @@ void gnrc_lorawan_mcps_process_downlink(gnrc_lorawan_t *mac, uint8_t *psdu,
struct parsed_packet _pkt;
/* NOTE: MIC is in pkt */
if (!gnrc_lorawan_mic_is_valid(psdu, size, mac->nwkskey)) {
if (!gnrc_lorawan_mic_is_valid(psdu, size, mac->ctx.snwksintkey,
mac->mcps.fcnt, gnrc_lorawan_optneg_is_set(mac))) {
DEBUG("gnrc_lorawan: invalid MIC\n");
gnrc_lorawan_event_no_rx(mac);
return;
@ -163,10 +188,10 @@ void gnrc_lorawan_mcps_process_downlink(gnrc_lorawan_t *mac, uint8_t *psdu,
if (_pkt.enc_payload.iol_base) {
uint8_t *key;
if (_pkt.port) {
key = mac->appskey;
key = mac->ctx.appskey;
}
else {
key = mac->nwkskey;
key = mac->ctx.nwksenckey;
fopts = &_pkt.enc_payload;
}
gnrc_lorawan_encrypt_payload(&_pkt.enc_payload, &_pkt.hdr->addr,
@ -175,7 +200,17 @@ void gnrc_lorawan_mcps_process_downlink(gnrc_lorawan_t *mac, uint8_t *psdu,
key);
}
mac->mcps.fcnt_down = _pkt.fcnt_down;
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && _pkt.port) {
gnrc_lorawan_set_afcnt_down(mac, _pkt.fcnt_down);
}
else {
mac->mcps.fcnt_down = _pkt.fcnt_down;
}
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
gnrc_lorawan_set_last_fcnt_down(mac, _pkt.fcnt_down);
}
if (mac->mcps.waiting_for_ack && !_pkt.ack) {
DEBUG("gnrc_lorawan: expected ACK packet\n");
gnrc_lorawan_event_no_rx(mac);
@ -188,6 +223,22 @@ void gnrc_lorawan_mcps_process_downlink(gnrc_lorawan_t *mac, uint8_t *psdu,
/* if there are fopts, it's either an empty packet or application payload */
if (fopts) {
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
if (_pkt.port) {
gnrc_lorawan_encrypt_fopts(fopts->iol_base, fopts->iol_len,
&mac->dev_addr,
gnrc_lorawan_get_afcnt_down(mac), true,
GNRC_LORAWAN_DIR_DOWNLINK,
mac->ctx.nwksenckey);
}
else {
gnrc_lorawan_encrypt_fopts(fopts->iol_base, fopts->iol_len,
&mac->dev_addr,
mac->mcps.fcnt_down, false,
GNRC_LORAWAN_DIR_DOWNLINK,
mac->ctx.nwksenckey);
}
}
DEBUG("gnrc_lorawan: processing fopts\n");
gnrc_lorawan_process_fopts(mac, fopts->iol_base, fopts->iol_len);
}
@ -257,24 +308,32 @@ size_t gnrc_lorawan_build_uplink(gnrc_lorawan_t *mac, iolist_t *payload,
buf.index += sizeof(lorawan_hdr_t);
int fopts_length = gnrc_lorawan_build_options(mac, &buf);
size_t fopts_length = gnrc_lorawan_build_options(mac, &buf);
assert(fopts_length < 16);
lorawan_hdr_set_frame_opts_len(lw_hdr, fopts_length);
buf.data[buf.index++] = port;
uint8_t *key;
if (port) {
key = mac->ctx.appskey;
}
else {
key = mac->ctx.nwksenckey;
}
gnrc_lorawan_encrypt_payload(payload, &mac->dev_addr, mac->mcps.fcnt,
GNRC_LORAWAN_DIR_UPLINK,
port ? mac->appskey : mac->nwkskey);
GNRC_LORAWAN_DIR_UPLINK, key);
iolist_t iol =
{ .iol_base = buf.data, .iol_len = buf.index, .iol_next = payload };
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
key = mac->ctx.nwksenckey;
gnrc_lorawan_calculate_mic(&mac->dev_addr, mac->mcps.fcnt,
GNRC_LORAWAN_DIR_UPLINK,
&iol, mac->nwkskey,
(le_uint32_t *)&buf.data[buf.index]);
gnrc_lorawan_encrypt_fopts(&buf.data[sizeof(lorawan_hdr_t)], fopts_length,
&mac->dev_addr, mac->mcps.fcnt, false,
GNRC_LORAWAN_DIR_UPLINK, key);
}
return buf.index;
}
@ -321,8 +380,28 @@ static void _transmit_pkt(gnrc_lorawan_t *mac)
last_snip = last_snip->iol_next;
}
mac->last_chan_idx = gnrc_lorawan_pick_channel(mac);
uint16_t conf_fcnt = 0;
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
/**
* If the ACK bit of the uplink frame is set, meaning this frame is
* acknowledging a downlink confirmed frame, then ConfFCnt is the frame
* counter value modulo 2^16 of the confirmed downlink frame that is being
* acknowledged. In all other cases ConfFCnt = 0x0000
*/
lorawan_hdr_t *lw_hdr = (lorawan_hdr_t *)header.iol_base;
if (lorawan_hdr_get_ack(lw_hdr)) {
conf_fcnt = gnrc_lorawan_get_last_fcnt_down(mac);
}
}
gnrc_lorawan_calculate_mic_uplink(&header, conf_fcnt, mac, footer.iol_base);
last_snip->iol_next = &footer;
gnrc_lorawan_send_pkt(mac, &header, mac->last_dr);
gnrc_lorawan_send_pkt(mac, &header, mac->last_dr,
mac->channel[mac->last_chan_idx]);
/* cppcheck-suppress redundantAssignment
* (reason: cppcheck bug. The pointer is temporally modified to add a footer.

View File

@ -30,8 +30,8 @@
#define ENABLE_DEBUG 0
#include "debug.h"
static void _build_join_req_pkt(uint8_t *appeui, uint8_t *deveui,
uint8_t *appkey, uint8_t *dev_nonce,
static void _build_join_req_pkt(uint8_t *joineui, uint8_t *deveui,
uint8_t *key, uint8_t *dev_nonce,
uint8_t *psdu)
{
lorawan_join_request_t *hdr = (lorawan_join_request_t *)psdu;
@ -40,46 +40,63 @@ static void _build_join_req_pkt(uint8_t *appeui, uint8_t *deveui,
lorawan_hdr_set_mtype((lorawan_hdr_t *)hdr, MTYPE_JOIN_REQUEST);
lorawan_hdr_set_maj((lorawan_hdr_t *)hdr, MAJOR_LRWAN_R1);
le_uint64_t l_appeui = *((le_uint64_t *)appeui);
le_uint64_t l_joineui = *((le_uint64_t *)joineui);
le_uint64_t l_deveui = *((le_uint64_t *)deveui);
hdr->app_eui = l_appeui;
hdr->join_eui = l_joineui;
hdr->dev_eui = l_deveui;
le_uint16_t l_dev_nonce = *((le_uint16_t *)dev_nonce);
hdr->dev_nonce = l_dev_nonce;
gnrc_lorawan_calculate_join_mic(psdu, JOIN_REQUEST_SIZE - MIC_SIZE, appkey,
&hdr->mic);
gnrc_lorawan_calculate_join_req_mic(psdu, JOIN_REQUEST_SIZE - MIC_SIZE, key,
&hdr->mic);
}
void gnrc_lorawan_trigger_join(gnrc_lorawan_t *mac)
{
iolist_t pkt = {.iol_base = mac->mcps.mhdr_mic, .iol_len =
sizeof(lorawan_join_request_t), .iol_next = NULL};
gnrc_lorawan_send_pkt(mac, &pkt, mac->last_dr);
iolist_t pkt = { .iol_base = mac->mcps.mhdr_mic, .iol_len =
sizeof(lorawan_join_request_t), .iol_next = NULL };
mac->last_chan_idx = gnrc_lorawan_pick_channel(mac);
gnrc_lorawan_send_pkt(mac, &pkt, mac->last_dr,
mac->channel[mac->last_chan_idx]);
}
static int gnrc_lorawan_send_join_request(gnrc_lorawan_t *mac, uint8_t *deveui,
uint8_t *appeui, uint8_t *appkey,
uint8_t dr)
uint8_t *eui, uint8_t *key, uint8_t dr)
{
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
/**
* DevNonce starting at 0 when device is powered up and incremented with
* every Join-request.
*/
uint16_t dev_nonce = byteorder_lebuftohs(mac->mlme.dev_nonce);
byteorder_htolebufs(mac->mlme.dev_nonce, ++dev_nonce);
gnrc_lorawan_store_dev_nonce(mac->mlme.dev_nonce);
/* Dev Nonce */
uint32_t random_number;
gnrc_lorawan_generate_lifetime_session_keys(deveui, mac->ctx.nwksenckey,
gnrc_lorawan_get_jsintkey(mac),
gnrc_lorawan_get_jsenckey(mac));
}
else {
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
dev->driver->get(dev, NETOPT_RANDOM, &random_number, sizeof(random_number));
/* Dev Nonce */
uint32_t random_number;
mac->mlme.dev_nonce[0] = random_number & 0xFF;
mac->mlme.dev_nonce[1] = (random_number >> 8) & 0xFF;
dev->driver->get(dev, NETOPT_RANDOM, &random_number, sizeof(random_number));
mac->mlme.dev_nonce[0] = random_number & 0xFF;
mac->mlme.dev_nonce[1] = (random_number >> 8) & 0xFF;
}
mac->last_dr = dr;
mac->state = LORAWAN_STATE_JOIN;
/* Use the buffer for MHDR */
_build_join_req_pkt(appeui, deveui, appkey, mac->mlme.dev_nonce, (uint8_t*) mac->mcps.mhdr_mic);
_build_join_req_pkt(eui, deveui, key, mac->mlme.dev_nonce, (uint8_t *)mac->mcps.mhdr_mic);
/* We need a random delay for join request. Otherwise there might be
* network congestion if a group of nodes start at the same time */
@ -111,25 +128,31 @@ void gnrc_lorawan_mlme_process_join(gnrc_lorawan_t *mac, uint8_t *data,
uint8_t out[GNRC_LORAWAN_JOIN_ACCEPT_MAX_SIZE - 1];
uint8_t has_cflist = (size - 1) > CFLIST_SIZE;
gnrc_lorawan_decrypt_join_accept(mac->appskey, data + 1,
has_cflist, out);
gnrc_lorawan_decrypt_join_accept(mac->ctx.nwksenckey, data + 1, has_cflist, out);
memcpy(data + 1, out, size - 1);
le_uint32_t mic;
le_uint32_t *expected_mic = (le_uint32_t *)(data + size - MIC_SIZE);
gnrc_lorawan_calculate_join_mic(data, size - MIC_SIZE, mac->appskey, &mic);
lorawan_join_accept_t *ja_hdr = (lorawan_join_accept_t *)data;
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
gnrc_lorawan_set_optneg(mac, lorawan_ja_hdr_get_optneg(ja_hdr));
}
gnrc_lorawan_calculate_join_acpt_mic(data, size - MIC_SIZE, mac, &mic);
if (mic.u32 != expected_mic->u32) {
DEBUG("gnrc_lorawan_mlme: wrong MIC.\n");
status = -EBADMSG;
goto out;
}
lorawan_join_accept_t *ja_hdr = (lorawan_join_accept_t *)data;
void *joineui = IS_USED(MODULE_GNRC_LORAWAN_1_1) ? mac->joineui : NULL;
gnrc_lorawan_generate_session_keys(ja_hdr->app_nonce, mac->mlme.dev_nonce,
mac->appskey, mac->nwkskey,
mac->appskey);
gnrc_lorawan_generate_session_keys(ja_hdr->join_nonce,
mac->mlme.dev_nonce, joineui, mac);
le_uint32_t le_nid;
@ -152,6 +175,11 @@ void gnrc_lorawan_mlme_process_join(gnrc_lorawan_t *mac, uint8_t *data,
mac->mlme.activation = MLME_ACTIVATION_OTAA;
status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
/* schedule rekey indication command */
if (IS_USED(MODULE_GNRC_LORAWAN_1_1) && gnrc_lorawan_optneg_is_set(mac)) {
mac->mlme.pending_mlme_opts |= GNRC_LORAWAN_MLME_OPTS_REKEY_IND_REQ;
}
out:
mlme_confirm.type = MLME_JOIN;
mlme_confirm.status = status;
@ -167,21 +195,21 @@ void gnrc_lorawan_mlme_backoff_expire_cb(gnrc_lorawan_t *mac)
if (counter == 0) {
switch (state) {
case GNRC_LORAWAN_BACKOFF_STATE_1:
counter = GNRC_LORAWAN_BACKOFF_TIME_1;
state = GNRC_LORAWAN_BACKOFF_STATE_2;
mac->mlme.backoff_budget = GNRC_LORAWAN_BACKOFF_BUDGET_1;
break;
case GNRC_LORAWAN_BACKOFF_STATE_2:
counter = GNRC_LORAWAN_BACKOFF_TIME_2;
state = GNRC_LORAWAN_BACKOFF_STATE_3;
mac->mlme.backoff_budget = GNRC_LORAWAN_BACKOFF_BUDGET_2;
break;
case GNRC_LORAWAN_BACKOFF_STATE_3:
default:
counter = GNRC_LORAWAN_BACKOFF_TIME_3;
mac->mlme.backoff_budget = GNRC_LORAWAN_BACKOFF_BUDGET_3;
break;
case GNRC_LORAWAN_BACKOFF_STATE_1:
counter = GNRC_LORAWAN_BACKOFF_TIME_1;
state = GNRC_LORAWAN_BACKOFF_STATE_2;
mac->mlme.backoff_budget = GNRC_LORAWAN_BACKOFF_BUDGET_1;
break;
case GNRC_LORAWAN_BACKOFF_STATE_2:
counter = GNRC_LORAWAN_BACKOFF_TIME_2;
state = GNRC_LORAWAN_BACKOFF_STATE_3;
mac->mlme.backoff_budget = GNRC_LORAWAN_BACKOFF_BUDGET_2;
break;
case GNRC_LORAWAN_BACKOFF_STATE_3:
default:
counter = GNRC_LORAWAN_BACKOFF_TIME_3;
mac->mlme.backoff_budget = GNRC_LORAWAN_BACKOFF_BUDGET_3;
break;
}
}
@ -194,23 +222,23 @@ static void _mlme_set(gnrc_lorawan_t *mac, const mlme_request_t *mlme_request,
{
mlme_confirm->status = -EINVAL;
switch (mlme_request->mib.type) {
case MIB_ACTIVATION_METHOD:
if (mlme_request->mib.activation != MLME_ACTIVATION_OTAA) {
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
mac->mlme.activation = mlme_request->mib.activation;
}
break;
case MIB_DEV_ADDR:
case MIB_ACTIVATION_METHOD:
if (mlme_request->mib.activation != MLME_ACTIVATION_OTAA) {
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
memcpy(&mac->dev_addr, mlme_request->mib.dev_addr,
sizeof(uint32_t));
break;
case MIB_RX2_DR:
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
gnrc_lorawan_set_rx2_dr(mac, mlme_request->mib.rx2_dr);
break;
default:
break;
mac->mlme.activation = mlme_request->mib.activation;
}
break;
case MIB_DEV_ADDR:
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
memcpy(&mac->dev_addr, mlme_request->mib.dev_addr,
sizeof(uint32_t));
break;
case MIB_RX2_DR:
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
gnrc_lorawan_set_rx2_dr(mac, mlme_request->mib.rx2_dr);
break;
default:
break;
}
}
@ -218,17 +246,17 @@ static void _mlme_get(gnrc_lorawan_t *mac, const mlme_request_t *mlme_request,
mlme_confirm_t *mlme_confirm)
{
switch (mlme_request->mib.type) {
case MIB_ACTIVATION_METHOD:
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
mlme_confirm->mib.activation = mac->mlme.activation;
break;
case MIB_DEV_ADDR:
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
mlme_confirm->mib.dev_addr = &mac->dev_addr;
break;
default:
mlme_confirm->status = -EINVAL;
break;
case MIB_ACTIVATION_METHOD:
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
mlme_confirm->mib.activation = mac->mlme.activation;
break;
case MIB_DEV_ADDR:
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
mlme_confirm->mib.dev_addr = &mac->dev_addr;
break;
default:
mlme_confirm->status = -EINVAL;
break;
}
}
@ -237,47 +265,54 @@ void gnrc_lorawan_mlme_request(gnrc_lorawan_t *mac,
mlme_confirm_t *mlme_confirm)
{
switch (mlme_request->type) {
case MLME_JOIN:
if (mac->mlme.activation != MLME_ACTIVATION_NONE) {
mlme_confirm->status = -EINVAL;
break;
}
if (!gnrc_lorawan_mac_acquire(mac)) {
mlme_confirm->status = -EBUSY;
break;
}
case MLME_JOIN:
if (mac->mlme.activation != MLME_ACTIVATION_NONE) {
mlme_confirm->status = -EINVAL;
break;
}
if (!gnrc_lorawan_mac_acquire(mac)) {
mlme_confirm->status = -EBUSY;
break;
}
if (mac->mlme.backoff_budget < 0) {
mlme_confirm->status = -EDQUOT;
break;
}
memcpy(mac->appskey, mlme_request->join.appkey, LORAMAC_APPKEY_LEN);
mlme_confirm->status = gnrc_lorawan_send_join_request(mac,
mlme_request->join.deveui,
mlme_request->join.appeui, mlme_request->join.appkey,
mlme_request->join.dr);
break;
case MLME_LINK_CHECK:
mac->mlme.pending_mlme_opts |=
GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ;
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_DEFERRED;
break;
case MLME_SET:
_mlme_set(mac, mlme_request, mlme_confirm);
break;
case MLME_GET:
_mlme_get(mac, mlme_request, mlme_confirm);
break;
case MLME_RESET:
gnrc_lorawan_reset(mac);
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
break;
default:
if (mac->mlme.backoff_budget < 0) {
mlme_confirm->status = -EDQUOT;
break;
}
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
memcpy(mac->ctx.appskey, gnrc_lorawan_mlme_join_get_appkey(
&mlme_request->join), LORAMAC_APPKEY_LEN);
}
memcpy(mac->ctx.nwksenckey, mlme_request->join.nwkkey, LORAMAC_NWKKEY_LEN);
mlme_confirm->status = gnrc_lorawan_send_join_request(mac,
mlme_request->join.deveui,
mlme_request->join.joineui,
mlme_request->join.nwkkey,
mlme_request->join.dr);
break;
case MLME_LINK_CHECK:
mac->mlme.pending_mlme_opts |=
GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ;
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_DEFERRED;
break;
case MLME_SET:
_mlme_set(mac, mlme_request, mlme_confirm);
break;
case MLME_GET:
_mlme_get(mac, mlme_request, mlme_confirm);
break;
case MLME_RESET:
gnrc_lorawan_reset(mac);
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
break;
default:
break;
}
}
int _fopts_mlme_link_check_req(lorawan_buffer_t *buf)
static int _fopts_mlme_link_check_req(lorawan_buffer_t *buf)
{
if (buf) {
assert(buf->index + GNRC_LORAWAN_CID_SIZE <= buf->size);
@ -301,6 +336,28 @@ static void _mlme_link_check_ans(gnrc_lorawan_t *mac, uint8_t *p)
mac->mlme.pending_mlme_opts &= ~GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ;
}
static int _fopts_mlme_link_rekey_ind(lorawan_buffer_t *buf)
{
if (buf) {
assert(buf->index + GNRC_LORAWAN_CID_SIZE +
GNCR_LORAWAN_REKEY_IND_SIZE <= buf->size);
buf->data[buf->index++] = GNCR_LORAWAN_CID_REKEY_CONF;
buf->data[buf->index++] = MINOR_LRWAN;
}
return GNRC_LORAWAN_CID_SIZE + GNCR_LORAWAN_REKEY_IND_SIZE;
}
static void _mlme_rekey_check_conf(gnrc_lorawan_t *mac, uint8_t *p)
{
/* server version must by smaller or equal to device's LoRaWAN version */
uint8_t server_minor = p[1];
if (server_minor <= MINOR_LRWAN) {
mac->mlme.pending_mlme_opts &= ~GNRC_LORAWAN_MLME_OPTS_REKEY_IND_REQ;
}
}
void gnrc_lorawan_process_fopts(gnrc_lorawan_t *mac, uint8_t *fopts,
size_t size)
{
@ -314,12 +371,16 @@ void gnrc_lorawan_process_fopts(gnrc_lorawan_t *mac, uint8_t *fopts,
for (uint8_t pos = 0; pos < size; pos += ret) {
switch (fopts[pos]) {
case GNRC_LORAWAN_CID_LINK_CHECK_ANS:
ret += GNRC_LORAWAN_FOPT_LINK_CHECK_ANS_SIZE;
cb = _mlme_link_check_ans;
break;
default:
return;
case GNRC_LORAWAN_CID_LINK_CHECK_ANS:
ret += GNRC_LORAWAN_FOPT_LINK_CHECK_ANS_SIZE;
cb = _mlme_link_check_ans;
break;
case GNCR_LORAWAN_CID_REKEY_CONF:
ret += GNRC_LORAWAN_FOPT_REKEY_CONF_SIZE;
cb = _mlme_rekey_check_conf;
break;
default:
return;
}
if (pos + ret > size) {
@ -338,5 +399,9 @@ uint8_t gnrc_lorawan_build_options(gnrc_lorawan_t *mac, lorawan_buffer_t *buf)
size += _fopts_mlme_link_check_req(buf);
}
if (mac->mlme.pending_mlme_opts & GNRC_LORAWAN_MLME_OPTS_REKEY_IND_REQ) {
size += _fopts_mlme_link_rekey_ind(buf);
}
return size;
}

View File

@ -38,7 +38,7 @@ int gnrc_lorawan_set_dr(gnrc_lorawan_t *mac, uint8_t datarate)
if (!gnrc_lorawan_validate_dr(datarate)) {
return -EINVAL;
}
DEBUG("gnrc_lorawan_region: Data Rate: DR%u \n",datarate);
DEBUG("gnrc_lorawan_region: Data Rate: DR%u \n", datarate);
uint8_t bw = dr_bw[datarate];
uint8_t sf = dr_sf[datarate];
@ -60,6 +60,7 @@ uint8_t gnrc_lorawan_rx1_get_dr_offset(uint8_t dr_up, uint8_t dr_offset)
{
DEBUG("gnrc_lorawan_region: RX1DRoffset: %u \n", dr_offset);
int dr_eff = dr_offset > 5 ? 5 - dr_offset : dr_offset;
return MIN(5, MAX(0, dr_up - dr_eff));
}
#endif
@ -72,7 +73,7 @@ int gnrc_lorawan_phy_set_channel_mask(gnrc_lorawan_t *mac, uint16_t channel_mask
for (int n = channel_mask, i = 0; n; n = n >> 1, i++) {
if ((n & 0x1) && !mac->channel[i]) {
return -EINVAL;
return -EINVAL;
}
}
@ -96,7 +97,7 @@ void gnrc_lorawan_channels_init(gnrc_lorawan_t *mac)
}
}
uint32_t gnrc_lorawan_pick_channel(gnrc_lorawan_t *mac)
uint8_t gnrc_lorawan_pick_channel(gnrc_lorawan_t *mac)
{
uint8_t index = 0;
@ -106,7 +107,8 @@ uint32_t gnrc_lorawan_pick_channel(gnrc_lorawan_t *mac)
for (int i = 0; i < pos + 1; i++) {
state = bitarithm_test_and_clear(state, &index);
}
return mac->channel[index];
return index;
}
void gnrc_lorawan_process_cflist(gnrc_lorawan_t *mac, uint8_t *cflist)

View File

@ -46,6 +46,8 @@ extern "C" {
#define MAJOR_MASK 0x3 /**< Major mtype mask */
#define MAJOR_LRWAN_R1 0x0 /**< LoRaWAN R1 version type */
#define MINOR_LRWAN 0x1 /**< Minor LoRaWAN version of device */
#define JOIN_REQUEST_SIZE (23U) /**< Join Request size in bytes */
#define MIC_SIZE (4U) /**< MIC size in bytes */
#define CFLIST_SIZE (16U) /**< Channel Frequency list size in bytes */
@ -68,11 +70,16 @@ extern "C" {
#define GNRC_LORAWAN_BACKOFF_BUDGET_3 (8700000LL) /**< budget of time on air every 24 hours */
#define GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ (1 << 0) /**< Internal Link Check request flag */
#define GNRC_LORAWAN_MLME_OPTS_REKEY_IND_REQ (1 << 1) /**< Internal Rekey Indication flag */
#define GNRC_LORAWAN_CID_SIZE (1U) /**< size of Command ID in FOps */
#define GNRC_LORAWAN_CID_LINK_CHECK_ANS (0x02) /**< Link Check CID */
#define GNCR_LORAWAN_REKEY_IND_SIZE (1U) /**< RekeyInd MAC command size */
#define GNCR_LORAWAN_CID_REKEY_CONF (0x0B) /**< Reykey Confirmation CID */
#define GNRC_LORAWAN_FOPT_LINK_CHECK_ANS_SIZE (3U) /**< size of Link check answer */
#define GNRC_LORAWAN_FOPT_REKEY_CONF_SIZE (2U) /**< size of Rekey confirmation */
#define GNRC_LORAWAN_JOIN_DELAY_U32_MASK (0x1FFFFF) /**< mask for detecting overflow in frame counter */
@ -92,12 +99,21 @@ extern "C" {
#define GNRC_LORAWAN_BACKOFF_TIME_3 (24U) /**< duration of third backoff state (in hours) */
#define GNRC_LORAWAN_APP_NONCE_SIZE (3U) /**< App Nonce size */
#define GNRC_LORAWAN_JOIN_NONCE_SIZE (3U) /**< Join nonce size */
#define GNRC_LORAWAN_NET_ID_SIZE (3U) /**< Net ID size */
#define GNRC_LORAWAN_DEV_NONCE_SIZE (2U) /**< Dev Nonce size */
#define GNRC_LORAWAN_FOPTS_MAX_SIZE (15U) /**< Maximum size of Fopts field */
#define GNRC_LORAWAN_FPORT_SIZE (1U) /**< Size of the Fport field */
#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7)
#define GNRC_LORAWAN_STATE_FLASHPAGE_NUM (0x7) /**< Flashpage number where to store state */
#else
#define GNRC_LORAWAN_STATE_FLASHPAGE_NUM (FLASHPAGE_NUMOF - 0x4) /**< Flashpage number where to store state */
#endif
#define GNRC_LORAWAN_INITIALIZED_MARKER (0x52f94f54U) /**< Persistent state initialized marker */
/**
* @brief Size of the internal MHDR-MIC buffer
*/
@ -112,7 +128,7 @@ extern "C" {
typedef struct {
uint8_t *data; /**< pointer to the beginning of the buffer holding data */
uint8_t size; /**< size of the buffer */
uint8_t index; /**< current inxed in the buffer */
uint8_t index; /**< current index in the buffer */
} lorawan_buffer_t;
/**
@ -120,11 +136,24 @@ typedef struct {
*/
typedef struct {
void *deveui; /**< pointer to the Device EUI */
void *appeui; /**< pointer to the Application EUI */
void *appkey; /**< pointer to the Application Key */
void *joineui; /**< pointer to the Join EUI */
void *nwkkey; /**< pointer to the Network Key. Mapped to App key if LoRaWAN 1.0x */
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
void *appkey; /**< pointer to the App key */
#endif
uint8_t dr; /**< datarate for the Join Request */
} mlme_lorawan_join_t;
/**
* @brief MLME Join Request type
*/
typedef enum {
REJOIN_REQ_0, /**< Rejoin-request type 0 */
REJOIN_REQ_1, /**< Rejoin-request type 1 */
REJOIN_REQ_2, /**< Rejoin-request type 2 */
JOIN_REQ = 0xFF /**< Join-request type */
} mlme_join_req_type_t;
/**
* @brief MLME Link Check confirmation data
*/
@ -147,7 +176,11 @@ typedef struct {
*/
typedef struct {
uint32_t fcnt; /**< uplink framecounter */
uint32_t fcnt_down; /**< downlink frame counter */
uint32_t fcnt_down; /**< downlink frame counter. Mapped to network downlink frame counter if using LoRaWAN 1.1 */
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
uint32_t afcnt_down; /**< application downlink frame counter */
uint32_t last_fcnt_down; /**< last downlink frame counter used to decrypt frame. Needed to compute ConfFCnt */
#endif
iolist_t *msdu; /**< current MSDU */
int nb_trials; /**< holds the remaining number of retransmissions */
int ack_requested; /**< whether the network server requested an ACK */
@ -168,6 +201,20 @@ typedef struct {
uint8_t backoff_state; /**< state in the backoff state machine */
} gnrc_lorawan_mlme_t;
/**
* @brief GNRC LoRaWAN key context struct
*/
typedef struct {
uint8_t *appskey; /**< pointer to Application SKey buffer */
uint8_t *fnwksintkey; /**< pointer to Forwarding Network session integrity key */
uint8_t *snwksintkey; /**< pointer to Serving Network session integrity key */
uint8_t *nwksenckey; /**< pointer to Network session encryption key */
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
uint8_t *jsintkey; /**< pointer to join session integrity key */
uint8_t *jsenckey; /**< pointer to join session encryption key */
#endif
} gnrc_lorawan_key_ctx_t;
/**
* @brief GNRC LoRaWAN mac descriptor */
typedef struct {
@ -175,8 +222,11 @@ typedef struct {
gnrc_lorawan_mlme_t mlme; /**< MLME descriptor */
void *mlme_buf; /**< pointer to MLME buffer */
void *mcps_buf; /**< pointer to MCPS buffer */
uint8_t *nwkskey; /**< pointer to Network SKey buffer */
uint8_t *appskey; /**< pointer to Application SKey buffer */
uint8_t *joineui; /**< pointer to Join EUI */
gnrc_lorawan_key_ctx_t ctx; /**< GNRC LoRaWAN key context struct */
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
bool optneg; /**< optneg bit */
#endif
uint32_t channel[GNRC_LORAWAN_MAX_CHANNELS]; /**< channel array */
uint16_t channel_mask; /**< channel mask */
uint32_t toa; /**< Time on Air of the last transmission */
@ -188,8 +238,17 @@ typedef struct {
uint8_t rx_delay; /**< Delay of first reception window */
uint8_t dr_range[GNRC_LORAWAN_MAX_CHANNELS]; /**< Datarate Range for all channels */
uint8_t last_dr; /**< datarate of the last transmission */
uint8_t last_chan_idx; /**< index of channel used for last transmission */
} gnrc_lorawan_t;
/**
* @brief LoRaWAN state that needs to be preserved across reboots
*/
typedef struct {
uint32_t initialized_marker; /**< state initialized marker */
uint8_t dev_nonce[2]; /**< Device Nonce */
} gnrc_lorawan_persistent_state_t;
/**
* @brief Encrypts LoRaWAN payload
*
@ -205,6 +264,24 @@ void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr,
uint32_t fcnt, uint8_t dir,
const uint8_t *appskey);
/**
* @brief Encrypts FOpts field
*
* @note This function is also used for decrypting the FOpts field. The LoRaWAN server encrypts the packet using decryption, so the end device only needs to implement encryption
* @note This function is used only in LoRaWAN 1.1
*
* @param[in] fopts pointer to fopts
* @param[in] len length of fopts
* @param[in] dev_addr device address
* @param[in] fcnt frame counter
* @param[in] afcnt flag indicating if aFCntDown is used
* @param[in] dir direction of the packet (0 if uplink, 1 if downlink)
* @param[in] key pointer to key
*/
void gnrc_lorawan_encrypt_fopts(uint8_t *fopts, size_t len,
const le_uint32_t *dev_addr, uint32_t fcnt,
bool afcnt, uint8_t dir, const uint8_t *key);
/**
* @brief Decrypts join accept message
*
@ -220,19 +297,34 @@ void gnrc_lorawan_decrypt_join_accept(const uint8_t *key, uint8_t *pkt,
* @brief Generate LoRaWAN session keys
*
* Intended to be called after a successful Join Request in order to generate
* NwkSKey and AppSKey
* AppSKey, SNwkSIntKey, FNwkSIntKey and NwkSEncKey
*
* @param[in] app_nonce pointer to the app_nonce of the Join Accept message
* @param[in] dev_nonce pointer to the dev_nonce buffer
* @param[in] appkey pointer to eh AppKey
* @param[out] nwkskey pointer to the NwkSKey
* @param[out] appskey pointer to the AppSKey
* @param[in] join_nonce pointer to the join_nonce of the Join Accept message
* @param[in] dev_nonce pointer to the dev_nonce buffer
* @param[in] joineui pointer to the Join EUI. NULL if LoRaWAN 1.0x
* @param[in, out] mac pointer to the LoRaWAN mac descriptor
*/
void gnrc_lorawan_generate_session_keys(const uint8_t *app_nonce,
void gnrc_lorawan_generate_session_keys(const uint8_t *join_nonce,
const uint8_t *dev_nonce,
const uint8_t *appkey, uint8_t *nwkskey,
uint8_t *appskey);
const uint8_t *joineui,
gnrc_lorawan_t *mac);
/**
* @brief Generate LoRaWAN 1.1x lifetime session keys
*
* Called in order to derive JSIntKey and JSEncKey.
*
* LoRaWAN specification 1.1 section 6.1.1.4
*
* @param[in] deveui pointer to the join_nonce of the Join Accept message
* @param[in] nwkkey pointer to the Network key
* @param[out] jsintkey pointer to the Join session integrity key
* @param[out] jsenckey pointer to the Join session encryption key
*/
void gnrc_lorawan_generate_lifetime_session_keys(const uint8_t *deveui,
const uint8_t *nwkkey,
uint8_t *jsintkey,
uint8_t *jsenckey);
/**
* @brief Set datarate for the next transmission
*
@ -263,9 +355,9 @@ size_t gnrc_lorawan_build_uplink(gnrc_lorawan_t *mac, iolist_t *payload,
*
* @param[in] mac pointer to the MAC descriptor
*
* @return a free channel
* @return index of free channel inside channel array
*/
uint32_t gnrc_lorawan_pick_channel(gnrc_lorawan_t *mac);
uint8_t gnrc_lorawan_pick_channel(gnrc_lorawan_t *mac);
/**
* @brief Build fopts header
@ -289,29 +381,55 @@ void gnrc_lorawan_process_fopts(gnrc_lorawan_t *mac, uint8_t *fopts,
size_t size);
/**
* @brief calculate join Message Integrity Code
* @brief Calculate join-request Message Integrity Code
*
* @param[in] buf pointer to the frame
* @param[in] len length of the frame
* @param[in] key key used to calculate the MIC
* @param[in] key key to be used to calculate the MIC
* @param[out] out calculated MIC
*/
void gnrc_lorawan_calculate_join_mic(const uint8_t *buf, size_t len,
const uint8_t *key, le_uint32_t *out);
void gnrc_lorawan_calculate_join_req_mic(const uint8_t *buf, size_t len,
uint8_t *key, le_uint32_t *out);
/**
* @brief Calculate Message Integrity Code for a MCPS message
* @brief Calculate join-accept Message Integrity Code
*
* @param[in] buf pointer to the frame
* @param[in] len length of the frame
* @param[in] mac pointer to MAC descriptor
* @param[out] out calculated MIC
*/
void gnrc_lorawan_calculate_join_acpt_mic(const uint8_t *buf, size_t len,
gnrc_lorawan_t *mac, le_uint32_t *out);
/**
* @brief Calculate Message Integrity Code for an uplink MCPS message
*
* @param[in] frame pointer to the PSDU frame (without MIC)
* @param[in] conf_fcnt frame counter value of confirmed uplink frame. Always
* zero if using LoRaWAN 1.0x
* @param[in] mac pointer to MAC descriptor
* @param[out] out calculated MIC
*/
void gnrc_lorawan_calculate_mic_uplink(iolist_t *frame, uint16_t conf_fcnt,
gnrc_lorawan_t *mac, le_uint32_t *out);
/**
* @brief Calculate Message Integrity Code for downlink MCPS message
*
* @param[in] dev_addr the Device Address
* @param[in] fcnt frame counter
* @param[in] dir direction of the packet (0 is uplink, 1 is downlink)
* @param[in] conf_fcnt frame counter value of confirmed uplink frame
* @param[in] frame pointer to the PSDU frame (without MIC)
* @param[in] nwkskey pointer to the Network Session Key
* @param[in] snwksintkey pointer to serving network session integrity key
* @param[out] out calculated MIC
*/
void gnrc_lorawan_calculate_mic(const le_uint32_t *dev_addr, uint32_t fcnt,
uint8_t dir, iolist_t *frame,
const uint8_t *nwkskey, le_uint32_t *out);
void gnrc_lorawan_calculate_mic_downlink(const le_uint32_t *dev_addr,
uint32_t fcnt, uint16_t conf_fcnt,
iolist_t *frame,
const uint8_t *snwksintkey,
le_uint32_t *out);
/**
* @brief Build a MCPS LoRaWAN header
*
@ -362,8 +480,10 @@ void gnrc_lorawan_reset(gnrc_lorawan_t *mac);
* @param[in] mac pointer to the MAC descriptor
* @param[in] psdu the psdu frame to be sent
* @param[in] dr the datarate used for the transmission
* @param[in] chan the channel used for transmission
*/
void gnrc_lorawan_send_pkt(gnrc_lorawan_t *mac, iolist_t *psdu, uint8_t dr);
void gnrc_lorawan_send_pkt(gnrc_lorawan_t *mac, iolist_t *psdu, uint8_t dr,
uint32_t chan);
/**
* @brief Process join accept message
@ -488,6 +608,209 @@ void gnrc_lorawan_set_rx2_dr(gnrc_lorawan_t *mac, uint8_t rx2_dr);
*/
void gnrc_lorawan_trigger_join(gnrc_lorawan_t *mac);
/**
* @brief Store DevNonce in flash memory
*
* @param[in] dev_nonce pointer to the DevNonce
*/
void gnrc_lorawan_store_dev_nonce(uint8_t *dev_nonce);
/**
* @brief Check whether OptNeg bit is set
*
* When using LoRaWAN 1.1x the OptNeg bit indicates whether the Network Server
* implements the LoRaWAN1.0 protocol version (unset) or 1.1 and later (set).
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mac pointer to the MAC descriptor
* @return true if OptNeg bit is set
* @return false if OptNeg bit is unset
*/
static inline bool gnrc_lorawan_optneg_is_set(const gnrc_lorawan_t *mac)
{
(void)mac;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
return mac->optneg;
#else
return 1; /* NO-OP */
#endif
}
/**
* @brief Set OptNeg bit in the MAC descriptor
*
* When using LoRaWAN 1.1x the OptNeg bit indicates whether the Network Server
* implements the LoRaWAN1.0 protocol version (unset) or 1.1 and later (set).
*
* This setter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mac pointer to the MAC descriptor
* @param[in] optneg OptNeg bit
*/
static inline void gnrc_lorawan_set_optneg(gnrc_lorawan_t *mac, uint8_t optneg)
{
(void)mac;
(void)optneg;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
mac->optneg = optneg;
#endif
}
/**
* @brief Get the join session integrity key from the MAC descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mac pointer to the MAC descriptor
* @return pointer to join session integrity key
*/
static inline uint8_t *gnrc_lorawan_get_jsintkey(const gnrc_lorawan_t *mac)
{
(void)mac;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
return mac->ctx.jsintkey;
#else
return NULL; /* NO-OP */
#endif
}
/**
* @brief Get the join session encryption key from the MAC descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mac pointer to the MAC descriptor
* @return pointer to join session encryption key
*/
static inline uint8_t *gnrc_lorawan_get_jsenckey(const gnrc_lorawan_t *mac)
{
(void)mac;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
return mac->ctx.jsenckey;
#else
return NULL; /* NO-OP */
#endif
}
/**
* @brief Get the application downlink frame counter from the MAC descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mac pointer to the MAC descriptor
* @return application downlink frame counter
*/
static inline uint32_t gnrc_lorawan_get_afcnt_down(const gnrc_lorawan_t *mac)
{
(void)mac;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
return mac->mcps.afcnt_down;
#else
return 0; /* NO-OP */
#endif
}
/**
* @brief Set the application downlink frame counter in the MAC descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mac pointer to the MAC descriptor
* @param[in] afcnt_down application downlink frame counter
*/
static inline void gnrc_lorawan_set_afcnt_down(gnrc_lorawan_t *mac, uint32_t afcnt_down)
{
(void)mac;
(void)afcnt_down;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
mac->mcps.afcnt_down = afcnt_down;
#endif
}
/**
* @brief Get the last downlink frame counter from the MAC descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mac pointer to the MAC descriptor
*/
static inline uint32_t gnrc_lorawan_get_last_fcnt_down(const gnrc_lorawan_t *mac)
{
(void)mac;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
return mac->mcps.last_fcnt_down;
#else
return 0; /* NO-OP */
#endif
}
/**
* @brief Set the last downlink frame counter in the MAC descriptor
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mac pointer to the MAC descriptor
* @param[in] last_fcnt_down last downlink frame counter
*/
static inline void gnrc_lorawan_set_last_fcnt_down(gnrc_lorawan_t *mac, uint32_t last_fcnt_down)
{
(void)mac;
(void)last_fcnt_down;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
mac->mcps.last_fcnt_down = last_fcnt_down;
#endif
}
/**
* @brief Get the app key from the MLME join request data
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mlme_join pointer to the MLME join request data
* @return pointer to the app key
*/
static inline uint8_t * gnrc_lorawan_mlme_join_get_appkey(const mlme_lorawan_join_t *mlme_join)
{
(void)mlme_join;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
return mlme_join->appkey;
#else
return NULL; /* NO-OP */
#endif
}
/**
* @brief Se the app key in the MLME join request data
*
* This getter function exists to allow if (IS_USED(...)) constructs in the
* LoRaWAN code in order to increase code coverage.
*
* @param[in] mlme_join pointer to the MLME join request data
* @param[in] key pointer to the app key
*/
static inline void gnrc_lorawan_mlme_join_set_appkey(mlme_lorawan_join_t *mlme_join, uint8_t *key)
{
(void)mlme_join;
(void)key;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
mlme_join->appkey = key;
#endif
}
#ifdef __cplusplus
}
#endif

View File

@ -33,15 +33,18 @@
#define MSG_TYPE_MLME_BACKOFF_EXPIRE (0x3458) /**< Backoff timer expiration message type */
static uint8_t _nwkskey[LORAMAC_NWKSKEY_LEN];
static uint8_t _appskey[LORAMAC_APPSKEY_LEN];
static uint8_t _appkey[LORAMAC_APPKEY_LEN];
static uint8_t _snwksintkey[LORAMAC_SNWKSINTKEY_LEN];
static uint8_t _nwksenckey[LORAMAC_NWKSENCKEY_LEN];
static uint8_t _nwkkey[LORAMAC_NWKKEY_LEN];
static uint8_t _joineui[LORAMAC_JOINEUI_LEN];
static uint8_t _fnwksintkey[LORAMAC_FNWKSINTKEY_LEN];
static uint8_t _deveui[LORAMAC_DEVEUI_LEN];
static uint8_t _appeui[LORAMAC_APPEUI_LEN];
static uint8_t _devaddr[LORAMAC_DEVADDR_LEN];
static msg_t timeout_msg = {.type = MSG_TYPE_TIMEOUT};
static msg_t backoff_msg = {.type = MSG_TYPE_MLME_BACKOFF_EXPIRE};
static msg_t timeout_msg = { .type = MSG_TYPE_TIMEOUT };
static msg_t backoff_msg = { .type = MSG_TYPE_MLME_BACKOFF_EXPIRE };
static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif);
@ -82,12 +85,14 @@ void gnrc_lorawan_mlme_confirm(gnrc_lorawan_t *mac, mlme_confirm_t *confirm)
void gnrc_lorawan_set_timer(gnrc_lorawan_t *mac, uint32_t us)
{
gnrc_netif_lorawan_t *lw_netif = container_of(mac, gnrc_netif_lorawan_t, mac);
ztimer_set_msg(ZTIMER_MSEC, &lw_netif->timer, us/1000, &timeout_msg, thread_getpid());
ztimer_set_msg(ZTIMER_MSEC, &lw_netif->timer, us / 1000, &timeout_msg, thread_getpid());
}
void gnrc_lorawan_remove_timer(gnrc_lorawan_t *mac)
{
gnrc_netif_lorawan_t *lw_netif = container_of(mac, gnrc_netif_lorawan_t, mac);
ztimer_remove(ZTIMER_MSEC, &lw_netif->timer);
}
@ -121,6 +126,7 @@ void gnrc_lorawan_mcps_indication(gnrc_lorawan_t *mac, mcps_indication_t *ind)
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, ind->data.pkt->iol_base,
ind->data.pkt->iol_len,
nettype);
if (!pkt) {
DEBUG("gnrc_lorawan: mcps_indication: couldn't allocate pktbuf\n");
return;
@ -205,18 +211,18 @@ static void _driver_cb(netdev_t *dev, netdev_event_t event)
else {
DEBUG("gnrc_netif: event triggered -> %i\n", event);
switch (event) {
case NETDEV_EVENT_RX_COMPLETE:
_rx_done(mac);
break;
case NETDEV_EVENT_TX_COMPLETE:
gnrc_lorawan_radio_tx_done_cb(mac);
break;
case NETDEV_EVENT_RX_TIMEOUT:
gnrc_lorawan_radio_rx_timeout_cb(mac);
break;
default:
DEBUG("gnrc_netif: warning: unhandled event %u.\n", event);
break;
case NETDEV_EVENT_RX_COMPLETE:
_rx_done(mac);
break;
case NETDEV_EVENT_TX_COMPLETE:
gnrc_lorawan_radio_tx_done_cb(mac);
break;
case NETDEV_EVENT_RX_TIMEOUT:
gnrc_lorawan_radio_rx_timeout_cb(mac);
break;
default:
DEBUG("gnrc_netif: warning: unhandled event %u.\n", event);
break;
}
}
}
@ -249,6 +255,7 @@ netdev_t *gnrc_lorawan_get_netdev(gnrc_lorawan_t *mac)
static int _init(gnrc_netif_t *netif)
{
DEBUG("netif init ! \n");
int res = gnrc_netif_default_init(netif);
if (res < 0) {
@ -259,22 +266,54 @@ static int _init(gnrc_netif_t *netif)
_reset(netif);
/* Convert default keys, address and EUIs to hex */
fmt_hex_bytes(_nwkskey, CONFIG_LORAMAC_NWK_SKEY_DEFAULT);
fmt_hex_bytes(_appskey, CONFIG_LORAMAC_APP_SKEY_DEFAULT);
fmt_hex_bytes(_appkey, CONFIG_LORAMAC_APP_KEY_DEFAULT);
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
fmt_hex_bytes(_joineui, CONFIG_LORAMAC_JOIN_EUI_DEFAULT);
fmt_hex_bytes(_appkey, CONFIG_LORAMAC_APP_KEY_DEFAULT);
fmt_hex_bytes(_nwkkey, CONFIG_LORAMAC_NWK_KEY_DEFAULT);
fmt_hex_bytes(_fnwksintkey, CONFIG_LORAMAC_FNWKSINT_KEY_DEFAULT);
fmt_hex_bytes(_snwksintkey, CONFIG_LORAMAC_SNWKSINT_KEY_DEFAULT);
fmt_hex_bytes(_nwksenckey, CONFIG_LORAMAC_NWKSENC_KEY_DEFAULT);
}
else {
fmt_hex_bytes(_joineui, CONFIG_LORAMAC_APP_EUI_DEFAULT);
fmt_hex_bytes(_nwkkey, CONFIG_LORAMAC_APP_KEY_DEFAULT);
fmt_hex_bytes(_fnwksintkey, CONFIG_LORAMAC_NWK_SKEY_DEFAULT);
}
fmt_hex_bytes(_deveui, CONFIG_LORAMAC_DEV_EUI_DEFAULT);
fmt_hex_bytes(_appeui, CONFIG_LORAMAC_APP_EUI_DEFAULT);
fmt_hex_bytes(_devaddr, CONFIG_LORAMAC_DEV_ADDR_DEFAULT);
/* Initialize default keys, address and EUIs */
memcpy(netif->lorawan.nwkskey, _nwkskey, sizeof(_nwkskey));
memcpy(netif->lorawan.appskey, _appskey, sizeof(_appskey));
_memcpy_reversed(netif->lorawan.deveui, _deveui, sizeof(_deveui));
memcpy(netif->lorawan.appkey, _appkey, sizeof(_appkey));
_memcpy_reversed(netif->lorawan.appeui, _appeui, sizeof(_appeui));
_memcpy_reversed(netif->lorawan.joineui, _joineui, sizeof(_joineui));
memcpy(netif->lorawan.nwkkey, _nwkkey, sizeof(_nwkkey));
memcpy(netif->lorawan.fnwksintkey, _fnwksintkey, sizeof(_fnwksintkey));
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
gnrc_netif_lorawan_set_appkey(&netif->lorawan, _appkey, sizeof(_appkey));
gnrc_netif_lorawan_set_snwksintkey(&netif->lorawan, _snwksintkey, sizeof(_snwksintkey));
gnrc_netif_lorawan_set_nwksenckey(&netif->lorawan, _nwksenckey, sizeof(_nwksenckey));
}
_set_be_addr(&netif->lorawan.mac, _devaddr);
gnrc_lorawan_init(&netif->lorawan.mac, netif->lorawan.nwkskey, netif->lorawan.appskey);
const gnrc_lorawan_key_ctx_t ctx = {
.appskey = netif->lorawan.appskey,
.fnwksintkey = netif->lorawan.fnwksintkey,
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
.snwksintkey = netif->lorawan.snwksintkey,
.nwksenckey = netif->lorawan.nwksenckey,
.jsintkey = netif->lorawan.jsintkey,
.jsenckey = netif->lorawan.jsenckey
#else
.snwksintkey = netif->lorawan.fnwksintkey,
.nwksenckey = netif->lorawan.fnwksintkey
#endif
};
gnrc_lorawan_init(&netif->lorawan.mac, netif->lorawan.joineui, &ctx);
ztimer_set_msg(ZTIMER_MSEC, &netif->lorawan.backoff_timer,
GNRC_LORAWAN_BACKOFF_WINDOW_TICK / 1000,
@ -338,7 +377,7 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *payload)
{ .type = netif->lorawan.ack_req ? MCPS_CONFIRMED : MCPS_UNCONFIRMED,
.data =
{ .pkt = (iolist_t *)payload, .port = port,
.dr = netif->lorawan.datarate } };
.dr = netif->lorawan.datarate } };
mcps_confirm_t conf;
gnrc_lorawan_mcps_request(&netif->lorawan.mac, &req, &conf);
@ -357,16 +396,16 @@ static void _msg_handler(gnrc_netif_t *netif, msg_t *msg)
(void)netif;
(void)msg;
switch (msg->type) {
case MSG_TYPE_TIMEOUT:
gnrc_lorawan_timeout_cb(&netif->lorawan.mac);
break;
case MSG_TYPE_MLME_BACKOFF_EXPIRE:
gnrc_lorawan_mlme_backoff_expire_cb(&netif->lorawan.mac);
ztimer_set_msg(ZTIMER_MSEC, &netif->lorawan.backoff_timer,
GNRC_LORAWAN_BACKOFF_WINDOW_TICK / 1000,
&backoff_msg, thread_getpid());
default:
break;
case MSG_TYPE_TIMEOUT:
gnrc_lorawan_timeout_cb(&netif->lorawan.mac);
break;
case MSG_TYPE_MLME_BACKOFF_EXPIRE:
gnrc_lorawan_mlme_backoff_expire_cb(&netif->lorawan.mac);
ztimer_set_msg(ZTIMER_MSEC, &netif->lorawan.backoff_timer,
GNRC_LORAWAN_BACKOFF_WINDOW_TICK / 1000,
&backoff_msg, thread_getpid());
default:
break;
}
}
@ -379,47 +418,47 @@ static int _get(gnrc_netif_t *netif, gnrc_netapi_opt_t *opt)
mlme_request_t mlme_request;
switch (opt->opt) {
case NETOPT_OTAA:
assert(opt->data_len >= sizeof(netopt_enable_t));
*((netopt_enable_t *)opt->data) = netif->lorawan.otaa;
break;
case NETOPT_LINK:
mlme_request.type = MLME_GET;
mlme_request.mib.type = MIB_ACTIVATION_METHOD;
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
&mlme_confirm);
*((netopt_enable_t *)opt->data) = mlme_confirm.mib.activation !=
MLME_ACTIVATION_NONE;
break;
case NETOPT_LINK_CHECK:
assert(opt->data_len == sizeof(netopt_enable_t));
*((netopt_enable_t *)opt->data) =
(netif->lorawan.flags & GNRC_NETIF_LORAWAN_FLAGS_LINK_CHECK) ?
NETOPT_ENABLE : NETOPT_DISABLE;
break;
case NETOPT_NUM_GATEWAYS:
assert(opt->data_len == sizeof(uint8_t));
*((uint8_t *)opt->data) = netif->lorawan.num_gateways;
break;
case NETOPT_DEMOD_MARGIN:
assert(opt->data_len == sizeof(uint8_t));
*((uint8_t *)opt->data) = netif->lorawan.demod_margin;
break;
case NETOPT_ADDRESS:
mlme_request.type = MLME_GET;
mlme_request.mib.type = MIB_DEV_ADDR;
case NETOPT_OTAA:
assert(opt->data_len >= sizeof(netopt_enable_t));
*((netopt_enable_t *)opt->data) = netif->lorawan.otaa;
break;
case NETOPT_LINK:
mlme_request.type = MLME_GET;
mlme_request.mib.type = MIB_ACTIVATION_METHOD;
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
&mlme_confirm);
*((netopt_enable_t *)opt->data) = mlme_confirm.mib.activation !=
MLME_ACTIVATION_NONE;
break;
case NETOPT_LINK_CHECK:
assert(opt->data_len == sizeof(netopt_enable_t));
*((netopt_enable_t *)opt->data) =
(netif->lorawan.flags & GNRC_NETIF_LORAWAN_FLAGS_LINK_CHECK) ?
NETOPT_ENABLE : NETOPT_DISABLE;
break;
case NETOPT_NUM_GATEWAYS:
assert(opt->data_len == sizeof(uint8_t));
*((uint8_t *)opt->data) = netif->lorawan.num_gateways;
break;
case NETOPT_DEMOD_MARGIN:
assert(opt->data_len == sizeof(uint8_t));
*((uint8_t *)opt->data) = netif->lorawan.demod_margin;
break;
case NETOPT_ADDRESS:
mlme_request.type = MLME_GET;
mlme_request.mib.type = MIB_DEV_ADDR;
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
&mlme_confirm);
tmp = *((uint32_t *)mlme_confirm.mib.dev_addr);
tmp = byteorder_swapl(tmp);
memcpy(opt->data, &tmp, sizeof(uint32_t));
res = sizeof(uint32_t);
break;
default:
res = netif->dev->driver->get(netif->dev, opt->opt, opt->data,
opt->data_len);
break;
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
&mlme_confirm);
tmp = *((uint32_t *)mlme_confirm.mib.dev_addr);
tmp = byteorder_swapl(tmp);
memcpy(opt->data, &tmp, sizeof(uint32_t));
res = sizeof(uint32_t);
break;
default:
res = netif->dev->driver->get(netif->dev, opt->opt, opt->data,
opt->data_len);
break;
}
return res;
}
@ -432,101 +471,138 @@ static int _set(gnrc_netif_t *netif, const gnrc_netapi_opt_t *opt)
gnrc_netif_acquire(netif);
switch (opt->opt) {
case NETOPT_LORAWAN_DR:
assert(opt->data_len == sizeof(uint8_t));
if (!gnrc_lorawan_validate_dr(*((uint8_t *)opt->data))) {
DEBUG("gnrc_netif_lorawan: Invalid datarate\n");
res = -EINVAL;
break;
}
netif->lorawan.datarate = *((uint8_t *)opt->data);
break;
case NETOPT_LORAWAN_TX_PORT:
assert(opt->data_len == sizeof(uint8_t));
netif->lorawan.port = *((uint8_t *)opt->data);
break;
case NETOPT_ACK_REQ:
assert(opt->data_len == sizeof(netopt_enable_t));
netif->lorawan.ack_req = *((netopt_enable_t *)opt->data);
break;
case NETOPT_LORAWAN_APPKEY:
assert(opt->data_len == LORAMAC_APPKEY_LEN);
memcpy(netif->lorawan.appkey, opt->data, LORAMAC_APPKEY_LEN);
break;
case NETOPT_ADDRESS_LONG:
assert(opt->data_len == LORAMAC_DEVEUI_LEN);
_memcpy_reversed(netif->lorawan.deveui, opt->data,
LORAMAC_DEVEUI_LEN);
break;
case NETOPT_LORAWAN_APPEUI:
assert(opt->data_len == LORAMAC_APPEUI_LEN);
_memcpy_reversed(netif->lorawan.appeui, opt->data,
LORAMAC_APPEUI_LEN);
break;
case NETOPT_OTAA:
assert(opt->data_len == sizeof(netopt_enable_t));
netif->lorawan.otaa = *((netopt_enable_t *)opt->data);
break;
case NETOPT_LORAWAN_APPSKEY:
assert(opt->data_len >= LORAMAC_APPSKEY_LEN);
memcpy(netif->lorawan.appskey, opt->data, LORAMAC_APPSKEY_LEN);
break;
case NETOPT_LORAWAN_NWKSKEY:
assert(opt->data_len >= LORAMAC_NWKSKEY_LEN);
memcpy(netif->lorawan.nwkskey, opt->data, LORAMAC_NWKSKEY_LEN);
break;
case NETOPT_LINK:
{
netopt_enable_t en = *((netopt_enable_t *)opt->data);
if (en) {
if (netif->lorawan.otaa) {
mlme_request.type = MLME_JOIN;
mlme_request.join.deveui = netif->lorawan.deveui;
mlme_request.join.appeui = netif->lorawan.appeui;
mlme_request.join.appkey = netif->lorawan.appkey;
mlme_request.join.dr = netif->lorawan.datarate;
gnrc_lorawan_mlme_request(&netif->lorawan.mac,
&mlme_request, &mlme_confirm);
}
else {
mlme_request.type = MLME_SET;
mlme_request.mib.type = MIB_ACTIVATION_METHOD;
mlme_request.mib.activation = MLME_ACTIVATION_ABP;
gnrc_lorawan_mlme_request(&netif->lorawan.mac,
&mlme_request, &mlme_confirm);
}
}
else {
mlme_request.type = MLME_RESET;
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
&mlme_confirm);
res = mlme_confirm.status;
if (mlme_confirm.status == 0) {
/* reset netif as well */
_reset(netif);
}
}
case NETOPT_LORAWAN_DR:
assert(opt->data_len == sizeof(uint8_t));
if (!gnrc_lorawan_validate_dr(*((uint8_t *)opt->data))) {
DEBUG("gnrc_netif_lorawan: Invalid datarate\n");
res = -EINVAL;
break;
}
case NETOPT_ADDRESS:
assert(opt->data_len == sizeof(uint32_t));
_set_be_addr(&netif->lorawan.mac, opt->data);
break;
case NETOPT_LINK_CHECK:
netif->lorawan.flags |= GNRC_NETIF_LORAWAN_FLAGS_LINK_CHECK;
break;
case NETOPT_LORAWAN_RX2_DR:
assert(opt->data_len == sizeof(uint8_t));
mlme_request.type = MLME_SET;
mlme_request.mib.type = MIB_RX2_DR;
mlme_request.mib.rx2_dr = *((uint8_t *)opt->data);
netif->lorawan.datarate = *((uint8_t *)opt->data);
break;
case NETOPT_LORAWAN_TX_PORT:
assert(opt->data_len == sizeof(uint8_t));
netif->lorawan.port = *((uint8_t *)opt->data);
break;
case NETOPT_ACK_REQ:
assert(opt->data_len == sizeof(netopt_enable_t));
netif->lorawan.ack_req = *((netopt_enable_t *)opt->data);
break;
case NETOPT_ADDRESS_LONG:
assert(opt->data_len == LORAMAC_DEVEUI_LEN);
_memcpy_reversed(netif->lorawan.deveui, opt->data,
LORAMAC_DEVEUI_LEN);
break;
case NETOPT_LORAWAN_APPEUI:
case NETOPT_LORAWAN_JOINEUI:
assert(opt->data_len == LORAMAC_JOINEUI_LEN);
_memcpy_reversed(netif->lorawan.joineui, opt->data,
LORAMAC_JOINEUI_LEN);
break;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
case NETOPT_LORAWAN_NWKKEY:
assert(opt->data_len == LORAMAC_NWKKEY_LEN);
memcpy(netif->lorawan.nwkkey, opt->data, LORAMAC_NWKKEY_LEN);
break;
case NETOPT_LORAWAN_APPKEY:
assert(opt->data_len == LORAMAC_APPKEY_LEN);
memcpy(netif->lorawan.appkey, opt->data, LORAMAC_APPKEY_LEN);
break;
case NETOPT_LORAWAN_FNWKSINTKEY:
assert(opt->data_len == LORAMAC_FNWKSINTKEY_LEN);
_memcpy_reversed(netif->lorawan.fnwksintkey, opt->data,
LORAMAC_FNWKSINTKEY_LEN);
break;
case NETOPT_LORAWAN_SNWKSINTKEY:
assert(opt->data_len == LORAMAC_SNWKSINTKEY_LEN);
_memcpy_reversed(netif->lorawan.snwksintkey, opt->data,
LORAMAC_SNWKSINTKEY_LEN);
break;
case NETOPT_LORAWAN_NWKSENCKEY:
assert(opt->data_len == LORAMAC_NWKSENCKEY_LEN);
_memcpy_reversed(netif->lorawan.nwksenckey, opt->data,
LORAMAC_NWKSKEY_LEN);
break;
#else
case NETOPT_LORAWAN_APPKEY:
assert(opt->data_len == LORAMAC_NWKKEY_LEN);
memcpy(netif->lorawan.nwkkey, opt->data, LORAMAC_NWKKEY_LEN);
break;
case NETOPT_LORAWAN_NWKSKEY:
case NETOPT_LORAWAN_FNWKSINTKEY:
case NETOPT_LORAWAN_SNWKSINTKEY:
case NETOPT_LORAWAN_NWKSENCKEY:
assert(opt->data_len == LORAMAC_FNWKSINTKEY_LEN);
_memcpy_reversed(netif->lorawan.fnwksintkey, opt->data,
LORAMAC_FNWKSINTKEY_LEN);
break;
#endif
case NETOPT_OTAA:
assert(opt->data_len == sizeof(netopt_enable_t));
netif->lorawan.otaa = *((netopt_enable_t *)opt->data);
break;
case NETOPT_LORAWAN_APPSKEY:
assert(opt->data_len >= LORAMAC_APPSKEY_LEN);
memcpy(netif->lorawan.appskey, opt->data, LORAMAC_APPSKEY_LEN);
break;
case NETOPT_LINK:
{
netopt_enable_t en = *((netopt_enable_t *)opt->data);
if (en) {
if (netif->lorawan.otaa) {
mlme_request.type = MLME_JOIN;
mlme_request.join.deveui = netif->lorawan.deveui;
mlme_request.join.joineui = netif->lorawan.joineui;
mlme_request.join.nwkkey = netif->lorawan.nwkkey;
if (IS_USED(MODULE_GNRC_LORAWAN_1_1)) {
gnrc_lorawan_mlme_join_set_appkey(&mlme_request.join, gnrc_netif_lorawan_get_appkey(
&netif->lorawan));
}
mlme_request.join.dr = netif->lorawan.datarate;
gnrc_lorawan_mlme_request(&netif->lorawan.mac,
&mlme_request, &mlme_confirm);
}
else {
mlme_request.type = MLME_SET;
mlme_request.mib.type = MIB_ACTIVATION_METHOD;
mlme_request.mib.activation = MLME_ACTIVATION_ABP;
gnrc_lorawan_mlme_request(&netif->lorawan.mac,
&mlme_request, &mlme_confirm);
}
}
else {
mlme_request.type = MLME_RESET;
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
&mlme_confirm);
break;
default:
res = netif->dev->driver->set(netif->dev, opt->opt, opt->data,
opt->data_len);
break;
res = mlme_confirm.status;
if (mlme_confirm.status == 0) {
/* reset netif as well */
_reset(netif);
}
}
break;
}
case NETOPT_ADDRESS:
assert(opt->data_len == sizeof(uint32_t));
_set_be_addr(&netif->lorawan.mac, opt->data);
break;
case NETOPT_LINK_CHECK:
netif->lorawan.flags |= GNRC_NETIF_LORAWAN_FLAGS_LINK_CHECK;
break;
case NETOPT_LORAWAN_RX2_DR:
assert(opt->data_len == sizeof(uint8_t));
mlme_request.type = MLME_SET;
mlme_request.mib.type = MIB_RX2_DR;
mlme_request.mib.rx2_dr = *((uint8_t *)opt->data);
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
&mlme_confirm);
break;
default:
res = netif->dev->driver->set(netif->dev, opt->opt, opt->data,
opt->data_len);
break;
}
gnrc_netif_release(netif);
return res;

View File

@ -89,7 +89,7 @@ config LORAMAC_DEFAULT_JOIN_PROCEDURE_ABP
endchoice
if USEMODULE_GNRC_LORAWAN || USEPKG_SEMTECH_LORAMAC
if (USEMODULE_GNRC_LORAWAN || USEPKG_SEMTECH_LORAMAC)
menu "OTAA credentials"
@ -99,17 +99,37 @@ config LORAMAC_DEV_EUI_DEFAULT
help
Configure the default device EUI for join procedure.
config LORAMAC_APP_KEY_DEFAULT
string "Application key"
default "00000000000000000000000000000000"
help
Configure the default application key for join procedure.
if USEMODULE_GNRC_LORAWAN_1_1
config LORAMAC_JOIN_EUI_DEFAULT
string "Join EUI"
default "0000000000000000"
help
Configure the default join EUI for join procedure.
config LORAMAC_NWK_KEY_DEFAULT
string "Network key"
default "00000000000000000000000000000000"
help
Configure the default network key for join procedure.
endif # GNRC_LORAWAN_1_1
if !USEMODULE_GNRC_LORAWAN_1_1
config LORAMAC_APP_EUI_DEFAULT
string "Application EUI"
default "0000000000000000"
help
Configure the default application EUI for join procedure.
config LORAMAC_APP_KEY_DEFAULT
string "Application key"
default "00000000000000000000000000000000"
help
Configure the default application key for join procedure.
endif # !USEMODULE_GNRC_LORAWAN_1_1
endmenu # OTAA credentials
@ -125,18 +145,50 @@ config LORAMAC_DEV_ADDR_DEFAULT
help
Configure the default device address for ABP.
config LORAMAC_NWK_SKEY_DEFAULT
string "Network session key"
default "00000000000000000000000000000000"
help
Configure the default network session key for ABP.
config LORAMAC_APP_SKEY_DEFAULT
string "Application session key"
default "00000000000000000000000000000000"
help
Configure the default application session key for ABP.
if USEMODULE_GNRC_LORAWAN_1_1
config LORAMAC_FNWKSINT_KEY_DEFAULT
string "Forwarding network session integrity key"
default "00000000000000000000000000000000"
help
Configure the default forwarding network session integrity key for ABP.
config LORAMAC_SNWKSINT_KEY_DEFAULT
string "Serving network session integrity key"
default "00000000000000000000000000000000"
help
Configure the default serving network session integrity key for ABP.
config LORAMAC_NWKSENC_KEY_DEFAULT
string "Network session encryption key"
default "00000000000000000000000000000000"
help
Configure the default network session encryption key for ABP.
config LORAMAC_NWK_KEY_DEFAULT
string "Network key"
default "00000000000000000000000000000000"
help
Configure the default network key for ABP.
endif # USEMODULE_GNRC_LORAWAN_1_1
if !USEMODULE_GNRC_LORAWAN_1_1
config LORAMAC_NWK_SKEY_DEFAULT
string "Network session key"
default "00000000000000000000000000000000"
help
Configure the default network session key for ABP.
endif # !USEMODULE_GNRC_LORAWAN_1_1
endmenu # ABP credentials
endif # USEMODULE_GNRC_LORAWAN

View File

@ -217,13 +217,21 @@ static void _set_usage(char *cmd_name)
" * \"bw\" - alias for channel bandwidth\n"
" * \"sf\" - alias for spreading factor\n"
" * \"cr\" - alias for coding rate\n"
" * \"appeui\" - sets Application EUI\n"
" * \"appkey\" - sets Application key\n"
" * \"appskey\" - sets Application session key\n"
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
" * \"joineui\" - sets Join EUI\n"
" * \"nwkkey\" - sets Network key\n"
" * \"nwksenckey\" - sets Network session encryption key\n"
" * \"snwksintkey\" - sets Serving network session integrity key\n"
" * \"fnwksintkey\" - sets Forwarding network session integrity key\n"
#else
" * \"appeui\" - sets Application EUI\n"
" * \"nwkskey\" - sets Network Session Key\n"
#endif
" * \"deveui\" - sets Device EUI\n"
" * \"dr\" - sets datarate\n"
" * \"rx2_dr\" - sets datarate of RX2 (lorawan)\n"
" * \"nwkskey\" - sets Network Session Key\n"
#endif
#ifdef MODULE_NETDEV_IEEE802154_MULTIMODE
" * \"phy_mode\" - select PHY mode\n"
@ -300,13 +308,34 @@ static void _print_netopt(netopt_t opt)
printf("AppSKey");
break;
case NETOPT_LORAWAN_NWKSKEY:
printf("NwkSKey");
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
case NETOPT_LORAWAN_JOINEUI:
printf("JoinEUI");
break;
case NETOPT_LORAWAN_NWKKEY:
printf("NwkKey");
break;
case NETOPT_LORAWAN_NWKSENCKEY:
printf("NwkSEncKey");
break;
case NETOPT_LORAWAN_SNWKSINTKEY:
printf("SNwkSIntKey");
break;
case NETOPT_LORAWAN_FNWKSINTKEY:
printf("FNwkSIntKey");
break;
#else
case NETOPT_LORAWAN_APPEUI:
printf("AppEUI");
break;
case NETOPT_LORAWAN_NWKSKEY:
printf("NwkSKey");
break;
#endif /* IS_USED(MODULE_GNRC_LORAWAN_1_1) */
case NETOPT_SRC_LEN:
printf("source address length");
@ -1228,6 +1257,10 @@ static int _netif_set_lw_key(netif_t *iface, netopt_t opt, char *key_str)
case NETOPT_LORAWAN_APPKEY:
case NETOPT_LORAWAN_APPSKEY:
case NETOPT_LORAWAN_NWKSKEY:
case NETOPT_LORAWAN_NWKKEY:
case NETOPT_LORAWAN_SNWKSINTKEY:
case NETOPT_LORAWAN_FNWKSINTKEY:
case NETOPT_LORAWAN_NWKSENCKEY:
/* All keys have the same length as the APP KEY */
expected_len = LORAMAC_APPKEY_LEN;
break;
@ -1472,21 +1505,40 @@ static int _netif_set(char *cmd_name, netif_t *iface, char *key, char *value)
else if ((strcmp("coding_rate", key) == 0) || (strcmp("cr", key) == 0)) {
return _netif_set_coding_rate(iface, value);
}
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
else if (strcmp("joineui", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_JOINEUI, value);
}
else if (strcmp("fnwksintkey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_FNWKSINTKEY, value);
}
else if (strcmp("snwksintkey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_SNWKSINTKEY, value);
}
else if (strcmp("nwksenckey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_NWKSENCKEY, value);
}
else if (strcmp("nwkkey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_NWKKEY, value);
}
#else
else if (strcmp("appeui", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_APPEUI, value);
}
else if (strcmp("nwkskey", key) == 0) {
return _netif_set_addr(iface, NETOPT_LORAWAN_NWKSKEY, value);
}
#endif /* IS_USED(MODULE_GNRC_LORAWAN_1_1) */
else if (strcmp("appskey", key) == 0) {
return _netif_set_addr(iface, NETOPT_LORAWAN_APPSKEY, value);
}
else if (strcmp("appkey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_APPKEY, value);
}
else if (strcmp("deveui", key) == 0) {
return _netif_set_addr(iface, NETOPT_ADDRESS_LONG, value);
}
else if (strcmp("appskey", key) == 0) {
return _netif_set_addr(iface, NETOPT_LORAWAN_APPSKEY, value);
}
else if (strcmp("nwkskey", key) == 0) {
return _netif_set_addr(iface, NETOPT_LORAWAN_NWKSKEY, value);
}
else if (strcmp("dr", key) == 0) {
return _netif_set_u8(iface, NETOPT_LORAWAN_DR, 0, value);
}

View File

@ -70,7 +70,12 @@ static void test_gnrc_lorawan__validate_mic(void)
/* Uplink packet */
le_uint32_t calc_mic;
gnrc_lorawan_calculate_mic(&dev_addr, fcnt, 0, &pkt, nwkskey, &calc_mic);
gnrc_lorawan_t mac = {0};
memcpy(&mac.dev_addr, &dev_addr, sizeof(dev_addr));
mac.ctx.fnwksintkey = nwkskey;
mac.mcps.fcnt = fcnt;
gnrc_lorawan_calculate_mic_uplink(&pkt, 0x00, &mac, &calc_mic);
TEST_ASSERT(memcmp(&calc_mic, mic, sizeof(le_uint32_t)) == 0);
}
@ -84,7 +89,12 @@ static void test_gnrc_lorawan__wrong_mic(void)
/* Uplink packet */
le_uint32_t calc_mic;
gnrc_lorawan_calculate_mic(&dev_addr, fcnt, 0, &pkt, nwkskey, &calc_mic);
gnrc_lorawan_t mac = {0};
memcpy(&mac.dev_addr, &dev_addr, sizeof(dev_addr));
mac.ctx.fnwksintkey = nwkskey;
mac.mcps.fcnt = fcnt;
gnrc_lorawan_calculate_mic_uplink(&pkt, 0x00, &mac, &calc_mic);
TEST_ASSERT(memcmp(&calc_mic, mic, sizeof(le_uint32_t)) != 0);
}