44 "crypto/rand"
55 "crypto/tls"
66 "crypto/x509"
7+ "encoding/base64"
78 "encoding/binary"
89 "encoding/json"
910 "fmt"
@@ -20,9 +21,9 @@ import (
2021 "github.com/pkg/errors"
2122 log "github.com/sirupsen/logrus"
2223
24+ "github.com/brocaar/chirpstack-api/go/v3/gw"
2325 "github.com/brocaar/chirpstack-gateway-bridge/internal/backend/basicstation/structs"
2426 "github.com/brocaar/chirpstack-gateway-bridge/internal/config"
25- "github.com/brocaar/chirpstack-api/go/v3/gw"
2627 "github.com/brocaar/lorawan"
2728 "github.com/brocaar/lorawan/band"
2829)
@@ -48,9 +49,10 @@ type Backend struct {
4849
4950 gateways gateways
5051
51- downlinkTXAckChan chan gw.DownlinkTXAck
52- uplinkFrameChan chan gw.UplinkFrame
53- gatewayStatsChan chan gw.GatewayStats
52+ downlinkTXAckChan chan gw.DownlinkTXAck
53+ uplinkFrameChan chan gw.UplinkFrame
54+ gatewayStatsChan chan gw.GatewayStats
55+ rawPacketForwarderEventChan chan gw.RawPacketForwarderEvent
5456
5557 band band.Band
5658 region band.Name
@@ -77,9 +79,10 @@ func NewBackend(conf config.Config) (*Backend, error) {
7779 disconnectChan : make (chan lorawan.EUI64 ),
7880 },
7981
80- downlinkTXAckChan : make (chan gw.DownlinkTXAck ),
81- uplinkFrameChan : make (chan gw.UplinkFrame ),
82- gatewayStatsChan : make (chan gw.GatewayStats ),
82+ downlinkTXAckChan : make (chan gw.DownlinkTXAck ),
83+ uplinkFrameChan : make (chan gw.UplinkFrame ),
84+ gatewayStatsChan : make (chan gw.GatewayStats ),
85+ rawPacketForwarderEventChan : make (chan gw.RawPacketForwarderEvent ),
8386
8487 pingInterval : conf .Backend .BasicStation .PingInterval ,
8588 readTimeout : conf .Backend .BasicStation .ReadTimeout ,
@@ -210,6 +213,11 @@ func (b *Backend) GetDisconnectChan() chan lorawan.EUI64 {
210213 return b .gateways .disconnectChan
211214}
212215
216+ // GetRawPacketForwarderEventChan returns the raw packet-forwarder command channel.
217+ func (b * Backend ) GetRawPacketForwarderEventChan () chan gw.RawPacketForwarderEvent {
218+ return b .rawPacketForwarderEventChan
219+ }
220+
213221func (b * Backend ) SendDownlinkFrame (df gw.DownlinkFrame ) error {
214222 b .Lock ()
215223 defer b .Unlock ()
@@ -269,6 +277,36 @@ func (b *Backend) ApplyConfiguration(gwConfig gw.GatewayConfiguration) error {
269277 return nil
270278}
271279
280+ // RawPacketForwarderCommand sends the given raw command to the packet-forwarder.
281+ func (b * Backend ) RawPacketForwarderCommand (pl gw.RawPacketForwarderCommand ) error {
282+ var gatewayID lorawan.EUI64
283+ var rawID uuid.UUID
284+
285+ copy (gatewayID [:], pl .GatewayId )
286+ copy (rawID [:], pl .RawId )
287+
288+ if len (pl .Payload ) == 0 {
289+ return errors .New ("raw packet-forwarder command payload is empty" )
290+ }
291+
292+ mt := websocket .BinaryMessage
293+ if strings .HasPrefix (string (pl .Payload ), "{" ) {
294+ mt = websocket .TextMessage
295+ }
296+
297+ websocketSendCounter ("raw" ).Inc ()
298+ if err := b .sendRawToGateway (gatewayID , mt , pl .Payload ); err != nil {
299+ return errors .Wrap (err , "send raw packet-forwarder command to gateway error" )
300+ }
301+
302+ log .WithFields (log.Fields {
303+ "gateway_id" : gatewayID ,
304+ "raw_id" : rawID ,
305+ }).Info ("backend/basicstation: raw packet-forwarder command sent to gateway" )
306+
307+ return nil
308+ }
309+
272310// Close closes the backend.
273311func (b * Backend ) Close () error {
274312 b .isClosed = true
@@ -302,8 +340,14 @@ func (b *Backend) handleRouterInfo(r *http.Request, c *websocket.Conn) {
302340 }
303341 }
304342
343+ bb , err := json .Marshal (resp )
344+ if err != nil {
345+ log .WithError (err ).Error ("backend/basicstation: marshal json error" )
346+ return
347+ }
348+
305349 c .SetWriteDeadline (time .Now ().Add (b .writeTimeout ))
306- if err := c .WriteJSON ( resp ); err != nil {
350+ if err := c .WriteMessage ( websocket . TextMessage , bb ); err != nil {
307351 log .WithError (err ).Error ("backend/basicstation: websocket send message error" )
308352 return
309353 }
@@ -367,7 +411,7 @@ func (b *Backend) handleGateway(r *http.Request, c *websocket.Conn) {
367411
368412 // receive data
369413 for {
370- _ , msg , err := c .ReadMessage ()
414+ mt , msg , err := c .ReadMessage ()
371415 if err != nil {
372416 if websocket .IsUnexpectedCloseError (err , websocket .CloseNormalClosure , websocket .CloseGoingAway , websocket .CloseAbnormalClosure ) {
373417 log .WithField ("gateway_id" , gatewayID ).WithError (err ).Error ("backend/basicstation: read message error" )
@@ -378,6 +422,16 @@ func (b *Backend) handleGateway(r *http.Request, c *websocket.Conn) {
378422 // reset the read deadline as the Basic Station doesn't respond to PONG messages (yet)
379423 c .SetReadDeadline (time .Now ().Add (b .readTimeout ))
380424
425+ if mt == websocket .BinaryMessage {
426+ log .WithFields (log.Fields {
427+ "gateway_id" : gatewayID ,
428+ "message_base64" : base64 .StdEncoding .EncodeToString (msg ),
429+ }).Debug ("backend/basicstation: binary message received" )
430+
431+ b .handleRawPacketForwarderEvent (gatewayID , msg )
432+ continue
433+ }
434+
381435 log .WithFields (log.Fields {
382436 "gateway_id" : gatewayID ,
383437 "message" : string (msg ),
@@ -458,11 +512,7 @@ func (b *Backend) handleGateway(r *http.Request, c *websocket.Conn) {
458512 }
459513 b .handleDownlinkTransmittedMessage (gatewayID , pl )
460514 default :
461- log .WithFields (log.Fields {
462- "message_type" : msgType ,
463- "gateway_id" : gatewayID ,
464- "payload" : string (msg ),
465- }).Warning ("backend/basicstation: unexpected message-type" )
515+ b .handleRawPacketForwarderEvent (gatewayID , msg )
466516 }
467517 }
468518}
@@ -616,14 +666,56 @@ func (b *Backend) handleUplinkDataFrame(gatewayID lorawan.EUI64, v structs.Uplin
616666 b .uplinkFrameChan <- uplinkFrame
617667}
618668
669+ func (b * Backend ) handleRawPacketForwarderEvent (gatewayID lorawan.EUI64 , pl []byte ) {
670+ rawID , err := uuid .NewV4 ()
671+ if err != nil {
672+ log .WithError (err ).WithFields (log.Fields {
673+ "gateway_id" : gatewayID ,
674+ }).Error ("backend/basicstation: get random raw id error" )
675+ return
676+ }
677+
678+ rawEvent := gw.RawPacketForwarderEvent {
679+ GatewayId : gatewayID [:],
680+ RawId : rawID [:],
681+ Payload : pl ,
682+ }
683+
684+ log .WithFields (log.Fields {
685+ "gateway_id" : gatewayID ,
686+ "raw_id" : rawID ,
687+ }).Info ("backend/basicstation: raw packet-forwarder event received" )
688+
689+ b .rawPacketForwarderEventChan <- rawEvent
690+ }
691+
619692func (b * Backend ) sendToGateway (gatewayID lorawan.EUI64 , v interface {}) error {
620693 gw , err := b .gateways .get (gatewayID )
621694 if err != nil {
622695 return errors .Wrap (err , "get gateway error" )
623696 }
624697
698+ bb , err := json .Marshal (v )
699+ if err != nil {
700+ return errors .Wrap (err , "marshal json error" )
701+ }
702+
703+ gw .conn .SetWriteDeadline (time .Now ().Add (b .writeTimeout ))
704+ if err := gw .conn .WriteMessage (websocket .TextMessage , bb ); err != nil {
705+ return errors .Wrap (err , "send message to gateway error" )
706+ }
707+
708+ return nil
709+ }
710+
711+ func (b * Backend ) sendRawToGateway (gatewayID lorawan.EUI64 , messageType int , data []byte ) error {
712+ gw , err := b .gateways .get (gatewayID )
713+ if err != nil {
714+ return errors .Wrap (err , "get gateway error" )
715+ }
716+
625717 gw .conn .SetWriteDeadline (time .Now ().Add (b .writeTimeout ))
626- if err := gw .conn .WriteJSON ( v ); err != nil {
718+ if err := gw .conn .WriteMessage ( messageType , data ); err != nil {
627719 return errors .Wrap (err , "send message to gateway error" )
628720 }
629721
0 commit comments