// Bytes returns the bytes func (m *Message) Bytes() []byte { if m.FPort == 0 { m.FPort = 1 } macPayload := &lorawan.MACPayload{} macPayload.FHDR = lorawan.FHDR{ DevAddr: lorawan.DevAddr(m.devAddr), FCnt: uint32(m.FCnt), } macPayload.FPort = pointer.Uint8(uint8(m.FPort)) macPayload.FRMPayload = []lorawan.Payload{&lorawan.DataPayload{Bytes: m.Payload}} phyPayload := &lorawan.PHYPayload{} phyPayload.MHDR = lorawan.MHDR{ MType: lorawan.UnconfirmedDataUp, Major: lorawan.LoRaWANR1, } if m.confirmed { phyPayload.MHDR.MType = lorawan.ConfirmedDataUp } phyPayload.MACPayload = macPayload phyPayload.EncryptFRMPayload(lorawan.AES128Key(m.appSKey)) phyPayload.SetMIC(lorawan.AES128Key(m.nwkSKey)) uplinkBytes, _ := phyPayload.MarshalBinary() return uplinkBytes }
// newReferenceUplink returns a default uplink message func newReferenceUplink() *pb.UplinkMessage { gtwID := "eui-0102030405060708" phy := lorawan.PHYPayload{ MHDR: lorawan.MHDR{ MType: lorawan.UnconfirmedDataUp, Major: lorawan.LoRaWANR1, }, MACPayload: &lorawan.MACPayload{ FHDR: lorawan.FHDR{ DevAddr: lorawan.DevAddr([4]byte{1, 2, 3, 4}), }, }, } bytes, _ := phy.MarshalBinary() up := &pb.UplinkMessage{ Payload: bytes, ProtocolMetadata: &pb_protocol.RxMetadata{Protocol: &pb_protocol.RxMetadata_Lorawan{Lorawan: &pb_lorawan.Metadata{ CodingRate: "4/5", DataRate: "SF7BW125", Modulation: pb_lorawan.Modulation_LORA, }}}, GatewayMetadata: &pb_gateway.RxMetadata{ GatewayId: gtwID, Timestamp: 100, Frequency: 868100000, Rssi: -25.0, Snr: 5.0, }, } return up }
func (n *networkServer) HandleDownlink(message *pb_broker.DownlinkMessage) (*pb_broker.DownlinkMessage, error) { // Get Device dev, err := n.devices.Get(*message.AppEui, *message.DevEui) if err != nil { return nil, err } n.status.downlink.Mark(1) dev.StartUpdate() if dev.AppID != message.AppId || dev.DevID != message.DevId { return nil, errors.NewErrInvalidArgument("Downlink", "AppID and DevID do not match AppEUI and DevEUI") } // Unmarshal LoRaWAN Payload var phyPayload lorawan.PHYPayload err = phyPayload.UnmarshalBinary(message.Payload) if err != nil { return nil, err } macPayload, ok := phyPayload.MACPayload.(*lorawan.MACPayload) if !ok { return nil, errors.NewErrInvalidArgument("Downlink", "does not contain a MAC payload") } // Set DevAddr macPayload.FHDR.DevAddr = lorawan.DevAddr(dev.DevAddr) // FIRST set and THEN increment FCntDown // TODO: For confirmed downlink, FCntDown should be incremented AFTER ACK macPayload.FHDR.FCnt = dev.FCntDown dev.FCntDown++ err = n.devices.Set(dev) if err != nil { return nil, err } // Sign MIC phyPayload.SetMIC(lorawan.AES128Key(dev.NwkSKey)) // Update message bytes, err := phyPayload.MarshalBinary() if err != nil { return nil, err } message.Payload = bytes return message, nil }
// Payload converts the MACPayload to a lorawan.Payload func (msg *Message_MacPayload) Payload() lorawan.Payload { m := *msg.MacPayload var mac lorawan.MACPayload mac.FHDR.DevAddr = lorawan.DevAddr(m.DevAddr) mac.FHDR.FCtrl.ADR = m.Adr mac.FHDR.FCtrl.ADRACKReq = m.AdrAckReq mac.FHDR.FCtrl.ACK = m.Ack mac.FHDR.FCtrl.FPending = m.FPending mac.FHDR.FCnt = m.FCnt for _, cmd := range m.FOpts { mac.FHDR.FOpts = append(mac.FHDR.FOpts, cmd.MACCommand()) } if m.FPort >= 0 { fPort := uint8(m.FPort) mac.FPort = &fPort } mac.FRMPayload = []lorawan.Payload{ &lorawan.DataPayload{Bytes: m.FrmPayload}, } return &mac }
// Payload converts the JoinAcceptPayload to a lorawan.Payload func (msg *Message_JoinAcceptPayload) Payload() lorawan.Payload { m := *msg.JoinAcceptPayload if len(m.Encrypted) != 0 { return &lorawan.DataPayload{Bytes: m.Encrypted} } var mac lorawan.JoinAcceptPayload mac.AppNonce = m.AppNonce mac.NetID = m.NetId mac.DevAddr = lorawan.DevAddr(m.DevAddr) mac.DLSettings.RX1DROffset = uint8(m.Rx1DrOffset) mac.DLSettings.RX2DataRate = uint8(m.Rx2Dr) mac.RXDelay = uint8(m.RxDelay) if m.CfList != nil && len(m.CfList.Freq) == 5 { mac.CFList = &lorawan.CFList{ m.CfList.Freq[0], m.CfList.Freq[1], m.CfList.Freq[2], m.CfList.Freq[3], m.CfList.Freq[4], } } return &mac }
func TestHandleUplink(t *testing.T) { a := New(t) ns := &networkServer{ devices: device.NewRedisDeviceStore(GetRedisClient(), "ns-test-handle-uplink"), } ns.InitStatus() appEUI := types.AppEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)) devEUI := types.DevEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)) devAddr := getDevAddr(1, 2, 3, 4) // Device Not Found message := &pb_broker.DeduplicatedUplinkMessage{ AppEui: &appEUI, DevEui: &devEUI, Payload: []byte{}, } _, err := ns.HandleUplink(message) a.So(err, ShouldNotBeNil) ns.devices.Set(&device.Device{ DevAddr: devAddr, AppEUI: appEUI, DevEUI: devEUI, }) defer func() { ns.devices.Delete(appEUI, devEUI) }() // Invalid Payload message = &pb_broker.DeduplicatedUplinkMessage{ AppEui: &appEUI, DevEui: &devEUI, Payload: []byte{}, } _, err = ns.HandleUplink(message) a.So(err, ShouldNotBeNil) phy := lorawan.PHYPayload{ MHDR: lorawan.MHDR{ MType: lorawan.UnconfirmedDataUp, Major: lorawan.LoRaWANR1, }, MACPayload: &lorawan.MACPayload{ FHDR: lorawan.FHDR{ DevAddr: lorawan.DevAddr([4]byte{1, 2, 3, 4}), FCnt: 1, FCtrl: lorawan.FCtrl{ ADR: true, ADRACKReq: true, }, FOpts: []lorawan.MACCommand{ lorawan.MACCommand{CID: lorawan.LinkCheckReq}, }, }, }, } bytes, _ := phy.MarshalBinary() // Valid Uplink message = &pb_broker.DeduplicatedUplinkMessage{ AppEui: &appEUI, DevEui: &devEUI, Payload: bytes, ResponseTemplate: &pb_broker.DownlinkMessage{}, GatewayMetadata: []*pb_gateway.RxMetadata{ &pb_gateway.RxMetadata{}, }, ProtocolMetadata: &pb_protocol.RxMetadata{Protocol: &pb_protocol.RxMetadata_Lorawan{ Lorawan: &pb_lorawan.Metadata{ DataRate: "SF7BW125", }, }}, } res, err := ns.HandleUplink(message) a.So(err, ShouldBeNil) a.So(res.ResponseTemplate, ShouldNotBeNil) // LoRaWAN: Unmarshal var phyPayload lorawan.PHYPayload phyPayload.UnmarshalBinary(res.ResponseTemplate.Payload) macPayload, _ := phyPayload.MACPayload.(*lorawan.MACPayload) // ResponseTemplate DevAddr should match a.So([4]byte(macPayload.FHDR.DevAddr), ShouldEqual, [4]byte(devAddr)) // ResponseTemplate should ACK the ADRACKReq a.So(macPayload.FHDR.FCtrl.ACK, ShouldBeTrue) a.So(macPayload.FHDR.FOpts, ShouldHaveLength, 1) a.So(macPayload.FHDR.FOpts[0].Payload, ShouldResemble, &lorawan.LinkCheckAnsPayload{GwCnt: 1, Margin: 7}) // Frame Counter should have been updated dev, _ := ns.devices.Get(appEUI, devEUI) a.So(dev.FCntUp, ShouldEqual, 1) a.So(time.Now().Sub(dev.LastSeen), ShouldBeLessThan, 1*time.Second) }
func (n *networkServer) HandlePrepareActivation(activation *pb_broker.DeduplicatedDeviceActivationRequest) (*pb_broker.DeduplicatedDeviceActivationRequest, error) { if activation.AppEui == nil || activation.DevEui == nil { return nil, errors.NewErrInvalidArgument("Activation", "missing AppEUI or DevEUI") } dev, err := n.devices.Get(*activation.AppEui, *activation.DevEui) if err != nil { return nil, err } activation.AppId = dev.AppID activation.DevId = dev.DevID // Get activation constraints (for DevAddr prefix selection) activationConstraints := strings.Split(dev.Options.ActivationConstraints, ",") if len(activationConstraints) == 1 && activationConstraints[0] == "" { activationConstraints = []string{} } activationConstraints = append(activationConstraints, "otaa") // Build activation metadata if not present if meta := activation.GetActivationMetadata(); meta == nil { activation.ActivationMetadata = &pb_protocol.ActivationMetadata{} } // Build lorawan metadata if not present if lorawan := activation.ActivationMetadata.GetLorawan(); lorawan == nil { return nil, errors.NewErrInvalidArgument("Activation", "missing LoRaWAN metadata") } // Build response template if not present if pld := activation.GetResponseTemplate(); pld == nil { return nil, errors.NewErrInvalidArgument("Activation", "missing response template") } lorawanMeta := activation.ActivationMetadata.GetLorawan() // Get a random device address devAddr, err := n.getDevAddr(activationConstraints...) if err != nil { return nil, err } // Set the DevAddr in the Activation Metadata lorawanMeta.DevAddr = &devAddr // Build JoinAccept Payload phy := lorawan.PHYPayload{ MHDR: lorawan.MHDR{ MType: lorawan.JoinAccept, Major: lorawan.LoRaWANR1, }, MACPayload: &lorawan.JoinAcceptPayload{ NetID: n.netID, DLSettings: lorawan.DLSettings{RX2DataRate: uint8(lorawanMeta.Rx2Dr), RX1DROffset: uint8(lorawanMeta.Rx1DrOffset)}, RXDelay: uint8(lorawanMeta.RxDelay), DevAddr: lorawan.DevAddr(devAddr), }, } if lorawanMeta.CfList != nil { var cfList lorawan.CFList for i, cfListItem := range lorawanMeta.CfList.Freq { cfList[i] = cfListItem } phy.MACPayload.(*lorawan.JoinAcceptPayload).CFList = &cfList } // Set the Payload phyBytes, err := phy.MarshalBinary() if err != nil { return nil, err } activation.ResponseTemplate.Payload = phyBytes return activation, nil }
func TestHandleUplink(t *testing.T) { a := New(t) b := getTestBroker(t) gtwID := "eui-0102030405060708" // Invalid Payload err := b.HandleUplink(&pb.UplinkMessage{ Payload: []byte{0x01, 0x02, 0x03}, GatewayMetadata: &gateway.RxMetadata{Snr: 1.2, GatewayId: gtwID}, ProtocolMetadata: &protocol.RxMetadata{}, }) a.So(err, ShouldNotBeNil) // Valid Payload phy := lorawan.PHYPayload{ MHDR: lorawan.MHDR{ MType: lorawan.UnconfirmedDataUp, Major: lorawan.LoRaWANR1, }, MACPayload: &lorawan.MACPayload{ FHDR: lorawan.FHDR{ DevAddr: lorawan.DevAddr([4]byte{1, 2, 3, 4}), FCnt: 1, }, }, } bytes, _ := phy.MarshalBinary() // Device not found b.uplinkDeduplicator = NewDeduplicator(10 * time.Millisecond) b.ns.EXPECT().GetDevices(gomock.Any(), gomock.Any()).Return(&pb_networkserver.DevicesResponse{ Results: []*pb_lorawan.Device{}, }, nil) err = b.HandleUplink(&pb.UplinkMessage{ Payload: bytes, GatewayMetadata: &gateway.RxMetadata{Snr: 1.2, GatewayId: gtwID}, ProtocolMetadata: &protocol.RxMetadata{Protocol: &protocol.RxMetadata_Lorawan{Lorawan: &pb_lorawan.Metadata{}}}, }) a.So(err, ShouldHaveSameTypeAs, &errors.ErrNotFound{}) devEUI := types.DevEUI{1, 2, 3, 4, 5, 6, 7, 8} wrongDevEUI := types.DevEUI{1, 2, 3, 4, 5, 6, 7, 9} appEUI := types.AppEUI{1, 2, 3, 4, 5, 6, 7, 8} appID := "appid-1" nwkSKey := types.NwkSKey{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8} // Add devices b = getTestBroker(t) nsResponse := &pb_networkserver.DevicesResponse{ Results: []*pb_lorawan.Device{ &pb_lorawan.Device{ DevEui: &wrongDevEUI, AppEui: &appEUI, AppId: appID, NwkSKey: &nwkSKey, FCntUp: 4, }, &pb_lorawan.Device{ DevEui: &devEUI, AppEui: &appEUI, AppId: appID, NwkSKey: &nwkSKey, FCntUp: 3, }, }, } b.handlers["handlerID"] = &handler{uplink: make(chan *pb.DeduplicatedUplinkMessage, 10)} // Device doesn't match b.uplinkDeduplicator = NewDeduplicator(10 * time.Millisecond) b.ns.EXPECT().GetDevices(gomock.Any(), gomock.Any()).Return(nsResponse, nil) err = b.HandleUplink(&pb.UplinkMessage{ Payload: bytes, GatewayMetadata: &gateway.RxMetadata{Snr: 1.2, GatewayId: gtwID}, ProtocolMetadata: &protocol.RxMetadata{Protocol: &protocol.RxMetadata_Lorawan{Lorawan: &pb_lorawan.Metadata{}}}, }) a.So(err, ShouldHaveSameTypeAs, &errors.ErrNotFound{}) phy.SetMIC(lorawan.AES128Key{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}) bytes, _ = phy.MarshalBinary() // Wrong FCnt b.uplinkDeduplicator = NewDeduplicator(10 * time.Millisecond) b.ns.EXPECT().GetDevices(gomock.Any(), gomock.Any()).Return(nsResponse, nil) err = b.HandleUplink(&pb.UplinkMessage{ Payload: bytes, GatewayMetadata: &gateway.RxMetadata{Snr: 1.2, GatewayId: gtwID}, ProtocolMetadata: &protocol.RxMetadata{Protocol: &protocol.RxMetadata_Lorawan{Lorawan: &pb_lorawan.Metadata{}}}, }) a.So(err, ShouldHaveSameTypeAs, &errors.ErrNotFound{}) // Disable FCnt Check b.uplinkDeduplicator = NewDeduplicator(10 * time.Millisecond) nsResponse.Results[0].DisableFCntCheck = true b.ns.EXPECT().GetDevices(gomock.Any(), gomock.Any()).Return(nsResponse, nil) b.ns.EXPECT().Uplink(gomock.Any(), gomock.Any()) b.discovery.EXPECT().GetAllHandlersForAppID("appid-1").Return([]*pb_discovery.Announcement{ &pb_discovery.Announcement{ Id: "handlerID", }, }, nil) err = b.HandleUplink(&pb.UplinkMessage{ Payload: bytes, GatewayMetadata: &gateway.RxMetadata{Snr: 1.2, GatewayId: gtwID}, ProtocolMetadata: &protocol.RxMetadata{Protocol: &protocol.RxMetadata_Lorawan{Lorawan: &pb_lorawan.Metadata{}}}, }) a.So(err, ShouldBeNil) // OK FCnt b.uplinkDeduplicator = NewDeduplicator(10 * time.Millisecond) nsResponse.Results[0].FCntUp = 0 nsResponse.Results[0].DisableFCntCheck = false b.ns.EXPECT().GetDevices(gomock.Any(), gomock.Any()).Return(nsResponse, nil) b.ns.EXPECT().Uplink(gomock.Any(), gomock.Any()) b.discovery.EXPECT().GetAllHandlersForAppID("appid-1").Return([]*pb_discovery.Announcement{ &pb_discovery.Announcement{ Id: "handlerID", }, }, nil) err = b.HandleUplink(&pb.UplinkMessage{ Payload: bytes, GatewayMetadata: &gateway.RxMetadata{Snr: 1.2, GatewayId: gtwID}, ProtocolMetadata: &protocol.RxMetadata{Protocol: &protocol.RxMetadata_Lorawan{Lorawan: &pb_lorawan.Metadata{}}}, }) a.So(err, ShouldBeNil) }