// NewRedisNetworkServer creates a new Redis-backed NetworkServer func NewRedisNetworkServer(client *redis.Client, netID int) NetworkServer { ns := &networkServer{ devices: device.NewRedisDeviceStore(client, "ns"), prefixes: map[types.DevAddrPrefix][]string{}, } ns.netID = [3]byte{byte(netID >> 16), byte(netID >> 8), byte(netID)} return ns }
func TestHandleActivate(t *testing.T) { a := New(t) ns := &networkServer{ devices: device.NewRedisDeviceStore(GetRedisClient(), "test-handle-activate"), } ns.InitStatus() dev := &device.Device{ AppEUI: types.AppEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)), DevEUI: types.DevEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)), } a.So(ns.devices.Set(dev), ShouldBeNil) defer func() { ns.devices.Delete(types.AppEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)), types.DevEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1))) }() _, err := ns.HandleActivate(&pb_handler.DeviceActivationResponse{}) a.So(err, ShouldNotBeNil) _, err = ns.HandleActivate(&pb_handler.DeviceActivationResponse{ ActivationMetadata: &pb_protocol.ActivationMetadata{}, }) a.So(err, ShouldNotBeNil) devAddr := getDevAddr(0, 0, 3, 1) var nwkSKey types.NwkSKey copy(nwkSKey[:], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1}) appEUI := types.AppEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)) devEUI := types.DevEUI(getEUI(0, 0, 0, 0, 0, 0, 3, 1)) _, err = ns.HandleActivate(&pb_handler.DeviceActivationResponse{ ActivationMetadata: &pb_protocol.ActivationMetadata{Protocol: &pb_protocol.ActivationMetadata_Lorawan{ Lorawan: &pb_lorawan.ActivationMetadata{ AppEui: &appEUI, DevEui: &devEUI, DevAddr: &devAddr, NwkSKey: &nwkSKey, }, }}, }) a.So(err, ShouldBeNil) }
func TestHandleDownlink(t *testing.T) { a := New(t) ns := &networkServer{ devices: device.NewRedisDeviceStore(GetRedisClient(), "test-handle-downlink"), } 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.DownlinkMessage{ AppEui: &appEUI, DevEui: &devEUI, Payload: []byte{}, } _, err := ns.HandleDownlink(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.DownlinkMessage{ AppEui: &appEUI, DevEui: &devEUI, Payload: []byte{}, } _, err = ns.HandleDownlink(message) a.So(err, ShouldNotBeNil) fPort := uint8(3) phy := lorawan.PHYPayload{ MHDR: lorawan.MHDR{ MType: lorawan.UnconfirmedDataDown, Major: lorawan.LoRaWANR1, }, MACPayload: &lorawan.MACPayload{ FPort: &fPort, FHDR: lorawan.FHDR{ FCtrl: lorawan.FCtrl{ ACK: true, }, }, }, } bytes, _ := phy.MarshalBinary() message = &pb_broker.DownlinkMessage{ AppEui: &appEUI, DevEui: &devEUI, Payload: bytes, } res, err := ns.HandleDownlink(message) a.So(err, ShouldBeNil) var phyPayload lorawan.PHYPayload phyPayload.UnmarshalBinary(res.Payload) macPayload, _ := phyPayload.MACPayload.(*lorawan.MACPayload) a.So(*macPayload.FPort, ShouldEqual, 3) a.So(macPayload.FHDR.DevAddr, ShouldEqual, lorawan.DevAddr{1, 2, 3, 4}) a.So(macPayload.FHDR.FCnt, ShouldEqual, 0) // The first Frame counter is zero a.So(phyPayload.MIC, ShouldNotEqual, [4]byte{0, 0, 0, 0}) // MIC should be set, we'll check it with actual examples in the integration test dev, _ := ns.devices.Get(appEUI, devEUI) a.So(dev.FCntDown, ShouldEqual, 1) }
func TestHandlePrepareActivation(t *testing.T) { a := New(t) ns := &networkServer{ netID: [3]byte{0x00, 0x00, 0x13}, prefixes: map[types.DevAddrPrefix][]string{ types.DevAddrPrefix{DevAddr: [4]byte{0x26, 0x00, 0x00, 0x00}, Length: 7}: []string{ "otaa", "local", }, }, devices: device.NewRedisDeviceStore(GetRedisClient(), "test-handle-prepare-activation"), } appEUI := types.AppEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)) devEUI := types.DevEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)) // Device not registered resp, err := ns.HandlePrepareActivation(&pb_broker.DeduplicatedDeviceActivationRequest{ ActivationMetadata: &pb_protocol.ActivationMetadata{Protocol: &pb_protocol.ActivationMetadata_Lorawan{ Lorawan: &pb_lorawan.ActivationMetadata{ CfList: &pb_lorawan.CFList{Freq: []uint32{867100000, 867300000, 867500000, 867700000, 867900000}}, }, }}, ResponseTemplate: &pb_broker.DeviceActivationResponse{}, }) a.So(err, ShouldNotBeNil) dev := &device.Device{AppEUI: appEUI, DevEUI: devEUI, Options: device.Options{ ActivationConstraints: "private", }} a.So(ns.devices.Set(dev), ShouldBeNil) defer func() { ns.devices.Delete(appEUI, devEUI) }() // Constrained Device resp, err = ns.HandlePrepareActivation(&pb_broker.DeduplicatedDeviceActivationRequest{ DevEui: &devEUI, AppEui: &appEUI, ActivationMetadata: &pb_protocol.ActivationMetadata{Protocol: &pb_protocol.ActivationMetadata_Lorawan{ Lorawan: &pb_lorawan.ActivationMetadata{ CfList: &pb_lorawan.CFList{Freq: []uint32{867100000, 867300000, 867500000, 867700000, 867900000}}, }, }}, ResponseTemplate: &pb_broker.DeviceActivationResponse{}, }) a.So(err, ShouldNotBeNil) dev.StartUpdate() dev.Options = device.Options{} a.So(ns.devices.Set(dev), ShouldBeNil) // Device registered resp, err = ns.HandlePrepareActivation(&pb_broker.DeduplicatedDeviceActivationRequest{ DevEui: &devEUI, AppEui: &appEUI, ActivationMetadata: &pb_protocol.ActivationMetadata{Protocol: &pb_protocol.ActivationMetadata_Lorawan{ Lorawan: &pb_lorawan.ActivationMetadata{ CfList: &pb_lorawan.CFList{Freq: []uint32{867100000, 867300000, 867500000, 867700000, 867900000}}, }, }}, ResponseTemplate: &pb_broker.DeviceActivationResponse{}, }) a.So(err, ShouldBeNil) devAddr := resp.ActivationMetadata.GetLorawan().DevAddr a.So(devAddr.IsEmpty(), ShouldBeFalse) a.So(devAddr[0]&254, ShouldEqual, 19<<1) // 7 MSB should be NetID var resPHY lorawan.PHYPayload resPHY.UnmarshalBinary(resp.ResponseTemplate.Payload) resMAC, _ := resPHY.MACPayload.(*lorawan.DataPayload) joinAccept := &lorawan.JoinAcceptPayload{} joinAccept.UnmarshalBinary(false, resMAC.Bytes) a.So(joinAccept.DevAddr[0]&254, ShouldEqual, 19<<1) a.So(*joinAccept.CFList, ShouldEqual, lorawan.CFList{867100000, 867300000, 867500000, 867700000, 867900000}) }
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 TestHandleGetDevices(t *testing.T) { a := New(t) ns := &networkServer{ devices: device.NewRedisDeviceStore(GetRedisClient(), "ns-test-handle-get-devices"), } nwkSKey := types.NwkSKey{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8} // No Devices devAddr1 := getDevAddr(1, 2, 3, 4) res, err := ns.HandleGetDevices(&pb.DevicesRequest{ DevAddr: &devAddr1, FCnt: 5, }) a.So(err, ShouldBeNil) a.So(res.Results, ShouldBeEmpty) // Matching Device ns.devices.Set(&device.Device{ DevAddr: getDevAddr(1, 2, 3, 4), AppEUI: types.AppEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)), DevEUI: types.DevEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)), NwkSKey: nwkSKey, FCntUp: 5, }) defer func() { ns.devices.Delete(types.AppEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8)), types.DevEUI(getEUI(1, 2, 3, 4, 5, 6, 7, 8))) }() res, err = ns.HandleGetDevices(&pb.DevicesRequest{ DevAddr: &devAddr1, FCnt: 5, }) a.So(err, ShouldBeNil) a.So(res.Results, ShouldHaveLength, 1) // Non-Matching DevAddr devAddr2 := getDevAddr(5, 6, 7, 8) res, err = ns.HandleGetDevices(&pb.DevicesRequest{ DevAddr: &devAddr2, FCnt: 5, }) a.So(err, ShouldBeNil) a.So(res.Results, ShouldHaveLength, 0) // Non-Matching FCnt res, err = ns.HandleGetDevices(&pb.DevicesRequest{ DevAddr: &devAddr1, FCnt: 4, }) a.So(err, ShouldBeNil) a.So(res.Results, ShouldHaveLength, 0) // Non-Matching FCnt, but FCnt Check Disabled ns.devices.Set(&device.Device{ DevAddr: getDevAddr(5, 6, 7, 8), AppEUI: types.AppEUI(getEUI(5, 6, 7, 8, 1, 2, 3, 4)), DevEUI: types.DevEUI(getEUI(5, 6, 7, 8, 1, 2, 3, 4)), NwkSKey: nwkSKey, FCntUp: 5, Options: device.Options{ DisableFCntCheck: true, }, }) defer func() { ns.devices.Delete(types.AppEUI(getEUI(5, 6, 7, 8, 1, 2, 3, 4)), types.DevEUI(getEUI(5, 6, 7, 8, 1, 2, 3, 4))) }() res, err = ns.HandleGetDevices(&pb.DevicesRequest{ DevAddr: &devAddr2, FCnt: 4, }) a.So(err, ShouldBeNil) a.So(res.Results, ShouldHaveLength, 1) // 32 Bit Frame Counter (A) ns.devices.Set(&device.Device{ DevAddr: getDevAddr(2, 2, 3, 4), AppEUI: types.AppEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)), DevEUI: types.DevEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)), NwkSKey: nwkSKey, FCntUp: 5 + (2 << 16), Options: device.Options{ Uses32BitFCnt: true, }, }) defer func() { ns.devices.Delete(types.AppEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8)), types.DevEUI(getEUI(2, 2, 3, 4, 5, 6, 7, 8))) }() devAddr3 := getDevAddr(2, 2, 3, 4) res, err = ns.HandleGetDevices(&pb.DevicesRequest{ DevAddr: &devAddr3, FCnt: 5, }) a.So(err, ShouldBeNil) a.So(res.Results, ShouldHaveLength, 1) // 32 Bit Frame Counter (B) ns.devices.Set(&device.Device{ DevAddr: getDevAddr(2, 2, 3, 5), AppEUI: types.AppEUI(getEUI(2, 2, 3, 4, 5, 3, 7, 8)), DevEUI: types.DevEUI(getEUI(2, 2, 3, 4, 5, 3, 7, 8)), NwkSKey: nwkSKey, FCntUp: (2 << 16) - 1, Options: device.Options{ Uses32BitFCnt: true, }, }) defer func() { ns.devices.Delete(types.AppEUI(getEUI(2, 2, 3, 4, 5, 3, 7, 8)), types.DevEUI(getEUI(2, 2, 3, 4, 5, 3, 7, 8))) }() devAddr4 := getDevAddr(2, 2, 3, 5) res, err = ns.HandleGetDevices(&pb.DevicesRequest{ DevAddr: &devAddr4, FCnt: 5, }) a.So(err, ShouldBeNil) a.So(res.Results, ShouldHaveLength, 1) }