wayne roberts / Mbed OS LoRaWAN_singlechannel_gateway

Dependencies:   SX127x sx12xx_hal

Committer:
dudmuck
Date:
Wed Jul 12 00:12:41 2017 +0000
Revision:
10:6783623cc886
Parent:
9:a0ce66c18ec0
Child:
12:9a8c13c4298b
comma printing

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:2ff18de8d48b 1 #define MBEDTLS_CMAC_C
dudmuck 0:2ff18de8d48b 2 #include <stdint.h>
dudmuck 0:2ff18de8d48b 3 #include "lorawan.h"
dudmuck 0:2ff18de8d48b 4 #include "Commissioning.h"
dudmuck 0:2ff18de8d48b 5
dudmuck 0:2ff18de8d48b 6 #include "gladman_aes.h"
dudmuck 0:2ff18de8d48b 7 #include "gladman_cmac.h"
dudmuck 0:2ff18de8d48b 8
dudmuck 0:2ff18de8d48b 9 #define RECEIVE_DELAY_ms 100
dudmuck 0:2ff18de8d48b 10
dudmuck 0:2ff18de8d48b 11 #define LORA_FRAMEMICBYTES 4
dudmuck 0:2ff18de8d48b 12 #define LORA_ENCRYPTIONBLOCKBYTES 16
dudmuck 0:2ff18de8d48b 13 #define LORA_AUTHENTICATIONBLOCKBYTES 16
dudmuck 0:2ff18de8d48b 14 #define LORA_MAXFRAMELENGTH 235
dudmuck 0:2ff18de8d48b 15 #define LORA_MACHEADERLENGTH 1
dudmuck 0:2ff18de8d48b 16 #define LORA_MINDATAHEADERLENGTH 7
dudmuck 0:2ff18de8d48b 17 #define LORA_PORTLENGTH 1
dudmuck 0:2ff18de8d48b 18 #define LORA_MAXDATABYTES (LORA_MAXFRAMELENGTH - (LORA_MACHEADERLENGTH + LORA_MINDATAHEADERLENGTH + LORA_PORTLENGTH + LORA_FRAMEMICBYTES)) //excluding port
dudmuck 0:2ff18de8d48b 19 #define LORA_NETWORKADDRESSBITS 25
dudmuck 0:2ff18de8d48b 20
dudmuck 0:2ff18de8d48b 21
dudmuck 0:2ff18de8d48b 22 #define DEFAULT_DOWNLINK_PORT 2
dudmuck 0:2ff18de8d48b 23
dudmuck 0:2ff18de8d48b 24 const uint32_t network_id = 0x24;
dudmuck 0:2ff18de8d48b 25 uint32_t networkAddress = 0; // bits 24..0 of DevAddr, for join accept
dudmuck 0:2ff18de8d48b 26 uint16_t next_available_tx_slot = 0;
dudmuck 0:2ff18de8d48b 27
dudmuck 0:2ff18de8d48b 28 uint8_t LoRaWan::user_downlink[128];
dudmuck 0:2ff18de8d48b 29 volatile uint16_t LoRaWan::rx_slot;
dudmuck 0:2ff18de8d48b 30 volatile uint32_t LoRaWan::rx_ms; // captured timer milliseconds at RxDone
dudmuck 0:2ff18de8d48b 31 bool LoRaWan::do_downlink;
dudmuck 0:2ff18de8d48b 32
dudmuck 0:2ff18de8d48b 33 /*
dudmuck 0:2ff18de8d48b 34 * TX_SLOT_STEPPING: time for each mote
dudmuck 0:2ff18de8d48b 35 * PERIODICITY_SLOTS: slot at which first mote can again transmit
dudmuck 0:2ff18de8d48b 36 */
dudmuck 0:2ff18de8d48b 37 #if (LORAMAC_DEFAULT_DATARATE == DR_8)
dudmuck 0:2ff18de8d48b 38 #define TX_SLOT_STEPPING 267 //approx 8 seconds
dudmuck 0:2ff18de8d48b 39 #define PERIODICITY_SLOTS (TX_SLOT_STEPPING * 15)
dudmuck 0:2ff18de8d48b 40 #elif (LORAMAC_DEFAULT_DATARATE == DR_9)
dudmuck 0:2ff18de8d48b 41 #define TX_SLOT_STEPPING 133 //approx 4 seconds
dudmuck 0:2ff18de8d48b 42 #define PERIODICITY_SLOTS (TX_SLOT_STEPPING * 24)
dudmuck 0:2ff18de8d48b 43 #elif (LORAMAC_DEFAULT_DATARATE == DR_10)
dudmuck 0:2ff18de8d48b 44 #define TX_SLOT_STEPPING 67 //approx 2 seconds
dudmuck 0:2ff18de8d48b 45 #define PERIODICITY_SLOTS (TX_SLOT_STEPPING * 24)
dudmuck 0:2ff18de8d48b 46 #elif (LORAMAC_DEFAULT_DATARATE == DR_11)
dudmuck 0:2ff18de8d48b 47 #define TX_SLOT_STEPPING 33 //approx 1.0 seconds
dudmuck 0:2ff18de8d48b 48 #define PERIODICITY_SLOTS (TX_SLOT_STEPPING * 24)
dudmuck 0:2ff18de8d48b 49 #elif (LORAMAC_DEFAULT_DATARATE == DR_12)
dudmuck 0:2ff18de8d48b 50 #define TX_SLOT_STEPPING 16 //approx 0.5 seconds
dudmuck 0:2ff18de8d48b 51 #define PERIODICITY_SLOTS (TX_SLOT_STEPPING * 24)
dudmuck 0:2ff18de8d48b 52 #elif (LORAMAC_DEFAULT_DATARATE == DR_13)
dudmuck 0:2ff18de8d48b 53 #define TX_SLOT_STEPPING 8 //approx 0.25 seconds
dudmuck 0:2ff18de8d48b 54 #define PERIODICITY_SLOTS (TX_SLOT_STEPPING * 24)
dudmuck 0:2ff18de8d48b 55 #endif
dudmuck 0:2ff18de8d48b 56
dudmuck 0:2ff18de8d48b 57 #if (PERIODICITY_SLOTS > 4095)
dudmuck 0:2ff18de8d48b 58 #error "PERIODICITY_SLOTS too large"
dudmuck 0:2ff18de8d48b 59 #endif
dudmuck 0:2ff18de8d48b 60
dudmuck 0:2ff18de8d48b 61
dudmuck 0:2ff18de8d48b 62 typedef enum {
dudmuck 0:2ff18de8d48b 63 MTYPE_JOIN_REQ = 0,
dudmuck 0:2ff18de8d48b 64 MTYPE_JOIN_ACC,//1
dudmuck 0:2ff18de8d48b 65 MTYPE_UNCONF_UP,//2
dudmuck 0:2ff18de8d48b 66 MTYPE_UNCONF_DN,//3
dudmuck 0:2ff18de8d48b 67 MTYPE_CONF_UP,//4
dudmuck 0:2ff18de8d48b 68 MTYPE_CONF_DN,//5
dudmuck 0:2ff18de8d48b 69 MTYPE_RFU,//6
dudmuck 0:2ff18de8d48b 70 MTYPE_P,//7
dudmuck 0:2ff18de8d48b 71 } mtype_e;
dudmuck 0:2ff18de8d48b 72
dudmuck 0:2ff18de8d48b 73 typedef union {
dudmuck 0:2ff18de8d48b 74 struct {
dudmuck 0:2ff18de8d48b 75 uint8_t major : 2; // 0 1
dudmuck 0:2ff18de8d48b 76 uint8_t rfu : 3; // 2 3 4
dudmuck 0:2ff18de8d48b 77 uint8_t MType : 3; // 5 6 7
dudmuck 0:2ff18de8d48b 78 } bits;
dudmuck 0:2ff18de8d48b 79 uint8_t octet;
dudmuck 0:2ff18de8d48b 80 } mhdr_t;
dudmuck 0:2ff18de8d48b 81
dudmuck 0:2ff18de8d48b 82 typedef union {
dudmuck 0:2ff18de8d48b 83 struct {
dudmuck 0:2ff18de8d48b 84 uint8_t FOptsLen : 4; // 0 1 2 3
dudmuck 0:2ff18de8d48b 85 uint8_t FPending : 1; // 4
dudmuck 0:2ff18de8d48b 86 uint8_t ACK : 1; // 5
dudmuck 0:2ff18de8d48b 87 uint8_t ADCACKReq : 1; // 6
dudmuck 0:2ff18de8d48b 88 uint8_t ADR : 1; // 7
dudmuck 0:2ff18de8d48b 89 } dlBits; // downlink (gwtx)
dudmuck 0:2ff18de8d48b 90 struct {
dudmuck 0:2ff18de8d48b 91 uint8_t FOptsLen : 4; // 0 1 2 3
dudmuck 0:2ff18de8d48b 92 uint8_t classB : 1; // 4 unused in classA
dudmuck 0:2ff18de8d48b 93 uint8_t ACK : 1; // 5
dudmuck 0:2ff18de8d48b 94 uint8_t ADCACKReq : 1; // 6
dudmuck 0:2ff18de8d48b 95 uint8_t ADR : 1; // 7
dudmuck 0:2ff18de8d48b 96 } ulBits; // uplink (gwrx)
dudmuck 0:2ff18de8d48b 97 uint8_t octet;
dudmuck 0:2ff18de8d48b 98 } FCtrl_t;
dudmuck 0:2ff18de8d48b 99
dudmuck 0:2ff18de8d48b 100 typedef struct {
dudmuck 0:2ff18de8d48b 101 uint32_t DevAddr;
dudmuck 0:2ff18de8d48b 102 FCtrl_t FCtrl;
dudmuck 0:2ff18de8d48b 103 uint16_t FCnt;
dudmuck 0:2ff18de8d48b 104 } __attribute__((packed)) fhdr_t;
dudmuck 0:2ff18de8d48b 105
dudmuck 0:2ff18de8d48b 106
dudmuck 0:2ff18de8d48b 107 typedef struct {
dudmuck 0:2ff18de8d48b 108 mhdr_t mhdr;
dudmuck 0:2ff18de8d48b 109 uint8_t AppEUI[LORA_EUI_LENGTH];
dudmuck 0:2ff18de8d48b 110 uint8_t DevEUI[LORA_EUI_LENGTH];
dudmuck 0:2ff18de8d48b 111 uint16_t DevNonce;
dudmuck 0:2ff18de8d48b 112 } __attribute__((packed)) join_req_t;
dudmuck 0:2ff18de8d48b 113
dudmuck 0:2ff18de8d48b 114 typedef enum eLoRaMacMoteCmd
dudmuck 0:2ff18de8d48b 115 {
dudmuck 0:2ff18de8d48b 116 /*!
dudmuck 0:2ff18de8d48b 117 * LinkCheckReq
dudmuck 0:2ff18de8d48b 118 */
dudmuck 0:2ff18de8d48b 119 MOTE_MAC_LINK_CHECK_REQ = 0x02,
dudmuck 0:2ff18de8d48b 120 /*!
dudmuck 0:2ff18de8d48b 121 * LinkADRAns
dudmuck 0:2ff18de8d48b 122 */
dudmuck 0:2ff18de8d48b 123 //MOTE_MAC_LINK_ADR_ANS = 0x03,
dudmuck 0:2ff18de8d48b 124 /*!
dudmuck 0:2ff18de8d48b 125 * DutyCycleAns
dudmuck 0:2ff18de8d48b 126 */
dudmuck 0:2ff18de8d48b 127 //MOTE_MAC_DUTY_CYCLE_ANS = 0x04,
dudmuck 0:2ff18de8d48b 128 /*!
dudmuck 0:2ff18de8d48b 129 * RXParamSetupAns
dudmuck 0:2ff18de8d48b 130 */
dudmuck 0:2ff18de8d48b 131 MOTE_MAC_RX_PARAM_SETUP_ANS = 0x05,
dudmuck 0:2ff18de8d48b 132 /*!
dudmuck 0:2ff18de8d48b 133 * DevStatusAns
dudmuck 0:2ff18de8d48b 134 */
dudmuck 0:2ff18de8d48b 135 MOTE_MAC_DEV_STATUS_ANS = 0x06,
dudmuck 0:2ff18de8d48b 136 /*!
dudmuck 0:2ff18de8d48b 137 * NewChannelAns
dudmuck 0:2ff18de8d48b 138 */
dudmuck 0:2ff18de8d48b 139 MOTE_MAC_NEW_CHANNEL_ANS = 0x07,
dudmuck 0:2ff18de8d48b 140 /*!
dudmuck 0:2ff18de8d48b 141 * RXTimingSetupAns
dudmuck 0:2ff18de8d48b 142 */
dudmuck 0:2ff18de8d48b 143 MOTE_MAC_RX_TIMING_SETUP_ANS = 0x08,
dudmuck 0:2ff18de8d48b 144 /*!
dudmuck 0:2ff18de8d48b 145 * PingSlotInfoReq
dudmuck 0:2ff18de8d48b 146 */
dudmuck 0:2ff18de8d48b 147 MOTE_MAC_PING_SLOT_INFO_REQ = 0x10,
dudmuck 0:2ff18de8d48b 148 /*!
dudmuck 0:2ff18de8d48b 149 * PingSlotFreqAns
dudmuck 0:2ff18de8d48b 150 */
dudmuck 0:2ff18de8d48b 151 MOTE_MAC_PING_SLOT_FREQ_ANS = 0x11,
dudmuck 0:2ff18de8d48b 152 /*!
dudmuck 0:2ff18de8d48b 153 * BeaconTimingReq
dudmuck 0:2ff18de8d48b 154 */
dudmuck 0:2ff18de8d48b 155 MOTE_MAC_BEACON_TIMING_REQ = 0x12,
dudmuck 0:2ff18de8d48b 156 /*!
dudmuck 0:2ff18de8d48b 157 * BeaconFreqAns
dudmuck 0:2ff18de8d48b 158 */
dudmuck 0:2ff18de8d48b 159 MOTE_MAC_BEACON_FREQ_ANS = 0x13,
dudmuck 0:2ff18de8d48b 160 }LoRaMacMoteCmd_t;
dudmuck 0:2ff18de8d48b 161
dudmuck 0:2ff18de8d48b 162 typedef enum eLoRaMacSrvCmd
dudmuck 0:2ff18de8d48b 163 {
dudmuck 0:2ff18de8d48b 164 /*!
dudmuck 0:2ff18de8d48b 165 * LinkCheckAns
dudmuck 0:2ff18de8d48b 166 */
dudmuck 0:2ff18de8d48b 167 SRV_MAC_LINK_CHECK_ANS = 0x02,
dudmuck 0:2ff18de8d48b 168 /*!
dudmuck 0:2ff18de8d48b 169 * LinkADRReq
dudmuck 0:2ff18de8d48b 170 */
dudmuck 0:2ff18de8d48b 171 //SRV_MAC_LINK_ADR_REQ = 0x03,
dudmuck 0:2ff18de8d48b 172 /*!
dudmuck 0:2ff18de8d48b 173 * DutyCycleReq
dudmuck 0:2ff18de8d48b 174 */
dudmuck 0:2ff18de8d48b 175 //SRV_MAC_DUTY_CYCLE_REQ = 0x04,
dudmuck 0:2ff18de8d48b 176 /*!
dudmuck 0:2ff18de8d48b 177 * RXParamSetupReq
dudmuck 0:2ff18de8d48b 178 */
dudmuck 0:2ff18de8d48b 179 SRV_MAC_RX_PARAM_SETUP_REQ = 0x05,
dudmuck 0:2ff18de8d48b 180 /*!
dudmuck 0:2ff18de8d48b 181 * DevStatusReq
dudmuck 0:2ff18de8d48b 182 */
dudmuck 0:2ff18de8d48b 183 SRV_MAC_DEV_STATUS_REQ = 0x06,
dudmuck 0:2ff18de8d48b 184 /*!
dudmuck 0:2ff18de8d48b 185 * NewChannelReq
dudmuck 0:2ff18de8d48b 186 */
dudmuck 0:2ff18de8d48b 187 SRV_MAC_NEW_CHANNEL_REQ = 0x07,
dudmuck 0:2ff18de8d48b 188 /*!
dudmuck 0:2ff18de8d48b 189 * RXTimingSetupReq
dudmuck 0:2ff18de8d48b 190 */
dudmuck 0:2ff18de8d48b 191 SRV_MAC_RX_TIMING_SETUP_REQ = 0x08,
dudmuck 0:2ff18de8d48b 192 /*!
dudmuck 0:2ff18de8d48b 193 * PingSlotInfoAns
dudmuck 0:2ff18de8d48b 194 */
dudmuck 0:2ff18de8d48b 195 SRV_MAC_PING_SLOT_INFO_ANS = 0x10,
dudmuck 0:2ff18de8d48b 196 /*!
dudmuck 0:2ff18de8d48b 197 * PingSlotChannelReq
dudmuck 0:2ff18de8d48b 198 */
dudmuck 0:2ff18de8d48b 199 SRV_MAC_PING_SLOT_CHANNEL_REQ = 0x11,
dudmuck 0:2ff18de8d48b 200 /*!
dudmuck 0:2ff18de8d48b 201 * BeaconTimingAns
dudmuck 0:2ff18de8d48b 202 */
dudmuck 0:2ff18de8d48b 203 SRV_MAC_BEACON_TIMING_ANS = 0x12,
dudmuck 0:2ff18de8d48b 204 /*!
dudmuck 0:2ff18de8d48b 205 * BeaconFreqReq
dudmuck 0:2ff18de8d48b 206 */
dudmuck 0:2ff18de8d48b 207 SRV_MAC_BEACON_FREQ_REQ = 0x13,
dudmuck 0:2ff18de8d48b 208 }LoRaMacSrvCmd_t;
dudmuck 0:2ff18de8d48b 209
dudmuck 0:2ff18de8d48b 210 /* us915-single-channel spreading factors: */
dudmuck 0:2ff18de8d48b 211 const uint8_t LoRaWan::Datarates[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
dudmuck 0:2ff18de8d48b 212
dudmuck 0:2ff18de8d48b 213 mtype_e user_dowlink_mtype = MTYPE_UNCONF_DN;
dudmuck 0:2ff18de8d48b 214
dudmuck 0:2ff18de8d48b 215 void print_octets(char const* label, uint8_t const* buf, uint8_t buf_len)
dudmuck 0:2ff18de8d48b 216 {
dudmuck 0:2ff18de8d48b 217 int i;
dudmuck 0:2ff18de8d48b 218 printf("%s:", label);
dudmuck 0:2ff18de8d48b 219 for (i = 0; i < buf_len; i++)
dudmuck 0:2ff18de8d48b 220 printf(" %02x", buf[i]);
dudmuck 0:2ff18de8d48b 221 // printf("\n");
dudmuck 0:2ff18de8d48b 222 }
dudmuck 0:2ff18de8d48b 223
dudmuck 9:a0ce66c18ec0 224 void LoRaWan::print_octets_rev(char const* label, uint8_t const* buf, uint8_t buf_len)
dudmuck 0:2ff18de8d48b 225 {
dudmuck 0:2ff18de8d48b 226 int i;
dudmuck 0:2ff18de8d48b 227 printf("%s:", label);
dudmuck 0:2ff18de8d48b 228 for (i = buf_len-1; i >= 0; i--)
dudmuck 0:2ff18de8d48b 229 printf(" %02x", buf[i]);
dudmuck 0:2ff18de8d48b 230 // printf("\n");
dudmuck 0:2ff18de8d48b 231 }
dudmuck 0:2ff18de8d48b 232
dudmuck 0:2ff18de8d48b 233 uint8_t* Write4ByteValue(uint8_t output[], uint32_t input)
dudmuck 0:2ff18de8d48b 234 {
dudmuck 0:2ff18de8d48b 235 uint8_t* ptr = output;
dudmuck 0:2ff18de8d48b 236
dudmuck 0:2ff18de8d48b 237 *(ptr++) = (uint8_t)input,
dudmuck 0:2ff18de8d48b 238 input >>= 8;
dudmuck 0:2ff18de8d48b 239 *(ptr++) = (uint8_t)input,
dudmuck 0:2ff18de8d48b 240 input >>= 8;
dudmuck 0:2ff18de8d48b 241 *(ptr++) = (uint8_t)input,
dudmuck 0:2ff18de8d48b 242 input >>= 8;
dudmuck 0:2ff18de8d48b 243 *(ptr++) = (uint8_t)input;
dudmuck 0:2ff18de8d48b 244
dudmuck 0:2ff18de8d48b 245 return ptr;
dudmuck 0:2ff18de8d48b 246 }
dudmuck 0:2ff18de8d48b 247
dudmuck 0:2ff18de8d48b 248
dudmuck 0:2ff18de8d48b 249 uint8_t* Write3ByteValue(uint8_t output[], uint32_t input)
dudmuck 0:2ff18de8d48b 250 {
dudmuck 0:2ff18de8d48b 251 uint8_t* ptr = output;
dudmuck 0:2ff18de8d48b 252
dudmuck 0:2ff18de8d48b 253 *(ptr++) = (uint8_t)input,
dudmuck 0:2ff18de8d48b 254 input >>= 8;
dudmuck 0:2ff18de8d48b 255 *(ptr++) = (uint8_t)input,
dudmuck 0:2ff18de8d48b 256 input >>= 8;
dudmuck 0:2ff18de8d48b 257 *(ptr++) = (uint8_t)input;
dudmuck 0:2ff18de8d48b 258
dudmuck 0:2ff18de8d48b 259 return ptr;
dudmuck 0:2ff18de8d48b 260 }
dudmuck 0:2ff18de8d48b 261
dudmuck 0:2ff18de8d48b 262 uint8_t* Write2ByteValue(uint8_t output[], uint32_t input)
dudmuck 0:2ff18de8d48b 263 {
dudmuck 0:2ff18de8d48b 264 uint8_t* ptr = output;
dudmuck 0:2ff18de8d48b 265
dudmuck 0:2ff18de8d48b 266 *(ptr++) = (uint8_t)input,
dudmuck 0:2ff18de8d48b 267 input >>= 8;
dudmuck 0:2ff18de8d48b 268 *(ptr++) = (uint8_t)input;
dudmuck 0:2ff18de8d48b 269
dudmuck 0:2ff18de8d48b 270 return ptr;
dudmuck 0:2ff18de8d48b 271 }
dudmuck 0:2ff18de8d48b 272
dudmuck 0:2ff18de8d48b 273 uint8_t* Write1ByteValue(uint8_t output[], uint32_t input)
dudmuck 0:2ff18de8d48b 274 {
dudmuck 0:2ff18de8d48b 275 uint8_t* ptr = output;
dudmuck 0:2ff18de8d48b 276
dudmuck 0:2ff18de8d48b 277 *(ptr++) = (uint8_t)input;
dudmuck 0:2ff18de8d48b 278
dudmuck 0:2ff18de8d48b 279 return ptr;
dudmuck 0:2ff18de8d48b 280 }
dudmuck 0:2ff18de8d48b 281
dudmuck 0:2ff18de8d48b 282 void LoRa_GenerateJoinFrameIntegrityCode(const uint8_t key[], uint8_t const input[], uint16_t dataLength, uint8_t* output)
dudmuck 0:2ff18de8d48b 283 {
dudmuck 0:2ff18de8d48b 284 AES_CMAC_CTX cmacctx;
dudmuck 0:2ff18de8d48b 285 AES_CMAC_Init(&cmacctx);
dudmuck 0:2ff18de8d48b 286 AES_CMAC_SetKey(&cmacctx, key);
dudmuck 0:2ff18de8d48b 287
dudmuck 0:2ff18de8d48b 288 AES_CMAC_Update(&cmacctx, input, dataLength);
dudmuck 0:2ff18de8d48b 289 uint8_t temp[LORA_AUTHENTICATIONBLOCKBYTES];
dudmuck 0:2ff18de8d48b 290 AES_CMAC_Final(temp, &cmacctx);
dudmuck 0:2ff18de8d48b 291 memcpy(output, temp, LORA_FRAMEMICBYTES);
dudmuck 0:2ff18de8d48b 292 #if 0
dudmuck 0:2ff18de8d48b 293 TODO https://tls.mbed.org/kb/compiling-and-building/how-do-i-configure-mbedtls
dudmuck 0:2ff18de8d48b 294 int ret;
dudmuck 0:2ff18de8d48b 295 mbedtls_cipher_context_t m_ctx;
dudmuck 0:2ff18de8d48b 296 const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_AES_128_CBC );
dudmuck 0:2ff18de8d48b 297 mbedtls_cipher_init(&m_ctx);
dudmuck 0:2ff18de8d48b 298 ret = mbedtls_cipher_setup( &m_ctx, cipher_info );
dudmuck 0:2ff18de8d48b 299 printf("%d = mbedtls_cipher_setup()\r\n", ret);
dudmuck 0:2ff18de8d48b 300 ret = mbedtls_cipher_cmac_starts(&m_ctx, key, LORA_CYPHERKEYBYTES * 8);
dudmuck 0:2ff18de8d48b 301 printf("%d = mbedtls_cipher_cmac_starts()\r\n", ret);
dudmuck 0:2ff18de8d48b 302
dudmuck 0:2ff18de8d48b 303 ret= mbedtls_cipher_cmac_update(&m_ctx, input, dataLength);
dudmuck 0:2ff18de8d48b 304 printf("%d = mbedtls_cipher_cmac_update returned\r\n",ret);
dudmuck 0:2ff18de8d48b 305
dudmuck 0:2ff18de8d48b 306 ret=mbedtls_cipher_cmac_finish(&m_ctx, output);
dudmuck 0:2ff18de8d48b 307 printf("%d = mbedtls_cipher_cmac_starts returned\r\n",ret);
dudmuck 0:2ff18de8d48b 308 #endif
dudmuck 0:2ff18de8d48b 309 }
dudmuck 0:2ff18de8d48b 310
dudmuck 0:2ff18de8d48b 311 void GenerateSessionKey(bool generateNetworkKey, const uint8_t* applicationKey, uint32_t networkId, uint32_t applicationNonce, uint16_t deviceNonce, uint8_t* output)
dudmuck 0:2ff18de8d48b 312 {
dudmuck 0:2ff18de8d48b 313 uint8_t input[LORA_ENCRYPTIONBLOCKBYTES];
dudmuck 0:2ff18de8d48b 314
dudmuck 0:2ff18de8d48b 315 input[0] = generateNetworkKey ? 0x01 : 0x02;
dudmuck 0:2ff18de8d48b 316 uint8_t* ptr = &input[1];
dudmuck 0:2ff18de8d48b 317
dudmuck 0:2ff18de8d48b 318 ptr = Write3ByteValue(ptr, applicationNonce);
dudmuck 0:2ff18de8d48b 319 ptr = Write3ByteValue(ptr, networkId);
dudmuck 0:2ff18de8d48b 320 ptr = Write2ByteValue(ptr, deviceNonce);
dudmuck 0:2ff18de8d48b 321 memset(ptr, 0, LORA_ENCRYPTIONBLOCKBYTES - (ptr - input));
dudmuck 0:2ff18de8d48b 322
dudmuck 0:2ff18de8d48b 323 aes_context aesContext;
dudmuck 0:2ff18de8d48b 324 aes_set_key(applicationKey, LORA_CYPHERKEYBYTES, &aesContext);
dudmuck 0:2ff18de8d48b 325
dudmuck 0:2ff18de8d48b 326 aes_encrypt(input, output, &aesContext);
dudmuck 0:2ff18de8d48b 327 }
dudmuck 0:2ff18de8d48b 328
dudmuck 0:2ff18de8d48b 329 void CryptJoinServer(uint8_t const* key, uint8_t const* input, uint16_t length, uint8_t* output)
dudmuck 0:2ff18de8d48b 330 {
dudmuck 0:2ff18de8d48b 331 aes_context aesContext;
dudmuck 0:2ff18de8d48b 332 memset(aesContext.ksch, '\0', 240);
dudmuck 0:2ff18de8d48b 333 aes_set_key(key, LORA_CYPHERKEYBYTES, &aesContext);
dudmuck 0:2ff18de8d48b 334
dudmuck 0:2ff18de8d48b 335 aes_decrypt(input, output, &aesContext);
dudmuck 0:2ff18de8d48b 336 if (length >= 16) {
dudmuck 0:2ff18de8d48b 337 aes_decrypt(input + 16, output + 16, &aesContext);
dudmuck 0:2ff18de8d48b 338 }
dudmuck 0:2ff18de8d48b 339
dudmuck 0:2ff18de8d48b 340 }
dudmuck 0:2ff18de8d48b 341
dudmuck 0:2ff18de8d48b 342 void LoRaWan::SendJoinComplete(uint16_t deviceNonce, uint8_t firstReceiveWindowDataRateoffset, ota_mote_t* mote)
dudmuck 0:2ff18de8d48b 343 {
dudmuck 0:2ff18de8d48b 344 uint8_t secondReceiveWindowDataRateNibble = 0; // unused
dudmuck 0:2ff18de8d48b 345 uint8_t networkSessionKey[LORA_CYPHERKEYBYTES];
dudmuck 0:2ff18de8d48b 346 uint8_t uncyphered[LORA_MAXDATABYTES];
dudmuck 0:2ff18de8d48b 347 uint8_t* current = uncyphered;
dudmuck 0:2ff18de8d48b 348 uint32_t applicationNonce = rand() & 0xffffff; // 24bit
dudmuck 0:2ff18de8d48b 349
dudmuck 0:2ff18de8d48b 350 if (do_downlink) {
dudmuck 0:2ff18de8d48b 351 printf("SendJoinComplete(): tx busy\r\n");
dudmuck 0:2ff18de8d48b 352 return;
dudmuck 0:2ff18de8d48b 353 }
dudmuck 0:2ff18de8d48b 354
dudmuck 0:2ff18de8d48b 355 GenerateSessionKey(true, mote->app_key, network_id, applicationNonce, deviceNonce, networkSessionKey);
dudmuck 0:2ff18de8d48b 356
dudmuck 0:2ff18de8d48b 357 memcpy(mote->network_session_key, networkSessionKey, LORA_CYPHERKEYBYTES);
dudmuck 0:2ff18de8d48b 358
dudmuck 0:2ff18de8d48b 359 printf("SendJoinComplete() ");
dudmuck 0:2ff18de8d48b 360 if (mote->dev_addr == DEVADDR_NONE) {
dudmuck 0:2ff18de8d48b 361 // new mote joining
dudmuck 0:2ff18de8d48b 362 printf("new-mote ");
dudmuck 0:2ff18de8d48b 363 if ( mote->tx_slot_offset >= PERIODICITY_SLOTS) {
dudmuck 0:2ff18de8d48b 364 printf("max motes reached\r\n");
dudmuck 0:2ff18de8d48b 365 return;
dudmuck 0:2ff18de8d48b 366 }
dudmuck 0:2ff18de8d48b 367 mote->dev_addr = ++networkAddress | (network_id << LORA_NETWORKADDRESSBITS);
dudmuck 0:2ff18de8d48b 368 mote->tx_slot_offset = next_available_tx_slot;
dudmuck 0:2ff18de8d48b 369 next_available_tx_slot += TX_SLOT_STEPPING;
dudmuck 0:2ff18de8d48b 370 } else
dudmuck 0:2ff18de8d48b 371 printf("rejoin ");
dudmuck 0:2ff18de8d48b 372
dudmuck 0:2ff18de8d48b 373 printf(" mote->dev_addr:%lx ", mote->dev_addr);
dudmuck 0:2ff18de8d48b 374 printf("networkAddress:%lu\r\n", networkAddress);
dudmuck 0:2ff18de8d48b 375 *(current++) = MTYPE_JOIN_ACC << 5; // MHDR 0
dudmuck 0:2ff18de8d48b 376 current = Write3ByteValue(current, applicationNonce);// 1 2 3
dudmuck 0:2ff18de8d48b 377 current = Write3ByteValue(current, network_id);// 4 5 6
dudmuck 0:2ff18de8d48b 378 current = Write4ByteValue(current, mote->dev_addr); // 7 8 9 10
dudmuck 0:2ff18de8d48b 379 current = Write1ByteValue(current, (firstReceiveWindowDataRateoffset << 4) | (secondReceiveWindowDataRateNibble & 0xf)); // 11
dudmuck 0:2ff18de8d48b 380 //current = Write1ByteValue(current, classARxWindowDelay_s - 1); // 12
dudmuck 0:2ff18de8d48b 381 current = Write1ByteValue(current, 0); // 12
dudmuck 0:2ff18de8d48b 382
dudmuck 0:2ff18de8d48b 383 /* put beacon timing answer */
dudmuck 0:2ff18de8d48b 384 printf("slots:%u\r\n", rx_slot);
dudmuck 0:2ff18de8d48b 385 current = Write2ByteValue(current, rx_slot); // 13 14
dudmuck 0:2ff18de8d48b 386 current = Write2ByteValue(current, mote->tx_slot_offset); // 15 16
dudmuck 0:2ff18de8d48b 387 current = Write2ByteValue(current, PERIODICITY_SLOTS); //
dudmuck 0:2ff18de8d48b 388 current = Write2ByteValue(current, 0); //
dudmuck 0:2ff18de8d48b 389 current = Write4ByteValue(current, 0); //
dudmuck 0:2ff18de8d48b 390 current = Write4ByteValue(current, 0); //
dudmuck 0:2ff18de8d48b 391
dudmuck 0:2ff18de8d48b 392 uint16_t authenticatedBytes = current - uncyphered;
dudmuck 0:2ff18de8d48b 393 LoRa_GenerateJoinFrameIntegrityCode(mote->app_key, uncyphered, authenticatedBytes, current);
dudmuck 0:2ff18de8d48b 394 current += LORA_FRAMEMICBYTES;
dudmuck 0:2ff18de8d48b 395
dudmuck 0:2ff18de8d48b 396 radio.tx_buf[0] = MTYPE_JOIN_ACC << 5; // MHDR
dudmuck 0:2ff18de8d48b 397 //encrypt
dudmuck 0:2ff18de8d48b 398 uint16_t cypherBytes = (current - uncyphered) - LORA_MACHEADERLENGTH;
dudmuck 0:2ff18de8d48b 399 CryptJoinServer(mote->app_key, &uncyphered[LORA_MACHEADERLENGTH], cypherBytes, &radio.tx_buf[LORA_MACHEADERLENGTH]);
dudmuck 0:2ff18de8d48b 400
dudmuck 0:2ff18de8d48b 401 /**** RF TX ********/
dudmuck 0:2ff18de8d48b 402 lora.RegPayloadLength = current - uncyphered;
dudmuck 0:2ff18de8d48b 403 uint32_t now_ms = timer.read_ms();
dudmuck 0:2ff18de8d48b 404 queue.call_in(rx_ms + 100 - now_ms, send_downlink);
dudmuck 0:2ff18de8d48b 405 do_downlink = true;
dudmuck 0:2ff18de8d48b 406 mote->FCntDown = 0;
dudmuck 0:2ff18de8d48b 407
dudmuck 0:2ff18de8d48b 408 GenerateSessionKey(false, mote->app_key, network_id, applicationNonce, deviceNonce, mote->app_session_key);
dudmuck 0:2ff18de8d48b 409 }
dudmuck 0:2ff18de8d48b 410
dudmuck 0:2ff18de8d48b 411 void LoRa_GenerateDataFrameIntegrityCode(const uint8_t key[], uint8_t const input[], uint16_t dataLength, uint32_t address, bool up, uint32_t sequenceNumber, uint8_t* output)
dudmuck 0:2ff18de8d48b 412 {
dudmuck 0:2ff18de8d48b 413 /*
dudmuck 0:2ff18de8d48b 414 Generate artificial B[0] block
dudmuck 0:2ff18de8d48b 415 Encrypt B[0] to give X[1]
dudmuck 0:2ff18de8d48b 416
dudmuck 0:2ff18de8d48b 417 for n = 1 to number of blocks
dudmuck 0:2ff18de8d48b 418 exclusive OR B[n] with X[n] to give Y[n]
dudmuck 0:2ff18de8d48b 419 encrypt Yi using key to give X[n+1]
dudmuck 0:2ff18de8d48b 420 */
dudmuck 0:2ff18de8d48b 421 uint8_t b0[LORA_AUTHENTICATIONBLOCKBYTES];
dudmuck 0:2ff18de8d48b 422 memset(b0, 0 , LORA_AUTHENTICATIONBLOCKBYTES);
dudmuck 0:2ff18de8d48b 423
dudmuck 0:2ff18de8d48b 424 b0[ 0] = 0x49; //authentication flags
dudmuck 0:2ff18de8d48b 425
dudmuck 0:2ff18de8d48b 426 b0[ 5] = up ? 0 : 1;
dudmuck 0:2ff18de8d48b 427 Write4ByteValue(&b0[6], address);
dudmuck 0:2ff18de8d48b 428 Write4ByteValue(&b0[10], sequenceNumber);
dudmuck 0:2ff18de8d48b 429
dudmuck 0:2ff18de8d48b 430 b0[15] = (uint8_t)dataLength;
dudmuck 0:2ff18de8d48b 431
dudmuck 0:2ff18de8d48b 432 AES_CMAC_CTX cmacctx;
dudmuck 0:2ff18de8d48b 433 AES_CMAC_Init(&cmacctx);
dudmuck 0:2ff18de8d48b 434 AES_CMAC_SetKey(&cmacctx, key);
dudmuck 0:2ff18de8d48b 435
dudmuck 0:2ff18de8d48b 436 AES_CMAC_Update(&cmacctx, b0, LORA_AUTHENTICATIONBLOCKBYTES);
dudmuck 0:2ff18de8d48b 437 AES_CMAC_Update(&cmacctx, input, dataLength);
dudmuck 0:2ff18de8d48b 438
dudmuck 0:2ff18de8d48b 439 uint8_t temp[LORA_AUTHENTICATIONBLOCKBYTES];
dudmuck 0:2ff18de8d48b 440 AES_CMAC_Final(temp, &cmacctx);
dudmuck 0:2ff18de8d48b 441
dudmuck 0:2ff18de8d48b 442 memcpy(output, temp, LORA_FRAMEMICBYTES);
dudmuck 0:2ff18de8d48b 443 }
dudmuck 0:2ff18de8d48b 444
dudmuck 0:2ff18de8d48b 445 static uint16_t FindBlockOverhang(uint16_t inputDataLength)
dudmuck 0:2ff18de8d48b 446 {
dudmuck 0:2ff18de8d48b 447 return inputDataLength & (LORA_ENCRYPTIONBLOCKBYTES - 1);
dudmuck 0:2ff18de8d48b 448 }
dudmuck 0:2ff18de8d48b 449
dudmuck 0:2ff18de8d48b 450 uint16_t CountBlocks(uint16_t inputDataLength)
dudmuck 0:2ff18de8d48b 451 {
dudmuck 0:2ff18de8d48b 452 uint16_t blockSizeMinus1 = LORA_ENCRYPTIONBLOCKBYTES - 1;
dudmuck 0:2ff18de8d48b 453 uint16_t inRoundDown = inputDataLength & ~blockSizeMinus1;
dudmuck 0:2ff18de8d48b 454 uint16_t roundUp = (FindBlockOverhang(inputDataLength) > 0) ? 1 : 0;
dudmuck 0:2ff18de8d48b 455 uint16_t result = inRoundDown / LORA_ENCRYPTIONBLOCKBYTES + roundUp;
dudmuck 0:2ff18de8d48b 456
dudmuck 0:2ff18de8d48b 457 return result;
dudmuck 0:2ff18de8d48b 458 }
dudmuck 0:2ff18de8d48b 459
dudmuck 0:2ff18de8d48b 460 void BlockExOr(uint8_t const l[], uint8_t const r[], uint8_t out[], uint16_t bytes)
dudmuck 0:2ff18de8d48b 461 {
dudmuck 0:2ff18de8d48b 462 uint8_t const* lptr = l;
dudmuck 0:2ff18de8d48b 463 uint8_t const* rptr = r;
dudmuck 0:2ff18de8d48b 464 uint8_t* optr = out;
dudmuck 0:2ff18de8d48b 465 uint8_t const* const end = out + bytes;
dudmuck 0:2ff18de8d48b 466
dudmuck 0:2ff18de8d48b 467 for (;optr < end; lptr++, rptr++, optr++)
dudmuck 0:2ff18de8d48b 468 *optr = *lptr ^ *rptr;
dudmuck 0:2ff18de8d48b 469 }
dudmuck 0:2ff18de8d48b 470
dudmuck 0:2ff18de8d48b 471 void LoRa_EncryptPayload(const uint8_t key[], const uint8_t* in, uint16_t inputDataLength, uint32_t address, bool up, uint32_t sequenceNumber, uint8_t out[])
dudmuck 0:2ff18de8d48b 472 {
dudmuck 0:2ff18de8d48b 473 if (inputDataLength == 0)
dudmuck 0:2ff18de8d48b 474 return;
dudmuck 0:2ff18de8d48b 475
dudmuck 0:2ff18de8d48b 476 uint8_t A[LORA_ENCRYPTIONBLOCKBYTES];
dudmuck 0:2ff18de8d48b 477
dudmuck 0:2ff18de8d48b 478 memset(A, 0, LORA_ENCRYPTIONBLOCKBYTES);
dudmuck 0:2ff18de8d48b 479
dudmuck 0:2ff18de8d48b 480 A[ 0] = 0x01; //encryption flags
dudmuck 0:2ff18de8d48b 481 A[ 5] = up ? 0 : 1;
dudmuck 0:2ff18de8d48b 482
dudmuck 0:2ff18de8d48b 483 Write4ByteValue(&A[6], address);
dudmuck 0:2ff18de8d48b 484 Write4ByteValue(&A[10], sequenceNumber);
dudmuck 0:2ff18de8d48b 485
dudmuck 0:2ff18de8d48b 486 uint16_t const blocks = CountBlocks(inputDataLength);
dudmuck 0:2ff18de8d48b 487 uint16_t const overHangBytes = FindBlockOverhang(inputDataLength);
dudmuck 0:2ff18de8d48b 488
dudmuck 0:2ff18de8d48b 489 uint8_t const* blockInput = in;
dudmuck 0:2ff18de8d48b 490 uint8_t* blockOutput = out;
dudmuck 0:2ff18de8d48b 491 for (uint16_t i = 1; i <= blocks; i++, blockInput += LORA_ENCRYPTIONBLOCKBYTES, blockOutput += LORA_ENCRYPTIONBLOCKBYTES)
dudmuck 0:2ff18de8d48b 492 {
dudmuck 0:2ff18de8d48b 493 A[15] = (uint8_t)i;
dudmuck 0:2ff18de8d48b 494
dudmuck 0:2ff18de8d48b 495 aes_context aesContext;
dudmuck 0:2ff18de8d48b 496 aes_set_key(key, LORA_CYPHERKEYBYTES, &aesContext);
dudmuck 0:2ff18de8d48b 497
dudmuck 0:2ff18de8d48b 498 uint8_t S[LORA_CYPHERKEYBYTES];
dudmuck 0:2ff18de8d48b 499 aes_encrypt(A, S, &aesContext);
dudmuck 0:2ff18de8d48b 500
dudmuck 0:2ff18de8d48b 501 uint16_t bytesToExOr;
dudmuck 0:2ff18de8d48b 502 if ((i < blocks) || (overHangBytes == 0))
dudmuck 0:2ff18de8d48b 503 bytesToExOr = LORA_CYPHERKEYBYTES;
dudmuck 0:2ff18de8d48b 504 else
dudmuck 0:2ff18de8d48b 505 bytesToExOr = overHangBytes;
dudmuck 0:2ff18de8d48b 506
dudmuck 0:2ff18de8d48b 507 BlockExOr(S, blockInput, blockOutput, bytesToExOr);
dudmuck 0:2ff18de8d48b 508 }
dudmuck 0:2ff18de8d48b 509 }
dudmuck 0:2ff18de8d48b 510
dudmuck 0:2ff18de8d48b 511 void put_queue_mac_cmds(ota_mote_t* mote, uint8_t cmd_len, uint8_t* cmd_buf)
dudmuck 0:2ff18de8d48b 512 {
dudmuck 0:2ff18de8d48b 513 int i;
dudmuck 0:2ff18de8d48b 514 uint8_t* this_cmd_buf = mote->macCmd_queue[mote->macCmd_queue_in_idx];
dudmuck 0:2ff18de8d48b 515 this_cmd_buf[0] = cmd_len;
dudmuck 0:2ff18de8d48b 516
dudmuck 0:2ff18de8d48b 517 printf("put_queue_mac_cmds %u: ", cmd_len);
dudmuck 0:2ff18de8d48b 518 for (i = 0; i < cmd_len; i++) {
dudmuck 0:2ff18de8d48b 519 this_cmd_buf[i+1] = cmd_buf[i];
dudmuck 0:2ff18de8d48b 520 printf("%02x ", cmd_buf[i]);
dudmuck 0:2ff18de8d48b 521 }
dudmuck 0:2ff18de8d48b 522 printf("\r\n");
dudmuck 0:2ff18de8d48b 523
dudmuck 0:2ff18de8d48b 524 if (++mote->macCmd_queue_in_idx == MAC_CMD_QUEUE_SIZE)
dudmuck 0:2ff18de8d48b 525 mote->macCmd_queue_in_idx = 0;
dudmuck 0:2ff18de8d48b 526
dudmuck 0:2ff18de8d48b 527 if (mote->macCmd_queue_in_idx == mote->macCmd_queue_out_idx) {
dudmuck 0:2ff18de8d48b 528 printf("macCmd_queue full\r\n");
dudmuck 0:2ff18de8d48b 529 }
dudmuck 0:2ff18de8d48b 530 }
dudmuck 0:2ff18de8d48b 531
dudmuck 0:2ff18de8d48b 532 void
dudmuck 0:2ff18de8d48b 533 LoRaWan::parse_mac_command(ota_mote_t* mote, uint8_t* rx_cmd_buf, uint8_t rx_cmd_buf_len)
dudmuck 0:2ff18de8d48b 534 {
dudmuck 0:2ff18de8d48b 535 uint8_t cmd_buf[MAC_CMD_SIZE];
dudmuck 0:2ff18de8d48b 536 uint8_t rx_cmd_buf_idx = 0;
dudmuck 0:2ff18de8d48b 537 int i;
dudmuck 0:2ff18de8d48b 538 printf("rx_mac_command(s):");
dudmuck 0:2ff18de8d48b 539 for (i = 0; i < rx_cmd_buf_len; i++)
dudmuck 0:2ff18de8d48b 540 printf("%02x ", rx_cmd_buf[i]);
dudmuck 0:2ff18de8d48b 541 printf("\n");
dudmuck 0:2ff18de8d48b 542
dudmuck 0:2ff18de8d48b 543 while (rx_cmd_buf_idx < rx_cmd_buf_len) {
dudmuck 0:2ff18de8d48b 544
dudmuck 0:2ff18de8d48b 545 switch (rx_cmd_buf[rx_cmd_buf_idx++]) {
dudmuck 0:2ff18de8d48b 546 //float diff;
dudmuck 0:2ff18de8d48b 547 uint16_t i_diff;
dudmuck 0:2ff18de8d48b 548 case MOTE_MAC_LINK_CHECK_REQ: // 0x02
dudmuck 0:2ff18de8d48b 549 printf("MOTE_MAC_LINK_CHECK_REQ\n");
dudmuck 0:2ff18de8d48b 550 /* no payload in request */
dudmuck 0:2ff18de8d48b 551 cmd_buf[0] = SRV_MAC_LINK_CHECK_ANS;
dudmuck 0:2ff18de8d48b 552 cmd_buf[1] = 20; // db margin above noise floor
dudmuck 0:2ff18de8d48b 553 cmd_buf[2] = 1; // gateway count
dudmuck 0:2ff18de8d48b 554 put_queue_mac_cmds(mote, 3, cmd_buf);
dudmuck 0:2ff18de8d48b 555 break;
dudmuck 0:2ff18de8d48b 556 #if 0
dudmuck 0:2ff18de8d48b 557 #endif
dudmuck 0:2ff18de8d48b 558 case MOTE_MAC_BEACON_TIMING_REQ: // 0x12
dudmuck 0:2ff18de8d48b 559 /* no payload in request */
dudmuck 0:2ff18de8d48b 560 /*diff = (float)(tick_at_next_beacon - tick_at_RxDone) / 30.0;
dudmuck 0:2ff18de8d48b 561 i_diff = (int)floor(diff);*/
dudmuck 0:2ff18de8d48b 562 i_diff = rx_slot;
dudmuck 0:2ff18de8d48b 563 //printf("MOTE_MAC_BEACON_TIMING_REQ slots:%.1f=%.1fms (int:%u,%u)", diff, diff*30.0, i_diff, i_diff*30);
dudmuck 0:2ff18de8d48b 564 printf("MOTE_MAC_BEACON_TIMING_REQ slots:%u", i_diff);
dudmuck 0:2ff18de8d48b 565 cmd_buf[0] = SRV_MAC_BEACON_TIMING_ANS; // 0x12
dudmuck 0:2ff18de8d48b 566 cmd_buf[1] = i_diff & 0xff; //lsbyte first byte
dudmuck 0:2ff18de8d48b 567 cmd_buf[2] = (i_diff >> 8) & 0xff;
dudmuck 0:2ff18de8d48b 568 cmd_buf[3] = 0; // beacon channel index
dudmuck 0:2ff18de8d48b 569 put_queue_mac_cmds(mote, 4, cmd_buf);
dudmuck 0:2ff18de8d48b 570 printf("%02x %02x %02x\n", cmd_buf[1], cmd_buf[2], cmd_buf[3]);
dudmuck 0:2ff18de8d48b 571 break;
dudmuck 0:2ff18de8d48b 572 case MOTE_MAC_PING_SLOT_FREQ_ANS:
dudmuck 0:2ff18de8d48b 573 i = rx_cmd_buf[rx_cmd_buf_idx++];
dudmuck 0:2ff18de8d48b 574 printf("PING_SLOT_FREQ_ANS status:0x%02x\n", i);
dudmuck 0:2ff18de8d48b 575 break;
dudmuck 0:2ff18de8d48b 576 case MOTE_MAC_BEACON_FREQ_ANS:
dudmuck 0:2ff18de8d48b 577 i = rx_cmd_buf[rx_cmd_buf_idx++];
dudmuck 0:2ff18de8d48b 578 printf("BEACON_FREQ_ANS status:0x%02x\n", i);
dudmuck 0:2ff18de8d48b 579 break;
dudmuck 0:2ff18de8d48b 580 case MOTE_MAC_RX_PARAM_SETUP_ANS:
dudmuck 0:2ff18de8d48b 581 i = rx_cmd_buf[rx_cmd_buf_idx++];
dudmuck 0:2ff18de8d48b 582 printf("RX_PARAM_SETUP_ANS status:0x%02x\n", i);
dudmuck 0:2ff18de8d48b 583 break;
dudmuck 0:2ff18de8d48b 584 case MOTE_MAC_NEW_CHANNEL_ANS:
dudmuck 0:2ff18de8d48b 585 i = rx_cmd_buf[rx_cmd_buf_idx++];
dudmuck 0:2ff18de8d48b 586 printf("NEW_CHANNEL_ANS status:0x%02x\n", i);
dudmuck 0:2ff18de8d48b 587 break;
dudmuck 0:2ff18de8d48b 588 default:
dudmuck 0:2ff18de8d48b 589 printf("TODO mac cmd %02x\n", rx_cmd_buf[rx_cmd_buf_idx-1]);
dudmuck 0:2ff18de8d48b 590 return;
dudmuck 0:2ff18de8d48b 591 } // ..switch (<mac_command>)
dudmuck 0:2ff18de8d48b 592 } // .. while have mac comannds
dudmuck 0:2ff18de8d48b 593
dudmuck 0:2ff18de8d48b 594 }
dudmuck 0:2ff18de8d48b 595
dudmuck 0:2ff18de8d48b 596 void LoRaWan::classA_downlink(ota_mote_t* mote)
dudmuck 0:2ff18de8d48b 597 {
dudmuck 0:2ff18de8d48b 598 fhdr_t* fhdr = (fhdr_t*)&radio.tx_buf[1];
dudmuck 0:2ff18de8d48b 599 uint8_t* mic_ptr;
dudmuck 0:2ff18de8d48b 600
dudmuck 0:2ff18de8d48b 601 fhdr->DevAddr = mote->dev_addr;
dudmuck 0:2ff18de8d48b 602 fhdr->FCnt = mote->FCntDown++;
dudmuck 0:2ff18de8d48b 603 lora.RegPayloadLength += LORA_MACHEADERLENGTH + sizeof(fhdr_t) + fhdr->FCtrl.dlBits.FOptsLen;
dudmuck 0:2ff18de8d48b 604 mic_ptr = &radio.tx_buf[lora.RegPayloadLength];
dudmuck 0:2ff18de8d48b 605
dudmuck 0:2ff18de8d48b 606 LoRa_GenerateDataFrameIntegrityCode(mote->network_session_key, radio.tx_buf, lora.RegPayloadLength, fhdr->DevAddr, false, fhdr->FCnt, mic_ptr);
dudmuck 0:2ff18de8d48b 607 lora.RegPayloadLength += LORA_FRAMEMICBYTES;
dudmuck 0:2ff18de8d48b 608
dudmuck 0:2ff18de8d48b 609
dudmuck 0:2ff18de8d48b 610 queue.call_in(rx_ms + RECEIVE_DELAY_ms - timer.read_ms(), send_downlink);
dudmuck 0:2ff18de8d48b 611 do_downlink = true;
dudmuck 0:2ff18de8d48b 612 }
dudmuck 0:2ff18de8d48b 613
dudmuck 0:2ff18de8d48b 614 void LoRaWan::parse_uplink(ota_mote_t* mote)
dudmuck 0:2ff18de8d48b 615 {
dudmuck 0:2ff18de8d48b 616 uint8_t decrypted[256];
dudmuck 0:2ff18de8d48b 617 uint32_t calculated_mic, rx_mic;
dudmuck 0:2ff18de8d48b 618 fhdr_t *rx_fhdr = (fhdr_t*)&radio.rx_buf[1];
dudmuck 0:2ff18de8d48b 619 mhdr_t* rx_mhdr = (mhdr_t*)&radio.rx_buf[0];
dudmuck 0:2ff18de8d48b 620 int rxofs = sizeof(mhdr_t) + sizeof(fhdr_t) + rx_fhdr->FCtrl.ulBits.FOptsLen;
dudmuck 0:2ff18de8d48b 621 int rxFRMPayload_length = 0;
dudmuck 0:2ff18de8d48b 622 uint8_t* rxFRMPayload = NULL;
dudmuck 0:2ff18de8d48b 623 uint8_t* rx_fport_ptr = NULL;
dudmuck 0:2ff18de8d48b 624
dudmuck 0:2ff18de8d48b 625 if ((lora.RegRxNbBytes - LORA_FRAMEMICBYTES) > rxofs) {
dudmuck 0:2ff18de8d48b 626 rxFRMPayload_length = (lora.RegRxNbBytes - LORA_FRAMEMICBYTES) - (rxofs + 1);
dudmuck 0:2ff18de8d48b 627 rxFRMPayload = &radio.rx_buf[rxofs+1];
dudmuck 0:2ff18de8d48b 628 rx_fport_ptr = &radio.rx_buf[rxofs];
dudmuck 10:6783623cc886 629 printf("port:%d, len:%d, ", *rx_fport_ptr, rxFRMPayload_length);
dudmuck 0:2ff18de8d48b 630 } else
dudmuck 0:2ff18de8d48b 631 printf("no-payload\r\n");
dudmuck 0:2ff18de8d48b 632
dudmuck 0:2ff18de8d48b 633 LoRa_GenerateDataFrameIntegrityCode(mote->network_session_key, radio.rx_buf, lora.RegRxNbBytes-LORA_FRAMEMICBYTES, rx_fhdr->DevAddr, true, rx_fhdr->FCnt, (uint8_t*)&calculated_mic);
dudmuck 0:2ff18de8d48b 634
dudmuck 0:2ff18de8d48b 635 rx_mic = radio.rx_buf[lora.RegRxNbBytes-1] << 24;
dudmuck 0:2ff18de8d48b 636 rx_mic += radio.rx_buf[lora.RegRxNbBytes-2] << 16;
dudmuck 0:2ff18de8d48b 637 rx_mic += radio.rx_buf[lora.RegRxNbBytes-3] << 8;
dudmuck 0:2ff18de8d48b 638 rx_mic += radio.rx_buf[lora.RegRxNbBytes-4];
dudmuck 0:2ff18de8d48b 639 if (calculated_mic != rx_mic) {
dudmuck 0:2ff18de8d48b 640 printf("genMic:%08lx, rxMic:%08lx\r\n", calculated_mic, rx_mic);
dudmuck 0:2ff18de8d48b 641 printf("mic fail\n");
dudmuck 0:2ff18de8d48b 642 return;
dudmuck 0:2ff18de8d48b 643 }
dudmuck 0:2ff18de8d48b 644
dudmuck 0:2ff18de8d48b 645 if (rx_fport_ptr != NULL && *rx_fport_ptr == 0) {
dudmuck 0:2ff18de8d48b 646 /* mac commands are encrypted onto port 0 */
dudmuck 0:2ff18de8d48b 647 LoRa_EncryptPayload(mote->network_session_key, rxFRMPayload, rxFRMPayload_length, rx_fhdr->DevAddr, true, rx_fhdr->FCnt, decrypted);
dudmuck 0:2ff18de8d48b 648 printf("mac commands encrypted on port 0\r\n");
dudmuck 0:2ff18de8d48b 649 parse_mac_command(mote, decrypted, rxFRMPayload_length);
dudmuck 0:2ff18de8d48b 650 } else {
dudmuck 0:2ff18de8d48b 651 if (rx_fhdr->FCtrl.ulBits.FOptsLen > 0) {
dudmuck 0:2ff18de8d48b 652 /* mac commands are in header */
dudmuck 0:2ff18de8d48b 653 printf("mac commands in header\r\n");
dudmuck 0:2ff18de8d48b 654 rxofs = sizeof(mhdr_t) + sizeof(fhdr_t);
dudmuck 0:2ff18de8d48b 655 parse_mac_command(mote, &radio.rx_buf[rxofs], rx_fhdr->FCtrl.ulBits.FOptsLen);
dudmuck 0:2ff18de8d48b 656 }
dudmuck 0:2ff18de8d48b 657 if (rxFRMPayload != NULL) {
dudmuck 0:2ff18de8d48b 658 LoRa_EncryptPayload(mote->app_session_key, rxFRMPayload, rxFRMPayload_length, rx_fhdr->DevAddr, true, rx_fhdr->FCnt, decrypted);
dudmuck 9:a0ce66c18ec0 659 /*printf("app-decrypt:");
dudmuck 0:2ff18de8d48b 660 for (rxofs = 0; rxofs < rxFRMPayload_length; rxofs++) {
dudmuck 0:2ff18de8d48b 661 printf("%02x ", decrypted[rxofs]);
dudmuck 0:2ff18de8d48b 662 }
dudmuck 0:2ff18de8d48b 663 printf(" ");
dudmuck 0:2ff18de8d48b 664 for (rxofs = 0; rxofs < rxFRMPayload_length; rxofs++) {
dudmuck 0:2ff18de8d48b 665 if (decrypted[rxofs] >= ' ' && decrypted[rxofs] < 0x7f)
dudmuck 0:2ff18de8d48b 666 printf("%c", decrypted[rxofs]);
dudmuck 0:2ff18de8d48b 667 }
dudmuck 9:a0ce66c18ec0 668 printf("\n");*/
dudmuck 9:a0ce66c18ec0 669 decrypted_uplink(decrypted, rxFRMPayload_length, *rx_fport_ptr);
dudmuck 0:2ff18de8d48b 670 }
dudmuck 0:2ff18de8d48b 671 }
dudmuck 0:2ff18de8d48b 672
dudmuck 0:2ff18de8d48b 673 fhdr_t* tx_fhdr = (fhdr_t*)&radio.tx_buf[1];
dudmuck 0:2ff18de8d48b 674 tx_fhdr->FCtrl.dlBits.FOptsLen = 0;
dudmuck 0:2ff18de8d48b 675
dudmuck 0:2ff18de8d48b 676 /* TODO get queued mac cmds */
dudmuck 0:2ff18de8d48b 677
dudmuck 0:2ff18de8d48b 678 lora.RegPayloadLength = 0;
dudmuck 0:2ff18de8d48b 679
dudmuck 0:2ff18de8d48b 680 if (tx_fhdr->FCtrl.dlBits.FOptsLen > 0 || rx_mhdr->bits.MType == MTYPE_CONF_UP ||
dudmuck 0:2ff18de8d48b 681 mote->user_downlink_length > 0 || rx_fhdr->FCtrl.ulBits.ADCACKReq)
dudmuck 0:2ff18de8d48b 682 {
dudmuck 0:2ff18de8d48b 683 /* something to send via downlink */
dudmuck 0:2ff18de8d48b 684 if (rx_mhdr->bits.MType == MTYPE_CONF_UP)
dudmuck 0:2ff18de8d48b 685 tx_fhdr->FCtrl.dlBits.ACK = 1;
dudmuck 0:2ff18de8d48b 686 else
dudmuck 0:2ff18de8d48b 687 tx_fhdr->FCtrl.dlBits.ACK = 0;
dudmuck 0:2ff18de8d48b 688
dudmuck 0:2ff18de8d48b 689 if (mote->user_downlink_length > 0) {
dudmuck 0:2ff18de8d48b 690 /* add user payload */
dudmuck 0:2ff18de8d48b 691 int txo = sizeof(mhdr_t) + sizeof(fhdr_t) + tx_fhdr->FCtrl.dlBits.FOptsLen;
dudmuck 0:2ff18de8d48b 692 uint8_t* tx_fport_ptr = &radio.tx_buf[txo];
dudmuck 0:2ff18de8d48b 693 uint8_t* txFRMPayload = &radio.tx_buf[txo+1];
dudmuck 0:2ff18de8d48b 694 LoRa_EncryptPayload(mote->app_session_key, user_downlink, mote->user_downlink_length, mote->dev_addr, false, mote->FCntDown, txFRMPayload);
dudmuck 0:2ff18de8d48b 695 if (rx_fport_ptr != NULL)
dudmuck 0:2ff18de8d48b 696 *tx_fport_ptr = *rx_fport_ptr;
dudmuck 0:2ff18de8d48b 697 else
dudmuck 0:2ff18de8d48b 698 *tx_fport_ptr = DEFAULT_DOWNLINK_PORT;
dudmuck 0:2ff18de8d48b 699
dudmuck 0:2ff18de8d48b 700 lora.RegPayloadLength = tx_fhdr->FCtrl.dlBits.FOptsLen + mote->user_downlink_length + 1; // +1 for fport
dudmuck 0:2ff18de8d48b 701 radio.tx_buf[0] = user_dowlink_mtype << 5; // MHDR
dudmuck 0:2ff18de8d48b 702 printf("DL-send %d\r\n", mote->user_downlink_length);
dudmuck 0:2ff18de8d48b 703 } else {
dudmuck 0:2ff18de8d48b 704 /* downlink not triggered by user_downlink */
dudmuck 0:2ff18de8d48b 705 /* downlink triggered by FOpotsLen > 0 or conf_uplink */
dudmuck 0:2ff18de8d48b 706 radio.tx_buf[0] = MTYPE_UNCONF_DN << 5; // MHDR
dudmuck 0:2ff18de8d48b 707 }
dudmuck 0:2ff18de8d48b 708
dudmuck 0:2ff18de8d48b 709 classA_downlink(mote);
dudmuck 0:2ff18de8d48b 710
dudmuck 0:2ff18de8d48b 711 mote->user_downlink_length = 0; // mark as sent
dudmuck 0:2ff18de8d48b 712 }
dudmuck 0:2ff18de8d48b 713 }
dudmuck 0:2ff18de8d48b 714
dudmuck 0:2ff18de8d48b 715 void LoRaWan::parse_join_req(ota_mote_t* mote)
dudmuck 0:2ff18de8d48b 716 {
dudmuck 0:2ff18de8d48b 717 join_req_t* jreq_ptr = (join_req_t*)&radio.rx_buf[0];
dudmuck 0:2ff18de8d48b 718 uint32_t rx_mic, calculated_mic;
dudmuck 0:2ff18de8d48b 719
dudmuck 0:2ff18de8d48b 720 LoRa_GenerateJoinFrameIntegrityCode(mote->app_key, radio.rx_buf, lora.RegRxNbBytes-LORA_FRAMEMICBYTES, (uint8_t*)&calculated_mic);
dudmuck 0:2ff18de8d48b 721
dudmuck 0:2ff18de8d48b 722
dudmuck 0:2ff18de8d48b 723 rx_mic = radio.rx_buf[lora.RegRxNbBytes-1] << 24;
dudmuck 0:2ff18de8d48b 724 rx_mic += radio.rx_buf[lora.RegRxNbBytes-2] << 16;
dudmuck 0:2ff18de8d48b 725 rx_mic += radio.rx_buf[lora.RegRxNbBytes-3] << 8;
dudmuck 0:2ff18de8d48b 726 rx_mic += radio.rx_buf[lora.RegRxNbBytes-4];
dudmuck 0:2ff18de8d48b 727 if (calculated_mic != rx_mic) {
dudmuck 0:2ff18de8d48b 728 printf("join_req mic fail: %08lx, %08lx\r\n", calculated_mic, rx_mic);
dudmuck 0:2ff18de8d48b 729 return;
dudmuck 0:2ff18de8d48b 730 }
dudmuck 0:2ff18de8d48b 731
dudmuck 0:2ff18de8d48b 732 /* TODO check devNonce */
dudmuck 0:2ff18de8d48b 733 SendJoinComplete(jreq_ptr->DevNonce, 0, mote);
dudmuck 0:2ff18de8d48b 734 }
dudmuck 0:2ff18de8d48b 735
dudmuck 0:2ff18de8d48b 736
dudmuck 0:2ff18de8d48b 737 int memcmp_rev(const uint8_t* a, const uint8_t* b, uint8_t len)
dudmuck 0:2ff18de8d48b 738 {
dudmuck 0:2ff18de8d48b 739 int a_i, b_i = len - 1;
dudmuck 0:2ff18de8d48b 740 for (a_i = 0; a_i < len; a_i++) {
dudmuck 0:2ff18de8d48b 741 if (a[a_i] != b[b_i])
dudmuck 0:2ff18de8d48b 742 return a[a_i] - b[b_i];
dudmuck 0:2ff18de8d48b 743 else
dudmuck 0:2ff18de8d48b 744 b_i--;
dudmuck 0:2ff18de8d48b 745 }
dudmuck 0:2ff18de8d48b 746 return 0;
dudmuck 0:2ff18de8d48b 747 }
dudmuck 0:2ff18de8d48b 748
dudmuck 0:2ff18de8d48b 749 void LoRaWan::init()
dudmuck 0:2ff18de8d48b 750 {
dudmuck 0:2ff18de8d48b 751 int i;
dudmuck 0:2ff18de8d48b 752 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 753 motes[i].dev_addr = DEVADDR_NONE;
dudmuck 0:2ff18de8d48b 754 }
dudmuck 0:2ff18de8d48b 755 }
dudmuck 0:2ff18de8d48b 756
dudmuck 0:2ff18de8d48b 757 int LoRaWan::parse_receive()
dudmuck 0:2ff18de8d48b 758 {
dudmuck 0:2ff18de8d48b 759 int i;
dudmuck 0:2ff18de8d48b 760 ota_mote_t* mote = NULL;
dudmuck 0:2ff18de8d48b 761 mhdr_t *mhdr = (mhdr_t*)radio.rx_buf;
dudmuck 0:2ff18de8d48b 762
dudmuck 0:2ff18de8d48b 763 if (lora.RegRxNbBytes <= (sizeof(fhdr_t) + LORA_FRAMEMICBYTES)) {
dudmuck 0:2ff18de8d48b 764 printf("too small %d, snr:%.1f %ddBm\r\n", lora.RegRxNbBytes, lora.RegPktSnrValue/4.0, lora.get_pkt_rssi());
dudmuck 0:2ff18de8d48b 765 return 1;
dudmuck 0:2ff18de8d48b 766 }
dudmuck 0:2ff18de8d48b 767 if (mhdr->bits.major != 0) {
dudmuck 0:2ff18de8d48b 768 printf("unsupported major:%u\n", mhdr->bits.major);
dudmuck 0:2ff18de8d48b 769 return 0;
dudmuck 0:2ff18de8d48b 770 }
dudmuck 0:2ff18de8d48b 771
dudmuck 0:2ff18de8d48b 772 if (mhdr->bits.MType == MTYPE_JOIN_REQ) {
dudmuck 0:2ff18de8d48b 773 join_req_t* join_req = (join_req_t*)&radio.rx_buf[0];
dudmuck 10:6783623cc886 774 printf("MTYPE_JOIN_REQ, ");
dudmuck 0:2ff18de8d48b 775
dudmuck 0:2ff18de8d48b 776 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 777 if ((memcmp_rev(join_req->AppEUI, motes[i].app_eui, LORA_EUI_LENGTH) == 0) &&
dudmuck 0:2ff18de8d48b 778 (memcmp_rev(join_req->DevEUI, motes[i].dev_eui, LORA_EUI_LENGTH) == 0))
dudmuck 0:2ff18de8d48b 779 {
dudmuck 0:2ff18de8d48b 780 printf("found mote\r\n");
dudmuck 0:2ff18de8d48b 781 mote = &motes[i];
dudmuck 0:2ff18de8d48b 782 }
dudmuck 0:2ff18de8d48b 783 }
dudmuck 0:2ff18de8d48b 784 if (mote != NULL) {
dudmuck 0:2ff18de8d48b 785 printf("Join-Found\r\n");
dudmuck 0:2ff18de8d48b 786 parse_join_req(mote);
dudmuck 0:2ff18de8d48b 787 } else {
dudmuck 0:2ff18de8d48b 788 printf("join-not-found:\r\n");
dudmuck 9:a0ce66c18ec0 789 print_octets_rev("app_eui", join_req->AppEUI, LORA_EUI_LENGTH);
dudmuck 9:a0ce66c18ec0 790 print_octets_rev("\r\ndev_eui", join_req->DevEUI, LORA_EUI_LENGTH);
dudmuck 0:2ff18de8d48b 791 printf("\r\n");
dudmuck 0:2ff18de8d48b 792 }
dudmuck 0:2ff18de8d48b 793 } else if (mhdr->bits.MType == MTYPE_UNCONF_UP || mhdr->bits.MType == MTYPE_CONF_UP) {
dudmuck 0:2ff18de8d48b 794 fhdr_t *fhdr = (fhdr_t*)&radio.rx_buf[1];
dudmuck 0:2ff18de8d48b 795 if (mhdr->bits.MType == MTYPE_UNCONF_UP)
dudmuck 10:6783623cc886 796 printf("MTYPE_UNCONF_UP, ");
dudmuck 0:2ff18de8d48b 797 else if (mhdr->bits.MType == MTYPE_CONF_UP)
dudmuck 10:6783623cc886 798 printf("MTYPE_CONF_UP, ");
dudmuck 0:2ff18de8d48b 799
dudmuck 0:2ff18de8d48b 800 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 801 if (motes[i].dev_addr == fhdr->DevAddr) {
dudmuck 0:2ff18de8d48b 802 mote = &motes[i];
dudmuck 0:2ff18de8d48b 803 }
dudmuck 0:2ff18de8d48b 804 }
dudmuck 0:2ff18de8d48b 805
dudmuck 0:2ff18de8d48b 806 if (mote != NULL) {
dudmuck 10:6783623cc886 807 printf("mote:%lx, ", mote->dev_addr);
dudmuck 0:2ff18de8d48b 808 parse_uplink(mote);
dudmuck 0:2ff18de8d48b 809 } else {
dudmuck 0:2ff18de8d48b 810 printf("mote-not-found %08lx", fhdr->DevAddr);
dudmuck 0:2ff18de8d48b 811 }
dudmuck 0:2ff18de8d48b 812
dudmuck 0:2ff18de8d48b 813 printf("\r\n");
dudmuck 0:2ff18de8d48b 814 } else
dudmuck 0:2ff18de8d48b 815 printf(" %02x mtype:%d\r\n", radio.rx_buf[0], mhdr->bits.MType);
dudmuck 0:2ff18de8d48b 816
dudmuck 0:2ff18de8d48b 817
dudmuck 0:2ff18de8d48b 818 return 0;
dudmuck 0:2ff18de8d48b 819 }
dudmuck 0:2ff18de8d48b 820