Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: SX127x sx12xx_hal
lorawan.cpp@10:6783623cc886, 2017-07-12 (annotated)
- 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?
| User | Revision | Line number | New 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("[31mSendJoinComplete(): tx busy[0m\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("[31mTODO mac cmd %02x[0m\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("[31mgenMic:%08lx, rxMic:%08lx\r\n", calculated_mic, rx_mic); |
| dudmuck | 0:2ff18de8d48b | 641 | printf("mic fail[0m\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(" [31m%02x mtype:%d[0m\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 |