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:
parent
3f8f6e929d
commit
12a4e1c1ec
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
/** @} */
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user