Skip to content

Commit a524727

Browse files
committed
Support both protocol v1 and v2.
1 parent ad6c0c8 commit a524727

File tree

4 files changed

+147
-79
lines changed

4 files changed

+147
-79
lines changed

gateway/backend.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ type udpPacket struct {
2727
}
2828

2929
type gateway struct {
30-
addr *net.UDPAddr
31-
lastSeen time.Time
30+
addr *net.UDPAddr
31+
lastSeen time.Time
32+
protocolVersion uint8
3233
}
3334

3435
type gateways struct {
@@ -176,6 +177,7 @@ func (b *Backend) Send(txPacket models.TXPacket) error {
176177
return err
177178
}
178179
pullResp := PullRespPacket{
180+
ProtocolVersion: gw.protocolVersion,
179181
Payload: PullRespPayload{
180182
TXPK: txpk,
181183
},
@@ -222,8 +224,9 @@ func (b *Backend) sendPackets() error {
222224
continue
223225
}
224226
log.WithFields(log.Fields{
225-
"addr": p.addr,
226-
"type": pt,
227+
"addr": p.addr,
228+
"type": pt,
229+
"protocol_version": p.data[0],
227230
}).Info("gateway: sending udp packet to gateway")
228231

229232
if _, err := b.conn.WriteToUDP(p.data, p.addr); err != nil {
@@ -239,8 +242,9 @@ func (b *Backend) handlePacket(addr *net.UDPAddr, data []byte) error {
239242
return err
240243
}
241244
log.WithFields(log.Fields{
242-
"addr": addr,
243-
"type": pt,
245+
"addr": addr,
246+
"type": pt,
247+
"protocol_version": data[0],
244248
}).Info("gateway: received udp packet from gateway")
245249

246250
switch pt {
@@ -261,16 +265,18 @@ func (b *Backend) handlePullData(addr *net.UDPAddr, data []byte) error {
261265
return err
262266
}
263267
ack := PullACKPacket{
264-
RandomToken: p.RandomToken,
268+
ProtocolVersion: p.ProtocolVersion,
269+
RandomToken: p.RandomToken,
265270
}
266271
bytes, err := ack.MarshalBinary()
267272
if err != nil {
268273
return err
269274
}
270275

271276
err = b.gateways.set(p.GatewayMAC, gateway{
272-
addr: addr,
273-
lastSeen: time.Now().UTC(),
277+
addr: addr,
278+
lastSeen: time.Now().UTC(),
279+
protocolVersion: p.ProtocolVersion,
274280
})
275281
if err != nil {
276282
return err
@@ -291,7 +297,8 @@ func (b *Backend) handlePushData(addr *net.UDPAddr, data []byte) error {
291297

292298
// ack the packet
293299
ack := PushACKPacket{
294-
RandomToken: p.RandomToken,
300+
ProtocolVersion: p.ProtocolVersion,
301+
RandomToken: p.RandomToken,
295302
}
296303
bytes, err := ack.MarshalBinary()
297304
if err != nil {

gateway/backend_test.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ func TestBackend(t *testing.T) {
3030

3131
Convey("When sending a PULL_DATA packet", func() {
3232
p := PullDataPacket{
33-
RandomToken: 12345,
34-
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
33+
ProtocolVersion: ProtocolVersion2,
34+
RandomToken: 12345,
35+
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
3536
}
3637
b, err := p.MarshalBinary()
3738
So(err, ShouldBeNil)
@@ -45,13 +46,15 @@ func TestBackend(t *testing.T) {
4546
var ack PullACKPacket
4647
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
4748
So(ack.RandomToken, ShouldEqual, p.RandomToken)
49+
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
4850
})
4951
})
5052

5153
Convey("When sending a PUSH_DATA packet with stats", func() {
5254
p := PushDataPacket{
53-
RandomToken: 1234,
54-
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
55+
ProtocolVersion: ProtocolVersion2,
56+
RandomToken: 1234,
57+
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
5558
Payload: PushDataPayload{
5659
Stat: &Stat{
5760
Time: ExpandedTime(time.Time{}.UTC()),
@@ -78,6 +81,7 @@ func TestBackend(t *testing.T) {
7881
var ack PushACKPacket
7982
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
8083
So(ack.RandomToken, ShouldEqual, p.RandomToken)
84+
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
8185

8286
Convey("Then the gateway stats are returned by the stats channel", func() {
8387
stats := <-backend.StatsChan()
@@ -88,8 +92,9 @@ func TestBackend(t *testing.T) {
8892

8993
Convey("When sending a PUSH_DATA packet with RXPK", func() {
9094
p := PushDataPacket{
91-
RandomToken: 1234,
92-
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
95+
ProtocolVersion: ProtocolVersion2,
96+
RandomToken: 1234,
97+
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
9398
Payload: PushDataPayload{
9499
RXPK: []RXPK{
95100
{
@@ -122,6 +127,7 @@ func TestBackend(t *testing.T) {
122127
var ack PushACKPacket
123128
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
124129
So(ack.RandomToken, ShouldEqual, p.RandomToken)
130+
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
125131
})
126132

127133
Convey("Then the packet is returned by the RX packet channel", func() {
@@ -172,8 +178,9 @@ func TestBackend(t *testing.T) {
172178
Convey("When sending the TXPacket when the gateway is known to the backend", func() {
173179
// sending a ping should register the gateway to the backend
174180
p := PullDataPacket{
175-
RandomToken: 12345,
176-
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
181+
ProtocolVersion: ProtocolVersion2,
182+
RandomToken: 12345,
183+
GatewayMAC: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
177184
}
178185
b, err := p.MarshalBinary()
179186
So(err, ShouldBeNil)
@@ -185,6 +192,7 @@ func TestBackend(t *testing.T) {
185192
var ack PullACKPacket
186193
So(ack.UnmarshalBinary(buf[:i]), ShouldBeNil)
187194
So(ack.RandomToken, ShouldEqual, p.RandomToken)
195+
So(ack.ProtocolVersion, ShouldEqual, p.ProtocolVersion)
188196

189197
err = backend.Send(txPacket)
190198

@@ -203,6 +211,7 @@ func TestBackend(t *testing.T) {
203211
So(err, ShouldBeNil)
204212

205213
So(pullResp, ShouldResemble, PullRespPacket{
214+
ProtocolVersion: p.ProtocolVersion,
206215
Payload: PullRespPayload{
207216
TXPK: TXPK{
208217
Imme: true,

gateway/structs.go

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,20 @@ var (
3737
ErrInvalidProtocolVersion = errors.New("gateway: invalid protocol version")
3838
)
3939

40+
func protocolSupported(p uint8) bool {
41+
if p == ProtocolVersion1 || p == ProtocolVersion2 {
42+
return true
43+
}
44+
return false
45+
}
46+
4047
// PushDataPacket type is used by the gateway mainly to forward the RF packets
4148
// received, and associated metadata, to the server.
4249
type PushDataPacket struct {
43-
RandomToken uint16
44-
GatewayMAC lorawan.EUI64
45-
Payload PushDataPayload
50+
ProtocolVersion uint8
51+
RandomToken uint16
52+
GatewayMAC lorawan.EUI64
53+
Payload PushDataPayload
4654
}
4755

4856
// MarshalBinary marshals the object in binary form.
@@ -53,7 +61,7 @@ func (p PushDataPacket) MarshalBinary() ([]byte, error) {
5361
}
5462

5563
out := make([]byte, 4, len(pb)+12)
56-
out[0] = ProtocolVersion2
64+
out[0] = p.ProtocolVersion
5765
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken)
5866
out[3] = byte(PushData)
5967
out = append(out, p.GatewayMAC[0:len(p.GatewayMAC)]...)
@@ -69,10 +77,12 @@ func (p *PushDataPacket) UnmarshalBinary(data []byte) error {
6977
if data[3] != byte(PushData) {
7078
return errors.New("gateway: identifier mismatch (PUSH_DATA expected)")
7179
}
72-
if data[0] != ProtocolVersion2 {
80+
81+
if !protocolSupported(data[0]) {
7382
return ErrInvalidProtocolVersion
7483
}
7584

85+
p.ProtocolVersion = data[0]
7686
p.RandomToken = binary.LittleEndian.Uint16(data[1:3])
7787
for i := 0; i < 8; i++ {
7888
p.GatewayMAC[i] = data[4+i]
@@ -84,13 +94,14 @@ func (p *PushDataPacket) UnmarshalBinary(data []byte) error {
8494
// PushACKPacket is used by the server to acknowledge immediately all the
8595
// PUSH_DATA packets received.
8696
type PushACKPacket struct {
87-
RandomToken uint16
97+
ProtocolVersion uint8
98+
RandomToken uint16
8899
}
89100

90101
// MarshalBinary marshals the object in binary form.
91102
func (p PushACKPacket) MarshalBinary() ([]byte, error) {
92103
out := make([]byte, 4)
93-
out[0] = ProtocolVersion2
104+
out[0] = p.ProtocolVersion
94105
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken)
95106
out[3] = byte(PushACK)
96107
return out, nil
@@ -104,23 +115,26 @@ func (p *PushACKPacket) UnmarshalBinary(data []byte) error {
104115
if data[3] != byte(PushACK) {
105116
return errors.New("gateway: identifier mismatch (PUSH_ACK expected)")
106117
}
107-
if data[0] != ProtocolVersion2 {
118+
119+
if !protocolSupported(data[0]) {
108120
return ErrInvalidProtocolVersion
109121
}
122+
p.ProtocolVersion = data[0]
110123
p.RandomToken = binary.LittleEndian.Uint16(data[1:3])
111124
return nil
112125
}
113126

114127
// PullDataPacket is used by the gateway to poll data from the server.
115128
type PullDataPacket struct {
116-
RandomToken uint16
117-
GatewayMAC [8]byte
129+
ProtocolVersion uint8
130+
RandomToken uint16
131+
GatewayMAC [8]byte
118132
}
119133

120134
// MarshalBinary marshals the object in binary form.
121135
func (p PullDataPacket) MarshalBinary() ([]byte, error) {
122136
out := make([]byte, 4, 12)
123-
out[0] = ProtocolVersion2
137+
out[0] = p.ProtocolVersion
124138
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken)
125139
out[3] = byte(PullData)
126140
out = append(out, p.GatewayMAC[0:len(p.GatewayMAC)]...)
@@ -135,9 +149,11 @@ func (p *PullDataPacket) UnmarshalBinary(data []byte) error {
135149
if data[3] != byte(PullData) {
136150
return errors.New("gateway: identifier mismatch (PULL_DATA expected)")
137151
}
138-
if data[0] != ProtocolVersion2 {
152+
153+
if !protocolSupported(data[0]) {
139154
return ErrInvalidProtocolVersion
140155
}
156+
p.ProtocolVersion = data[0]
141157
p.RandomToken = binary.LittleEndian.Uint16(data[1:3])
142158
for i := 0; i < 8; i++ {
143159
p.GatewayMAC[i] = data[4+i]
@@ -148,13 +164,14 @@ func (p *PullDataPacket) UnmarshalBinary(data []byte) error {
148164
// PullACKPacket is used by the server to confirm that the network route is
149165
// open and that the server can send PULL_RESP packets at any time.
150166
type PullACKPacket struct {
151-
RandomToken uint16
167+
ProtocolVersion uint8
168+
RandomToken uint16
152169
}
153170

154171
// MarshalBinary marshals the object in binary form.
155172
func (p PullACKPacket) MarshalBinary() ([]byte, error) {
156173
out := make([]byte, 4)
157-
out[0] = ProtocolVersion2
174+
out[0] = p.ProtocolVersion
158175
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken)
159176
out[3] = byte(PullACK)
160177
return out, nil
@@ -168,18 +185,20 @@ func (p *PullACKPacket) UnmarshalBinary(data []byte) error {
168185
if data[3] != byte(PullACK) {
169186
return errors.New("gateway: identifier mismatch (PULL_ACK expected)")
170187
}
171-
if data[0] != ProtocolVersion2 {
188+
if !protocolSupported(data[0]) {
172189
return ErrInvalidProtocolVersion
173190
}
191+
p.ProtocolVersion = data[0]
174192
p.RandomToken = binary.LittleEndian.Uint16(data[1:3])
175193
return nil
176194
}
177195

178196
// PullRespPacket is used by the server to send RF packets and associated
179197
// metadata that will have to be emitted by the gateway.
180198
type PullRespPacket struct {
181-
RandomToken uint16
182-
Payload PullRespPayload
199+
ProtocolVersion uint8
200+
RandomToken uint16
201+
Payload PullRespPayload
183202
}
184203

185204
// MarshalBinary marshals the object in binary form.
@@ -189,8 +208,12 @@ func (p PullRespPacket) MarshalBinary() ([]byte, error) {
189208
return nil, err
190209
}
191210
out := make([]byte, 4, 4+len(pb))
192-
out[0] = ProtocolVersion2
193-
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken)
211+
out[0] = p.ProtocolVersion
212+
213+
if p.ProtocolVersion != ProtocolVersion1 {
214+
// these two bytes are unused in ProtocolVersion1
215+
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken)
216+
}
194217
out[3] = byte(PullResp)
195218
out = append(out, pb...)
196219
return out, nil
@@ -204,9 +227,10 @@ func (p *PullRespPacket) UnmarshalBinary(data []byte) error {
204227
if data[3] != byte(PullResp) {
205228
return errors.New("gateway: identifier mismatch (PULL_RESP expected)")
206229
}
207-
if data[0] != ProtocolVersion2 {
230+
if !protocolSupported(data[0]) {
208231
return ErrInvalidProtocolVersion
209232
}
233+
p.ProtocolVersion = data[0]
210234
p.RandomToken = binary.LittleEndian.Uint16(data[1:3])
211235
return json.Unmarshal(data[4:], &p.Payload)
212236
}
@@ -215,9 +239,10 @@ func (p *PullRespPacket) UnmarshalBinary(data []byte) error {
215239
// to inform if a downlink request has been accepted or rejected by the
216240
// gateway.
217241
type TXACKPacket struct {
218-
RandomToken uint16
219-
GatewayMAC lorawan.EUI64
220-
Payload *TXACKPayload
242+
ProtocolVersion uint8
243+
RandomToken uint16
244+
GatewayMAC lorawan.EUI64
245+
Payload *TXACKPayload
221246
}
222247

223248
// MarshalBinary marshals the object into binary form.
@@ -232,7 +257,7 @@ func (p TXACKPacket) MarshalBinary() ([]byte, error) {
232257
}
233258

234259
out := make([]byte, 4, len(pb)+12)
235-
out[0] = ProtocolVersion2
260+
out[0] = p.ProtocolVersion
236261
binary.LittleEndian.PutUint16(out[1:3], p.RandomToken)
237262
out[3] = byte(TXACK)
238263
out = append(out, p.GatewayMAC[:]...)
@@ -248,9 +273,10 @@ func (p *TXACKPacket) UnmarshalBinary(data []byte) error {
248273
if data[3] != byte(TXACK) {
249274
return errors.New("gateway: identifier mismatch (TXACK expected)")
250275
}
251-
if data[0] != ProtocolVersion2 {
276+
if !protocolSupported(data[0]) {
252277
return ErrInvalidProtocolVersion
253278
}
279+
p.ProtocolVersion = data[0]
254280
p.RandomToken = binary.LittleEndian.Uint16(data[1:3])
255281
for i := 0; i < 8; i++ {
256282
p.GatewayMAC[i] = data[4+i]
@@ -403,7 +429,7 @@ func GetPacketType(data []byte) (PacketType, error) {
403429
return PacketType(0), errors.New("gateway: at least 4 bytes of data are expected")
404430
}
405431

406-
if data[0] != ProtocolVersion2 {
432+
if !protocolSupported(data[0]) {
407433
return PacketType(0), ErrInvalidProtocolVersion
408434
}
409435

0 commit comments

Comments
 (0)