-
Notifications
You must be signed in to change notification settings - Fork 159
/
macpayload.go
108 lines (91 loc) · 2.83 KB
/
macpayload.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package lorawan
import (
"errors"
)
// MACPayload represents the MAC payload. Use NewMACPayload for creating a new
// MACPayload.
type MACPayload struct {
FHDR FHDR `json:"fhdr"`
FPort *uint8 `json:"fPort"` // optional, but must be set when FRMPayload is set
FRMPayload []Payload `json:"frmPayload"`
}
func (p MACPayload) marshalPayload() ([]byte, error) {
var out []byte
var b []byte
var err error
for _, fp := range p.FRMPayload {
if mac, ok := fp.(*MACCommand); ok {
if p.FPort == nil || (p.FPort != nil && *p.FPort != 0) {
return []byte{}, errors.New("lorawan: a MAC command is only allowed when FPort=0")
}
b, err = mac.MarshalBinary()
} else {
b, err = fp.MarshalBinary()
}
if err != nil {
return nil, err
}
out = append(out, b...)
}
return out, nil
}
// MarshalBinary marshals the object in binary form.
func (p MACPayload) MarshalBinary() ([]byte, error) {
var b []byte
var out []byte
var err error
b, err = p.FHDR.MarshalBinary()
if err != nil {
return nil, err
}
out = append(out, b...)
if p.FPort == nil {
if len(p.FRMPayload) != 0 {
return nil, errors.New("lorawan: FPort must be set when FRMPayload is not empty")
}
return out, nil
} else if len(p.FHDR.FOpts) != 0 && *p.FPort == 0 {
return nil, errors.New("lorawan: FPort must not be 0 when FOpts are set")
}
out = append(out, *p.FPort)
if b, err = p.marshalPayload(); err != nil {
return nil, err
}
out = append(out, b...)
return out, nil
}
// UnmarshalBinary decodes the object from binary form.
func (p *MACPayload) UnmarshalBinary(uplink bool, data []byte) error {
dataLen := len(data)
// check that there are enough bytes to decode a minimal FHDR
if dataLen < 7 {
return errors.New("lorawan: at least 7 bytes needed to decode FHDR")
}
// unmarshal FCtrl so we know the FOptsLen
if err := p.FHDR.FCtrl.UnmarshalBinary(data[4:5]); err != nil {
return err
}
// check that there are at least as many bytes as FOptsLen claims
if dataLen < 7+int(p.FHDR.FCtrl.fOptsLen) {
return errors.New("lorawan: not enough bytes to decode FHDR")
}
// decode the full FHDR (including optional FOpts)
if err := p.FHDR.UnmarshalBinary(uplink, data[0:7+p.FHDR.FCtrl.fOptsLen]); err != nil {
return err
}
// decode the optional FPort
if dataLen > 7+int(p.FHDR.FCtrl.fOptsLen) {
fPort := uint8(data[7+int(p.FHDR.FCtrl.fOptsLen)])
p.FPort = &fPort
}
// decode the rest of the payload (if present)
if dataLen > 7+int(p.FHDR.FCtrl.fOptsLen)+1 {
if p.FPort != nil && *p.FPort == 0 && p.FHDR.FCtrl.fOptsLen > 0 {
return errors.New("lorawan: FPort must not be 0 when FOpts are set")
}
// even when FPort = 0, we store the mac-commands within a DataPayload.
// only after decryption we're able to unmarshal them.
p.FRMPayload = []Payload{&DataPayload{Bytes: data[7+p.FHDR.FCtrl.fOptsLen+1:]}}
}
return nil
}