IBM LoRa MAC in C (LMiC) mbed library port

Dependents:   lora-temperature LoRaWAN-lmic-app_HS LoRaWAN-lmic-app_huynh

LoRa WAN in C for sx1276 shield

Currently version 1.5


LoRaWAN network configuration for end-device

The following three pieces of information uniquely identifies end-device to network to allow over-the-air activation. These are stored in the end-device prior to join procedure.

AppEUI

Uniquely identifies application provider of end-device.

Least-significant byte first, 8 bytes, use reverse memcpy() to keep same order as shown on lora server.

example C code

static const u1_t APPEUI[8]  = { 0x01, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x25, 0x00 };

This is copied into LMIC by os_getArtEui() callback function in application.

DevEUI

End-device ID, unique to each end-node.

Least-significant byte first, 8 bytes, use reverse memcpy() to keep same order as shown on lora server.

example C code

static const u1_t DEVEUI[8]  = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x0C, 0x25, 0x00 }; 

This is copied into LMIC by os_getDevEui() callback function in application.

AppKey (aka DevKey)

128-bit (16byte) AES key.

example C code

static const u1_t DEVKEY[16] = { 0xe4, 0x72, 0x71, 0xc5, 0xf5, 0x30, 0xa9, 0x9f, 0xcf, 0xc4, 0x0e, 0xab, 0xea, 0xd7, 0x19, 0x42 };

This is copied into LMIC by os_getDevKey() callback function in application.

Using over-the air activation, the end-device (LMIC) performs a join procedure every time it starts for first time, or has lost session context information. When join procedure has successfully completed, the end-device will have a network session key (NwkSKey) and an application session key (AppSKey), which are used for encryption and message integrity check.


US915 configuration with http://us01-iot.semtech.com/

  • log in to server
  • click on Applications
  • find your application and click it
  • go to configure motes
  • to create a mote, you may enter a new DevEUI
    • you may copy-paste the 16byte application key from an already existing mote, if you desire.
CHNL_HYBRID125KHz500KHz
defined valuechannelschannel
00 to 764
18 to 1565
216 to 2366
324 to 3167
432 to 3968
540 to 4769
648 to 5570
756 to 6371
undef0 to 6364 to 71
Revision:
1:d3b7bde3995c
Parent:
0:62d1edcc13d1
--- a/aes.cpp	Thu Jan 22 12:50:49 2015 +0000
+++ b/aes.cpp	Tue Mar 31 13:36:56 2015 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014 IBM Corporation.
+ * Copyright (c) 2014-2015 IBM Corporation.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -181,23 +181,23 @@
 #define msbf4_write(p,v) (p)[0]=(v)>>24,(p)[1]=(v)>>16,(p)[2]=(v)>>8,(p)[3]=(v)
 #define swapmsbf(x)      ( (x&0xFF)<<24 | (x&0xFF00)<<8 | (x&0xFF0000)>>8 | (x>>24) )
 
-#define u1(v)		            ((u1_t)(v))
+#define u1(v)                       ((u1_t)(v))
 
 #define AES_key4(r1,r2,r3,r0,i)    r1 = ki[i+1]; \
                                    r2 = ki[i+2]; \
                                    r3 = ki[i+3]; \
                                    r0 = ki[i]
 
-#define AES_expr4(r1,r2,r3,r0,i)   r1 ^= AES_E4[u1(i)];	    \
-			           r2 ^= AES_E3[u1(i>>8)];  \
-			           r3 ^= AES_E2[u1(i>>16)]; \
-			           r0 ^= AES_E1[  (i>>24)]
+#define AES_expr4(r1,r2,r3,r0,i)   r1 ^= AES_E4[u1(i)];     \
+                                   r2 ^= AES_E3[u1(i>>8)];  \
+                                   r3 ^= AES_E2[u1(i>>16)]; \
+                                   r0 ^= AES_E1[  (i>>24)]
 
 #define AES_expr(a,r0,r1,r2,r3,i)  a = ki[i];                    \
-				   a ^= (AES_S[   r0>>24 ]<<24); \
-				   a ^= (AES_S[u1(r1>>16)]<<16); \
-				   a ^= (AES_S[u1(r2>> 8)]<< 8); \
-				   a ^=  AES_S[u1(r3)    ]
+                                   a ^= (AES_S[   r0>>24 ]<<24); \
+                                   a ^= (AES_S[u1(r1>>16)]<<16); \
+                                   a ^= (AES_S[u1(r2>> 8)]<< 8); \
+                                   a ^=  AES_S[u1(r3)    ]
 
 // global area for passing parameters (aux, key) and for storing round keys
 u4_t AESAUX[16/sizeof(u4_t)];
@@ -205,59 +205,59 @@
 
 // generate 1+10 roundkeys for encryption with 128-bit key
 // read 128-bit key from AESKEY in MSBF, generate roundkey words in place
-static void aesroundkeys (void) {
+static void aesroundkeys () {
     int i;
     u4_t b;
 
     for( i=0; i<4; i++) {
-	AESKEY[i] = swapmsbf(AESKEY[i]);
+        AESKEY[i] = swapmsbf(AESKEY[i]);
     }
     
     b = AESKEY[3];
     for( ; i<44; i++ ) {
-	if( i%4==0 ) {
+        if( i%4==0 ) {
             // b = SubWord(RotWord(b)) xor Rcon[i/4]
-	    b = (AES_S[u1(b >> 16)] << 24) ^
-		(AES_S[u1(b >>  8)] << 16) ^
-		(AES_S[u1(b)      ] <<  8) ^
-		(AES_S[   b >> 24 ]      ) ^
+            b = (AES_S[u1(b >> 16)] << 24) ^
+                (AES_S[u1(b >>  8)] << 16) ^
+                (AES_S[u1(b)      ] <<  8) ^
+                (AES_S[   b >> 24 ]      ) ^
                  AES_RCON[(i-4)/4];
-	}
-	AESKEY[i] = b ^= AESKEY[i-4];
+        }
+        AESKEY[i] = b ^= AESKEY[i-4];
     }
 }
 
 u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) {
         
-	aesroundkeys();
+        aesroundkeys();
 
-	if( mode & AES_MICNOAUX ) {
-	    AESAUX[0] = AESAUX[1] = AESAUX[2] = AESAUX[3] = 0;
-	} else {
-	    AESAUX[0] = swapmsbf(AESAUX[0]);
-	    AESAUX[1] = swapmsbf(AESAUX[1]);
-	    AESAUX[2] = swapmsbf(AESAUX[2]);
-	    AESAUX[3] = swapmsbf(AESAUX[3]);
-	}
+        if( mode & AES_MICNOAUX ) {
+            AESAUX[0] = AESAUX[1] = AESAUX[2] = AESAUX[3] = 0;
+        } else {
+            AESAUX[0] = swapmsbf(AESAUX[0]);
+            AESAUX[1] = swapmsbf(AESAUX[1]);
+            AESAUX[2] = swapmsbf(AESAUX[2]);
+            AESAUX[3] = swapmsbf(AESAUX[3]);
+        }
 
-	while( (signed char)len > 0 ) {
-	    u4_t a0, a1, a2, a3;
-	    u4_t t0, t1, t2, t3;
-	    u4_t *ki, *ke;
+        while( (signed char)len > 0 ) {
+            u4_t a0, a1, a2, a3;
+            u4_t t0, t1, t2, t3;
+            u4_t *ki, *ke;
 
-	    // load input block
-	    if( (mode & AES_CTR) || ((mode & AES_MIC) && (mode & AES_MICNOAUX)==0) ) { // load CTR block or first MIC block
-		a0 = AESAUX[0];
-		a1 = AESAUX[1];
-		a2 = AESAUX[2];
-		a3 = AESAUX[3];
+            // load input block
+            if( (mode & AES_CTR) || ((mode & AES_MIC) && (mode & AES_MICNOAUX)==0) ) { // load CTR block or first MIC block
+                a0 = AESAUX[0];
+                a1 = AESAUX[1];
+                a2 = AESAUX[2];
+                a3 = AESAUX[3];
             }
             else if( (mode & AES_MIC) && len <= 16 ) { // last MIC block
                 a0 = a1 = a2 = a3 = 0; // load null block
                 mode |= ((len == 16) ? 1 : 2) << 4; // set MICSUB: CMAC subkey K1 or K2
             } else
         LOADDATA: { // load data block (partially)
-		for(t0=0; t0<16; t0++) {
+                for(t0=0; t0<16; t0++) {
                     t1 = (t1<<8) | ((t0<len) ? buf[t0] : (t0==len) ? 0x80 : 0x00);
                     if((t0&3)==3) {
                         a0 = a1;
@@ -266,74 +266,74 @@
                         a3 = t1;
                     }
                 } 
-		if( mode & AES_MIC ) {
-		    a0 ^= AESAUX[0];
-		    a1 ^= AESAUX[1];
-		    a2 ^= AESAUX[2];
-		    a3 ^= AESAUX[3];
-		}
+                if( mode & AES_MIC ) {
+                    a0 ^= AESAUX[0];
+                    a1 ^= AESAUX[1];
+                    a2 ^= AESAUX[2];
+                    a3 ^= AESAUX[3];
+                }
             }
 
-	    // perform AES encryption on block in a0-a3
-	    ki = AESKEY;
-	    ke = ki + 8*4;
-	    a0 ^= ki[0];
-	    a1 ^= ki[1];
-	    a2 ^= ki[2];
-	    a3 ^= ki[3];
-	    do {
-		AES_key4 (t1,t2,t3,t0,4);
-		AES_expr4(t1,t2,t3,t0,a0);
-		AES_expr4(t2,t3,t0,t1,a1);
-		AES_expr4(t3,t0,t1,t2,a2);
-		AES_expr4(t0,t1,t2,t3,a3);
+            // perform AES encryption on block in a0-a3
+            ki = AESKEY;
+            ke = ki + 8*4;
+            a0 ^= ki[0];
+            a1 ^= ki[1];
+            a2 ^= ki[2];
+            a3 ^= ki[3];
+            do {
+                AES_key4 (t1,t2,t3,t0,4);
+                AES_expr4(t1,t2,t3,t0,a0);
+                AES_expr4(t2,t3,t0,t1,a1);
+                AES_expr4(t3,t0,t1,t2,a2);
+                AES_expr4(t0,t1,t2,t3,a3);
 
-		AES_key4 (a1,a2,a3,a0,8);
-		AES_expr4(a1,a2,a3,a0,t0);
-		AES_expr4(a2,a3,a0,a1,t1);
-		AES_expr4(a3,a0,a1,a2,t2);
-		AES_expr4(a0,a1,a2,a3,t3);
-	    } while( (ki+=8) < ke );
+                AES_key4 (a1,a2,a3,a0,8);
+                AES_expr4(a1,a2,a3,a0,t0);
+                AES_expr4(a2,a3,a0,a1,t1);
+                AES_expr4(a3,a0,a1,a2,t2);
+                AES_expr4(a0,a1,a2,a3,t3);
+            } while( (ki+=8) < ke );
 
-	    AES_key4 (t1,t2,t3,t0,4);
-	    AES_expr4(t1,t2,t3,t0,a0);
-	    AES_expr4(t2,t3,t0,t1,a1);
-	    AES_expr4(t3,t0,t1,t2,a2);
-	    AES_expr4(t0,t1,t2,t3,a3);
+            AES_key4 (t1,t2,t3,t0,4);
+            AES_expr4(t1,t2,t3,t0,a0);
+            AES_expr4(t2,t3,t0,t1,a1);
+            AES_expr4(t3,t0,t1,t2,a2);
+            AES_expr4(t0,t1,t2,t3,a3);
 
-	    AES_expr(a0,t0,t1,t2,t3,8);
-	    AES_expr(a1,t1,t2,t3,t0,9);
-	    AES_expr(a2,t2,t3,t0,t1,10);
-	    AES_expr(a3,t3,t0,t1,t2,11);
-	    // result of AES encryption in a0-a3
+            AES_expr(a0,t0,t1,t2,t3,8);
+            AES_expr(a1,t1,t2,t3,t0,9);
+            AES_expr(a2,t2,t3,t0,t1,10);
+            AES_expr(a3,t3,t0,t1,t2,11);
+            // result of AES encryption in a0-a3
 
-	    if( mode & AES_MIC ) {
-		if( (t1 = ((mode & AES_MICSUB) >> 4)) != 0 ) { // last block
-		    do {
-			// compute CMAC subkey K1 and K2
-			t0 = a0 >> 31; // save MSB
-			a0 = (a0 << 1) | (a1 >> 31);
-			a1 = (a1 << 1) | (a2 >> 31);
-			a2 = (a2 << 1) | (a3 >> 31);
-			a3 = (a3 << 1);
-			if( t0 ) a3 ^= 0x87;
-		    } while( --t1 );
+            if( mode & AES_MIC ) {
+                if( (t1 = (mode & AES_MICSUB) >> 4) != 0 ) { // last block
+                    do {
+                        // compute CMAC subkey K1 and K2
+                        t0 = a0 >> 31; // save MSB
+                        a0 = (a0 << 1) | (a1 >> 31);
+                        a1 = (a1 << 1) | (a2 >> 31);
+                        a2 = (a2 << 1) | (a3 >> 31);
+                        a3 = (a3 << 1);
+                        if( t0 ) a3 ^= 0x87;
+                    } while( --t1 );
 
-		    AESAUX[0] ^= a0;
-		    AESAUX[1] ^= a1;
-		    AESAUX[2] ^= a2;
-		    AESAUX[3] ^= a3;
+                    AESAUX[0] ^= a0;
+                    AESAUX[1] ^= a1;
+                    AESAUX[2] ^= a2;
+                    AESAUX[3] ^= a3;
                     mode &= ~AES_MICSUB;
-		    goto LOADDATA;
-		} else {
+                    goto LOADDATA;
+                } else {
                     // save cipher block as new iv
                     AESAUX[0] = a0;
                     AESAUX[1] = a1;
                     AESAUX[2] = a2;
                     AESAUX[3] = a3;
                 }
-	    } else { // CIPHER
-		if( mode & AES_CTR ) { // xor block (partially)
+            } else { // CIPHER
+                if( mode & AES_CTR ) { // xor block (partially)
                     t0 = (len > 16) ? 16: len;
                     for(t1=0; t1<t0; t1++) {
                         buf[t1] ^= (a0>>24);
@@ -344,16 +344,16 @@
                             a2 = a3;
                         }
                     }
-		    // update counter
-		    AESAUX[3]++;
-		} else { // ECB
+                    // update counter
+                    AESAUX[3]++;
+                } else { // ECB
                     // store block
                     msbf4_write(buf+0,  a0);
-		    msbf4_write(buf+4,  a1);
-		    msbf4_write(buf+8,  a2);
-		    msbf4_write(buf+12, a3);
-		}
-	    }
+                    msbf4_write(buf+4,  a1);
+                    msbf4_write(buf+8,  a2);
+                    msbf4_write(buf+12, a3);
+                }
+            }
 
             // update block state
             if( (mode & AES_MIC)==0 || (mode & AES_MICNOAUX) ) {
@@ -361,7 +361,7 @@
                 len -= 16;
             }
             mode |= AES_MICNOAUX;
-	}
-	return AESAUX[0];
+        }
+        return AESAUX[0];
 }