@@ -14,6 +14,7 @@ import (
14
14
"github.com/brocaar/chirpstack-api/go/v3/nc"
15
15
"github.com/brocaar/chirpstack-network-server/internal/backend/controller"
16
16
"github.com/brocaar/chirpstack-network-server/internal/backend/gateway"
17
+ "github.com/brocaar/chirpstack-network-server/internal/framelog"
17
18
"github.com/brocaar/chirpstack-network-server/internal/helpers"
18
19
"github.com/brocaar/chirpstack-network-server/internal/logging"
19
20
"github.com/brocaar/chirpstack-network-server/internal/storage"
@@ -26,21 +27,27 @@ var (
26
27
var handleDownlinkTXAckTasks = []func (* ackContext ) error {
27
28
getToken ,
28
29
getDownlinkFrames ,
29
- sendDownlinkMetaDataToNetworkControllerOnNoError ,
30
- sendTxAckToApplicationServerOnNoError ,
31
- abortOnNoError ,
32
- sendErrorToApplicationServerOnLastFrame ,
33
- sendDownlinkFrame ,
34
- saveDownlinkFrames ,
30
+ decodePHYPayload ,
31
+ onError (
32
+ sendErrorToApplicationServerOnLastFrame ,
33
+ sendDownlinkFrame ,
34
+ saveDownlinkFrames ,
35
+ ),
36
+ onNoError (
37
+ sendDownlinkMetaDataToNetworkController ,
38
+ sendTxAckToApplicationServer ,
39
+ logDownlinkFrame ,
40
+ ),
35
41
}
36
42
37
43
type ackContext struct {
38
44
ctx context.Context
39
45
40
46
Token uint16
41
- DevEUI lorawan.EUI64
42
47
DownlinkTXAck gw.DownlinkTXAck
43
48
DownlinkFrames storage.DownlinkFrames
49
+ MHDR lorawan.MHDR
50
+ MACPayload * lorawan.MACPayload
44
51
}
45
52
46
53
// HandleDownlinkTXAck handles the given downlink TX acknowledgement.
@@ -62,6 +69,38 @@ func HandleDownlinkTXAck(ctx context.Context, downlinkTXAck gw.DownlinkTXAck) er
62
69
return nil
63
70
}
64
71
72
+ func onError (funcs ... func (* ackContext ) error ) func (* ackContext ) error {
73
+ return func (ctx * ackContext ) error {
74
+ if ctx .DownlinkTXAck .Error == "" {
75
+ return nil
76
+ }
77
+
78
+ for _ , f := range funcs {
79
+ if err := f (ctx ); err != nil {
80
+ return err
81
+ }
82
+ }
83
+
84
+ return nil
85
+ }
86
+ }
87
+
88
+ func onNoError (funcs ... func (* ackContext ) error ) func (* ackContext ) error {
89
+ return func (ctx * ackContext ) error {
90
+ if ctx .DownlinkTXAck .Error != "" {
91
+ return nil
92
+ }
93
+
94
+ for _ , f := range funcs {
95
+ if err := f (ctx ); err != nil {
96
+ return err
97
+ }
98
+ }
99
+
100
+ return nil
101
+ }
102
+ }
103
+
65
104
func getToken (ctx * ackContext ) error {
66
105
if ctx .DownlinkTXAck .Token != 0 {
67
106
ctx .Token = uint16 (ctx .DownlinkTXAck .Token )
@@ -81,11 +120,7 @@ func getDownlinkFrames(ctx *ackContext) error {
81
120
return nil
82
121
}
83
122
84
- func sendDownlinkMetaDataToNetworkControllerOnNoError (ctx * ackContext ) error {
85
- if ctx .DownlinkTXAck .Error != "" || controller .Client () == nil {
86
- return nil
87
- }
88
-
123
+ func decodePHYPayload (ctx * ackContext ) error {
89
124
if len (ctx .DownlinkFrames .DownlinkFrames ) == 0 {
90
125
return errors .New ("downlink-frames is empty" )
91
126
}
@@ -97,9 +132,23 @@ func sendDownlinkMetaDataToNetworkControllerOnNoError(ctx *ackContext) error {
97
132
log .WithError (err ).WithFields (log.Fields {
98
133
"ctx_id" : ctx .ctx .Value (logging .ContextIDKey ),
99
134
}).Error ("unmarshal phypayload error" )
100
- return nil
101
135
}
102
136
137
+ ctx .MHDR = phy .MHDR
138
+ if macPL , ok := phy .MACPayload .(* lorawan.MACPayload ); ok {
139
+ ctx .MACPayload = macPL
140
+ }
141
+
142
+ return nil
143
+ }
144
+
145
+ func sendDownlinkMetaDataToNetworkController (ctx * ackContext ) error {
146
+ if len (ctx .DownlinkFrames .DownlinkFrames ) == 0 {
147
+ return errors .New ("downlink-frames is empty" )
148
+ }
149
+
150
+ downlinkFrame := ctx .DownlinkFrames .DownlinkFrames [0 ]
151
+
103
152
req := nc.HandleDownlinkMetaDataRequest {
104
153
DevEui : ctx .DownlinkFrames .DevEui ,
105
154
MulticastGroupId : ctx .DownlinkFrames .MulticastGroupId ,
@@ -108,7 +157,7 @@ func sendDownlinkMetaDataToNetworkControllerOnNoError(ctx *ackContext) error {
108
157
}
109
158
110
159
// message type
111
- switch phy .MHDR .MType {
160
+ switch ctx .MHDR .MType {
112
161
case lorawan .JoinAccept :
113
162
req .MessageType = nc .MType_JOIN_ACCEPT
114
163
case lorawan .UnconfirmedDataDown :
@@ -117,18 +166,18 @@ func sendDownlinkMetaDataToNetworkControllerOnNoError(ctx *ackContext) error {
117
166
req .MessageType = nc .MType_CONFIRMED_DATA_DOWN
118
167
}
119
168
120
- if macPL , ok := phy .MACPayload .( * lorawan. MACPayload ); ok {
121
- for _ , pl := range macPL .FRMPayload {
169
+ if ctx .MACPayload != nil {
170
+ for _ , pl := range ctx . MACPayload .FRMPayload {
122
171
if b , err := pl .MarshalBinary (); err == nil {
123
- if macPL . FPort != nil && * macPL .FPort != 0 {
172
+ if ctx . MACPayload . FPort != nil && * ctx . MACPayload .FPort != 0 {
124
173
req .ApplicationPayloadByteCount += uint32 (len (b ))
125
174
} else {
126
175
req .MacCommandByteCount += uint32 (len (b ))
127
176
}
128
177
}
129
178
}
130
179
131
- for _ , m := range macPL .FHDR .FOpts {
180
+ for _ , m := range ctx . MACPayload .FHDR .FOpts {
132
181
if b , err := m .MarshalBinary (); err == nil {
133
182
req .MacCommandByteCount += uint32 (len (b ))
134
183
}
@@ -153,9 +202,9 @@ func sendDownlinkMetaDataToNetworkControllerOnNoError(ctx *ackContext) error {
153
202
return nil
154
203
}
155
204
156
- func sendTxAckToApplicationServerOnNoError (ctx * ackContext ) error {
205
+ func sendTxAckToApplicationServer (ctx * ackContext ) error {
157
206
// We do not want to inform the AS on non-application TX events.
158
- if ctx .DownlinkTXAck . Error != "" || ctx .DownlinkFrames .FPort == 0 {
207
+ if len ( ctx .DownlinkFrames . DevEui ) == 0 || ctx .MACPayload == nil || ctx . MACPayload . FPort == nil || * ctx . MACPayload .FPort == 0 {
159
208
return nil
160
209
}
161
210
@@ -171,7 +220,7 @@ func sendTxAckToApplicationServerOnNoError(ctx *ackContext) error {
171
220
go func (ctx * ackContext , asClient as.ApplicationServerServiceClient ) {
172
221
_ , err := asClient .HandleTxAck (ctx .ctx , & as.HandleTxAckRequest {
173
222
DevEui : ctx .DownlinkFrames .DevEui ,
174
- FCnt : ctx .DownlinkFrames .FCnt ,
223
+ FCnt : ctx .MACPayload . FHDR .FCnt ,
175
224
})
176
225
if err != nil {
177
226
log .WithError (err ).WithFields (log.Fields {
@@ -188,18 +237,10 @@ func sendTxAckToApplicationServerOnNoError(ctx *ackContext) error {
188
237
return nil
189
238
}
190
239
191
- func abortOnNoError (ctx * ackContext ) error {
192
- if ctx .DownlinkTXAck .Error == "" {
193
- // no error, nothing to do
194
- return errAbort
195
- }
196
- return nil
197
- }
198
-
199
240
func sendErrorToApplicationServerOnLastFrame (ctx * ackContext ) error {
200
241
// Only send an error to the AS on the last possible attempt.
201
242
// We only want to send error for application payloads.
202
- if len (ctx .DownlinkFrames .DownlinkFrames ) >= 2 || ctx .DownlinkFrames .FPort == 0 {
243
+ if len (ctx .DownlinkFrames .DownlinkFrames ) >= 2 || ctx .MACPayload == nil || ctx . MACPayload . FPort == nil || * ctx . MACPayload .FPort == 0 {
203
244
return nil
204
245
}
205
246
@@ -215,7 +256,7 @@ func sendErrorToApplicationServerOnLastFrame(ctx *ackContext) error {
215
256
go func (ctx * ackContext , asClient as.ApplicationServerServiceClient ) {
216
257
_ , err := asClient .HandleError (ctx .ctx , & as.HandleErrorRequest {
217
258
DevEui : ctx .DownlinkFrames .DevEui ,
218
- FCnt : ctx .DownlinkFrames .FCnt ,
259
+ FCnt : ctx .MACPayload . FHDR .FCnt ,
219
260
Type : as .ErrorType_DATA_DOWN_GATEWAY ,
220
261
Error : ctx .DownlinkTXAck .Error ,
221
262
})
@@ -258,3 +299,61 @@ func saveDownlinkFrames(ctx *ackContext) error {
258
299
259
300
return nil
260
301
}
302
+
303
+ func logDownlinkFrame (ctx * ackContext ) error {
304
+ if len (ctx .DownlinkFrames .DownlinkFrames ) == 0 {
305
+ return errors .New ("downlink-frames is empty" )
306
+ }
307
+
308
+ downlinkFrame := ctx .DownlinkFrames .DownlinkFrames [0 ]
309
+
310
+ // log for gateway (with encrypted mac-commands)
311
+ if err := framelog .LogDownlinkFrameForGateway (ctx .ctx , storage .RedisPool (), * downlinkFrame ); err != nil {
312
+ log .WithError (err ).WithFields (log.Fields {
313
+ "ctx_id" : ctx .ctx .Value (logging .ContextIDKey ),
314
+ }).Error ("log downlink frame for gateway error" )
315
+ }
316
+
317
+ var devEUI lorawan.EUI64
318
+ var nwkSEncKey lorawan.AES128Key
319
+ copy (devEUI [:], ctx .DownlinkFrames .DevEui )
320
+ copy (nwkSEncKey [:], ctx .DownlinkFrames .NwkSEncKey )
321
+
322
+ // log for device (with decrypted mac-commands)
323
+ var phy lorawan.PHYPayload
324
+ if err := phy .UnmarshalBinary (downlinkFrame .PhyPayload ); err != nil {
325
+ return err
326
+ }
327
+
328
+ // decrypt FRMPayload mac-commands
329
+ if ctx .MACPayload != nil && ctx .MACPayload .FPort != nil && * ctx .MACPayload .FPort == 0 {
330
+ if err := phy .DecryptFRMPayload (nwkSEncKey ); err != nil {
331
+ return errors .Wrap (err , "decrypt frmpayload error" )
332
+ }
333
+ }
334
+
335
+ // decrypt FOpts mac-commands (LoRaWAN 1.1)
336
+ if ctx .DownlinkFrames .EncryptedFopts {
337
+ if err := phy .DecryptFOpts (nwkSEncKey ); err != nil {
338
+ return errors .Wrap (err , "decrypt FOpts error" )
339
+ }
340
+ }
341
+
342
+ phyB , err := phy .MarshalBinary ()
343
+ if err != nil {
344
+ return err
345
+ }
346
+
347
+ if err := framelog .LogDownlinkFrameForDevEUI (ctx .ctx , storage .RedisPool (), devEUI , gw.DownlinkFrame {
348
+ PhyPayload : phyB ,
349
+ TxInfo : downlinkFrame .TxInfo ,
350
+ Token : downlinkFrame .Token ,
351
+ DownlinkId : downlinkFrame .DownlinkId ,
352
+ }); err != nil {
353
+ log .WithError (err ).WithFields (log.Fields {
354
+ "ctx_id" : ctx .ctx .Value (logging .ContextIDKey ),
355
+ }).Error ("log downlink frame for device error" )
356
+ }
357
+
358
+ return nil
359
+ }
0 commit comments