Documentation ¶
Overview ¶
Package lorawan provides structures and tools to read and write LoraWAN messages from and to a slice of bytes.
The following structures are implemented (+ fields):
- PHYPayload (MHDR | MACPayload | MIC)
- MACPayload (FHDR | FPort | FRMPayload)
- FHDR (DevAddr | FCtrl | FCnt | FOpts)
The Following message types (MType) are implemented:
- JoinRequest
- JoinAccept
- UnconfirmedDataUp
- UnconfirmedDataDown
- ConfirmedDataUp
- ConfirmedDataDown
- Proprietary
The following MAC commands (and their optional payloads) are implemented:
- LinkCheckReq
- LinkCheckAns
- LinkADRReq
- LinkADRAns
- DutyCycleReq
- DutyCycleAns
- RXParamSetupReq
- RXParamSetupAns
- DevStatusReq
- DevStatusAns
- NewChannelReq
- NewChannelAns
- RXTimingSetupReq
- RXTimingSetupAns
- Support for proprietary commands (0x80 - 0xFF) will be implemented in the future (mapping between CID and payload (size) is already done in a map called macPayloadRegistry)
Support for calculating and setting the MIC is done by calling SetMIC():
err := phyPayload.SetMIC(key)
Validating the MIC is done by calling ValidateMIC():
valid, err := phyPayload.ValidateMIC(key)
Encryption and decryption of the MACPayload (for join-accept) is done by calling EncryptJoinAcceptPayload() and DecryptJoinAcceptPayload(). Note that you need to call SetMIC BEFORE encryption.
err := phyPayload.EncryptJoinAcceptPayload(key) err := phyPayload.DecryptJoinAcceptPayload(key)
Encryption and decryption of the FRMPayload is done by calling EncryptFRMPayload() and DecryptFRMPayload(). After encryption (and thus before decryption), the bytes are stored in the DataPayload struct.
err := phyPayload.EncryptFRMPayload(key) err := phyPayload.DecryptFRMPayload(key)
All payloads implement the Payload interface. Based on the MIC value, you should be able to know to which type to cast the Payload value, so you will be able to access its fields.
See the examples section of the documentation for concrete usage examples of this package.
When using this package, knowledge about the LoRaWAN specification is needed. You can download the LoRaWAN specification here: https://www.lora-alliance.org/For-Developers/LoRaWANDevelopers
Index ¶
- Constants
- func EncryptFRMPayload(key AES128Key, uplink bool, devAddr DevAddr, fCnt uint32, data []byte) ([]byte, error)
- type AES128Key
- type CFList
- type ChMask
- type DLsettings
- type DataPayload
- type DevAddr
- func (a DevAddr) MarshalBinary() ([]byte, error)
- func (a DevAddr) MarshalText() ([]byte, error)
- func (a DevAddr) NwkID() byte
- func (a *DevAddr) Scan(src interface{}) error
- func (a DevAddr) String() string
- func (a *DevAddr) UnmarshalBinary(data []byte) error
- func (a *DevAddr) UnmarshalText(text []byte) error
- type DevStatusAnsPayload
- type DutyCycleReqPayload
- type EUI64
- type FCtrl
- type FHDR
- type JoinAcceptPayload
- type JoinRequestPayload
- type LinkADRAnsPayload
- type LinkADRReqPayload
- type LinkCheckAnsPayload
- type MACCommand
- type MACCommandPayload
- type MACPayload
- type MHDR
- type MType
- type Major
- type NetID
- type NewChannelAnsPayload
- type NewChannelReqPayload
- type PHYPayload
- func (p *PHYPayload) DecryptFRMPayload(key AES128Key) error
- func (p *PHYPayload) DecryptJoinAcceptPayload(appKey AES128Key) error
- func (p *PHYPayload) EncryptFRMPayload(key AES128Key) error
- func (p *PHYPayload) EncryptJoinAcceptPayload(appKey AES128Key) error
- func (p PHYPayload) MarshalBinary() ([]byte, error)
- func (p PHYPayload) MarshalText() ([]byte, error)
- func (p *PHYPayload) SetMIC(key AES128Key) error
- func (p *PHYPayload) UnmarshalBinary(data []byte) error
- func (p *PHYPayload) UnmarshalText(text []byte) error
- func (p PHYPayload) ValidateMIC(key AES128Key) (bool, error)
- type Payload
- type RX2SetupAnsPayload
- type RX2SetupReqPayload
- type RXTimingSetupReqPayload
- type Redundancy
Examples ¶
Constants ¶
const ( LinkCheckReq cid = 0x02 LinkCheckAns cid = 0x02 LinkADRReq cid = 0x03 LinkADRAns cid = 0x03 DutyCycleReq cid = 0x04 DutyCycleAns cid = 0x04 RXParamSetupReq cid = 0x05 RXParamSetupAns cid = 0x05 DevStatusReq cid = 0x06 DevStatusAns cid = 0x06 NewChannelReq cid = 0x07 NewChannelAns cid = 0x07 RXTimingSetupReq cid = 0x08 RXTimingSetupAns cid = 0x08 )
MAC commands as specified by the LoRaWAN R1.0 specs. Note that each *Req / *Ans has the same value. Based on the fact if a message is uplink or downlink you should use on or the other.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type AES128Key ¶
type AES128Key [16]byte
AES128Key represents a 128 bit AES key.
func (AES128Key) MarshalText ¶
MarshalText implements encoding.TextMarshaler.
func (*AES128Key) UnmarshalText ¶
UnmarshalText implements encoding.TextUnmarshaler.
type CFList ¶
type CFList [5]uint32
CFList represents a list of channel frequencies. Each frequency is in Hz and must be multiple of 100, (since the frequency will be divided by 100 on encoding), the max allowed value is 2^24-1 * 100.
func (CFList) MarshalBinary ¶
MarshalBinary marshals the object in binary form.
func (*CFList) UnmarshalBinary ¶
UnmarshalBinary decodes the object from binary form.
type ChMask ¶
type ChMask [16]bool
ChMask encodes the channels usable for uplink access. 0 = channel 1, 15 = channel 16.
func (ChMask) MarshalBinary ¶
MarshalBinary marshals the object in binary form.
func (*ChMask) UnmarshalBinary ¶
UnmarshalBinary decodes the object from binary form.
type DLsettings ¶
DLsettings represents the DLsettings fields (downlink settings).
func (DLsettings) MarshalBinary ¶
func (s DLsettings) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*DLsettings) UnmarshalBinary ¶
func (s *DLsettings) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type DataPayload ¶
type DataPayload struct {
Bytes []byte
}
DataPayload represents a slice of bytes.
func (DataPayload) MarshalBinary ¶
func (p DataPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*DataPayload) UnmarshalBinary ¶
func (p *DataPayload) UnmarshalBinary(uplink bool, data []byte) error
UnmarshalBinary decodes the object from binary form.
type DevAddr ¶
type DevAddr [4]byte
DevAddr represents the device address.
func (DevAddr) MarshalBinary ¶
MarshalBinary marshals the object in binary form.
func (DevAddr) MarshalText ¶
MarshalText implements encoding.TextMarshaler.
func (*DevAddr) UnmarshalBinary ¶
UnmarshalBinary decodes the object from binary form.
func (*DevAddr) UnmarshalText ¶
UnmarshalText implements encoding.TextUnmarshaler.
type DevStatusAnsPayload ¶
DevStatusAnsPayload represents the DevStatusAns payload.
func (DevStatusAnsPayload) MarshalBinary ¶
func (p DevStatusAnsPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*DevStatusAnsPayload) UnmarshalBinary ¶
func (p *DevStatusAnsPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type DutyCycleReqPayload ¶
type DutyCycleReqPayload struct {
MaxDCCycle uint8
}
DutyCycleReqPayload represents the DutyCycleReq payload.
func (DutyCycleReqPayload) MarshalBinary ¶
func (p DutyCycleReqPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*DutyCycleReqPayload) UnmarshalBinary ¶
func (p *DutyCycleReqPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type EUI64 ¶
type EUI64 [8]byte
EUI64 data type
func (EUI64) MarshalBinary ¶
MarshalBinary implements encoding.BinaryMarshaler.
func (EUI64) MarshalText ¶
MarshalText implements encoding.TextMarshaler.
func (*EUI64) UnmarshalBinary ¶
UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (*EUI64) UnmarshalText ¶
UnmarshalText implements encoding.TextUnmarshaler.
type FCtrl ¶
type FCtrl struct { ADR bool ADRACKReq bool ACK bool FPending bool // only used for downlink messages // contains filtered or unexported fields }
FCtrl represents the FCtrl (frame control) field.
func (FCtrl) MarshalBinary ¶
MarshalBinary marshals the object in binary form.
func (*FCtrl) UnmarshalBinary ¶
UnmarshalBinary decodes the object from binary form.
type FHDR ¶
type FHDR struct { DevAddr DevAddr FCtrl FCtrl FCnt uint32 // only the least-significant 16 bits will be marshalled FOpts []MACCommand // max. number of allowed bytes is 15 }
FHDR represents the frame header.
func (FHDR) MarshalBinary ¶
MarshalBinary marshals the object in binary form.
type JoinAcceptPayload ¶
type JoinAcceptPayload struct { AppNonce [3]byte NetID [3]byte DevAddr DevAddr DLSettings DLsettings RXDelay uint8 CFList *CFList }
JoinAcceptPayload represents the join-accept message payload.
func (JoinAcceptPayload) MarshalBinary ¶
func (p JoinAcceptPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*JoinAcceptPayload) UnmarshalBinary ¶
func (p *JoinAcceptPayload) UnmarshalBinary(uplink bool, data []byte) error
UnmarshalBinary decodes the object from binary form.
type JoinRequestPayload ¶
JoinRequestPayload represents the join-request message payload.
func (JoinRequestPayload) MarshalBinary ¶
func (p JoinRequestPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*JoinRequestPayload) UnmarshalBinary ¶
func (p *JoinRequestPayload) UnmarshalBinary(uplink bool, data []byte) error
UnmarshalBinary decodes the object from binary form.
type LinkADRAnsPayload ¶
LinkADRAnsPayload represents the LinkADRAns payload.
func (LinkADRAnsPayload) MarshalBinary ¶
func (p LinkADRAnsPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*LinkADRAnsPayload) UnmarshalBinary ¶
func (p *LinkADRAnsPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type LinkADRReqPayload ¶
type LinkADRReqPayload struct { DataRate uint8 TXPower uint8 ChMask ChMask Redundancy Redundancy }
LinkADRReqPayload represents the LinkADRReq payload.
func (LinkADRReqPayload) MarshalBinary ¶
func (p LinkADRReqPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*LinkADRReqPayload) UnmarshalBinary ¶
func (p *LinkADRReqPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type LinkCheckAnsPayload ¶
LinkCheckAnsPayload represents the LinkCheckAns payload.
func (LinkCheckAnsPayload) MarshalBinary ¶
func (p LinkCheckAnsPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*LinkCheckAnsPayload) UnmarshalBinary ¶
func (p *LinkCheckAnsPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type MACCommand ¶
type MACCommand struct { CID cid Payload MACCommandPayload }
MACCommand represents a MAC command with optional payload.
func (MACCommand) MarshalBinary ¶
func (m MACCommand) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*MACCommand) UnmarshalBinary ¶
func (m *MACCommand) UnmarshalBinary(uplink bool, data []byte) error
UnmarshalBinary decodes the object from binary form.
type MACCommandPayload ¶
type MACCommandPayload interface { MarshalBinary() (data []byte, err error) UnmarshalBinary(data []byte) error }
MACCommandPayload is the interface that every MACCommand payload must implement.
type MACPayload ¶
type MACPayload struct { FHDR FHDR FPort *uint8 // optional, but must be set when FRMPayload is set FRMPayload []Payload }
MACPayload represents the MAC payload. Use NewMACPayload for creating a new MACPayload.
func (MACPayload) MarshalBinary ¶
func (p MACPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*MACPayload) UnmarshalBinary ¶
func (p *MACPayload) UnmarshalBinary(uplink bool, data []byte) error
UnmarshalBinary decodes the object from binary form.
type MHDR ¶
MHDR represents the MAC header.
func (MHDR) MarshalBinary ¶
MarshalBinary marshals the object in binary form.
func (*MHDR) UnmarshalBinary ¶
UnmarshalBinary decodes the object from binary form.
type MType ¶
type MType byte
MType represents the message type.
type Major ¶
type Major byte
Major defines the major version of data message.
const (
LoRaWANR1 Major = 0
)
Supported major versions
type NetID ¶
type NetID [3]byte
NetID represents the NetID.
func (NetID) MarshalText ¶
MarshalText implements encoding.TextMarshaler.
func (*NetID) UnmarshalText ¶
UnmarshalText implements encoding.TextUnmarshaler.
type NewChannelAnsPayload ¶
NewChannelAnsPayload represents the NewChannelAns payload.
func (NewChannelAnsPayload) MarshalBinary ¶
func (p NewChannelAnsPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*NewChannelAnsPayload) UnmarshalBinary ¶
func (p *NewChannelAnsPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type NewChannelReqPayload ¶
NewChannelReqPayload represents the NewChannelReq payload.
func (NewChannelReqPayload) MarshalBinary ¶
func (p NewChannelReqPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*NewChannelReqPayload) UnmarshalBinary ¶
func (p *NewChannelReqPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type PHYPayload ¶
PHYPayload represents the physical payload. Use NewPhyPayload for creating a new PHYPayload.
Example ¶
nwkSKey := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} appSKey := [16]byte{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1} fPort := uint8(10) phy := PHYPayload{ MHDR: MHDR{ MType: ConfirmedDataUp, Major: LoRaWANR1, }, MACPayload: &MACPayload{ FHDR: FHDR{ DevAddr: DevAddr([4]byte{1, 2, 3, 4}), FCtrl: FCtrl{ ADR: false, ADRACKReq: false, ACK: false, }, FCnt: 0, FOpts: []MACCommand{}, // you can leave this out when there is no MAC command to send }, FPort: &fPort, FRMPayload: []Payload{&DataPayload{Bytes: []byte{1, 2, 3, 4}}}, }, } if err := phy.EncryptFRMPayload(appSKey); err != nil { panic(err) } if err := phy.SetMIC(nwkSKey); err != nil { panic(err) } str, err := phy.MarshalText() if err != nil { panic(err) } bytes, err := phy.MarshalBinary() if err != nil { panic(err) } fmt.Println(string(str)) fmt.Println(bytes)
Output: gAQDAgEAAAAK4mTU97VqDnU= [128 4 3 2 1 0 0 0 10 226 100 212 247 181 106 14 117]
Example (JoinAcceptSend) ¶
appKey := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} phy := PHYPayload{ MHDR: MHDR{ MType: JoinAccept, Major: LoRaWANR1, }, MACPayload: &JoinAcceptPayload{ AppNonce: [3]byte{1, 1, 1}, NetID: [3]byte{2, 2, 2}, DevAddr: DevAddr([4]byte{1, 2, 3, 4}), DLSettings: DLsettings{RX2DataRate: 0, RX1DRoffset: 0}, RXDelay: 0, }, } // set the MIC before encryption if err := phy.SetMIC(appKey); err != nil { panic(err) } if err := phy.EncryptJoinAcceptPayload(appKey); err != nil { panic(err) } str, err := phy.MarshalText() if err != nil { panic(err) } bytes, err := phy.MarshalBinary() if err != nil { panic(err) } fmt.Println(string(str)) fmt.Println(bytes)
Output: ICPPM1SJquMYPAvguqje5fM= [32 35 207 51 84 137 170 227 24 60 11 224 186 168 222 229 243]
Example (JoinRequest) ¶
appKey := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} phy := PHYPayload{ MHDR: MHDR{ MType: JoinRequest, Major: LoRaWANR1, }, MACPayload: &JoinRequestPayload{ AppEUI: [8]byte{1, 1, 1, 1, 1, 1, 1, 1}, DevEUI: [8]byte{2, 2, 2, 2, 2, 2, 2, 2}, DevNonce: [2]byte{3, 3}, }, } if err := phy.SetMIC(appKey); err != nil { panic(err) } str, err := phy.MarshalText() if err != nil { panic(err) } bytes, err := phy.MarshalBinary() if err != nil { panic(err) } fmt.Println(string(str)) fmt.Println(bytes)
Output: AAEBAQEBAQEBAgICAgICAgIDAwm5ezI= [0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 9 185 123 50]
Example (ReadJoinRequest) ¶
var phy PHYPayload if err := phy.UnmarshalText([]byte("AAQDAgEEAwIBBQQDAgUEAwItEGqZDhI=")); err != nil { panic(err) } jrPL, ok := phy.MACPayload.(*JoinRequestPayload) if !ok { panic("MACPayload must be a *JoinRequestPayload") } fmt.Println(phy.MHDR.MType) fmt.Println(jrPL.AppEUI) fmt.Println(jrPL.DevEUI) fmt.Println(jrPL.DevNonce)
Output: JoinRequest 0102030401020304 0203040502030405 [16 45]
func (*PHYPayload) DecryptFRMPayload ¶
func (p *PHYPayload) DecryptFRMPayload(key AES128Key) error
DecryptFRMPayload decrypts the FRMPayload with the given key.
func (*PHYPayload) DecryptJoinAcceptPayload ¶
func (p *PHYPayload) DecryptJoinAcceptPayload(appKey AES128Key) error
DecryptJoinAcceptPayload decrypts the join-accept payload with the given AppKey. Note that you need to decrypte before you can validate the MIC.
func (*PHYPayload) EncryptFRMPayload ¶
func (p *PHYPayload) EncryptFRMPayload(key AES128Key) error
EncryptFRMPayload encrypts the FRMPayload with the given key.
func (*PHYPayload) EncryptJoinAcceptPayload ¶
func (p *PHYPayload) EncryptJoinAcceptPayload(appKey AES128Key) error
EncryptJoinAcceptPayload encrypts the join-accept payload with the given AppKey. Note that encrypted must be performed after calling SetMIC (sicne the MIC is part of the encrypted payload).
func (PHYPayload) MarshalBinary ¶
func (p PHYPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (PHYPayload) MarshalText ¶
func (p PHYPayload) MarshalText() ([]byte, error)
MarshalText encodes the PHYPayload into base64.
func (*PHYPayload) SetMIC ¶
func (p *PHYPayload) SetMIC(key AES128Key) error
SetMIC calculates and sets the MIC field.
func (*PHYPayload) UnmarshalBinary ¶
func (p *PHYPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
func (*PHYPayload) UnmarshalText ¶
func (p *PHYPayload) UnmarshalText(text []byte) error
UnmarshalText decodes the PHYPayload from base64.
func (PHYPayload) ValidateMIC ¶
func (p PHYPayload) ValidateMIC(key AES128Key) (bool, error)
ValidateMIC returns if the MIC is valid. When using 32 bit frame counters, only the least-signification 16 bits are sent / received. In order to validate the MIC, the receiver needs to set the FCnt to the full 32 bit value (based on the observation of the traffic). See section '4.3.1.5 Frame counter (FCnt)' of the LoRaWAN 1.0 specification for more details.
type Payload ¶
type Payload interface { MarshalBinary() (data []byte, err error) UnmarshalBinary(uplink bool, data []byte) error }
Payload is the interface that every payload needs to implement. Since it might be a MACPayload, an indication must be given if the direction is uplink or downlink (it has different payloads for the same CID, based on direction).
type RX2SetupAnsPayload ¶
RX2SetupAnsPayload represents the RX2SetupAns payload.
func (RX2SetupAnsPayload) MarshalBinary ¶
func (p RX2SetupAnsPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*RX2SetupAnsPayload) UnmarshalBinary ¶
func (p *RX2SetupAnsPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type RX2SetupReqPayload ¶
type RX2SetupReqPayload struct { Frequency uint32 DLsettings DLsettings }
RX2SetupReqPayload represents the RX2SetupReq payload.
func (RX2SetupReqPayload) MarshalBinary ¶
func (p RX2SetupReqPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*RX2SetupReqPayload) UnmarshalBinary ¶
func (p *RX2SetupReqPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type RXTimingSetupReqPayload ¶
type RXTimingSetupReqPayload struct {
Delay uint8
}
RXTimingSetupReqPayload represents the RXTimingSetupReq payload.
func (RXTimingSetupReqPayload) MarshalBinary ¶
func (p RXTimingSetupReqPayload) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*RXTimingSetupReqPayload) UnmarshalBinary ¶
func (p *RXTimingSetupReqPayload) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.
type Redundancy ¶
Redundancy represents the redundancy field.
func (Redundancy) MarshalBinary ¶
func (r Redundancy) MarshalBinary() ([]byte, error)
MarshalBinary marshals the object in binary form.
func (*Redundancy) UnmarshalBinary ¶
func (r *Redundancy) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the object from binary form.