Merge pull request #14065 from jia200x/pr/improve_gnrc_lorawan
gnrc_lorawan: refactor
This commit is contained in:
commit
e1418e0972
@ -84,7 +84,6 @@ ifneq (,$(filter gnrc_lorawan,$(USEMODULE)))
|
||||
USEMODULE += hashes
|
||||
USEMODULE += crypto_aes
|
||||
USEMODULE += netdev_layer
|
||||
USEMODULE += gnrc_neterr
|
||||
USEMODULE += gnrc_nettype_lorawan
|
||||
endif
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ USEMODULE += gnrc_netdev_default
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
USEMODULE += gnrc_lorawan
|
||||
USEMODULE += gnrc_pktdump
|
||||
USEMODULE += gnrc_neterr
|
||||
|
||||
BOARD ?= b-l072z-lrwan1
|
||||
RIOTBASE ?= ../../
|
||||
|
||||
@ -35,7 +35,8 @@
|
||||
#include "net/gnrc/pktdump.h"
|
||||
#include "net/gnrc/netreg.h"
|
||||
|
||||
#define LORAWAN_PORT (2U)
|
||||
#define LORAWAN_PORT (2U)
|
||||
#define LORAWAN_QUEUE_SIZE (4U)
|
||||
|
||||
static void _usage(void)
|
||||
{
|
||||
@ -48,7 +49,7 @@ int tx_cmd(int argc, char **argv)
|
||||
uint8_t port = LORAWAN_PORT; /* Default: 2 */
|
||||
int interface;
|
||||
|
||||
if(argc < 3) {
|
||||
if (argc < 3) {
|
||||
_usage();
|
||||
return 1;
|
||||
}
|
||||
@ -75,21 +76,22 @@ int tx_cmd(int argc, char **argv)
|
||||
gnrc_netapi_set(interface, NETOPT_LORAWAN_TX_PORT, 0, &port, sizeof(port));
|
||||
gnrc_netif_send(gnrc_netif_get_by_pid(interface), pkt);
|
||||
|
||||
msg_t msg;
|
||||
/* wait for packet status and check */
|
||||
msg_t msg;
|
||||
msg_receive(&msg);
|
||||
if ((msg.type != GNRC_NETERR_MSG_TYPE) ||
|
||||
(msg.content.value != GNRC_NETERR_SUCCESS)) {
|
||||
puts("Error sending packet (not joined?)");
|
||||
printf("Error sending packet: (status: %d\n)", (int) msg.content.value);
|
||||
}
|
||||
else {
|
||||
puts("Successfully sent packet");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "send", "Send LoRaWAN data", tx_cmd},
|
||||
{ "send", "Send LoRaWAN data", tx_cmd },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@ -100,6 +102,7 @@ int main(void)
|
||||
puts("Initialization successful - starting the shell now");
|
||||
gnrc_netreg_entry_t dump = GNRC_NETREG_ENTRY_INIT_PID(LORAWAN_PORT,
|
||||
gnrc_pktdump_pid);
|
||||
|
||||
gnrc_netreg_register(GNRC_NETTYPE_LORAWAN, &dump);
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
|
||||
|
||||
@ -61,54 +61,53 @@ extern "C" {
|
||||
* @brief MCPS events
|
||||
*/
|
||||
typedef enum {
|
||||
MCPS_EVENT_RX, /**< MCPS RX event */
|
||||
MCPS_EVENT_NO_RX, /**< MCPS no RX event */
|
||||
MCPS_EVENT_ACK_TIMEOUT /**< MCPS retrans event */
|
||||
MCPS_EVENT_RX, /**< MCPS RX event */
|
||||
MCPS_EVENT_NO_RX, /**< MCPS no RX event */
|
||||
} mcps_event_t;
|
||||
|
||||
/**
|
||||
* @brief LoRaWAN activation mechanism
|
||||
*/
|
||||
typedef enum {
|
||||
MLME_ACTIVATION_NONE, /**< MAC layer is not activated */
|
||||
MLME_ACTIVATION_ABP, /**< MAC layer activated by ABP */
|
||||
MLME_ACTIVATION_OTAA /**< MAC layer activated by OTAA */
|
||||
MLME_ACTIVATION_NONE, /**< MAC layer is not activated */
|
||||
MLME_ACTIVATION_ABP, /**< MAC layer activated by ABP */
|
||||
MLME_ACTIVATION_OTAA /**< MAC layer activated by OTAA */
|
||||
} mlme_activation_t;
|
||||
|
||||
/**
|
||||
* @brief MAC Information Base attributes
|
||||
*/
|
||||
typedef enum {
|
||||
MIB_ACTIVATION_METHOD, /**< type is activation method */
|
||||
MIB_DEV_ADDR, /**< type is dev addr */
|
||||
MIB_RX2_DR, /**< type is rx2 DR */
|
||||
MIB_ACTIVATION_METHOD, /**< type is activation method */
|
||||
MIB_DEV_ADDR, /**< type is dev addr */
|
||||
MIB_RX2_DR, /**< type is rx2 DR */
|
||||
} mlme_mib_type_t;
|
||||
|
||||
/**
|
||||
* @brief MLME primitive types
|
||||
*/
|
||||
typedef enum {
|
||||
MLME_JOIN, /**< join a LoRaWAN network */
|
||||
MLME_LINK_CHECK, /**< perform a Link Check */
|
||||
MLME_RESET, /**< reset the MAC layer */
|
||||
MLME_SET, /**< set the MIB */
|
||||
MLME_GET, /**< get the MIB */
|
||||
MLME_SCHEDULE_UPLINK /**< schedule uplink indication */
|
||||
MLME_JOIN, /**< join a LoRaWAN network */
|
||||
MLME_LINK_CHECK, /**< perform a Link Check */
|
||||
MLME_RESET, /**< reset the MAC layer */
|
||||
MLME_SET, /**< set the MIB */
|
||||
MLME_GET, /**< get the MIB */
|
||||
MLME_SCHEDULE_UPLINK /**< schedule uplink indication */
|
||||
} mlme_type_t;
|
||||
|
||||
/**
|
||||
* @brief MCPS primitive types
|
||||
*/
|
||||
typedef enum {
|
||||
MCPS_CONFIRMED, /**< confirmed data */
|
||||
MCPS_UNCONFIRMED /**< unconfirmed data */
|
||||
MCPS_CONFIRMED, /**< confirmed data */
|
||||
MCPS_UNCONFIRMED /**< unconfirmed data */
|
||||
} mcps_type_t;
|
||||
|
||||
/**
|
||||
* @brief MAC Information Base descriptor for MLME Request-Confirm
|
||||
*/
|
||||
typedef struct {
|
||||
mlme_mib_type_t type; /**< MIB attribute identifier */
|
||||
mlme_mib_type_t type; /**< MIB attribute identifier */
|
||||
union {
|
||||
mlme_activation_t activation; /**< holds activation mechanism */
|
||||
void *dev_addr; /**< pointer to the dev_addr */
|
||||
@ -121,10 +120,10 @@ typedef struct {
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
mlme_lorawan_join_t join; /**< Join Data holder */
|
||||
mlme_mib_t mib; /**< MIB holder */
|
||||
mlme_lorawan_join_t join; /**< Join Data holder */
|
||||
mlme_mib_t mib; /**< MIB holder */
|
||||
};
|
||||
mlme_type_t type; /**< type of the MLME request */
|
||||
mlme_type_t type; /**< type of the MLME request */
|
||||
} mlme_request_t;
|
||||
|
||||
/**
|
||||
@ -132,20 +131,20 @@ typedef struct {
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
mcps_data_t data; /**< MCPS data holder */
|
||||
mcps_data_t data; /**< MCPS data holder */
|
||||
};
|
||||
mcps_type_t type; /**< type of the MCPS request */
|
||||
mcps_type_t type; /**< type of the MCPS request */
|
||||
} mcps_request_t;
|
||||
|
||||
/**
|
||||
* @brief MAC (sub) Layer Management Entity (MLME) confirm representation
|
||||
*/
|
||||
typedef struct {
|
||||
int16_t status; /**< status of the MLME confirm */
|
||||
mlme_type_t type; /**< type of the MLME confirm */
|
||||
int16_t status; /**< status of the MLME confirm */
|
||||
mlme_type_t type; /**< type of the MLME confirm */
|
||||
union {
|
||||
mlme_link_req_confirm_t link_req; /**< Link Check confirmation data */
|
||||
mlme_mib_t mib; /**< MIB confirmation data */
|
||||
mlme_link_req_confirm_t link_req; /**< Link Check confirmation data */
|
||||
mlme_mib_t mib; /**< MIB confirmation data */
|
||||
};
|
||||
} mlme_confirm_t;
|
||||
|
||||
@ -153,18 +152,18 @@ typedef struct {
|
||||
* @brief Mac Common Part Sublayer (MCPS) confirm representation
|
||||
*/
|
||||
typedef struct {
|
||||
void *data; /**< data of the MCPS confirm */
|
||||
int16_t status; /**< status of the MCPS confirm */
|
||||
int16_t status; /**< status of the MCPS confirm */
|
||||
mcps_type_t type; /**< type of the MCPS confirm */
|
||||
iolist_t *msdu; /**< pointer to the msdu */
|
||||
} mcps_confirm_t;
|
||||
|
||||
/**
|
||||
* @brief Mac Common Part Sublayer (MCPS) indication representation
|
||||
*/
|
||||
typedef struct {
|
||||
mcps_type_t type; /**< type of the MCPS indication */
|
||||
mcps_type_t type; /**< type of the MCPS indication */
|
||||
union {
|
||||
mcps_data_t data; /**< MCPS Data holder */
|
||||
mcps_data_t data; /**< MCPS Data holder */
|
||||
};
|
||||
} mcps_indication_t;
|
||||
|
||||
@ -180,14 +179,14 @@ typedef struct {
|
||||
*
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
*/
|
||||
void gnrc_lorawan_event_timeout(gnrc_lorawan_t *mac);
|
||||
void gnrc_lorawan_radio_rx_timeout_cb(gnrc_lorawan_t *mac);
|
||||
|
||||
/**
|
||||
* @brief Indicate the MAC layer when the transmission finished
|
||||
*
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
*/
|
||||
void gnrc_lorawan_event_tx_complete(gnrc_lorawan_t *mac);
|
||||
void gnrc_lorawan_radio_tx_done_cb(gnrc_lorawan_t *mac);
|
||||
|
||||
/**
|
||||
* @brief Init GNRC LoRaWAN
|
||||
@ -208,7 +207,8 @@ void gnrc_lorawan_init(gnrc_lorawan_t *mac, uint8_t *nwkskey, uint8_t *appskey);
|
||||
* GNRC_LORAWAN_REQ_STATUS_DEFERRED if the confirmation is deferred
|
||||
* or an standard error number
|
||||
*/
|
||||
void gnrc_lorawan_mlme_request(gnrc_lorawan_t *mac, const mlme_request_t *mlme_request,
|
||||
void gnrc_lorawan_mlme_request(gnrc_lorawan_t *mac,
|
||||
const mlme_request_t *mlme_request,
|
||||
mlme_confirm_t *mlme_confirm);
|
||||
|
||||
/**
|
||||
@ -221,7 +221,8 @@ void gnrc_lorawan_mlme_request(gnrc_lorawan_t *mac, const mlme_request_t *mlme_r
|
||||
* GNRC_LORAWAN_REQ_STATUS_DEFERRED if the confirmation is deferred
|
||||
* or an standard error number
|
||||
*/
|
||||
void gnrc_lorawan_mcps_request(gnrc_lorawan_t *mac, const mcps_request_t *mcps_request,
|
||||
void gnrc_lorawan_mcps_request(gnrc_lorawan_t *mac,
|
||||
const mcps_request_t *mcps_request,
|
||||
mcps_confirm_t *mcps_confirm);
|
||||
|
||||
/**
|
||||
@ -230,8 +231,12 @@ void gnrc_lorawan_mcps_request(gnrc_lorawan_t *mac, const mcps_request_t *mcps_r
|
||||
* To be called on radio RX done event.
|
||||
*
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
* @param[in] data pointer to the psdu. Pass NULL if the packet was wrong (or
|
||||
* allocation failed)
|
||||
* @param[in] size size of the PSDU
|
||||
*/
|
||||
void gnrc_lorawan_recv(gnrc_lorawan_t *mac);
|
||||
void gnrc_lorawan_radio_rx_done_cb(gnrc_lorawan_t *mac, uint8_t *data,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief MCPS indication callback
|
||||
|
||||
@ -30,18 +30,19 @@
|
||||
/* This factor is used for converting "real" seconds into microcontroller
|
||||
* microseconds. This is done in order to correct timer drift.
|
||||
*/
|
||||
#define _DRIFT_FACTOR (int) (US_PER_SEC * 100 / (100 + (CONFIG_GNRC_LORAWAN_TIMER_DRIFT / 10.0)))
|
||||
#define _DRIFT_FACTOR (int)(US_PER_SEC * 100 / \
|
||||
(100 + (CONFIG_GNRC_LORAWAN_TIMER_DRIFT / 10.0)))
|
||||
|
||||
#define GNRC_LORAWAN_DL_RX2_DR_MASK (0x0F) /**< DL Settings DR Offset mask */
|
||||
#define GNRC_LORAWAN_DL_RX2_DR_POS (0) /**< DL Settings DR Offset pos */
|
||||
#define GNRC_LORAWAN_DL_DR_OFFSET_MASK (0x70) /**< DL Settings RX2 DR mask */
|
||||
#define GNRC_LORAWAN_DL_DR_OFFSET_POS (4) /**< DL Settings RX2 DR pos */
|
||||
#define GNRC_LORAWAN_DL_RX2_DR_MASK (0x0F) /**< DL Settings DR Offset mask */
|
||||
#define GNRC_LORAWAN_DL_RX2_DR_POS (0) /**< DL Settings DR Offset pos */
|
||||
#define GNRC_LORAWAN_DL_DR_OFFSET_MASK (0x70) /**< DL Settings RX2 DR mask */
|
||||
#define GNRC_LORAWAN_DL_DR_OFFSET_POS (4) /**< DL Settings RX2 DR pos */
|
||||
|
||||
static inline void gnrc_lorawan_mlme_reset(gnrc_lorawan_t *mac)
|
||||
{
|
||||
mac->mlme.activation = MLME_ACTIVATION_NONE;
|
||||
mac->mlme.pending_mlme_opts = 0;
|
||||
mac->rx_delay = (LORAMAC_DEFAULT_RX1_DELAY/MS_PER_SEC);
|
||||
mac->rx_delay = (LORAMAC_DEFAULT_RX1_DELAY / MS_PER_SEC);
|
||||
mac->mlme.nid = LORAMAC_DEFAULT_NETID;
|
||||
}
|
||||
|
||||
@ -65,7 +66,7 @@ void gnrc_lorawan_set_rx2_dr(gnrc_lorawan_t *mac, uint8_t rx2_dr)
|
||||
{
|
||||
mac->dl_settings &= ~GNRC_LORAWAN_DL_RX2_DR_MASK;
|
||||
mac->dl_settings |= (rx2_dr << GNRC_LORAWAN_DL_RX2_DR_POS) &
|
||||
GNRC_LORAWAN_DL_RX2_DR_MASK;
|
||||
GNRC_LORAWAN_DL_RX2_DR_MASK;
|
||||
}
|
||||
|
||||
static void _sleep_radio(gnrc_lorawan_t *mac)
|
||||
@ -94,10 +95,12 @@ void gnrc_lorawan_reset(gnrc_lorawan_t *mac)
|
||||
|
||||
uint8_t syncword = LORAMAC_DEFAULT_PUBLIC_NETWORK ? LORA_SYNCWORD_PUBLIC
|
||||
: LORA_SYNCWORD_PRIVATE;
|
||||
|
||||
dev->driver->set(dev, NETOPT_SYNCWORD, &syncword, sizeof(syncword));
|
||||
|
||||
/* Continuous reception */
|
||||
uint32_t rx_timeout = 0;
|
||||
|
||||
dev->driver->set(dev, NETOPT_RX_TIMEOUT, &rx_timeout, sizeof(rx_timeout));
|
||||
|
||||
gnrc_lorawan_set_rx2_dr(mac, LORAMAC_DEFAULT_RX2_DR);
|
||||
@ -108,15 +111,18 @@ void gnrc_lorawan_reset(gnrc_lorawan_t *mac)
|
||||
gnrc_lorawan_channels_init(mac);
|
||||
}
|
||||
|
||||
static void _config_radio(gnrc_lorawan_t *mac, uint32_t channel_freq, uint8_t dr, int rx)
|
||||
static void _config_radio(gnrc_lorawan_t *mac, uint32_t channel_freq,
|
||||
uint8_t dr, int rx)
|
||||
{
|
||||
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
|
||||
|
||||
if (channel_freq != 0) {
|
||||
dev->driver->set(dev, NETOPT_CHANNEL_FREQUENCY, &channel_freq, sizeof(channel_freq));
|
||||
dev->driver->set(dev, NETOPT_CHANNEL_FREQUENCY, &channel_freq,
|
||||
sizeof(channel_freq));
|
||||
}
|
||||
|
||||
netopt_enable_t iq_invert = rx;
|
||||
|
||||
dev->driver->set(dev, NETOPT_IQ_INVERT, &iq_invert, sizeof(iq_invert));
|
||||
|
||||
gnrc_lorawan_set_dr(mac, dr);
|
||||
@ -126,11 +132,13 @@ static void _config_radio(gnrc_lorawan_t *mac, uint32_t channel_freq, uint8_t dr
|
||||
const netopt_enable_t single = true;
|
||||
dev->driver->set(dev, NETOPT_SINGLE_RECEIVE, &single, sizeof(single));
|
||||
const uint16_t timeout = CONFIG_GNRC_LORAWAN_MIN_SYMBOLS_TIMEOUT;
|
||||
dev->driver->set(dev, NETOPT_RX_SYMBOL_TIMEOUT, &timeout, sizeof(timeout));
|
||||
dev->driver->set(dev, NETOPT_RX_SYMBOL_TIMEOUT, &timeout,
|
||||
sizeof(timeout));
|
||||
}
|
||||
}
|
||||
|
||||
static void _configure_rx_window(gnrc_lorawan_t *mac, uint32_t channel_freq, uint8_t dr)
|
||||
static void _configure_rx_window(gnrc_lorawan_t *mac, uint32_t channel_freq,
|
||||
uint8_t dr)
|
||||
{
|
||||
_config_radio(mac, channel_freq, dr, true);
|
||||
}
|
||||
@ -138,21 +146,24 @@ static void _configure_rx_window(gnrc_lorawan_t *mac, uint32_t channel_freq, uin
|
||||
void gnrc_lorawan_open_rx_window(gnrc_lorawan_t *mac)
|
||||
{
|
||||
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
|
||||
|
||||
mac->msg.type = MSG_TYPE_TIMEOUT;
|
||||
/* Switch to RX state */
|
||||
if (mac->state == LORAWAN_STATE_RX_1) {
|
||||
xtimer_set_msg(&mac->rx, _DRIFT_FACTOR, &mac->msg, thread_getpid());
|
||||
}
|
||||
netopt_state_t state = NETOPT_STATE_RX;
|
||||
|
||||
dev->driver->set(dev, NETOPT_STATE, &state, sizeof(state));
|
||||
}
|
||||
|
||||
void gnrc_lorawan_event_tx_complete(gnrc_lorawan_t *mac)
|
||||
void gnrc_lorawan_radio_tx_done_cb(gnrc_lorawan_t *mac)
|
||||
{
|
||||
mac->msg.type = MSG_TYPE_TIMEOUT;
|
||||
mac->state = LORAWAN_STATE_RX_1;
|
||||
|
||||
int rx_1;
|
||||
|
||||
/* if the MAC is not activated, then this is a Join Request */
|
||||
rx_1 = mac->mlme.activation == MLME_ACTIVATION_NONE ?
|
||||
LORAMAC_DEFAULT_JOIN_DELAY1 : mac->rx_delay;
|
||||
@ -160,25 +171,28 @@ void gnrc_lorawan_event_tx_complete(gnrc_lorawan_t *mac)
|
||||
xtimer_set_msg(&mac->rx, rx_1 * _DRIFT_FACTOR, &mac->msg, thread_getpid());
|
||||
|
||||
uint8_t dr_offset = (mac->dl_settings & GNRC_LORAWAN_DL_DR_OFFSET_MASK) >>
|
||||
GNRC_LORAWAN_DL_DR_OFFSET_POS;
|
||||
_configure_rx_window(mac, 0, gnrc_lorawan_rx1_get_dr_offset(mac->last_dr, dr_offset));
|
||||
GNRC_LORAWAN_DL_DR_OFFSET_POS;
|
||||
|
||||
_configure_rx_window(mac, 0,
|
||||
gnrc_lorawan_rx1_get_dr_offset(mac->last_dr,
|
||||
dr_offset));
|
||||
|
||||
_sleep_radio(mac);
|
||||
}
|
||||
|
||||
void gnrc_lorawan_event_timeout(gnrc_lorawan_t *mac)
|
||||
void gnrc_lorawan_radio_rx_timeout_cb(gnrc_lorawan_t *mac)
|
||||
{
|
||||
(void) mac;
|
||||
(void)mac;
|
||||
switch (mac->state) {
|
||||
case LORAWAN_STATE_RX_1:
|
||||
_configure_rx_window(mac, LORAMAC_DEFAULT_RX2_FREQ, mac->dl_settings & GNRC_LORAWAN_DL_RX2_DR_MASK);
|
||||
_configure_rx_window(mac, 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:
|
||||
gnrc_lorawan_mlme_no_rx(mac);
|
||||
gnrc_lorawan_mcps_event(mac, MCPS_EVENT_NO_RX, 0);
|
||||
gnrc_lorawan_event_no_rx(mac);
|
||||
mac->state = LORAWAN_STATE_IDLE;
|
||||
gnrc_lorawan_mac_release(mac);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
@ -207,6 +221,7 @@ static uint32_t lora_time_on_air(size_t payload_size, uint8_t dr, uint8_t cr)
|
||||
int nb_symbols;
|
||||
|
||||
uint8_t offset = _K[index][1];
|
||||
|
||||
if (payload_size < offset) {
|
||||
nb_symbols = 8 + n0 * cr;
|
||||
}
|
||||
@ -219,79 +234,53 @@ static uint32_t lora_time_on_air(size_t payload_size, uint8_t dr, uint8_t cr)
|
||||
}
|
||||
|
||||
uint32_t t_payload = t_sym * nb_symbols;
|
||||
|
||||
return t_preamble + t_payload;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_send_pkt(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt, uint8_t dr)
|
||||
void gnrc_lorawan_send_pkt(gnrc_lorawan_t *mac, iolist_t *psdu, uint8_t dr)
|
||||
{
|
||||
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
|
||||
|
||||
mac->state = LORAWAN_STATE_TX;
|
||||
|
||||
iolist_t iolist = {
|
||||
.iol_base = pkt->data,
|
||||
.iol_len = pkt->size,
|
||||
.iol_next = (iolist_t *) pkt->next
|
||||
};
|
||||
|
||||
uint32_t chan = gnrc_lorawan_pick_channel(mac);
|
||||
|
||||
_config_radio(mac, chan, dr, false);
|
||||
|
||||
mac->last_dr = dr;
|
||||
|
||||
uint8_t cr;
|
||||
|
||||
dev->driver->get(dev, NETOPT_CODING_RATE, &cr, sizeof(cr));
|
||||
|
||||
mac->toa = lora_time_on_air(gnrc_pkt_len(pkt), dr, cr + 4);
|
||||
mac->toa = lora_time_on_air(iolist_size(psdu), dr, cr + 4);
|
||||
|
||||
if (dev->driver->send(dev, &iolist) == -ENOTSUP) {
|
||||
if (dev->driver->send(dev, psdu) == -ENOTSUP) {
|
||||
DEBUG("gnrc_lorawan: Cannot send: radio is still transmitting");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gnrc_lorawan_process_pkt(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt)
|
||||
void gnrc_lorawan_radio_rx_done_cb(gnrc_lorawan_t *mac, uint8_t *psdu,
|
||||
size_t size)
|
||||
{
|
||||
_sleep_radio(mac);
|
||||
if (psdu == NULL) {
|
||||
return;
|
||||
}
|
||||
mac->state = LORAWAN_STATE_IDLE;
|
||||
xtimer_remove(&mac->rx);
|
||||
|
||||
uint8_t *p = pkt->data;
|
||||
uint8_t mtype = (*psdu & MTYPE_MASK) >> 5;
|
||||
|
||||
uint8_t mtype = (*p & MTYPE_MASK) >> 5;
|
||||
switch (mtype) {
|
||||
case MTYPE_JOIN_ACCEPT:
|
||||
gnrc_lorawan_mlme_process_join(mac, pkt);
|
||||
gnrc_lorawan_mlme_process_join(mac, psdu, size);
|
||||
break;
|
||||
case MTYPE_CNF_DOWNLINK:
|
||||
case MTYPE_UNCNF_DOWNLINK:
|
||||
gnrc_lorawan_mcps_process_downlink(mac, pkt);
|
||||
gnrc_lorawan_mcps_process_downlink(mac, psdu, size);
|
||||
break;
|
||||
default:
|
||||
gnrc_pktbuf_release(pkt);
|
||||
break;
|
||||
}
|
||||
|
||||
gnrc_lorawan_mac_release(mac);
|
||||
}
|
||||
|
||||
void gnrc_lorawan_recv(gnrc_lorawan_t *mac)
|
||||
{
|
||||
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
|
||||
int bytes_expected = dev->driver->recv(dev, NULL, 0, 0);
|
||||
int nread;
|
||||
struct netdev_radio_rx_info rx_info;
|
||||
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, bytes_expected, GNRC_NETTYPE_UNDEF);
|
||||
if (pkt == NULL) {
|
||||
DEBUG("_recv_ieee802154: cannot allocate pktsnip.\n");
|
||||
/* Discard packet on netdev device */
|
||||
dev->driver->recv(dev, NULL, bytes_expected, NULL);
|
||||
return;
|
||||
}
|
||||
nread = dev->driver->recv(dev, pkt->data, bytes_expected, &rx_info);
|
||||
_sleep_radio(mac);
|
||||
if (nread <= 0) {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
gnrc_lorawan_process_pkt(mac, pkt);
|
||||
}
|
||||
|
||||
@ -45,20 +45,19 @@ typedef struct __attribute__((packed)) {
|
||||
uint8_t len;
|
||||
} lorawan_block_t;
|
||||
|
||||
void gnrc_lorawan_calculate_join_mic(const iolist_t *io, const uint8_t *key, le_uint32_t *out)
|
||||
void gnrc_lorawan_calculate_join_mic(const uint8_t *buf, size_t len,
|
||||
const uint8_t *key, le_uint32_t *out)
|
||||
{
|
||||
cmac_init(&CmacContext, key, LORAMAC_APPKEY_LEN);
|
||||
while (io != NULL) {
|
||||
cmac_update(&CmacContext, io->iol_base, io->iol_len);
|
||||
io = io->iol_next;
|
||||
}
|
||||
cmac_update(&CmacContext, buf, len);
|
||||
cmac_final(&CmacContext, digest);
|
||||
|
||||
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 *pkt, const uint8_t *nwkskey, le_uint32_t *out)
|
||||
uint8_t dir, iolist_t *frame,
|
||||
const uint8_t *nwkskey, le_uint32_t *out)
|
||||
{
|
||||
lorawan_block_t block;
|
||||
|
||||
@ -72,14 +71,21 @@ void gnrc_lorawan_calculate_mic(const le_uint32_t *dev_addr, uint32_t fcnt,
|
||||
|
||||
block.u32_pad = 0;
|
||||
|
||||
block.len = iolist_size(pkt);
|
||||
block.len = iolist_size(frame);
|
||||
|
||||
iolist_t io = { .iol_base = &block, .iol_len = sizeof(block),
|
||||
.iol_next = pkt };
|
||||
gnrc_lorawan_calculate_join_mic(&io, nwkskey, out);
|
||||
cmac_init(&CmacContext, nwkskey, LORAMAC_APPKEY_LEN);
|
||||
cmac_update(&CmacContext, &block, sizeof(block));
|
||||
for (iolist_t *io = frame; io != NULL; io = io->iol_next) {
|
||||
cmac_update(&CmacContext, io->iol_base, io->iol_len);
|
||||
}
|
||||
cmac_final(&CmacContext, digest);
|
||||
|
||||
memcpy(out, digest, sizeof(le_uint32_t));
|
||||
}
|
||||
|
||||
void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr, uint32_t fcnt, uint8_t dir, const uint8_t *appskey)
|
||||
void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr,
|
||||
uint32_t fcnt, uint8_t dir,
|
||||
const uint8_t *appskey)
|
||||
{
|
||||
uint8_t s_block[16];
|
||||
uint8_t a_block[16];
|
||||
@ -87,7 +93,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_block_t *block = (lorawan_block_t *)a_block;
|
||||
|
||||
cipher_init(&AesContext, CIPHER_AES_128, appskey, LORAMAC_APPKEY_LEN);
|
||||
|
||||
@ -102,6 +108,7 @@ void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr,
|
||||
block->u32_pad = 0;
|
||||
|
||||
int c = 0;
|
||||
|
||||
for (iolist_t *io = iolist; io != NULL; io = io->iol_next) {
|
||||
for (unsigned i = 0; i < io->iol_len; i++) {
|
||||
uint8_t *v = io->iol_base;
|
||||
@ -117,17 +124,22 @@ void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr,
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_lorawan_decrypt_join_accept(const uint8_t *key, uint8_t *pkt, int has_clist, uint8_t *out)
|
||||
void gnrc_lorawan_decrypt_join_accept(const uint8_t *key, uint8_t *pkt,
|
||||
int has_clist, uint8_t *out)
|
||||
{
|
||||
cipher_init(&AesContext, CIPHER_AES_128, key, LORAMAC_APPKEY_LEN);
|
||||
cipher_encrypt(&AesContext, pkt, out);
|
||||
|
||||
if (has_clist) {
|
||||
cipher_encrypt(&AesContext, pkt + LORAMAC_APPKEY_LEN, out + LORAMAC_APPKEY_LEN);
|
||||
cipher_encrypt(&AesContext, pkt + LORAMAC_APPKEY_LEN,
|
||||
out + LORAMAC_APPKEY_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
uint8_t buf[LORAMAC_APPSKEY_LEN];
|
||||
|
||||
@ -136,8 +148,10 @@ void gnrc_lorawan_generate_session_keys(const uint8_t *app_nonce, const uint8_t
|
||||
cipher_init(&AesContext, CIPHER_AES_128, appkey, LORAMAC_APPSKEY_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);
|
||||
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);
|
||||
|
||||
/* Calculate Application Session Key */
|
||||
buf[0] = APP_SKEY_B0_START;
|
||||
|
||||
@ -30,17 +30,21 @@
|
||||
#define _16_UPPER_BITMASK 0xFFFF0000
|
||||
#define _16_LOWER_BITMASK 0xFFFF
|
||||
|
||||
int gnrc_lorawan_mic_is_valid(gnrc_pktsnip_t *mic, uint8_t *nwkskey)
|
||||
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)
|
||||
{
|
||||
le_uint32_t calc_mic;
|
||||
|
||||
assert(mic->size == MIC_SIZE);
|
||||
assert(mic->next->data);
|
||||
lorawan_hdr_t *lw_hdr = (lorawan_hdr_t *) mic->next->data;
|
||||
lorawan_hdr_t *lw_hdr = (lorawan_hdr_t *)buf;
|
||||
|
||||
uint32_t fcnt = byteorder_ntohs(byteorder_ltobs(lw_hdr->fcnt));
|
||||
gnrc_lorawan_calculate_mic(&lw_hdr->addr, fcnt, GNRC_LORAWAN_DIR_DOWNLINK, (iolist_t *) mic->next, nwkskey, &calc_mic);
|
||||
return calc_mic.u32 == ((le_uint32_t *) mic->data)->u32;
|
||||
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);
|
||||
return calc_mic.u32 == ((le_uint32_t *)(buf + len - MIC_SIZE))->u32;
|
||||
}
|
||||
|
||||
uint32_t gnrc_lorawan_fcnt_stol(uint32_t fcnt_down, uint16_t s_fcnt)
|
||||
@ -54,127 +58,156 @@ uint32_t gnrc_lorawan_fcnt_stol(uint32_t fcnt_down, uint16_t s_fcnt)
|
||||
return u32_fcnt;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mcps_process_downlink(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *hdr, *data, *fopts = NULL, *fport = NULL;
|
||||
int release = true;
|
||||
int error = true;
|
||||
/**
|
||||
* @brief holder of parsed packet
|
||||
*/
|
||||
struct parsed_packet {
|
||||
uint32_t fcnt_down; /**< frame counter */
|
||||
lorawan_hdr_t *hdr; /**< pointer to the LoRaWAN header */
|
||||
bool ack_req; /**< whether an ACK was requested or not */
|
||||
iolist_t fopts; /**< iolist with Fopts information */
|
||||
iolist_t enc_payload; /**< iolist with encrypted payload */
|
||||
uint8_t port; /**< Fport of the packet */
|
||||
bool ack; /**< whether the ACK bit was set or not */
|
||||
bool frame_pending; /**< whether there's pending data or not */
|
||||
};
|
||||
|
||||
/* mark MIC */
|
||||
if (!(data = gnrc_pktbuf_mark(pkt, (pkt->size - MIC_SIZE > 0) ? pkt->size - MIC_SIZE : 0, GNRC_NETTYPE_UNDEF))) {
|
||||
DEBUG("gnrc_lorawan: failed to mark MIC\n");
|
||||
goto out;
|
||||
int gnrc_lorawan_parse_dl(gnrc_lorawan_t *mac, uint8_t *buf, size_t len,
|
||||
struct parsed_packet *pkt)
|
||||
{
|
||||
memset(pkt, 0, sizeof(struct parsed_packet));
|
||||
|
||||
lorawan_hdr_t *_hdr = (lorawan_hdr_t *)buf;
|
||||
uint8_t *p_mic = buf + len - MIC_SIZE;
|
||||
|
||||
pkt->hdr = _hdr;
|
||||
buf += sizeof(lorawan_hdr_t);
|
||||
|
||||
/* Validate header */
|
||||
if (_hdr->addr.u32 != mac->dev_addr.u32) {
|
||||
DEBUG("gnrc_lorawan: received packet with wrong dev addr. Drop\n");
|
||||
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 +
|
||||
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) {
|
||||
pkt->fopts.iol_base = buf;
|
||||
pkt->fopts.iol_len = fopts_length;
|
||||
buf += fopts_length;
|
||||
}
|
||||
|
||||
if (buf < p_mic) {
|
||||
pkt->port = *(buf++);
|
||||
|
||||
if (!pkt->port && fopts_length) {
|
||||
DEBUG("gnrc_lorawan: packet with fopts and port == 0. Drop\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buf < p_mic) {
|
||||
pkt->enc_payload.iol_base = buf;
|
||||
pkt->enc_payload.iol_len = p_mic - buf;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mcps_process_downlink(gnrc_lorawan_t *mac, uint8_t *psdu,
|
||||
size_t size)
|
||||
{
|
||||
struct parsed_packet _pkt;
|
||||
|
||||
/* NOTE: MIC is in pkt */
|
||||
if (!gnrc_lorawan_mic_is_valid(pkt, mac->nwkskey)) {
|
||||
if (!gnrc_lorawan_mic_is_valid(psdu, size, mac->nwkskey)) {
|
||||
DEBUG("gnrc_lorawan: invalid MIC\n");
|
||||
goto out;
|
||||
gnrc_lorawan_event_no_rx(mac);
|
||||
return;
|
||||
}
|
||||
|
||||
/* remove snip */
|
||||
pkt = gnrc_pktbuf_remove_snip(pkt, pkt);
|
||||
|
||||
if (!(hdr = gnrc_pktbuf_mark(pkt, sizeof(lorawan_hdr_t), GNRC_NETTYPE_UNDEF))) {
|
||||
DEBUG("gnrc_lorawan: failed to allocate hdr\n");
|
||||
goto out;
|
||||
if (gnrc_lorawan_parse_dl(mac, psdu, size, &_pkt) < 0) {
|
||||
DEBUG("gnrc_lorawan: couldn't parse packet\n");
|
||||
gnrc_lorawan_event_no_rx(mac);
|
||||
return;
|
||||
}
|
||||
|
||||
int _fopts_length = lorawan_hdr_get_frame_opts_len((lorawan_hdr_t *) hdr->data);
|
||||
if (_fopts_length && !(fopts = gnrc_pktbuf_mark(pkt, _fopts_length, GNRC_NETTYPE_UNDEF))) {
|
||||
DEBUG("gnrc_lorawan: failed to allocate fopts\n");
|
||||
goto out;
|
||||
iolist_t *fopts = NULL;
|
||||
|
||||
if (_pkt.fopts.iol_base) {
|
||||
fopts = &_pkt.fopts;
|
||||
}
|
||||
|
||||
assert(pkt != NULL);
|
||||
|
||||
int fopts_in_payload = 0;
|
||||
/* only for download frames with payload the FPort must be present */
|
||||
if (pkt->size) {
|
||||
if ((fport = gnrc_pktbuf_mark(pkt, 1, GNRC_NETTYPE_UNDEF)) == NULL) {
|
||||
DEBUG("gnrc_lorawan: failed to allocate fport\n");
|
||||
goto out;
|
||||
if (_pkt.enc_payload.iol_base) {
|
||||
uint8_t *key;
|
||||
if (_pkt.port) {
|
||||
key = mac->appskey;
|
||||
}
|
||||
|
||||
assert(fport->data);
|
||||
|
||||
fopts_in_payload = *((uint8_t *) fport->data) == 0;
|
||||
if (fopts && fopts_in_payload) {
|
||||
DEBUG("gnrc_lorawan: packet with fopts and port == 0. Drop\n");
|
||||
goto out;
|
||||
else {
|
||||
key = mac->nwkskey;
|
||||
fopts = &_pkt.enc_payload;
|
||||
}
|
||||
gnrc_lorawan_encrypt_payload(&_pkt.enc_payload, &_pkt.hdr->addr,
|
||||
byteorder_ntohs(byteorder_ltobs(
|
||||
_pkt.hdr->fcnt)), GNRC_LORAWAN_DIR_DOWNLINK,
|
||||
key);
|
||||
}
|
||||
|
||||
lorawan_hdr_t *lw_hdr = hdr->data;
|
||||
|
||||
if (lw_hdr->addr.u32 != mac->dev_addr.u32) {
|
||||
DEBUG("gnrc_lorawan: received packet with wrong dev addr. Drop\n");
|
||||
goto out;
|
||||
mac->mcps.fcnt_down = _pkt.fcnt_down;
|
||||
if (mac->mcps.waiting_for_ack && !_pkt.ack) {
|
||||
DEBUG("gnrc_lorawan: expected ACK packet\n");
|
||||
gnrc_lorawan_event_no_rx(mac);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t fcnt = gnrc_lorawan_fcnt_stol(mac->mcps.fcnt_down, lw_hdr->fcnt.u16);
|
||||
if (mac->mcps.fcnt_down > fcnt || mac->mcps.fcnt_down +
|
||||
LORAMAC_DEFAULT_MAX_FCNT_GAP < fcnt) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
mac->mcps.fcnt_down = fcnt;
|
||||
error = false;
|
||||
|
||||
int ack_req = lorawan_hdr_get_mtype(lw_hdr) == MTYPE_CNF_DOWNLINK;
|
||||
if (ack_req) {
|
||||
if (_pkt.ack_req) {
|
||||
mac->mcps.ack_requested = true;
|
||||
}
|
||||
|
||||
iolist_t payload = { .iol_base = pkt->data, .iol_len = pkt->size };
|
||||
if (pkt->data) {
|
||||
gnrc_lorawan_encrypt_payload(&payload, &lw_hdr->addr,
|
||||
byteorder_ntohs(byteorder_ltobs(lw_hdr->fcnt)),
|
||||
GNRC_LORAWAN_DIR_DOWNLINK,
|
||||
fopts_in_payload ? mac->nwkskey : mac->appskey);
|
||||
}
|
||||
|
||||
/* if there are fopts, it's either an empty packet or application payload */
|
||||
if (fopts) {
|
||||
gnrc_lorawan_process_fopts(mac, fopts->data, fopts->size);
|
||||
}
|
||||
else if (fopts_in_payload) {
|
||||
gnrc_lorawan_process_fopts(mac, pkt->data, pkt->size);
|
||||
DEBUG("gnrc_lorawan: processing fopts\n");
|
||||
gnrc_lorawan_process_fopts(mac, fopts->iol_base, fopts->iol_len);
|
||||
}
|
||||
|
||||
gnrc_lorawan_mcps_event(mac, MCPS_EVENT_RX, lorawan_hdr_get_ack(lw_hdr));
|
||||
if (pkt->data && fport && *((uint8_t *) fport->data) != 0) {
|
||||
pkt->type = GNRC_NETTYPE_LORAWAN;
|
||||
release = false;
|
||||
_end_of_tx(mac, MCPS_CONFIRMED, GNRC_LORAWAN_REQ_STATUS_SUCCESS);
|
||||
|
||||
mcps_indication_t mcps_indication;
|
||||
mcps_indication.type = ack_req;
|
||||
mcps_indication.data.pkt = pkt;
|
||||
mcps_indication.data.port = *((uint8_t *) fport->data);
|
||||
gnrc_lorawan_mcps_indication(mac, &mcps_indication);
|
||||
}
|
||||
|
||||
if (lorawan_hdr_get_frame_pending(lw_hdr)) {
|
||||
if (_pkt.frame_pending) {
|
||||
mlme_indication_t mlme_indication;
|
||||
mlme_indication.type = MLME_SCHEDULE_UPLINK;
|
||||
gnrc_lorawan_mlme_indication(mac, &mlme_indication);
|
||||
}
|
||||
|
||||
out:
|
||||
if (error) {
|
||||
gnrc_lorawan_mcps_event(mac, MCPS_EVENT_NO_RX, 0);
|
||||
}
|
||||
|
||||
if (release) {
|
||||
DEBUG("gnrc_lorawan: release packet\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
if (_pkt.port) {
|
||||
mcps_indication_t mcps_indication;
|
||||
mcps_indication.type = _pkt.ack_req;
|
||||
mcps_indication.data.pkt = &_pkt.enc_payload;
|
||||
mcps_indication.data.port = _pkt.port;
|
||||
gnrc_lorawan_mcps_indication(mac, &mcps_indication);
|
||||
}
|
||||
}
|
||||
|
||||
size_t gnrc_lorawan_build_hdr(uint8_t mtype, le_uint32_t *dev_addr, uint32_t fcnt, uint8_t ack, uint8_t fopts_length, lorawan_buffer_t *buf)
|
||||
size_t gnrc_lorawan_build_hdr(uint8_t mtype, le_uint32_t *dev_addr,
|
||||
uint32_t fcnt, uint8_t ack, uint8_t fopts_length,
|
||||
lorawan_buffer_t *buf)
|
||||
{
|
||||
assert(fopts_length < 16);
|
||||
lorawan_hdr_t *lw_hdr = (lorawan_hdr_t *) buf->data;
|
||||
lorawan_hdr_t *lw_hdr = (lorawan_hdr_t *)buf->data;
|
||||
|
||||
lw_hdr->mt_maj = 0;
|
||||
lorawan_hdr_set_mtype(lw_hdr, mtype);
|
||||
@ -193,95 +226,150 @@ size_t gnrc_lorawan_build_hdr(uint8_t mtype, le_uint32_t *dev_addr, uint32_t fcn
|
||||
return sizeof(lorawan_hdr_t);
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *gnrc_lorawan_build_uplink(gnrc_lorawan_t *mac, gnrc_pktsnip_t *payload, int confirmed_data, uint8_t port)
|
||||
size_t gnrc_lorawan_build_uplink(gnrc_lorawan_t *mac, iolist_t *payload,
|
||||
int confirmed_data, uint8_t port)
|
||||
{
|
||||
/* Encrypt payload (it's block encryption so we can use the same buffer!) */
|
||||
gnrc_lorawan_encrypt_payload((iolist_t *) payload, &mac->dev_addr, mac->mcps.fcnt, GNRC_LORAWAN_DIR_UPLINK, port ? mac->appskey : mac->nwkskey);
|
||||
|
||||
/* We try to allocate the whole header with fopts at once */
|
||||
uint8_t fopts_length = gnrc_lorawan_build_options(mac, NULL);
|
||||
|
||||
gnrc_pktsnip_t *mac_hdr = gnrc_pktbuf_add(payload, NULL, sizeof(lorawan_hdr_t) + fopts_length + 1, GNRC_NETTYPE_UNDEF);
|
||||
|
||||
if (!mac_hdr) {
|
||||
gnrc_pktbuf_release_error(payload, -ENOBUFS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *mic = gnrc_pktbuf_add(NULL, NULL, MIC_SIZE, GNRC_NETTYPE_UNDEF);
|
||||
if (!mic) {
|
||||
gnrc_pktbuf_release_error(mac_hdr, -ENOBUFS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lorawan_buffer_t buf = {
|
||||
.data = (uint8_t *) mac_hdr->data,
|
||||
.size = mac_hdr->size,
|
||||
.data = (uint8_t *)mac->mcps.mhdr_mic,
|
||||
.size = sizeof(mac->mcps.mhdr_mic),
|
||||
.index = 0
|
||||
};
|
||||
lorawan_hdr_t *lw_hdr = (lorawan_hdr_t *)buf.data;
|
||||
|
||||
gnrc_lorawan_build_hdr(confirmed_data ? MTYPE_CNF_UPLINK : MTYPE_UNCNF_UPLINK,
|
||||
&mac->dev_addr, mac->mcps.fcnt, mac->mcps.ack_requested, fopts_length, &buf);
|
||||
lw_hdr->mt_maj = 0;
|
||||
lorawan_hdr_set_mtype(lw_hdr,
|
||||
confirmed_data ? MTYPE_CNF_UPLINK : MTYPE_UNCNF_UPLINK);
|
||||
lorawan_hdr_set_maj(lw_hdr, MAJOR_LRWAN_R1);
|
||||
|
||||
gnrc_lorawan_build_options(mac, &buf);
|
||||
lw_hdr->addr = mac->dev_addr;
|
||||
lw_hdr->fctrl = 0;
|
||||
|
||||
assert(buf.index == mac_hdr->size - 1);
|
||||
lorawan_hdr_set_ack(lw_hdr, mac->mcps.ack_requested);
|
||||
|
||||
lw_hdr->fcnt = byteorder_btols(byteorder_htons(mac->mcps.fcnt));
|
||||
|
||||
buf.index += sizeof(lorawan_hdr_t);
|
||||
|
||||
int 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;
|
||||
|
||||
gnrc_lorawan_calculate_mic(&mac->dev_addr, mac->mcps.fcnt, GNRC_LORAWAN_DIR_UPLINK,
|
||||
(iolist_t *) mac_hdr, mac->nwkskey, mic->data);
|
||||
gnrc_lorawan_encrypt_payload(payload, &mac->dev_addr, mac->mcps.fcnt,
|
||||
GNRC_LORAWAN_DIR_UPLINK,
|
||||
port ? mac->appskey : mac->nwkskey);
|
||||
|
||||
LL_APPEND(payload, mic);
|
||||
iolist_t iol =
|
||||
{ .iol_base = buf.data, .iol_len = buf.index, .iol_next = payload };
|
||||
|
||||
return mac_hdr;
|
||||
gnrc_lorawan_calculate_mic(&mac->dev_addr, mac->mcps.fcnt,
|
||||
GNRC_LORAWAN_DIR_UPLINK,
|
||||
&iol, mac->nwkskey,
|
||||
(le_uint32_t *)&buf.data[buf.index]);
|
||||
|
||||
return buf.index;
|
||||
}
|
||||
|
||||
static void _end_of_tx(gnrc_lorawan_t *mac, int type, int status)
|
||||
{
|
||||
mlme_confirm_t mlme_confirm;
|
||||
mcps_confirm_t mcps_confirm;
|
||||
|
||||
mac->mcps.waiting_for_ack = false;
|
||||
|
||||
mcps_confirm_t mcps_confirm;
|
||||
mac->mcps.fcnt++;
|
||||
|
||||
gnrc_lorawan_mac_release(mac);
|
||||
|
||||
if (mac->mlme.pending_mlme_opts & GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ) {
|
||||
mlme_confirm.type = MLME_LINK_CHECK;
|
||||
mlme_confirm.status = -ETIMEDOUT;
|
||||
mac->mlme.pending_mlme_opts &= ~GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ;
|
||||
gnrc_lorawan_mlme_confirm(mac, &mlme_confirm);
|
||||
}
|
||||
|
||||
mcps_confirm.type = type;
|
||||
mcps_confirm.status = status;
|
||||
mcps_confirm.msdu = mac->mcps.msdu;
|
||||
mac->mcps.msdu = NULL;
|
||||
gnrc_lorawan_mcps_confirm(mac, &mcps_confirm);
|
||||
|
||||
mac->mcps.fcnt += 1;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mcps_event(gnrc_lorawan_t *mac, int event, int data)
|
||||
static void _transmit_pkt(gnrc_lorawan_t *mac)
|
||||
{
|
||||
size_t mhdr_size = sizeof(lorawan_hdr_t) + 1 +
|
||||
lorawan_hdr_get_frame_opts_len((void *)mac->mcps.mhdr_mic);
|
||||
|
||||
iolist_t header =
|
||||
{ .iol_base = mac->mcps.mhdr_mic, .iol_len = mhdr_size,
|
||||
.iol_next = mac->mcps.msdu };
|
||||
iolist_t footer =
|
||||
{ .iol_base = mac->mcps.mhdr_mic + header.iol_len, .iol_len = MIC_SIZE,
|
||||
.iol_next = NULL };
|
||||
iolist_t *last_snip = mac->mcps.msdu;
|
||||
|
||||
while (last_snip->iol_next != NULL) {
|
||||
last_snip = last_snip->iol_next;
|
||||
}
|
||||
|
||||
last_snip->iol_next = &footer;
|
||||
gnrc_lorawan_send_pkt(mac, &header, mac->last_dr);
|
||||
|
||||
/* cppcheck-suppress redundantAssignment
|
||||
* (reason: cppcheck bug. The pointer is temporally modified to add a footer.
|
||||
* The `gnrc_lorawan_send_pkt` function uses this hack to append
|
||||
* the MIC independently of `gnrc_pktsnip_t` structures) */
|
||||
last_snip->iol_next = NULL;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_event_ack_timeout(gnrc_lorawan_t *mac)
|
||||
{
|
||||
_transmit_pkt(mac);
|
||||
}
|
||||
|
||||
static void _handle_retransmissions(gnrc_lorawan_t *mac)
|
||||
{
|
||||
if (mac->mcps.nb_trials-- == 0) {
|
||||
_end_of_tx(mac, MCPS_CONFIRMED, -ETIMEDOUT);
|
||||
}
|
||||
else {
|
||||
mac->msg.type = MSG_TYPE_MCPS_ACK_TIMEOUT;
|
||||
xtimer_set_msg(&mac->rx, 1000000 + random_uint32_range(0,
|
||||
2000000), &mac->msg,
|
||||
thread_getpid());
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_lorawan_event_no_rx(gnrc_lorawan_t *mac)
|
||||
{
|
||||
mlme_confirm_t mlme_confirm;
|
||||
|
||||
if (mac->mlme.activation == MLME_ACTIVATION_NONE) {
|
||||
/* This was a Join Request */
|
||||
mlme_confirm.type = MLME_JOIN;
|
||||
mlme_confirm.status = -ETIMEDOUT;
|
||||
gnrc_lorawan_mac_release(mac);
|
||||
gnrc_lorawan_mlme_confirm(mac, &mlme_confirm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == MCPS_EVENT_ACK_TIMEOUT) {
|
||||
gnrc_lorawan_send_pkt(mac, mac->mcps.outgoing_pkt, mac->last_dr);
|
||||
/* Otherwise check if retransmission should be handled */
|
||||
|
||||
if (mac->mcps.waiting_for_ack) {
|
||||
_handle_retransmissions(mac);
|
||||
}
|
||||
else {
|
||||
int state = mac->mcps.waiting_for_ack ? MCPS_CONFIRMED : MCPS_UNCONFIRMED;
|
||||
if (state == MCPS_CONFIRMED && ((event == MCPS_EVENT_RX && !data) ||
|
||||
event == MCPS_EVENT_NO_RX)) {
|
||||
if (mac->mcps.nb_trials-- == 0) {
|
||||
_end_of_tx(mac, MCPS_CONFIRMED, -ETIMEDOUT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_end_of_tx(mac, state, GNRC_LORAWAN_REQ_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
mac->msg.type = MSG_TYPE_MCPS_ACK_TIMEOUT;
|
||||
if (mac->mcps.outgoing_pkt) {
|
||||
xtimer_set_msg(&mac->rx, 1000000 + random_uint32_range(0, 2000000), &mac->msg, thread_getpid());
|
||||
}
|
||||
_end_of_tx(mac, MCPS_UNCONFIRMED, GNRC_LORAWAN_REQ_STATUS_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mcps_request(gnrc_lorawan_t *mac, const mcps_request_t *mcps_request, mcps_confirm_t *mcps_confirm)
|
||||
void gnrc_lorawan_mcps_request(gnrc_lorawan_t *mac,
|
||||
const mcps_request_t *mcps_request,
|
||||
mcps_confirm_t *mcps_confirm)
|
||||
{
|
||||
int release = true;
|
||||
gnrc_pktsnip_t *pkt = mcps_request->data.pkt;
|
||||
iolist_t *pkt = mcps_request->data.pkt;
|
||||
|
||||
if (mac->mlme.activation == MLME_ACTIVATION_NONE) {
|
||||
DEBUG("gnrc_lorawan_mcps: LoRaWAN not activated\n");
|
||||
@ -291,7 +379,7 @@ void gnrc_lorawan_mcps_request(gnrc_lorawan_t *mac, const mcps_request_t *mcps_r
|
||||
|
||||
if (!gnrc_lorawan_mac_acquire(mac)) {
|
||||
mcps_confirm->status = -EBUSY;
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mcps_request->data.port < LORAMAC_PORT_MIN ||
|
||||
@ -305,39 +393,37 @@ void gnrc_lorawan_mcps_request(gnrc_lorawan_t *mac, const mcps_request_t *mcps_r
|
||||
goto out;
|
||||
}
|
||||
|
||||
int waiting_for_ack = mcps_request->type == MCPS_CONFIRMED;
|
||||
if (!(pkt = gnrc_lorawan_build_uplink(mac, pkt, waiting_for_ack, mcps_request->data.port))) {
|
||||
/* This function releases the pkt if fails */
|
||||
release = false;
|
||||
mcps_confirm->status = -ENOBUFS;
|
||||
goto out;
|
||||
}
|
||||
uint8_t fopts_length = gnrc_lorawan_build_options(mac, NULL);
|
||||
/* We don't include the port because `MACPayload` doesn't consider
|
||||
* the MHDR...*/
|
||||
size_t mac_payload_size = sizeof(lorawan_hdr_t) + fopts_length +
|
||||
iolist_size(pkt);
|
||||
|
||||
if ((gnrc_pkt_len(pkt) - MIC_SIZE - 1) > gnrc_lorawan_region_mac_payload_max(mcps_request->data.dr)) {
|
||||
if (mac_payload_size >
|
||||
gnrc_lorawan_region_mac_payload_max(mcps_request->data.dr)) {
|
||||
mcps_confirm->status = -EMSGSIZE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
release = false;
|
||||
int waiting_for_ack = mcps_request->type == MCPS_CONFIRMED;
|
||||
|
||||
gnrc_lorawan_build_uplink(mac, pkt, waiting_for_ack,
|
||||
mcps_request->data.port);
|
||||
|
||||
mac->mcps.waiting_for_ack = waiting_for_ack;
|
||||
mac->mcps.ack_requested = false;
|
||||
|
||||
mac->mcps.nb_trials = LORAMAC_DEFAULT_RETX;
|
||||
|
||||
assert(mac->mcps.outgoing_pkt == NULL);
|
||||
mac->mcps.outgoing_pkt = pkt;
|
||||
|
||||
gnrc_lorawan_send_pkt(mac, pkt, mcps_request->data.dr);
|
||||
mac->mcps.msdu = pkt;
|
||||
mac->last_dr = mcps_request->data.dr;
|
||||
_transmit_pkt(mac);
|
||||
mcps_confirm->status = GNRC_LORAWAN_REQ_STATUS_DEFERRED;
|
||||
out:
|
||||
|
||||
if (mcps_confirm->status != GNRC_LORAWAN_REQ_STATUS_DEFERRED) {
|
||||
gnrc_lorawan_mac_release(mac);
|
||||
}
|
||||
|
||||
if (release) {
|
||||
gnrc_pktbuf_release_error(pkt, mcps_confirm->status);
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@ -28,100 +28,105 @@
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static gnrc_pktsnip_t *_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 *appeui, uint8_t *deveui,
|
||||
uint8_t *appkey, uint8_t *dev_nonce,
|
||||
uint8_t *psdu)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, sizeof(lorawan_join_request_t), GNRC_NETTYPE_UNDEF);
|
||||
lorawan_join_request_t *hdr = (lorawan_join_request_t *)psdu;
|
||||
|
||||
if (pkt) {
|
||||
lorawan_join_request_t *hdr = (lorawan_join_request_t *) pkt->data;
|
||||
hdr->mt_maj = 0;
|
||||
lorawan_hdr_set_mtype((lorawan_hdr_t *)hdr, MTYPE_JOIN_REQUEST);
|
||||
lorawan_hdr_set_maj((lorawan_hdr_t *)hdr, MAJOR_LRWAN_R1);
|
||||
|
||||
hdr->mt_maj = 0;
|
||||
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_deveui = *((le_uint64_t *)deveui);
|
||||
|
||||
le_uint64_t l_appeui = *((le_uint64_t *) appeui);
|
||||
le_uint64_t l_deveui = *((le_uint64_t *) deveui);
|
||||
hdr->app_eui = l_appeui;
|
||||
hdr->dev_eui = l_deveui;
|
||||
|
||||
hdr->app_eui = l_appeui;
|
||||
hdr->dev_eui = l_deveui;
|
||||
le_uint16_t l_dev_nonce = *((le_uint16_t *)dev_nonce);
|
||||
|
||||
le_uint16_t l_dev_nonce = *((le_uint16_t *) dev_nonce);
|
||||
hdr->dev_nonce = l_dev_nonce;
|
||||
hdr->dev_nonce = l_dev_nonce;
|
||||
|
||||
iolist_t io = { .iol_base = pkt->data, .iol_len = JOIN_REQUEST_SIZE - MIC_SIZE,
|
||||
.iol_next = NULL };
|
||||
gnrc_lorawan_calculate_join_mic(&io, appkey, &hdr->mic);
|
||||
}
|
||||
|
||||
return pkt;
|
||||
gnrc_lorawan_calculate_join_mic(psdu, JOIN_REQUEST_SIZE - MIC_SIZE, appkey,
|
||||
&hdr->mic);
|
||||
}
|
||||
|
||||
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 *appeui, uint8_t *appkey,
|
||||
uint8_t dr)
|
||||
{
|
||||
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
|
||||
|
||||
/* Dev Nonce */
|
||||
uint32_t random_number;
|
||||
|
||||
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;
|
||||
|
||||
/* build join request */
|
||||
gnrc_pktsnip_t *pkt = _build_join_req_pkt(appeui, deveui, appkey, mac->mlme.dev_nonce);
|
||||
if (!pkt) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
uint8_t psdu[sizeof(lorawan_join_request_t)];
|
||||
|
||||
iolist_t pkt =
|
||||
{ .iol_base = &psdu, .iol_len = sizeof(psdu), .iol_next = NULL };
|
||||
|
||||
_build_join_req_pkt(appeui, deveui, appkey, mac->mlme.dev_nonce, psdu);
|
||||
|
||||
/* We need a random delay for join request. Otherwise there might be
|
||||
* network congestion if a group of nodes start at the same time */
|
||||
xtimer_usleep(random_uint32() & GNRC_LORAWAN_JOIN_DELAY_U32_MASK);
|
||||
gnrc_lorawan_send_pkt(mac, pkt, dr);
|
||||
gnrc_lorawan_send_pkt(mac, &pkt, dr);
|
||||
|
||||
mac->mlme.backoff_budget -= mac->toa;
|
||||
gnrc_pktbuf_release(pkt);
|
||||
|
||||
return GNRC_LORAWAN_REQ_STATUS_DEFERRED;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mlme_process_join(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt)
|
||||
void gnrc_lorawan_mlme_process_join(gnrc_lorawan_t *mac, uint8_t *data,
|
||||
size_t size)
|
||||
{
|
||||
int status;
|
||||
mlme_confirm_t mlme_confirm;
|
||||
|
||||
if (mac->mlme.activation != MLME_ACTIVATION_NONE) {
|
||||
status = -EBADMSG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pkt->size != GNRC_LORAWAN_JOIN_ACCEPT_MAX_SIZE - CFLIST_SIZE &&
|
||||
pkt->size != GNRC_LORAWAN_JOIN_ACCEPT_MAX_SIZE) {
|
||||
if (size != GNRC_LORAWAN_JOIN_ACCEPT_MAX_SIZE - CFLIST_SIZE &&
|
||||
size != GNRC_LORAWAN_JOIN_ACCEPT_MAX_SIZE) {
|
||||
status = -EBADMSG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Subtract 1 from join accept max size, since the MHDR was already read */
|
||||
uint8_t out[GNRC_LORAWAN_JOIN_ACCEPT_MAX_SIZE - 1];
|
||||
uint8_t has_cflist = (pkt->size - 1) >= CFLIST_SIZE;
|
||||
gnrc_lorawan_decrypt_join_accept(mac->appskey, ((uint8_t *) pkt->data) + 1,
|
||||
has_cflist, out);
|
||||
memcpy(((uint8_t *) pkt->data) + 1, out, pkt->size - 1);
|
||||
uint8_t has_cflist = (size - 1) >= CFLIST_SIZE;
|
||||
|
||||
gnrc_lorawan_decrypt_join_accept(mac->appskey, data + 1,
|
||||
has_cflist, out);
|
||||
memcpy(data + 1, out, size - 1);
|
||||
|
||||
iolist_t io = { .iol_base = pkt->data, .iol_len = pkt->size - MIC_SIZE,
|
||||
.iol_next = NULL };
|
||||
le_uint32_t mic;
|
||||
le_uint32_t *expected_mic = (le_uint32_t *) (((uint8_t *) pkt->data) + pkt->size - MIC_SIZE);
|
||||
gnrc_lorawan_calculate_join_mic(&io, mac->appskey, &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);
|
||||
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 *) pkt->data;
|
||||
gnrc_lorawan_generate_session_keys(ja_hdr->app_nonce, mac->mlme.dev_nonce, mac->appskey, mac->nwkskey, mac->appskey);
|
||||
lorawan_join_accept_t *ja_hdr = (lorawan_join_accept_t *)data;
|
||||
|
||||
gnrc_lorawan_generate_session_keys(ja_hdr->app_nonce, mac->mlme.dev_nonce,
|
||||
mac->appskey, mac->nwkskey,
|
||||
mac->appskey);
|
||||
|
||||
le_uint32_t le_nid;
|
||||
|
||||
le_nid.u32 = 0;
|
||||
memcpy(&le_nid, ja_hdr->net_id, 3);
|
||||
mac->mlme.nid = byteorder_ntohl(byteorder_ltobl(le_nid));
|
||||
@ -138,11 +143,10 @@ void gnrc_lorawan_mlme_process_join(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt)
|
||||
status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
|
||||
|
||||
out:
|
||||
gnrc_pktbuf_release(pkt);
|
||||
mlme_confirm_t mlme_confirm;
|
||||
mlme_confirm.type = MLME_JOIN;
|
||||
mlme_confirm.status = status;
|
||||
|
||||
gnrc_lorawan_mac_release(mac);
|
||||
gnrc_lorawan_mlme_confirm(mac, &mlme_confirm);
|
||||
}
|
||||
|
||||
@ -179,19 +183,20 @@ void gnrc_lorawan_mlme_backoff_expire(gnrc_lorawan_t *mac)
|
||||
}
|
||||
|
||||
static void _mlme_set(gnrc_lorawan_t *mac, const mlme_request_t *mlme_request,
|
||||
mlme_confirm_t *mlme_confirm)
|
||||
mlme_confirm_t *mlme_confirm)
|
||||
{
|
||||
mlme_confirm->status = -EINVAL;
|
||||
switch(mlme_request->mib.type) {
|
||||
switch (mlme_request->mib.type) {
|
||||
case MIB_ACTIVATION_METHOD:
|
||||
if(mlme_request->mib.activation != MLME_ACTIVATION_OTAA) {
|
||||
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:
|
||||
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
|
||||
memcpy(&mac->dev_addr, mlme_request->mib.dev_addr, sizeof(uint32_t));
|
||||
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;
|
||||
@ -203,9 +208,9 @@ static void _mlme_set(gnrc_lorawan_t *mac, const mlme_request_t *mlme_request,
|
||||
}
|
||||
|
||||
static void _mlme_get(gnrc_lorawan_t *mac, const mlme_request_t *mlme_request,
|
||||
mlme_confirm_t *mlme_confirm)
|
||||
mlme_confirm_t *mlme_confirm)
|
||||
{
|
||||
switch(mlme_request->mib.type) {
|
||||
switch (mlme_request->mib.type) {
|
||||
case MIB_ACTIVATION_METHOD:
|
||||
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_SUCCESS;
|
||||
mlme_confirm->mib.activation = mac->mlme.activation;
|
||||
@ -220,12 +225,13 @@ static void _mlme_get(gnrc_lorawan_t *mac, const mlme_request_t *mlme_request,
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mlme_request(gnrc_lorawan_t *mac, const mlme_request_t *mlme_request,
|
||||
void gnrc_lorawan_mlme_request(gnrc_lorawan_t *mac,
|
||||
const mlme_request_t *mlme_request,
|
||||
mlme_confirm_t *mlme_confirm)
|
||||
{
|
||||
switch (mlme_request->type) {
|
||||
case MLME_JOIN:
|
||||
if(mac->mlme.activation != MLME_ACTIVATION_NONE) {
|
||||
if (mac->mlme.activation != MLME_ACTIVATION_NONE) {
|
||||
mlme_confirm->status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
@ -239,11 +245,14 @@ void gnrc_lorawan_mlme_request(gnrc_lorawan_t *mac, const mlme_request_t *mlme_r
|
||||
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);
|
||||
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;
|
||||
mac->mlme.pending_mlme_opts |=
|
||||
GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ;
|
||||
mlme_confirm->status = GNRC_LORAWAN_REQ_STATUS_DEFERRED;
|
||||
break;
|
||||
case MLME_SET:
|
||||
@ -274,6 +283,7 @@ int _fopts_mlme_link_check_req(lorawan_buffer_t *buf)
|
||||
static void _mlme_link_check_ans(gnrc_lorawan_t *mac, uint8_t *p)
|
||||
{
|
||||
mlme_confirm_t mlme_confirm;
|
||||
|
||||
mlme_confirm.link_req.margin = p[1];
|
||||
mlme_confirm.link_req.num_gateways = p[2];
|
||||
|
||||
@ -284,16 +294,18 @@ 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;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_process_fopts(gnrc_lorawan_t *mac, uint8_t *fopts, size_t size)
|
||||
void gnrc_lorawan_process_fopts(gnrc_lorawan_t *mac, uint8_t *fopts,
|
||||
size_t size)
|
||||
{
|
||||
if (!fopts || !size) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t ret = 0;
|
||||
void (*cb)(gnrc_lorawan_t*, uint8_t *p) = NULL;
|
||||
|
||||
for(uint8_t pos = 0; pos < size; pos += ret) {
|
||||
void (*cb)(gnrc_lorawan_t *, uint8_t *p) = NULL;
|
||||
|
||||
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;
|
||||
@ -303,7 +315,7 @@ void gnrc_lorawan_process_fopts(gnrc_lorawan_t *mac, uint8_t *fopts, size_t size
|
||||
return;
|
||||
}
|
||||
|
||||
if(pos + ret > size) {
|
||||
if (pos + ret > size) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -315,26 +327,9 @@ uint8_t gnrc_lorawan_build_options(gnrc_lorawan_t *mac, lorawan_buffer_t *buf)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
if(mac->mlme.pending_mlme_opts & GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ) {
|
||||
if (mac->mlme.pending_mlme_opts & GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ) {
|
||||
size += _fopts_mlme_link_check_req(buf);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mlme_no_rx(gnrc_lorawan_t *mac)
|
||||
{
|
||||
mlme_confirm_t mlme_confirm;
|
||||
|
||||
mlme_confirm.status = -ETIMEDOUT;
|
||||
|
||||
if (mac->mlme.activation == MLME_ACTIVATION_NONE) {
|
||||
mlme_confirm.type = MLME_JOIN;
|
||||
gnrc_lorawan_mlme_confirm(mac, &mlme_confirm);
|
||||
}
|
||||
else if (mac->mlme.pending_mlme_opts & GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ) {
|
||||
mlme_confirm.type = MLME_LINK_CHECK;
|
||||
gnrc_lorawan_mlme_confirm(mac, &mlme_confirm);
|
||||
mac->mlme.pending_mlme_opts &= ~GNRC_LORAWAN_MLME_OPTS_LINK_CHECK_REQ;
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,6 +99,17 @@ extern "C" {
|
||||
#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 */
|
||||
|
||||
/**
|
||||
* @brief Size of the internal MHDR-MIC buffer
|
||||
*/
|
||||
#define MHDR_MIC_BUF_SIZE (sizeof(lorawan_hdr_t) + \
|
||||
GNRC_LORAWAN_FOPTS_MAX_SIZE + \
|
||||
GNRC_LORAWAN_FPORT_SIZE + \
|
||||
MIC_SIZE)
|
||||
|
||||
/**
|
||||
* @brief buffer helper for parsing and constructing LoRaWAN packets.
|
||||
*/
|
||||
@ -130,7 +141,7 @@ typedef struct {
|
||||
* @brief MCPS data
|
||||
*/
|
||||
typedef struct {
|
||||
gnrc_pktsnip_t *pkt; /**< packet of the request */
|
||||
iolist_t *pkt; /**< packet of the request */
|
||||
uint8_t port; /**< port of the request */
|
||||
uint8_t dr; /**< datarate of the request */
|
||||
} mcps_data_t;
|
||||
@ -139,26 +150,27 @@ typedef struct {
|
||||
* @brief MCPS service access point descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t fcnt; /**< uplink framecounter */
|
||||
uint32_t fcnt_down; /**< downlink frame counter */
|
||||
gnrc_pktsnip_t *outgoing_pkt; /**< holds the outgoing packet in case of retransmissions */
|
||||
int nb_trials; /**< holds the remaining number of retransmissions */
|
||||
int ack_requested; /**< whether the network server requested an ACK */
|
||||
int waiting_for_ack; /**< true if the MAC layer is waiting for an ACK */
|
||||
uint32_t fcnt; /**< uplink framecounter */
|
||||
uint32_t fcnt_down; /**< downlink frame counter */
|
||||
iolist_t *msdu; /**< current MSDU */
|
||||
int nb_trials; /**< holds the remaining number of retransmissions */
|
||||
int ack_requested; /**< whether the network server requested an ACK */
|
||||
int waiting_for_ack; /**< true if the MAC layer is waiting for an ACK */
|
||||
char mhdr_mic[MHDR_MIC_BUF_SIZE]; /**< internal retransmissions buffer */
|
||||
} gnrc_lorawan_mcps_t;
|
||||
|
||||
/**
|
||||
* @brief MLME service access point descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
xtimer_t backoff_timer; /**< timer used for backoff expiration */
|
||||
msg_t backoff_msg; /**< msg for backoff expiration */
|
||||
uint8_t activation; /**< Activation mechanism of the MAC layer */
|
||||
xtimer_t backoff_timer; /**< timer used for backoff expiration */
|
||||
msg_t backoff_msg; /**< msg for backoff expiration */
|
||||
uint8_t activation; /**< Activation mechanism of the MAC layer */
|
||||
int pending_mlme_opts; /**< holds pending mlme opts */
|
||||
uint32_t nid; /**< current Network ID */
|
||||
int32_t backoff_budget; /**< remaining Time On Air budget */
|
||||
uint8_t dev_nonce[2]; /**< Device Nonce */
|
||||
uint8_t backoff_state; /**< state in the backoff state machine */
|
||||
uint32_t nid; /**< current Network ID */
|
||||
int32_t backoff_budget; /**< remaining Time On Air budget */
|
||||
uint8_t dev_nonce[2]; /**< Device Nonce */
|
||||
uint8_t backoff_state; /**< state in the backoff state machine */
|
||||
} gnrc_lorawan_mlme_t;
|
||||
|
||||
/**
|
||||
@ -189,13 +201,15 @@ typedef struct {
|
||||
*
|
||||
* @note This function is also used for decrypting a LoRaWAN packet. The LoRaWAN server encrypts the packet using decryption, so the end device only needs to implement encryption
|
||||
*
|
||||
* @param[in] iolist packet iolist representation
|
||||
* @param[in] iolist pointer to the MSDU frame
|
||||
* @param[in] dev_addr device address
|
||||
* @param[in] fcnt frame counter
|
||||
* @param[in] dir direction of the packet (0 if uplink, 1 if downlink)
|
||||
* @param[in] appskey pointer to the Application Session Key
|
||||
*/
|
||||
void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr, uint32_t fcnt, uint8_t dir, const uint8_t *appskey);
|
||||
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 Decrypts join accept message
|
||||
@ -205,7 +219,8 @@ void gnrc_lorawan_encrypt_payload(iolist_t *iolist, const le_uint32_t *dev_addr,
|
||||
* @param[in] has_clist true if the Join Accept frame has CFList
|
||||
* @param[out] out buffer where the decryption is stored
|
||||
*/
|
||||
void gnrc_lorawan_decrypt_join_accept(const uint8_t *key, uint8_t *pkt, int has_clist, uint8_t *out);
|
||||
void gnrc_lorawan_decrypt_join_accept(const uint8_t *key, uint8_t *pkt,
|
||||
int has_clist, uint8_t *out);
|
||||
|
||||
/**
|
||||
* @brief Generate LoRaWAN session keys
|
||||
@ -219,7 +234,10 @@ void gnrc_lorawan_decrypt_join_accept(const uint8_t *key, uint8_t *pkt, int has_
|
||||
* @param[out] nwkskey pointer to the NwkSKey
|
||||
* @param[out] appskey pointer to the AppSKey
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Set datarate for the next transmission
|
||||
@ -243,7 +261,8 @@ int gnrc_lorawan_set_dr(gnrc_lorawan_t *mac, uint8_t datarate);
|
||||
* @return full LoRaWAN frame including payload
|
||||
* @return NULL if packet buffer is full. `payload` is released
|
||||
*/
|
||||
gnrc_pktsnip_t *gnrc_lorawan_build_uplink(gnrc_lorawan_t *mac, gnrc_pktsnip_t *payload, int confirmed_data, uint8_t port);
|
||||
size_t gnrc_lorawan_build_uplink(gnrc_lorawan_t *mac, iolist_t *payload,
|
||||
int confirmed_data, uint8_t port);
|
||||
|
||||
/**
|
||||
* @brief pick a random available LoRaWAN channel
|
||||
@ -272,16 +291,19 @@ uint8_t gnrc_lorawan_build_options(gnrc_lorawan_t *mac, lorawan_buffer_t *buf);
|
||||
* @param[in] fopts pointer to fopts frame
|
||||
* @param[in] size size of fopts frame
|
||||
*/
|
||||
void gnrc_lorawan_process_fopts(gnrc_lorawan_t *mac, uint8_t *fopts, size_t size);
|
||||
void gnrc_lorawan_process_fopts(gnrc_lorawan_t *mac, uint8_t *fopts,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief calculate join Message Integrity Code
|
||||
*
|
||||
* @param[in] io iolist representation of the packet
|
||||
* @param[in] buf pointer to the frame
|
||||
* @param[in] len length of the frame
|
||||
* @param[in] key key used to calculate the MIC
|
||||
* @param[out] out calculated MIC
|
||||
*/
|
||||
void gnrc_lorawan_calculate_join_mic(const iolist_t *io, const uint8_t *key, le_uint32_t *out);
|
||||
void gnrc_lorawan_calculate_join_mic(const uint8_t *buf, size_t len,
|
||||
const uint8_t *key, le_uint32_t *out);
|
||||
|
||||
/**
|
||||
* @brief Calculate Message Integrity Code for a MCPS message
|
||||
@ -289,13 +311,13 @@ void gnrc_lorawan_calculate_join_mic(const iolist_t *io, const uint8_t *key, le
|
||||
* @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] pkt the pkt
|
||||
* @param[in] frame pointer to the PSDU frame (witout MIC)
|
||||
* @param[in] nwkskey pointer to the Network Session 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 *pkt, const uint8_t *nwkskey, le_uint32_t *out);
|
||||
|
||||
uint8_t dir, iolist_t *frame,
|
||||
const uint8_t *nwkskey, le_uint32_t *out);
|
||||
/**
|
||||
* @brief Build a MCPS LoRaWAN header
|
||||
*
|
||||
@ -308,15 +330,19 @@ void gnrc_lorawan_calculate_mic(const le_uint32_t *dev_addr, uint32_t fcnt,
|
||||
*
|
||||
* @return the size of the header
|
||||
*/
|
||||
size_t gnrc_lorawan_build_hdr(uint8_t mtype, le_uint32_t *dev_addr, uint32_t fcnt, uint8_t ack, uint8_t fopts_length, lorawan_buffer_t *buf);
|
||||
size_t gnrc_lorawan_build_hdr(uint8_t mtype, le_uint32_t *dev_addr,
|
||||
uint32_t fcnt, uint8_t ack, uint8_t fopts_length,
|
||||
lorawan_buffer_t *buf);
|
||||
|
||||
/**
|
||||
* @brief Process an MCPS downlink message (confirmable or non comfirmable)
|
||||
*
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
* @param[in] pkt pointer to the downlink message
|
||||
* @param[in] psdu pointer to the downlink PSDU
|
||||
* @param[in] size size of the PSDU
|
||||
*/
|
||||
void gnrc_lorawan_mcps_process_downlink(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt);
|
||||
void gnrc_lorawan_mcps_process_downlink(gnrc_lorawan_t *mac, uint8_t *psdu,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Init regional channel settings.
|
||||
@ -340,18 +366,20 @@ void gnrc_lorawan_reset(gnrc_lorawan_t *mac);
|
||||
* @brief Send a LoRaWAN packet
|
||||
*
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
* @param[in] pkt the packet to be sent
|
||||
* @param[in] psdu the psdu frame to be sent
|
||||
* @param[in] dr the datarate used for the transmission
|
||||
*/
|
||||
void gnrc_lorawan_send_pkt(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt, uint8_t dr);
|
||||
void gnrc_lorawan_send_pkt(gnrc_lorawan_t *mac, iolist_t *psdu, uint8_t dr);
|
||||
|
||||
/**
|
||||
* @brief Process join accept message
|
||||
*
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
* @param[in] pkt the Join Accept packet
|
||||
* @param[in] data the Join Accept packet
|
||||
* @param[in] size size of the Join Accept packet
|
||||
*/
|
||||
void gnrc_lorawan_mlme_process_join(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt);
|
||||
void gnrc_lorawan_mlme_process_join(gnrc_lorawan_t *mac, uint8_t *data,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Inform the MAC layer that no packet was received during reception.
|
||||
@ -364,13 +392,18 @@ void gnrc_lorawan_mlme_process_join(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt);
|
||||
void gnrc_lorawan_mlme_no_rx(gnrc_lorawan_t *mac);
|
||||
|
||||
/**
|
||||
* @brief Trigger a MCPS event
|
||||
* @brief Mac callback for no RX
|
||||
*
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
* @param[in] event the event to be processed.
|
||||
* @param[in] data set to true if the packet contains payload
|
||||
*/
|
||||
void gnrc_lorawan_mcps_event(gnrc_lorawan_t *mac, int event, int data);
|
||||
void gnrc_lorawan_event_no_rx(gnrc_lorawan_t *mac);
|
||||
|
||||
/**
|
||||
* @brief Mac callback for ACK timeout event
|
||||
*
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
*/
|
||||
void gnrc_lorawan_event_ack_timeout(gnrc_lorawan_t *mac);
|
||||
|
||||
/**
|
||||
* @brief Get the maximum MAC payload (M value) for a given datarate.
|
||||
@ -400,7 +433,7 @@ void gnrc_lorawan_mlme_backoff_expire(gnrc_lorawan_t *mac);
|
||||
* @param[in] mac pointer to the MAC descriptor
|
||||
* @param[in] pkt the received packet
|
||||
*/
|
||||
void gnrc_lorawan_process_pkt(gnrc_lorawan_t *mac, gnrc_pktsnip_t *pkt);
|
||||
void gnrc_lorawan_process_pkt(gnrc_lorawan_t *mac, iolist_t *pkt);
|
||||
|
||||
/**
|
||||
* @brief Open a reception window
|
||||
|
||||
@ -51,7 +51,9 @@ static const gnrc_netif_ops_t lorawan_ops = {
|
||||
|
||||
void gnrc_lorawan_mlme_confirm(gnrc_lorawan_t *mac, mlme_confirm_t *confirm)
|
||||
{
|
||||
gnrc_netif_lorawan_t *lw_netif = container_of(mac, gnrc_netif_lorawan_t, mac);
|
||||
gnrc_netif_lorawan_t *lw_netif =
|
||||
container_of(mac, gnrc_netif_lorawan_t, mac);
|
||||
|
||||
if (confirm->type == MLME_JOIN) {
|
||||
if (confirm->status == 0) {
|
||||
DEBUG("gnrc_lorawan: join succeeded\n");
|
||||
@ -84,28 +86,58 @@ static inline void _set_be_addr(gnrc_lorawan_t *mac, uint8_t *be_addr)
|
||||
|
||||
void gnrc_lorawan_mcps_indication(gnrc_lorawan_t *mac, mcps_indication_t *ind)
|
||||
{
|
||||
(void) mac;
|
||||
(void)mac;
|
||||
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, ind->data.pkt->iol_base,
|
||||
ind->data.pkt->iol_len,
|
||||
GNRC_NETTYPE_LORAWAN);
|
||||
|
||||
if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_LORAWAN, ind->data.port,
|
||||
ind->data.pkt)) {
|
||||
gnrc_pktbuf_release(ind->data.pkt);
|
||||
pkt)) {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mlme_indication(gnrc_lorawan_t *mac, mlme_indication_t *ind)
|
||||
{
|
||||
(void) mac;
|
||||
(void) ind;
|
||||
(void)mac;
|
||||
(void)ind;
|
||||
}
|
||||
|
||||
void gnrc_lorawan_mcps_confirm(gnrc_lorawan_t *mac, mcps_confirm_t *confirm)
|
||||
{
|
||||
if (confirm->status == 0) {
|
||||
gnrc_pktbuf_release(mac->mcps.outgoing_pkt);
|
||||
(void)mac;
|
||||
|
||||
gnrc_pktbuf_release_error((gnrc_pktsnip_t *)confirm->msdu, confirm->status);
|
||||
|
||||
DEBUG("gnrc_lorawan: transmission finished with status %i\n",
|
||||
confirm->status);
|
||||
}
|
||||
|
||||
static void _rx_done(gnrc_lorawan_t *mac)
|
||||
{
|
||||
netdev_t *dev = gnrc_lorawan_get_netdev(mac);
|
||||
int bytes_expected = dev->driver->recv(dev, NULL, 0, 0);
|
||||
int nread;
|
||||
struct netdev_radio_rx_info rx_info;
|
||||
gnrc_pktsnip_t *pkt = gnrc_pktbuf_add(NULL, NULL, bytes_expected,
|
||||
GNRC_NETTYPE_UNDEF);
|
||||
|
||||
if (pkt == NULL) {
|
||||
DEBUG("_recv_lorawan: cannot allocate pktsnip.\n");
|
||||
/* Discard packet on netdev device */
|
||||
dev->driver->recv(dev, NULL, bytes_expected, NULL);
|
||||
gnrc_lorawan_radio_rx_done_cb(mac, NULL, 0);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
gnrc_pktbuf_release_error(mac->mcps.outgoing_pkt, 1);
|
||||
nread = dev->driver->recv(dev, pkt->data, bytes_expected, &rx_info);
|
||||
if (nread <= 0) {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
gnrc_lorawan_radio_rx_done_cb(mac, NULL, 0);
|
||||
return;
|
||||
}
|
||||
mac->mcps.outgoing_pkt = NULL;
|
||||
|
||||
gnrc_lorawan_radio_rx_done_cb(mac, pkt->data, pkt->size);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
|
||||
static void _driver_cb(netdev_t *dev, netdev_event_t event)
|
||||
@ -125,13 +157,13 @@ static void _driver_cb(netdev_t *dev, netdev_event_t event)
|
||||
DEBUG("gnrc_netif: event triggered -> %i\n", event);
|
||||
switch (event) {
|
||||
case NETDEV_EVENT_RX_COMPLETE:
|
||||
gnrc_lorawan_recv(mac);
|
||||
_rx_done(mac);
|
||||
break;
|
||||
case NETDEV_EVENT_TX_COMPLETE:
|
||||
gnrc_lorawan_event_tx_complete(mac);
|
||||
gnrc_lorawan_radio_tx_done_cb(mac);
|
||||
break;
|
||||
case NETDEV_EVENT_RX_TIMEOUT:
|
||||
gnrc_lorawan_event_timeout(mac);
|
||||
gnrc_lorawan_radio_rx_timeout_cb(mac);
|
||||
break;
|
||||
default:
|
||||
DEBUG("gnrc_netif: warning: unhandled event %u.\n", event);
|
||||
@ -142,7 +174,8 @@ static void _driver_cb(netdev_t *dev, netdev_event_t event)
|
||||
|
||||
static void _reset(gnrc_netif_t *netif)
|
||||
{
|
||||
netif->lorawan.otaa = LORAMAC_DEFAULT_JOIN_PROCEDURE == LORAMAC_JOIN_OTAA ? NETOPT_ENABLE : NETOPT_DISABLE;
|
||||
netif->lorawan.otaa = LORAMAC_DEFAULT_JOIN_PROCEDURE ==
|
||||
LORAMAC_JOIN_OTAA ? NETOPT_ENABLE : NETOPT_DISABLE;
|
||||
netif->lorawan.datarate = LORAMAC_DEFAULT_DR;
|
||||
netif->lorawan.demod_margin = 0;
|
||||
netif->lorawan.num_gateways = 0;
|
||||
@ -153,14 +186,15 @@ static void _reset(gnrc_netif_t *netif)
|
||||
|
||||
static void _memcpy_reversed(uint8_t *dst, uint8_t *src, size_t size)
|
||||
{
|
||||
for(size_t i=0;i<size;i++) {
|
||||
dst[size-i-1] = src[i];
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
dst[size - i - 1] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
netdev_t *gnrc_lorawan_get_netdev(gnrc_lorawan_t *mac)
|
||||
{
|
||||
gnrc_netif_t *netif = container_of(mac, gnrc_netif_t, lorawan.mac);
|
||||
|
||||
return netif->dev;
|
||||
}
|
||||
|
||||
@ -178,7 +212,8 @@ static void _init(gnrc_netif_t *netif)
|
||||
_memcpy_reversed(netif->lorawan.appeui, _appeui, sizeof(_appeui));
|
||||
|
||||
_set_be_addr(&netif->lorawan.mac, _devaddr);
|
||||
gnrc_lorawan_init(&netif->lorawan.mac, netif->lorawan.nwkskey, netif->lorawan.appskey);
|
||||
gnrc_lorawan_init(&netif->lorawan.mac, netif->lorawan.nwkskey,
|
||||
netif->lorawan.appskey);
|
||||
}
|
||||
|
||||
int gnrc_netif_lorawan_create(gnrc_netif_t *netif, char *stack, int stacksize,
|
||||
@ -190,7 +225,7 @@ int gnrc_netif_lorawan_create(gnrc_netif_t *netif, char *stack, int stacksize,
|
||||
|
||||
static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif)
|
||||
{
|
||||
(void) netif;
|
||||
(void)netif;
|
||||
/* Unused */
|
||||
return 0;
|
||||
}
|
||||
@ -202,26 +237,33 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *payload)
|
||||
|
||||
if (netif->lorawan.flags & GNRC_NETIF_LORAWAN_FLAGS_LINK_CHECK) {
|
||||
mlme_request.type = MLME_LINK_CHECK;
|
||||
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request, &mlme_confirm);
|
||||
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
|
||||
&mlme_confirm);
|
||||
}
|
||||
mcps_request_t req = { .type = netif->lorawan.ack_req ? MCPS_CONFIRMED : MCPS_UNCONFIRMED,
|
||||
.data = { .pkt = payload, .port = netif->lorawan.port,
|
||||
.dr = netif->lorawan.datarate } };
|
||||
mcps_request_t req =
|
||||
{ .type = netif->lorawan.ack_req ? MCPS_CONFIRMED : MCPS_UNCONFIRMED,
|
||||
.data =
|
||||
{ .pkt = (iolist_t *)payload, .port = netif->lorawan.port,
|
||||
.dr = netif->lorawan.datarate } };
|
||||
mcps_confirm_t conf;
|
||||
|
||||
gnrc_lorawan_mcps_request(&netif->lorawan.mac, &req, &conf);
|
||||
if (conf.status < 0) {
|
||||
gnrc_pktbuf_release_error(payload, conf.status);
|
||||
}
|
||||
return conf.status;
|
||||
}
|
||||
|
||||
static void _msg_handler(gnrc_netif_t *netif, msg_t *msg)
|
||||
{
|
||||
(void) netif;
|
||||
(void) msg;
|
||||
(void)netif;
|
||||
(void)msg;
|
||||
switch (msg->type) {
|
||||
case MSG_TYPE_TIMEOUT:
|
||||
gnrc_lorawan_open_rx_window(&netif->lorawan.mac);
|
||||
break;
|
||||
case MSG_TYPE_MCPS_ACK_TIMEOUT:
|
||||
gnrc_lorawan_mcps_event(&netif->lorawan.mac, MCPS_EVENT_ACK_TIMEOUT, 0);
|
||||
gnrc_lorawan_event_ack_timeout(&netif->lorawan.mac);
|
||||
break;
|
||||
case MSG_TYPE_MLME_BACKOFF_EXPIRE:
|
||||
gnrc_lorawan_mlme_backoff_expire(&netif->lorawan.mac);
|
||||
@ -237,42 +279,48 @@ static int _get(gnrc_netif_t *netif, gnrc_netapi_opt_t *opt)
|
||||
|
||||
mlme_confirm_t mlme_confirm;
|
||||
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;
|
||||
*((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;
|
||||
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;
|
||||
*((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;
|
||||
*((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;
|
||||
*((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);
|
||||
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);
|
||||
res = netif->dev->driver->get(netif->dev, opt->opt, opt->data,
|
||||
opt->data_len);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
@ -288,15 +336,15 @@ static int _set(gnrc_netif_t *netif, const gnrc_netapi_opt_t *opt)
|
||||
switch (opt->opt) {
|
||||
case NETOPT_LORAWAN_DR:
|
||||
assert(opt->data_len == sizeof(uint8_t));
|
||||
netif->lorawan.datarate = *((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);
|
||||
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);
|
||||
netif->lorawan.ack_req = *((netopt_enable_t *)opt->data);
|
||||
break;
|
||||
case NETOPT_LORAWAN_APPKEY:
|
||||
assert(opt->data_len == LORAMAC_APPKEY_LEN);
|
||||
@ -304,15 +352,17 @@ static int _set(gnrc_netif_t *netif, const gnrc_netapi_opt_t *opt)
|
||||
break;
|
||||
case NETOPT_ADDRESS_LONG:
|
||||
assert(opt->data_len == LORAMAC_DEVEUI_LEN);
|
||||
_memcpy_reversed(netif->lorawan.deveui, opt->data, 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);
|
||||
_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);
|
||||
netif->lorawan.otaa = *((netopt_enable_t *)opt->data);
|
||||
break;
|
||||
case NETOPT_LORAWAN_APPSKEY:
|
||||
assert(opt->data_len >= LORAMAC_APPSKEY_LEN);
|
||||
@ -324,26 +374,29 @@ static int _set(gnrc_netif_t *netif, const gnrc_netapi_opt_t *opt)
|
||||
break;
|
||||
case NETOPT_LINK:
|
||||
{
|
||||
netopt_enable_t en = *((netopt_enable_t *) opt->data);
|
||||
netopt_enable_t en = *((netopt_enable_t *)opt->data);
|
||||
if (en) {
|
||||
if(netif->lorawan.otaa) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
gnrc_lorawan_mlme_request(&netif->lorawan.mac, &mlme_request,
|
||||
&mlme_confirm);
|
||||
res = mlme_confirm.status;
|
||||
if (mlme_confirm.status == 0) {
|
||||
/* reset netif as well */
|
||||
@ -363,11 +416,13 @@ static int _set(gnrc_netif_t *netif, const gnrc_netapi_opt_t *opt)
|
||||
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);
|
||||
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);
|
||||
res = netif->dev->driver->set(netif->dev, opt->opt, opt->data,
|
||||
opt->data_len);
|
||||
break;
|
||||
}
|
||||
gnrc_netif_release(netif);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user