Skip to content

Commit f9eb89f

Browse files
committed
Log the actual downlink frame accepted by gw.
Previously, the first attempt would be logged. However, there is a possibility that the first attempt fails (e.g. collision with other items in the gateway queue), and that the downlink is scheduled using RX2 parameters (potentially with more / less mac-commands as a different data-rate might have different payload size constraints). With this change, a downlink is logged only when the gateway sends a positive acknowledgement.
1 parent 04f415f commit f9eb89f

File tree

6 files changed

+200
-135
lines changed

6 files changed

+200
-135
lines changed

internal/downlink/ack/ack.go

+130-31
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/brocaar/chirpstack-api/go/v3/nc"
1515
"github.com/brocaar/chirpstack-network-server/internal/backend/controller"
1616
"github.com/brocaar/chirpstack-network-server/internal/backend/gateway"
17+
"github.com/brocaar/chirpstack-network-server/internal/framelog"
1718
"github.com/brocaar/chirpstack-network-server/internal/helpers"
1819
"github.com/brocaar/chirpstack-network-server/internal/logging"
1920
"github.com/brocaar/chirpstack-network-server/internal/storage"
@@ -26,21 +27,27 @@ var (
2627
var handleDownlinkTXAckTasks = []func(*ackContext) error{
2728
getToken,
2829
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+
),
3541
}
3642

3743
type ackContext struct {
3844
ctx context.Context
3945

4046
Token uint16
41-
DevEUI lorawan.EUI64
4247
DownlinkTXAck gw.DownlinkTXAck
4348
DownlinkFrames storage.DownlinkFrames
49+
MHDR lorawan.MHDR
50+
MACPayload *lorawan.MACPayload
4451
}
4552

4653
// HandleDownlinkTXAck handles the given downlink TX acknowledgement.
@@ -62,6 +69,38 @@ func HandleDownlinkTXAck(ctx context.Context, downlinkTXAck gw.DownlinkTXAck) er
6269
return nil
6370
}
6471

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+
65104
func getToken(ctx *ackContext) error {
66105
if ctx.DownlinkTXAck.Token != 0 {
67106
ctx.Token = uint16(ctx.DownlinkTXAck.Token)
@@ -81,11 +120,7 @@ func getDownlinkFrames(ctx *ackContext) error {
81120
return nil
82121
}
83122

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 {
89124
if len(ctx.DownlinkFrames.DownlinkFrames) == 0 {
90125
return errors.New("downlink-frames is empty")
91126
}
@@ -97,9 +132,23 @@ func sendDownlinkMetaDataToNetworkControllerOnNoError(ctx *ackContext) error {
97132
log.WithError(err).WithFields(log.Fields{
98133
"ctx_id": ctx.ctx.Value(logging.ContextIDKey),
99134
}).Error("unmarshal phypayload error")
100-
return nil
101135
}
102136

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+
103152
req := nc.HandleDownlinkMetaDataRequest{
104153
DevEui: ctx.DownlinkFrames.DevEui,
105154
MulticastGroupId: ctx.DownlinkFrames.MulticastGroupId,
@@ -108,7 +157,7 @@ func sendDownlinkMetaDataToNetworkControllerOnNoError(ctx *ackContext) error {
108157
}
109158

110159
// message type
111-
switch phy.MHDR.MType {
160+
switch ctx.MHDR.MType {
112161
case lorawan.JoinAccept:
113162
req.MessageType = nc.MType_JOIN_ACCEPT
114163
case lorawan.UnconfirmedDataDown:
@@ -117,18 +166,18 @@ func sendDownlinkMetaDataToNetworkControllerOnNoError(ctx *ackContext) error {
117166
req.MessageType = nc.MType_CONFIRMED_DATA_DOWN
118167
}
119168

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 {
122171
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 {
124173
req.ApplicationPayloadByteCount += uint32(len(b))
125174
} else {
126175
req.MacCommandByteCount += uint32(len(b))
127176
}
128177
}
129178
}
130179

131-
for _, m := range macPL.FHDR.FOpts {
180+
for _, m := range ctx.MACPayload.FHDR.FOpts {
132181
if b, err := m.MarshalBinary(); err == nil {
133182
req.MacCommandByteCount += uint32(len(b))
134183
}
@@ -153,9 +202,9 @@ func sendDownlinkMetaDataToNetworkControllerOnNoError(ctx *ackContext) error {
153202
return nil
154203
}
155204

156-
func sendTxAckToApplicationServerOnNoError(ctx *ackContext) error {
205+
func sendTxAckToApplicationServer(ctx *ackContext) error {
157206
// 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 {
159208
return nil
160209
}
161210

@@ -171,7 +220,7 @@ func sendTxAckToApplicationServerOnNoError(ctx *ackContext) error {
171220
go func(ctx *ackContext, asClient as.ApplicationServerServiceClient) {
172221
_, err := asClient.HandleTxAck(ctx.ctx, &as.HandleTxAckRequest{
173222
DevEui: ctx.DownlinkFrames.DevEui,
174-
FCnt: ctx.DownlinkFrames.FCnt,
223+
FCnt: ctx.MACPayload.FHDR.FCnt,
175224
})
176225
if err != nil {
177226
log.WithError(err).WithFields(log.Fields{
@@ -188,18 +237,10 @@ func sendTxAckToApplicationServerOnNoError(ctx *ackContext) error {
188237
return nil
189238
}
190239

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-
199240
func sendErrorToApplicationServerOnLastFrame(ctx *ackContext) error {
200241
// Only send an error to the AS on the last possible attempt.
201242
// 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 {
203244
return nil
204245
}
205246

@@ -215,7 +256,7 @@ func sendErrorToApplicationServerOnLastFrame(ctx *ackContext) error {
215256
go func(ctx *ackContext, asClient as.ApplicationServerServiceClient) {
216257
_, err := asClient.HandleError(ctx.ctx, &as.HandleErrorRequest{
217258
DevEui: ctx.DownlinkFrames.DevEui,
218-
FCnt: ctx.DownlinkFrames.FCnt,
259+
FCnt: ctx.MACPayload.FHDR.FCnt,
219260
Type: as.ErrorType_DATA_DOWN_GATEWAY,
220261
Error: ctx.DownlinkTXAck.Error,
221262
})
@@ -258,3 +299,61 @@ func saveDownlinkFrames(ctx *ackContext) error {
258299

259300
return nil
260301
}
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+
}

internal/downlink/data/data.go

+2-51
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"github.com/brocaar/chirpstack-network-server/internal/channels"
1818
"github.com/brocaar/chirpstack-network-server/internal/config"
1919
dwngateway "github.com/brocaar/chirpstack-network-server/internal/downlink/gateway"
20-
"github.com/brocaar/chirpstack-network-server/internal/framelog"
2120
"github.com/brocaar/chirpstack-network-server/internal/helpers"
2221
"github.com/brocaar/chirpstack-network-server/internal/logging"
2322
"github.com/brocaar/chirpstack-network-server/internal/maccommand"
@@ -1131,55 +1130,6 @@ func sendDownlinkFrame(ctx *dataContext) error {
11311130
// set last downlink tx timestamp
11321131
ctx.DeviceSession.LastDownlinkTX = time.Now()
11331132

1134-
// log for gateway (with encrypted mac-commands)
1135-
if err := framelog.LogDownlinkFrameForGateway(ctx.ctx, storage.RedisPool(), ctx.DownlinkFrames[0].DownlinkFrame); err != nil {
1136-
log.WithError(err).WithFields(log.Fields{
1137-
"ctx_id": ctx.ctx.Value(logging.ContextIDKey),
1138-
}).Error("log downlink frame for gateway error")
1139-
}
1140-
1141-
// log for device (with decrypted mac-commands)
1142-
if err := func() error {
1143-
var phy lorawan.PHYPayload
1144-
if err := phy.UnmarshalBinary(ctx.DownlinkFrames[0].DownlinkFrame.PhyPayload); err != nil {
1145-
return err
1146-
}
1147-
1148-
// decrypt FRMPayload mac-commands
1149-
if ctx.FPort == 0 {
1150-
if err := phy.DecryptFRMPayload(ctx.DeviceSession.NwkSEncKey); err != nil {
1151-
return errors.Wrap(err, "decrypt frmpayload error")
1152-
}
1153-
}
1154-
1155-
// decrypt FOpts mac-commands (LoRaWAN 1.1)
1156-
if ctx.DeviceSession.GetMACVersion() != lorawan.LoRaWAN1_0 {
1157-
if err := phy.DecryptFOpts(ctx.DeviceSession.NwkSEncKey); err != nil {
1158-
return errors.Wrap(err, "encrypt FOpts error")
1159-
}
1160-
}
1161-
1162-
phyB, err := phy.MarshalBinary()
1163-
if err != nil {
1164-
return err
1165-
}
1166-
1167-
// log frame
1168-
if err := framelog.LogDownlinkFrameForDevEUI(ctx.ctx, storage.RedisPool(), ctx.DeviceSession.DevEUI, gw.DownlinkFrame{
1169-
Token: uint32(ctx.DownlinkFrames[0].DownlinkFrame.Token),
1170-
TxInfo: ctx.DownlinkFrames[0].DownlinkFrame.TxInfo,
1171-
PhyPayload: phyB,
1172-
}); err != nil {
1173-
return err
1174-
}
1175-
1176-
return nil
1177-
}(); err != nil {
1178-
log.WithError(err).WithFields(log.Fields{
1179-
"ctx_id": ctx.ctx.Value(logging.ContextIDKey),
1180-
}).Error("log downlink frame for device error")
1181-
}
1182-
11831133
return nil
11841134
}
11851135

@@ -1269,7 +1219,8 @@ func saveFrames(ctx *dataContext) error {
12691219
DevEui: ctx.DeviceSession.DevEUI[:],
12701220
RoutingProfileId: ctx.DeviceSession.RoutingProfileID.Bytes(),
12711221
FCnt: fCnt,
1272-
FPort: uint32(ctx.FPort),
1222+
EncryptedFopts: ctx.DeviceSession.GetMACVersion() != lorawan.LoRaWAN1_0,
1223+
NwkSEncKey: ctx.DeviceSession.NwkSEncKey[:],
12731224
}
12741225

12751226
for i := range ctx.DownlinkFrames {

internal/downlink/join/join.go

-11
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@ import (
88
"github.com/gofrs/uuid"
99
"github.com/golang/protobuf/ptypes"
1010
"github.com/pkg/errors"
11-
log "github.com/sirupsen/logrus"
1211

1312
"github.com/brocaar/chirpstack-api/go/v3/gw"
1413
"github.com/brocaar/chirpstack-network-server/internal/backend/gateway"
1514
"github.com/brocaar/chirpstack-network-server/internal/band"
1615
"github.com/brocaar/chirpstack-network-server/internal/config"
1716
dwngateway "github.com/brocaar/chirpstack-network-server/internal/downlink/gateway"
18-
"github.com/brocaar/chirpstack-network-server/internal/framelog"
1917
"github.com/brocaar/chirpstack-network-server/internal/helpers"
2018
"github.com/brocaar/chirpstack-network-server/internal/logging"
2119
"github.com/brocaar/chirpstack-network-server/internal/models"
@@ -258,15 +256,6 @@ func sendJoinAcceptResponse(ctx *joinContext) error {
258256
return errors.Wrap(err, "send downlink frame error")
259257
}
260258

261-
// log frame
262-
if err := framelog.LogDownlinkFrameForGateway(ctx.ctx, storage.RedisPool(), ctx.DownlinkFrames[0]); err != nil {
263-
log.WithError(err).Error("log downlink frame for gateway error")
264-
}
265-
266-
if err := framelog.LogDownlinkFrameForDevEUI(ctx.ctx, storage.RedisPool(), ctx.DeviceSession.DevEUI, ctx.DownlinkFrames[0]); err != nil {
267-
log.WithError(err).Error("log downlink frame for device error")
268-
}
269-
270259
return nil
271260
}
272261

0 commit comments

Comments
 (0)