diff --git a/CMakeLists.txt b/CMakeLists.txt index 767d9dd5c0..fdaf65dcfc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ set(source_files model/forwarder.cc model/lorawan-mac-header.cc model/lora-frame-header.cc + model/lorawan-mic-trailer.cc model/mac-command.cc model/lora-device-address.cc model/lora-device-address-generator.cc @@ -71,6 +72,7 @@ set(header_files model/forwarder.h model/lorawan-mac-header.h model/lora-frame-header.h + model/lorawan-mic-trailer.h model/mac-command.h model/lora-device-address.h model/lora-device-address-generator.h diff --git a/helper/lora-helper.cc b/helper/lora-helper.cc index 80a5822ccf..b57c2fffc4 100644 --- a/helper/lora-helper.cc +++ b/helper/lora-helper.cc @@ -39,9 +39,9 @@ NS_LOG_COMPONENT_DEFINE ("LoraHelper"); } NetDeviceContainer - LoraHelper::Install ( const LoraPhyHelper &phyHelper, - const LorawanMacHelper &macHelper, - NodeContainer c) const + LoraHelper::Install ( LoraPhyHelper &phyHelper, + LorawanMacHelper &macHelper, + NodeContainer c) { NS_LOG_FUNCTION_NOARGS (); @@ -147,9 +147,9 @@ NS_LOG_COMPONENT_DEFINE ("LoraHelper"); } NetDeviceContainer -LoraHelper::Install ( const LoraPhyHelper &phy, - const LorawanMacHelper &mac, - Ptr node) const +LoraHelper::Install ( LoraPhyHelper &phy, + LorawanMacHelper &mac, + Ptr node) { return Install (phy, mac, NodeContainer (node)); } diff --git a/helper/lora-helper.h b/helper/lora-helper.h index 98403224c7..a153d764de 100644 --- a/helper/lora-helper.h +++ b/helper/lora-helper.h @@ -56,9 +56,9 @@ class LoraHelper * \returns a device container which contains all the devices created by this * method. */ - virtual NetDeviceContainer Install (const LoraPhyHelper &phyHelper, - const LorawanMacHelper &macHelper, - NodeContainer c) const; + virtual NetDeviceContainer Install (LoraPhyHelper &phyHelper, + LorawanMacHelper &macHelper, + NodeContainer c); /** * Install LoraNetDevice on a single node @@ -69,9 +69,9 @@ class LoraHelper * \returns a device container which contains all the devices created by this * method. */ - virtual NetDeviceContainer Install (const LoraPhyHelper &phyHelper, - const LorawanMacHelper &macHelper, - Ptr node) const; + virtual NetDeviceContainer Install (LoraPhyHelper &phyHelper, + LorawanMacHelper &macHelper, + Ptr node); /** * Enable tracking of packets via trace sources. diff --git a/helper/lorawan-mac-helper.cc b/helper/lorawan-mac-helper.cc index 3de51c6de3..ff039389e9 100644 --- a/helper/lorawan-mac-helper.cc +++ b/helper/lorawan-mac-helper.cc @@ -32,6 +32,15 @@ NS_LOG_COMPONENT_DEFINE ("LorawanMacHelper"); LorawanMacHelper::LorawanMacHelper () : m_region (LorawanMacHelper::EU) { + for (unsigned int i = 0;i < 16;i++) + { + m_CurNwkKey[i] = 0; + } + + for (unsigned int i = 0;i < 8;i++) + { + m_CurJoinEUI[i] = 0; + } } void @@ -71,7 +80,7 @@ LorawanMacHelper::SetRegion (enum LorawanMacHelper::Regions region) } Ptr -LorawanMacHelper::Create (Ptr node, Ptr device) const +LorawanMacHelper::Create (Ptr node, Ptr device) { Ptr mac = m_mac.Create (); mac->SetDevice (device); @@ -106,6 +115,11 @@ LorawanMacHelper::Create (Ptr node, Ptr device) const break; } } + + edMac->SetNwkKey(m_CurNwkKey); + GenerateNwkKey(); + edMac->SetJoinEUI(m_CurJoinEUI); + GenerateJoinEUI(); } else { @@ -668,5 +682,51 @@ LorawanMacHelper::SetSpreadingFactorsGivenDistribution (NodeContainer endDevices } // end function +void +LorawanMacHelper::GenerateNwkKey(void) +{ + /* just increment from the last one */ + int i; + + for (i = 15;i >= 0;i--) + { + if (m_CurNwkKey[i] == 255) + { + /* carry over to next byte */ + m_CurNwkKey[i] = 0; + } + else + { + m_CurNwkKey[i]++; + break; + } + } + + return; +} + +void +LorawanMacHelper::GenerateJoinEUI(void) +{ + /* just increment from the last one */ + int i; + + for (i = 7;i >= 0;i--) + { + if (m_CurJoinEUI[i] == 255) + { + /* carry over to next byte */ + m_CurJoinEUI[i] = 0; + } + else + { + m_CurJoinEUI[i]++; + break; + } + } + + return; +} + } // namespace lorawan } // namespace ns3 diff --git a/helper/lorawan-mac-helper.h b/helper/lorawan-mac-helper.h index e472fa1e44..923edeef64 100644 --- a/helper/lorawan-mac-helper.h +++ b/helper/lorawan-mac-helper.h @@ -96,7 +96,7 @@ class LorawanMacHelper * \param device the device within which this MAC will be created. * \returns a newly-created LorawanMac object. */ - Ptr Create (Ptr node, Ptr device) const; + Ptr Create (Ptr node, Ptr device); /** * Set up the end device's data rates @@ -116,7 +116,7 @@ class LorawanMacHelper static std::vector SetSpreadingFactorsGivenDistribution (NodeContainer endDevices, NodeContainer gateways, std::vector distribution); - + private: /** * Perform region-specific configurations for the 868 MHz EU band. @@ -165,11 +165,17 @@ class LorawanMacHelper * ClassAEndDeviceLorawanMac classes. */ void ApplyCommonAlohaConfigurations (Ptr lorawanMac) const; - + ObjectFactory m_mac; Ptr m_addrGen; //!< Pointer to the address generator to use enum DeviceType m_deviceType; //!< The kind of device to install enum Regions m_region; //!< The region in which the device will operate + + void GenerateNwkKey(void); + void GenerateJoinEUI(void); + + uint8_t m_CurNwkKey[16]; + uint8_t m_CurJoinEUI[8]; }; } // namespace lorawan diff --git a/model/class-a-end-device-lorawan-mac.cc b/model/class-a-end-device-lorawan-mac.cc index 7b958375fe..ba2133031c 100644 --- a/model/class-a-end-device-lorawan-mac.cc +++ b/model/class-a-end-device-lorawan-mac.cc @@ -90,6 +90,15 @@ ClassAEndDeviceLorawanMac::SendToPhy (Ptr packetToSend) m_dataRate = m_dataRate - 1; } + Ptr packetCopy = packetToSend->Copy(); + LorawanMacHeader mHdr; + packetCopy->RemoveHeader(mHdr); + +// if (mHdr.GetMType() == JOIN_REQUEST) +// { +// m_devNonce++; +// } + // Craft LoraTxParameters object LoraTxParameters params; params.sf = GetSfFromDataRate (m_dataRate); @@ -102,7 +111,7 @@ ClassAEndDeviceLorawanMac::SendToPhy (Ptr packetToSend) // Wake up PHY layer and directly send the packet - Ptr txChannel = GetChannelForTx (); + Ptr txChannel = m_txCh; NS_LOG_DEBUG ("PacketToSend: " << packetToSend); m_phy->Send (packetToSend, params, txChannel->GetFrequency (), m_txPower); @@ -150,7 +159,7 @@ ClassAEndDeviceLorawanMac::Receive (Ptr packet) // Remove the Mac Header to get some information LorawanMacHeader mHdr; packetCopy->RemoveHeader (mHdr); - + NS_LOG_DEBUG ("Mac Header: " << mHdr); // Only keep analyzing the packet if it's downlink @@ -176,7 +185,26 @@ ClassAEndDeviceLorawanMac::Receive (Ptr packet) // THIS WILL BE GetReceiveWindow() Simulator::Cancel (m_secondReceiveWindow); - +// if (mHdr.GetMType() == JOIN_ACCEPT) +// { +// uint8_t temp[3]; +// uint32_t newJoinNonce = 0; +// packetCopy->CopyData(temp, 3); /* get the new joinNonce value */ +// +// for (i = 0;i < 3;i++) +// { +// newJoinNonce <<= 8; +// newJoinNonce |= temp[i]; +// } +// +// if (newJoinNonce > m_joinNonce) +// { +// /* update is value is greater */ +// m_joinNonce = newJoinNonce; +// } +// +// } + // Parse the MAC commands ParseCommands (fHdr); diff --git a/model/class-a-end-device-lorawan-mac.h b/model/class-a-end-device-lorawan-mac.h index 2facb632ae..79e97ad86d 100644 --- a/model/class-a-end-device-lorawan-mac.h +++ b/model/class-a-end-device-lorawan-mac.h @@ -27,17 +27,18 @@ #include "ns3/lorawan-mac.h" // Packet #include "ns3/end-device-lorawan-mac.h" // EndDeviceLorawanMac #include "ns3/lora-frame-header.h" // RxParamSetupReq -// #include "ns3/random-variable-stream.h" +//#include "ns3/random-variable-stream.h" #include "ns3/lora-device-address.h" -// #include "ns3/traced-value.h" +//#include "ns3/traced-value.h" namespace ns3 { namespace lorawan { - + /** * Class representing the MAC layer of a Class A LoRaWAN device. */ -class ClassAEndDeviceLorawanMac : public EndDeviceLorawanMac + +class ClassAEndDeviceLorawanMac : public EndDeviceLorawanMac { public: static TypeId GetTypeId (void); @@ -207,7 +208,7 @@ class ClassAEndDeviceLorawanMac : public EndDeviceLorawanMac * The Data Rate to listen for during the second downlink transmission. */ uint8_t m_secondReceiveWindowDataRate; - + /** * The RX1DROffset parameter value */ diff --git a/model/end-device-lorawan-mac.cc b/model/end-device-lorawan-mac.cc index aa06d0f9d6..73ea770cb8 100644 --- a/model/end-device-lorawan-mac.cc +++ b/model/end-device-lorawan-mac.cc @@ -141,6 +141,10 @@ EndDeviceLorawanMac::EndDeviceLorawanMac () // Initialize structure for retransmission parameters m_retxParams = EndDeviceLorawanMac::LoraRetxParameters (); m_retxParams.retxLeft = m_maxNumbTx; + + m_joinNonce = 1; + m_devNonce = 1; + m_isVersion1 = false; } EndDeviceLorawanMac::~EndDeviceLorawanMac () @@ -168,11 +172,11 @@ EndDeviceLorawanMac::Send (Ptr packet) } // Pick a channel on which to transmit the packet - Ptr txChannel = GetChannelForTx (); + m_txChIndex = GetChannelForTx(); - if (!(txChannel && m_retxParams.retxLeft > 0)) + if (!(m_txCh && m_retxParams.retxLeft > 0)) { - if (!txChannel) + if (!m_txCh) { m_cannotSendBecauseDutyCycle (packet); } @@ -185,7 +189,7 @@ EndDeviceLorawanMac::Send (Ptr packet) // the transmitting channel is available and we have not run out the maximum number of retransmissions { // Make sure we can transmit at the current power on this channel - NS_ASSERT_MSG (m_txPower <= m_channelHelper.GetTxPowerForChannel (txChannel), + NS_ASSERT_MSG (m_txPower <= m_channelHelper.GetTxPowerForChannel (m_txCh), " The selected power is too hight to be supported by this channel."); DoSend (packet); } @@ -214,6 +218,11 @@ EndDeviceLorawanMac::DoSend (Ptr packet) m_currentFCnt++; NS_LOG_DEBUG ("APP packet: " << packet << "."); + /* for MIC calculation later */ + uint8_t msglen = packet->GetSize(); + std::vector msg(msglen); + packet->CopyData(msg.data(), msglen); + // Add the Lora Frame Header to the packet LoraFrameHeader frameHdr; ApplyNecessaryOptions (frameHdr); @@ -236,10 +245,15 @@ EndDeviceLorawanMac::DoSend (Ptr packet) LorawanMacHeader macHdr; ApplyNecessaryOptions (macHdr); packet->AddHeader (macHdr); - + + //Add MIC trailer + LorawanMICTrailer micTrlr; + ApplyNecessaryOptions (micTrlr, msg.data(), msglen); + packet->AddTrailer (micTrlr); + // Reset MAC command list m_macCommandList.clear (); - + if (m_retxParams.waitingAck) { // Call the callback to notify about the failure @@ -249,6 +263,8 @@ EndDeviceLorawanMac::DoSend (Ptr packet) unsigned(txs) << " transmissions out of a maximum of " << unsigned(m_maxNumbTx) << "."); } + + // Reset retransmission parameters resetRetransmissionParameters (); @@ -266,7 +282,7 @@ EndDeviceLorawanMac::DoSend (Ptr packet) NS_LOG_INFO ("Added MAC header of size " << macHdr.GetSerializedSize () << " bytes."); - + // Sent a new packet NS_LOG_DEBUG ("Copied packet: " << m_retxParams.packet); m_sentNewPacket (m_retxParams.packet); @@ -291,9 +307,16 @@ EndDeviceLorawanMac::DoSend (Ptr packet) // Remove the headers LorawanMacHeader macHdr; LoraFrameHeader frameHdr; + LorawanMICTrailer micTrlr; + packet->RemoveTrailer (micTrlr); packet->RemoveHeader(macHdr); packet->RemoveHeader(frameHdr); - + + /* for MIC calculation later */ + uint8_t msglen = packet->GetSize(); + std::vector msg(msglen); + packet->CopyData(msg.data(), msglen); + // Add the Lora Frame Header to the packet frameHdr = LoraFrameHeader (); ApplyNecessaryOptions (frameHdr); @@ -301,11 +324,16 @@ EndDeviceLorawanMac::DoSend (Ptr packet) NS_LOG_INFO ("Added frame header of size " << frameHdr.GetSerializedSize () << " bytes."); - + // Add the Lorawan Mac header to the packet macHdr = LorawanMacHeader (); ApplyNecessaryOptions (macHdr); packet->AddHeader (macHdr); + + micTrlr = LorawanMICTrailer (); + ApplyNecessaryOptions (micTrlr, msg.data(), msglen); + packet->AddTrailer (micTrlr); + m_retxParams.retxLeft = m_retxParams.retxLeft - 1; // decreasing the number of retransmissions NS_LOG_DEBUG ("Retransmitting an old packet."); @@ -498,6 +526,77 @@ EndDeviceLorawanMac::ApplyNecessaryOptions (LorawanMacHeader& macHeader) macHeader.SetMajor (1); } +void +EndDeviceLorawanMac::ApplyNecessaryOptions (LorawanMICTrailer& micTrlr, uint8_t *msg, uint8_t len) +{ + uint8_t B0[16]; + uint8_t B1[16]; + uint8_t FNwkSIntKey[16]; + uint8_t SNwkSIntKey[16]; + uint32_t mic_temp; + + NS_LOG_FUNCTION_NOARGS (); + + if (IsVersion1()) + { + /* temp <= 0x01 | JoinNonce(3) | NetID(1) | DevNonce(2) | 0x000000000000000000 */ + uint8_t temp[16] = { + 0x01, (uint8_t)((GetJoinNonce() & 0x00FF0000) >> 16), + (uint8_t)((GetJoinNonce() & 0x0000FF00) >> 8), (uint8_t)(GetJoinNonce() & 0x000000FF), + m_address.GetNwkID(), (uint8_t)((GetDevNonce() & 0xFF00) >> 8), + (uint8_t)(GetDevNonce() & 0x00FF), 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 + }; + + micTrlr.aes128(m_nwkKey, temp, FNwkSIntKey); + micTrlr.GenerateB0UL(B0, m_address.GetNwkAddr(), (uint32_t)m_currentFCnt, len); + mic_temp = micTrlr.CalcMIC(len, msg, B0, FNwkSIntKey); + } + else /* v1.1 or later */ + { + /* tempf <= 0x01 | JoinNonce(3) | JoinEUI(8) | DevNonce(2) | 0x0000 */ + uint8_t tempf[16] = { + 0x01, (uint8_t)((GetJoinNonce() & 0x00FF0000) >> 16), + (uint8_t)((GetJoinNonce() & 0x0000FF00) >> 8), (uint8_t)(GetJoinNonce() & 0x000000FF), + m_joinEUI[7], m_joinEUI[6], + m_joinEUI[5], m_joinEUI[4], + m_joinEUI[3], m_joinEUI[2], + m_joinEUI[1], m_joinEUI[0], + (uint8_t)((GetDevNonce() & 0xFF00) >> 8), (uint8_t)(GetDevNonce() & 0x00FF), + 0x00, 0x00 + }; + + /* temps <= 0x03 | JoinNonce(3) | JoinEUI(8) | DevNonce(2) | 0x0000 */ + uint8_t temps[16] = { + 0x03, (uint8_t)((GetJoinNonce() & 0x00FF0000) >> 16), + (uint8_t)((GetJoinNonce() & 0x0000FF00) >> 8), (uint8_t)(GetJoinNonce() & 0x000000FF), + m_joinEUI[7], m_joinEUI[6], + m_joinEUI[5], m_joinEUI[4], + m_joinEUI[3], m_joinEUI[2], + m_joinEUI[1], m_joinEUI[0], + (uint8_t)((GetDevNonce() & 0xFF00) >> 8), (uint8_t)(GetDevNonce() & 0x00FF), + 0x00, 0x00 + }; + + micTrlr.aes128(m_nwkKey, tempf, FNwkSIntKey); + micTrlr.GenerateB0UL(B0, m_address.GetNwkAddr(), (uint32_t)m_currentFCnt, len); + + + micTrlr.aes128(m_nwkKey, temps, SNwkSIntKey); + micTrlr.GenerateB1UL(B1, 0x0000, m_dataRate, m_txChIndex, m_address.GetNwkAddr(), + (uint32_t)m_currentFCnt, len); + + mic_temp = micTrlr.CalcMIC_1_1_UL(len, msg, B0, B1, SNwkSIntKey, FNwkSIntKey); + } + + micTrlr.SetMIC(mic_temp); + + return; +} + void EndDeviceLorawanMac::SetMType (LorawanMacHeader::MType mType) { @@ -556,7 +655,7 @@ EndDeviceLorawanMac::GetNextTransmissionDelay (void) return waitingTime; } -Ptr +uint8_t EndDeviceLorawanMac::GetChannelForTx (void) { NS_LOG_FUNCTION_NOARGS (); @@ -568,7 +667,9 @@ EndDeviceLorawanMac::GetChannelForTx (void) // Try every channel std::vector >::iterator it; - for (it = logicalChannels.begin (); it != logicalChannels.end (); ++it) + unsigned int i; + + for (it = logicalChannels.begin (), i = 0; it != logicalChannels.end (); ++it, i++) { // Pointer to the current channel Ptr logicalChannel = *it; @@ -585,7 +686,8 @@ EndDeviceLorawanMac::GetChannelForTx (void) // Send immediately if we can if (waitingTime == Seconds (0)) { - return *it; + m_txCh = *it; + return i; } else { @@ -593,7 +695,9 @@ EndDeviceLorawanMac::GetChannelForTx (void) "the current channel because of duty cycle limitations."); } } - return 0; // In this case, no suitable channel was found + + m_txCh = 0; // In this case, no suitable channel was found + return 0; } @@ -917,7 +1021,7 @@ EndDeviceLorawanMac::GetAggregatedDutyCycle (void) return m_aggregatedDutyCycle; } -void +void EndDeviceLorawanMac::AddMacCommand (Ptr macCommand) { NS_LOG_FUNCTION (this << macCommand); @@ -925,10 +1029,111 @@ EndDeviceLorawanMac::AddMacCommand (Ptr macCommand) m_macCommandList.push_back (macCommand); } -uint8_t +uint8_t EndDeviceLorawanMac::GetTransmissionPower (void) { return m_txPower; } + +void +EndDeviceLorawanMac::SetNwkKey(uint8_t nwkKey[16]) +{ + unsigned int i; + + for (i = 0;i < 16;i++) + { + m_nwkKey[i] = nwkKey[i]; + } + + return; +} + +void +EndDeviceLorawanMac::GetNwkKey(uint8_t nwkKey[16]) const +{ + unsigned int i; + + for (i = 0;i < 16;i++) + { + nwkKey[i] = m_nwkKey[i]; + } + + return; +} + +void +EndDeviceLorawanMac::SetJoinEUI(uint8_t joinEUI[8]) +{ + unsigned int i; + + for (i = 0;i < 8;i++) + { + m_joinEUI[i] = joinEUI[i]; + } + + return; +} + +void +EndDeviceLorawanMac::GetJoinEUI(uint8_t joinEUI[8]) const +{ + unsigned int i; + + for (i = 0;i < 8;i++) + { + joinEUI[i] = m_joinEUI[i]; + } + + return; +} + +void +EndDeviceLorawanMac::SetJoinNonce(uint32_t joinNonce) +{ + /* three bytes long and should be at least one to be in the network */ + if (joinNonce > 0 && joinNonce < 0x01000000) + { + m_joinNonce = joinNonce; + } + + return; +} + +uint32_t +EndDeviceLorawanMac::GetJoinNonce(void) const +{ + return m_joinNonce; +} + +void +EndDeviceLorawanMac::SetDevNonce(uint16_t devNonce) +{ + if (devNonce > 0) + { + m_devNonce = devNonce; + } + + return; +} + +uint16_t +EndDeviceLorawanMac::GetDevNonce(void) const +{ + return m_devNonce; +} + +bool +EndDeviceLorawanMac::IsVersion1(void) const +{ + return m_isVersion1; +} + +void +EndDeviceLorawanMac::SetIsVersion1(bool isVersion1) +{ + m_isVersion1 = isVersion1; + return; +} + } } diff --git a/model/end-device-lorawan-mac.h b/model/end-device-lorawan-mac.h index a013a6a1a4..435fb7a502 100644 --- a/model/end-device-lorawan-mac.h +++ b/model/end-device-lorawan-mac.h @@ -27,13 +27,14 @@ #include "ns3/lorawan-mac.h" #include "ns3/lorawan-mac-header.h" #include "ns3/lora-frame-header.h" +#include "ns3/lorawan-mic-trailer.h" #include "ns3/random-variable-stream.h" #include "ns3/lora-device-address.h" #include "ns3/traced-value.h" namespace ns3 { namespace lorawan { - + /** * Class representing the MAC layer of a LoRaWAN device. */ @@ -217,6 +218,11 @@ class EndDeviceLorawanMac : public LorawanMac */ void ApplyNecessaryOptions (LorawanMacHeader &macHeader); + /** + * Add the necessary options and to the LorawanMICTrailer. + */ + void ApplyNecessaryOptions (LorawanMICTrailer& micTrlr, uint8_t *msg, uint8_t len); + /** * Set the message type to send when the Send method is called. */ @@ -331,6 +337,76 @@ class EndDeviceLorawanMac : public LorawanMac */ void AddMacCommand (Ptr macCommand); + /** + * Sets the JoinNonce value stored on this end device + * + * \param joinNonce the new JoinNonce value being set + */ + void SetJoinNonce(uint32_t joinNonce); + + /** + * Gets the JoinNonce value stored on this end device + * + * \return the currently stored JoinNonce value + */ + uint32_t GetJoinNonce(void) const; + + /** + * Sets the DevNonce value stored in this end device + * + * \param devNonce the new DevNonce value being set + */ + void SetDevNonce(uint16_t devNonce); + + /** + * Gets the DevNonce value stored in this device + * + * \return the currently stored devNonce value + */ + uint16_t GetDevNonce(void) const; + + /** + * Sets the NwkKey stored on this end device + * + * \param nwkKey the new 128-bit network key + */ + void SetNwkKey(uint8_t nwkKey[16]); + + /** + * Gets the NwkKey stored on this device + * + * \param nwkKey container to copy the currently stored NwkKey in this device to + */ + void GetNwkKey(uint8_t nwkKey[16]) const; + + /** + * Sets the JoinEUI stored on this end device + * + * \param joinEUI the new JoinEUI to be used by this device + */ + void SetJoinEUI(uint8_t joinEUI[8]); + + /** + * Gets the JoinEUI stored in this end device + * + * \param joinEUI container to JOinEUI stored on this device to + */ + void GetJoinEUI(uint8_t joinEUI[8]) const; + + /** + * Whether the version the LoRaWAN network this device is apart of is v1.0 or not + * + * \return true if v1.0, false if not + */ + bool IsVersion1(void) const; + + /** + * Set whether the LoRaWAN version of the network is v1.0 or not + * + * \param isVersion1 whether the version of the network is v1.0 or not + */ + void SetIsVersion1(bool isVersion1); + protected: /** * Structure representing the parameters that will be used in the @@ -390,7 +466,7 @@ class EndDeviceLorawanMac : public LorawanMac * ones that are available in the ED's LogicalLoraChannel, based on their duty * cycle limitations. */ - Ptr GetChannelForTx (void); + uint8_t GetChannelForTx (void); /** * The duration of a receive window in number of symbols. This should be @@ -419,7 +495,11 @@ class EndDeviceLorawanMac : public LorawanMac * the channel list. */ Ptr m_uniformRV; - + + Ptr m_txCh; + + uint8_t m_txChIndex; + ///////////////// // Callbacks // ///////////////// @@ -492,6 +572,17 @@ class EndDeviceLorawanMac : public LorawanMac LorawanMacHeader::MType m_mType; uint16_t m_currentFCnt; + + /* join accept count - should be 3 bytes long */ + uint32_t m_joinNonce; + + /* join request count */ + uint16_t m_devNonce; + + uint8_t m_nwkKey[16]; + uint8_t m_joinEUI[8]; + + bool m_isVersion1; /* whether or not the network server version is v1.0 or not */ }; diff --git a/model/end-device-status.h b/model/end-device-status.h index f6d15bc136..62bf7a9859 100644 --- a/model/end-device-status.h +++ b/model/end-device-status.h @@ -28,12 +28,11 @@ #include "ns3/class-a-end-device-lorawan-mac.h" #include "ns3/lora-frame-header.h" #include "ns3/pointer.h" -#include "ns3/lora-frame-header.h" #include namespace ns3 { namespace lorawan { - + /** * This class represents the Network Server's knowledge about an End Device in * the LoRaWAN network it is administering. diff --git a/model/lorawan-mic-trailer.cc b/model/lorawan-mic-trailer.cc new file mode 100644 index 0000000000..6fc947093d --- /dev/null +++ b/model/lorawan-mic-trailer.cc @@ -0,0 +1,655 @@ +#include "lorawan-mic-trailer.h" +#include "ns3/log.h" + +namespace ns3{ +namespace lorawan{ + +NS_LOG_COMPONENT_DEFINE ("LorawanMICTrailer"); + +LorawanMICTrailer::LorawanMICTrailer () +{ +} + +LorawanMICTrailer::~LorawanMICTrailer () +{ +} + +TypeId +LorawanMICTrailer::GetTypeId (void) +{ + static TypeId tid = TypeId ("LorawanMICTrailer") + .SetParent () + .AddConstructor () + ; + + return tid; +} + +TypeId +LorawanMICTrailer::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t +LorawanMICTrailer::GetSerializedSize (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + + return 4; +} + +void +LorawanMICTrailer::Serialize (Buffer::Iterator start) const +{ + NS_LOG_FUNCTION_NOARGS (); + + /* move iterator to start of trailer before writing */ + start.Prev(GetSerializedSize ()); + + start.WriteU32 (m_mic); + + return; +} + +uint32_t +LorawanMICTrailer::Deserialize (Buffer::Iterator end) +{ + uint32_t trailer_data; + + NS_LOG_FUNCTION_NOARGS (); + + /* move iterator to start of trailer before reading */ + end.Prev(GetSerializedSize ()); + + trailer_data = end.ReadU32 (); + + m_mic = trailer_data; + + return GetSerializedSize (); +} + +void +LorawanMICTrailer::Print (std::ostream &os) const +{ + NS_LOG_FUNCTION_NOARGS (); + + os << "MIC=" << m_mic << std::endl; + + return; +} + +void +LorawanMICTrailer::SetMIC (uint32_t newMIC) +{ + NS_LOG_FUNCTION_NOARGS (); + + m_mic = newMIC; + + return; +} + +uint32_t +LorawanMICTrailer::GetMIC (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + + return m_mic; +} + +void +LorawanMICTrailer::leftshift_1bit (uint8_t in[16], uint8_t out[16]) +{ + int i; + uint8_t overflow; /* from byte to the right */ + + for (i = 15, overflow = 0;i >= 0;i--) + { + out[i] = in[i] << 1; + out[i] |= overflow; + overflow = (in[i] & 0x80)?1:0; + } + + return; +} + +void +LorawanMICTrailer::xor_128 (uint8_t in1[16], uint8_t in2[16], uint8_t out[16]) +{ + unsigned int i; + + for (i = 0;i < 16;i++) + { + out[i] = in1[i] ^ in2[i]; + } + + return; +} + +void +LorawanMICTrailer::aes128_cmac_generate_subkeys (uint8_t K[16], uint8_t K1[16], uint8_t K2[16]) +{ + uint8_t tmp[16]; + uint8_t L[16]; + uint8_t Rb[16]; + unsigned int i; + + for (i = 0;i < 16;i++) + { + tmp[i] = 0; + Rb[i] = 0; + } + + Rb[15] = 0x87; + + aes128 (K, tmp, L); + + if ((L[0] & 0x80) == 0) /* MSB of L */ + { + leftshift_1bit (L, K1); + } + else + { + leftshift_1bit (L, tmp); + xor_128 (tmp, Rb, K1); + } + + if ((K1[0] & 0x80) == 0) + { + leftshift_1bit (K1, K2); + } + else + { + leftshift_1bit(K1, tmp); + xor_128 (tmp, Rb, K2); + } + + return; +} + +void +LorawanMICTrailer::padding_128 (uint8_t *in, uint8_t out[16], unsigned int length) +{ + unsigned int i; + + for (i = 0;i < 16;i++) + { + if (i < length) + { + out[i] = in[i]; + } + else if (i == length) + { + /* first byte to pad */ + out[i] = 0x80; + } + else + { + out[i] = 0x00; + } + } + + return; +} + +void +LorawanMICTrailer::aes128 (uint8_t K[16], uint8_t M[16], uint8_t O[16]) +{ + const uint8_t Nr = 10; /* number of rounds 10 for 128bit key */ + //const uint8_t Nb = 4; + uint8_t state[4][4]; + uint8_t w[44][4]; + unsigned int i, j; + + /* taken from NIST publication for AES: https://www.nist.gov/publications/advanced-encryption-standard-aes*/ + const uint8_t sbox[16][16] = { + {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76}, + {0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0}, + {0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15}, + {0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75}, + {0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84}, + {0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf}, + {0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8}, + {0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2}, + {0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73}, + {0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb}, + {0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79}, + {0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08}, + {0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a}, + {0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e}, + {0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf}, + {0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16} + }; + + aes128_keyexpansion(K, w, sbox); + + /* move input into state matrix */ + for (i = 0;i < 4;i++) + { + for (j = 0;j < 4;j++) + { + state[j][i] = M[(4 * i) + j]; + } + } + + /* cipher algorithm */ + aes128_addroundkeys(state, w, 0); + + for (i = 1;i < Nr;i++) + { + aes128_subbytes(state, sbox); + aes128_shiftrows(state); + aes128_mixcolumns(state); + aes128_addroundkeys(state, w, i); + } + + aes128_subbytes(state, sbox); + aes128_shiftrows(state); + aes128_addroundkeys(state, w, Nr); + + /* move state matrix to output */ + for (i = 0;i < 4;i++) + { + for (j = 0;j < 4;j++) + { + O[(4 * i) + j] = state[j][i]; + } + } + + return; +} + +void +LorawanMICTrailer::aes128_subbytes (uint8_t state[4][4], const uint8_t sbox[16][16]) +{ + unsigned int i, j, row, col; + + + for (i = 0;i < 4;i++) + { + for (j = 0;j < 4;j++) + { + col = state[i][j] & 0x0f; /* lower 4 bits */ + row = state[i][j] >> 4; /* upper 4 bits */ + + /* update state val */ + state[i][j] = sbox[row][col]; + } + } + + return; +} + +void +LorawanMICTrailer::aes128_shiftrows (uint8_t state[4][4]) +{ + unsigned int i; + uint8_t temp; + + /* first row doesn't shift */ + + /* second row: shift bytes left once*/ + temp = state[1][0]; + + for (i = 0;i < 3;i++) + { + state[1][i] = state[1][i + 1]; + } + + state[1][3] = temp; + + /* third row: shift bytes left twice -> swap bytes two spaces apart */ + + for (i = 0;i < 2;i++) + { + temp = state[2][i]; + state[2][i] = state[2][i + 2]; + state[2][i + 2] = temp; + } + + /* fourth row: shift bytes left thrice -> shift left once */ + temp = state[3][3]; + + for (i = 3;i > 0;i--) + { + state[3][i] = state[3][i - 1]; + } + + state[3][0] = temp; + + return; +} + +void +LorawanMICTrailer::aes128_mixcolumns (uint8_t state[4][4]) +{ + unsigned int i, j; + uint8_t temp[4]; + + for (i = 0;i < 4;i++) + { + for (j = 0;j < 4;j++) + { + temp[j] = gfmul (state[j][i], 0x02) ^ gfmul (state[(j + 1) % 4][i], 0x03) ^ state[(j + 2) % 4][i] ^ state[(j + 3) % 4][i]; + } + + /* update col */ + for (j = 0;j < 4;j++) + { + state[j][i] = temp[j]; + } + } + + return; +} + +uint8_t +LorawanMICTrailer::gfmul (uint8_t x, uint8_t y) +{ + uint16_t mulres, x16; + unsigned int i; + + /* cycle through bits and xor */ + for (i = 0, mulres = 0, x16 = x;i < 8;i++) + { + if (y & 0x01) /* check rightmost bit */ + { + mulres ^= (x16 << i); + } + + y >>= 1; + } + + /* modulo result with x^8 + x^4 + x^3 + x + 1 */ + for (i = 0;i < 8;i++) + { + if (mulres & (0x8000 >> i)) + { + mulres ^= (((mulres & (0x8000 >> i)) >> 8) * 0x001b); + } + } + + return (uint8_t)(mulres & 0x00ff); /* return rightmost byte */ +} + +void +LorawanMICTrailer::aes128_keyexpansion (uint8_t K[16], uint8_t w[44][4], const uint8_t sbox[16][16]) +{ + unsigned int i, j; + uint8_t temp[4]; + + const uint8_t rcon[11][4] = { + {0x8d, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00}, + {0x02, 0x00, 0x00, 0x00}, + {0x04, 0x00, 0x00, 0x00}, + {0x08, 0x00, 0x00, 0x00}, + {0x10, 0x00, 0x00, 0x00}, + {0x20, 0x00, 0x00, 0x00}, + {0x40, 0x00, 0x00, 0x00}, + {0x80, 0x00, 0x00, 0x00}, + {0x1b, 0x00, 0x00, 0x00}, + {0x36, 0x00, 0x00, 0x00} + }; + + for (i = 0;i < 4;i++) + { + for (j = 0;j < 4;j++) + { + w[i][j] = K[(i * 4) + j]; + } + } + + for (i = 4;i < 44;i++) + { + for (j = 0;j < 4;j++) + { + temp[j] = w[i - 1][j]; + } + + if (i % 4 == 0) + { + rotword (temp); + subword (temp, sbox); + + for (j = 0;j < 4;j++) + { + temp[j] ^= rcon[i / 4][j]; + } + } + /* condition in original algorithm for Nk > 6 not included as Nk = 4 for aes128 */ + + for (j = 0;j < 4;j++) + { + w[i][j] = w[i - 4][j] ^ temp[j]; + } + } + + return; +} + +void +LorawanMICTrailer::aes128_addroundkeys (uint8_t state[4][4], uint8_t w[44][4], unsigned int round) +{ + unsigned int i, j; + + for (i = 0;i < 4;i++) + { + for (j = 0;j < 4;j++) + { + state[j][i] ^= w[(4 * round) + i][j]; + } + } + + return; +} + +void +LorawanMICTrailer::rotword (uint8_t word[4]) +{ + uint8_t temp; + unsigned int i; + + /* shift bytes left once */ + temp = word[0]; + + for (i = 0;i < 3;i++) + { + word[i] = word[i + 1]; + } + + word[3] = temp; + + return; +} + +void +LorawanMICTrailer::subword (uint8_t word[4], const uint8_t sbox[16][16]) +{ + uint8_t row, col, i; + + for (i = 0;i < 4;i++) + { + col = word[i] & 0x0f; + row = word[i] >> 4; + + word[i] = sbox[row][col]; + } + + return; +} + +uint32_t +LorawanMICTrailer::aes128_cmac_4 (uint8_t xNwkSIntKey[16], uint8_t *Bx_msg, uint8_t len) +{ + uint8_t Mlast[16], padded[16], X[16], Y[16]; + uint8_t K1[16], K2[16]; + unsigned int i, n; + bool flag; + uint32_t mic; + + aes128_cmac_generate_subkeys (xNwkSIntKey, K1, K2); + + n = (len + 15) / 16; + + if (n == 0) + { + n = 1; + flag = false; + } + else if (len % 16 == 0) + { + flag = true; + } + else + { + flag = false; + } + + /* handle last block */ + if (flag == true) + { + xor_128 (&(Bx_msg[16 * (n - 1)]), K1, Mlast); + } + else + { + padding_128 (&(Bx_msg[16 * (n - 1)]), padded, len % 16); + xor_128 (padded, K2, Mlast); + } + + for (i = 0;i < 16;i++) + { + X[i] = 0; + } + + for (i = 0;i < (n - 1);i++) + { + xor_128 (X, &(Bx_msg[16 * i]), Y); + aes128 (xNwkSIntKey, Y, X); + } + + xor_128 (X, Mlast, Y); + aes128 (xNwkSIntKey, Y, X); + + /* mic is first 4 octets of entire code */ + + for (i = 0, mic = 0;i < 4;i++) + { + mic |= X[i]; + mic <<= 8; + } + + return mic; +} + +uint32_t +LorawanMICTrailer::CalcMIC (uint8_t msgLen, uint8_t *msg, uint8_t B0[16], uint8_t xNwkSIntKey[16]) +{ + uint8_t B0_msg[msgLen + 16]; + uint32_t mic; + unsigned int j; + + /* concatenate Bx and msg */ + + for (j = 0;j < 16;j++) + { + B0_msg[j] = B0[j]; + } + + for (j = 0;j < msgLen;j++) + { + B0_msg[j + 16] = msg[j]; + } + + mic = aes128_cmac_4(xNwkSIntKey, B0_msg, msgLen + (uint8_t)16); + + return mic; +} + +/* for LoRaWAN 1.1 Network Servers UL MIC */ +uint32_t +LorawanMICTrailer::CalcMIC_1_1_UL (uint8_t msgLen, uint8_t *msg, uint8_t B0[16], uint8_t B1[16], uint8_t SNwkSIntKey[16], uint8_t FNwkSIntKey[16]) +{ + uint32_t mic_f, mic_s, mic; + + mic_f = CalcMIC (msgLen, msg, B0, FNwkSIntKey); + mic_s = CalcMIC (msgLen, msg, B1, SNwkSIntKey); + + mic = 0; + mic |= (mic_s & 0xffff0000); /* first two bytes of each */ + mic |= ((mic_f & 0xffff0000) >> 16); + + return mic; +} + +void +LorawanMICTrailer::GenerateB0DL (uint8_t B0[16], uint16_t ConfFCnt, uint32_t DevAddr, uint32_t xFCntDwn, uint8_t msgLen) +{ + B0[0] = 0x49; + B0[1] = (uint8_t)(ConfFCnt >> 8); + B0[2] = (uint8_t)(ConfFCnt & 0x00ff); + B0[3] = 0x00; + B0[4] = 0x00; + B0[5] = 0x01; + B0[6] = (uint8_t)(DevAddr >> 24); + B0[7] = (uint8_t)((DevAddr & 0x00ff0000) >> 16); + B0[8] = (uint8_t)((DevAddr & 0x0000ff00) >> 8); + B0[9] = (uint8_t)(DevAddr & 0x000000ff); + B0[10] = (uint8_t)(xFCntDwn >> 24); + B0[11] = (uint8_t)((xFCntDwn & 0x00ff0000) >> 16); + B0[12] = (uint8_t)((xFCntDwn & 0x0000ff00) >> 8); + B0[13] = (uint8_t)(xFCntDwn & 0x000000ff); + B0[14] = 0x00; + B0[15] = msgLen; + + return; +} + +void +LorawanMICTrailer::GenerateB0UL (uint8_t B0[16], uint32_t DevAddr, uint32_t FCntUp, uint8_t msgLen) +{ + B0[0] = 0x49; + B0[1] = 0x00; + B0[2] = 0x00; + B0[3] = 0x00; + B0[4] = 0x00; + B0[5] = 0x00; + B0[6] = (uint8_t)(DevAddr >> 24); + B0[7] = (uint8_t)((DevAddr & 0x00ff0000) >> 16); + B0[8] = (uint8_t)((DevAddr & 0x0000ff00) >> 8); + B0[9] = (uint8_t)(DevAddr & 0x000000ff); + B0[10] = (uint8_t)(FCntUp >> 24); + B0[11] = (uint8_t)((FCntUp & 0x00ff0000) >> 16); + B0[12] = (uint8_t)((FCntUp & 0x0000ff00) >> 8); + B0[13] = (uint8_t)(FCntUp & 0x000000ff); + B0[14] = 0x00; + B0[15] = msgLen; + + return; +} + +void +LorawanMICTrailer::GenerateB1UL (uint8_t B1[16], uint16_t ConfFCnt, uint8_t TxDr, uint8_t TxCh, uint32_t DevAddr, uint32_t FCntUp, uint8_t msgLen) +{ + B1[0] = 0x49; + B1[1] = (uint8_t)(ConfFCnt >> 8); + B1[2] = (uint8_t)(ConfFCnt & 0x00ff); + B1[3] = TxDr; + B1[4] = TxCh; + B1[5] = 0x00; + B1[6] = (uint8_t)(DevAddr >> 24); + B1[7] = (uint8_t)((DevAddr & 0x00ff0000) >> 16); + B1[8] = (uint8_t)((DevAddr & 0x0000ff00) >> 8); + B1[9] = (uint8_t)(DevAddr & 0x000000ff); + B1[10] = (uint8_t)(FCntUp >> 24); + B1[11] = (uint8_t)((FCntUp & 0x00ff0000) >> 16); + B1[12] = (uint8_t)((FCntUp & 0x0000ff00) >> 8); + B1[13] = (uint8_t)(FCntUp & 0x000000ff); + B1[14] = 0x00; + B1[15] = msgLen; + + return; +} + +} +} diff --git a/model/lorawan-mic-trailer.h b/model/lorawan-mic-trailer.h new file mode 100644 index 0000000000..a1fc060766 --- /dev/null +++ b/model/lorawan-mic-trailer.h @@ -0,0 +1,184 @@ +#ifndef __LORAWAN_MIC_TRAILER__ +#define __LORAWAN_MIC_TRAILER__ + +#include "ns3/trailer.h" + +namespace ns3 { +namespace lorawan { + +/** + * Class used to hold and manage the Message Integrity Code (MIC) trailer + * of a LoRaWAN packet + */ + +class LorawanMICTrailer : public Trailer +{ +public: + + LorawanMICTrailer (); + ~LorawanMICTrailer (); + + /* required funcs for trailer*/ + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const ; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator end); + virtual void Print (std::ostream &os) const; + + /** + * Performs AES-128 to encrypt data + * + * \param K the 128-bit key to be used for encryption + * \param M the 128-bit message to be encrypted + * \param O the 128-bit container passed to hold the encrypted output + */ + void aes128 (uint8_t K[16], uint8_t M[16], uint8_t O[16]); + + /** + * Gets the currently stored MIC + * + * \return the 4-byte MIC currently stored in the trailer + */ + uint32_t GetMIC (void) const; + + /** + * Sets the MIC being used in the trailer + * + * \param newMIC the new MIC value to be used by the trailer + */ + void SetMIC (uint32_t newMIC); + + /** + * Calculates a MIC for DL and v1.0 LoRaWAN network UL packets + * + * \param msgLen the length (in bytes) of the "msg" parameter + * \param msg the message being sent in the packet for which the MIC is to be attached to + * \param B0 the B0 (128-bit) MIC computation block (See Figures 18 (DL) and 19 (UL) + * in LoRaWAN specification) + * \param xNwkSIntKey either the SNwkSIntKey (DL) or FNwkSIntKey (UL) 128-bit keys + * generated for this device + */ + uint32_t CalcMIC (uint8_t msgLen, uint8_t *msg, uint8_t B0[16], uint8_t xNwkSIntKey[16]); + + /** + * Calculates a MIC for v1.1 LoRaWAN networks UL packets + * + * \param msgLen the length in bytes of the "msg" parameter + * \param msg the message being sent in the packet for which the MIC is to be attached to + * \param B0 the UL B0 (128-bit) MIC computation block (See Figure 19 in LoRaWAN specification) + * \param B1 the UL B1 (128-bit) MIC computation block (See Figure 20 in LoRaWAN specification) + * \param SNwkSIntKey Serving Network session integrity 128-bit key + * \param FNwkSIntKey Forwarding Network session integrity 128-bit key + * + * \return the 4-byte MIC used for the packet trailer + */ + uint32_t CalcMIC_1_1_UL(uint8_t msgLen, uint8_t *msg, uint8_t B0[16], uint8_t B1[16], + uint8_t SNwkSIntKey[16], uint8_t FNwkSIntKey[16]); + + /** + * Used to verify the MIC currently stored in the trailer against that of a newly calculated one + * based on the parameters provided (for DL and v1.0 UL) + * + * \param msgLen the length (in bytes) of the "msg" parameter + * \param msg the message being sent in the packet for which the MIC is to be attached to + * \param B0 the B0 (128-bit) MIC computation block (See Figures 18 (DL) and 19 (UL) + * in LoRaWAN specification) + * \param xNwkSIntKey either the SNwkSIntKey (DL) or FNwkSIntKey (UL) 128-bit keys + * generated for this device + * + * \return whether the MIC calculated matches the one stored in the trailer or not + */ + bool VerifyMIC (uint8_t msgLen, uint8_t *msg, uint8_t B0[16], uint8_t xNwkSIntKey[16]); + + /** + * Used to verify the MIC currently stored in the trailer against that of a newly calculated one + * based on the parameters provided (for v1.1 UL) + * + * \param msgLen the length in bytes of the "msg" parameter + * \param msg the message being sent in the packet for which the MIC is to be attached to + * \param B0 the UL B0 (128-bit) MIC computation block (See Figure 19 in LoRaWAN specification) + * \param B1 the UL B1 (128-bit) MIC computation block (See Figure 20 in LoRaWAN specification) + * \param SNwkSIntKey Serving Network session integrity 128-bit key + * \param FNwkSIntKey Forwarding Network session integrity 128-bit key + * + * \return whether the MIC calculated matches the one stored in the trailer or not + */ + bool VerifyMIC_1_1_UL (uint8_t msgLen, uint8_t *msg, uint8_t B0[16], uint8_t B1[16], + uint8_t SNwkSIntKey[16], uint8_t FNwkSIntKey[16]); + + /** + * Generates the DL B0 computation block (See Figure 18 in LoRaWAN specification) needed for + * MIC calaculation + * + * \param B0 the container for storing the 128-bit B0 block once calculated + * \param ConfFCnt If the device is connected to a LoRaWAN1.1 Network Server and the + * ACK bit of the downlink frame is set, meaning this frame is + * acknowledging an uplink “confirmed” frame, then ConfFCnt is the frame + * counter value modulo 2^16 of the “confirmed” uplink frame that is + * being acknowledged. In all other cases ConfFCnt = 0x0000 + * \param DevAddr the end-device address + * \param xFCntDwn either AFCntDown or NFCntDown + * \param msgLen the length of the message being sent in the packet for which the + * MIC is to be attached to + */ + void GenerateB0DL (uint8_t B0[16], uint16_t ConfFCnt, uint32_t DevAddr, uint32_t xFCntDwn, uint8_t msgLen); + + /** + * Generates the UL B0 computation block (See Figure 19 in LoRaWAN specification) needed for + * MIC calaculation + * + * \param B0 the container for storing the 128-bit B0 block once calculated + * \param DevAddr the end-device address + * \param FCntUp current UL frame counter value + * \param msgLen the length of the message being sent in the packet for which the + * MIC is to be attached to + */ + void GenerateB0UL (uint8_t B0[16], uint32_t DevAddr, uint32_t FCntUp, uint8_t msgLen); + + /** + * Generates the UL B1 computation block (See Figure 20 in LoRaWAN specification) needed for + * MIC calaculation + * + * \param B1 the container for storing the 128-bit B1 block once calculated + * \param ConfFCnt If the ACK bit of the uplink frame is set, meaning this frame is + * acknowledging a downlink “confirmed” frame, then ConfFCnt is + * the frame counter value modulo 2^16 of the “confirmed” downlink + * frame that is being acknowledged. In all other cases ConfFCnt = 0x0000 + * \param TxDr the data rate that will be used for the UL transmission + * \param TxCh the index of the channel being used + * \param DevAddr the end-device address + * \param FCntUp current UL frame coutner value + * \param msgLen the length of the message being sent in the packet for which the + * MIC is to be attached to + * + */ + void GenerateB1UL (uint8_t B1[16], uint16_t ConfFCnt, uint8_t TxDr, uint8_t TxCh, + uint32_t DevAddr, uint32_t FCntUp, uint8_t msgLen); + +private: + uint32_t m_mic; /* the 4 byte mic */ + + /* AES-CMAC funcs (taken from RFC4493) */ + uint32_t aes128_cmac_4 (uint8_t xNwkSIntKey[16], uint8_t *Bx_msg, uint8_t msgLen); /* returns first 4 byte of cmac AKA the MIC */ + void aes128_cmac_generate_subkeys (uint8_t K[16], uint8_t K0[16], uint8_t K1[16]); + void leftshift_1bit (uint8_t in[16], uint8_t out[16]); + void xor_128 (uint8_t in1[16], uint8_t in2[16], uint8_t out[16]); + void padding_128 (uint8_t *in, uint8_t out[16], unsigned int length); + + /* AES-128 funcs taken from NIST publication */ + void aes128_subbytes (uint8_t state[4][4], const uint8_t sbox[16][16]); + void aes128_shiftrows (uint8_t state[4][4]); + void aes128_mixcolumns (uint8_t state[4][4]); + void aes128_addroundkeys (uint8_t state[4][4], uint8_t w[44][4], unsigned int round); + void aes128_keyexpansion(uint8_t K[16], uint8_t w[44][4], const uint8_t sbox[16][16]); + uint8_t gfmul (uint8_t x, uint8_t y); /* GF(2^8) multiplication */ + void rotword (uint8_t word[4]); + void subword (uint8_t word[4], const uint8_t sbox[16][16]); + +}; + +} +} + +#endif /* __LORAWAN_MIC_TRAILER__ */ diff --git a/model/network-controller.h b/model/network-controller.h index 7e7ee3e9ab..09cb17db80 100644 --- a/model/network-controller.h +++ b/model/network-controller.h @@ -25,6 +25,7 @@ #include "ns3/packet.h" #include "ns3/network-status.h" #include "ns3/network-controller-components.h" +#include "ns3/end-device-status.h" namespace ns3 { namespace lorawan { diff --git a/model/network-server.cc b/model/network-server.cc index c3150ff4f1..a8d61526b4 100644 --- a/model/network-server.cc +++ b/model/network-server.cc @@ -145,6 +145,8 @@ NetworkServer::AddNode (Ptr node) Ptr edLorawanMac = loraNetDevice->GetMac ()->GetObject (); + //edLorawanMac->SetNwkServer(this); + // Update the NetworkStatus about the existence of this node m_status->AddNode (edLorawanMac); } diff --git a/model/network-server.h b/model/network-server.h index 3610d4a364..169f6a05af 100644 --- a/model/network-server.h +++ b/model/network-server.h @@ -38,7 +38,7 @@ namespace ns3 { namespace lorawan { - + /** * The NetworkServer is an application standing on top of a node equipped with * links that connect it with the gateways. diff --git a/model/network-status.h b/model/network-status.h index 600559d602..ddcf509876 100644 --- a/model/network-status.h +++ b/model/network-status.h @@ -32,7 +32,7 @@ namespace ns3 { namespace lorawan { - + /** * This class represents the knowledge about the state of the network that is * available at the Network Server. It is essentially a collection of two maps: diff --git a/wscript b/wscript index e1c1e78ff7..6b16e7b090 100644 --- a/wscript +++ b/wscript @@ -34,6 +34,7 @@ def build(bld): 'model/forwarder.cc', 'model/lorawan-mac-header.cc', 'model/lora-frame-header.cc', + 'model/lorawan-mic-trailer.cc', 'model/mac-command.cc', 'model/lora-device-address.cc', 'model/lora-device-address-generator.cc', @@ -95,6 +96,7 @@ def build(bld): 'model/forwarder.h', 'model/lorawan-mac-header.h', 'model/lora-frame-header.h', + 'model/lorawan-mic-trailer.h', 'model/mac-command.h', 'model/lora-device-address.h', 'model/lora-device-address-generator.h',