func (h *handlerManager) DeleteDevice(ctx context.Context, in *pb.DeviceIdentifier) (*empty.Empty, error) { if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Device Identifier") } ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId) if err != nil { return nil, err } if !claims.AppRight(in.AppId, rights.Devices) { return nil, errors.NewErrPermissionDenied(fmt.Sprintf(`No "devices" rights to application "%s"`, in.AppId)) } if _, err := h.handler.applications.Get(in.AppId); err != nil { return nil, errors.Wrap(err, "Application not registered to this Handler") } dev, err := h.handler.devices.Get(in.AppId, in.DevId) if err != nil { return nil, err } _, err = h.deviceManager.DeleteDevice(ctx, &pb_lorawan.DeviceIdentifier{AppEui: &dev.AppEUI, DevEui: &dev.DevEUI}) if err != nil && errors.GetErrType(errors.FromGRPCError(err)) != errors.NotFound { return nil, errors.Wrap(errors.FromGRPCError(err), "Broker did not delete device") } err = h.handler.devices.Delete(in.AppId, in.DevId) if err != nil { return nil, err } return &empty.Empty{}, nil }
// GatewayStatus handles gateway status streams func (s *RouterStreamServer) GatewayStatus(stream Router_GatewayStatusServer) error { md, err := api.MetadataFromContext(stream.Context()) if err != nil { return err } ch, err := s.GatewayStatusChanFunc(md) if err != nil { return err } defer func() { close(ch) }() for { status, err := stream.Recv() if err == io.EOF { return stream.SendAndClose(&empty.Empty{}) } if err != nil { return err } if err := status.Validate(); err != nil { return errors.Wrap(err, "Invalid Gateway Status") } ch <- status } }
func (h *handlerManager) GetDevAddr(ctx context.Context, in *pb_lorawan.DevAddrRequest) (*pb_lorawan.DevAddrResponse, error) { res, err := h.devAddrManager.GetDevAddr(ctx, in) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "Broker did not return DevAddr") } return res, nil }
func (b *brokerManager) GetPrefixes(ctx context.Context, in *lorawan.PrefixesRequest) (*lorawan.PrefixesResponse, error) { res, err := b.devAddrManager.GetPrefixes(ctx, in) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "NetworkServer did not return prefixes") } return res, nil }
func (h *handlerManager) SetApplication(ctx context.Context, in *pb.Application) (*empty.Empty, error) { if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Application") } ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId) if err != nil { return nil, err } if !claims.AppRight(in.AppId, rights.AppSettings) { return nil, errors.NewErrPermissionDenied(`No "settings" rights to application`) } app, err := h.handler.applications.Get(in.AppId) if err != nil { return nil, err } app.StartUpdate() app.Decoder = in.Decoder app.Converter = in.Converter app.Validator = in.Validator app.Encoder = in.Encoder err = h.handler.applications.Set(app) if err != nil { return nil, err } return &empty.Empty{}, nil }
// Uplink handles uplink streams func (s *RouterStreamServer) Uplink(stream Router_UplinkServer) (err error) { md, err := api.MetadataFromContext(stream.Context()) if err != nil { return err } ch, err := s.UplinkChanFunc(md) if err != nil { return err } defer func() { ctx := s.ctx if err != nil { ctx = ctx.WithError(err) } close(ch) ctx.Debug("Closed Uplink stream") }() for { uplink, err := stream.Recv() if err == io.EOF { return stream.SendAndClose(&empty.Empty{}) } if err != nil { return err } if err := uplink.Validate(); err != nil { return errors.Wrap(err, "Invalid Uplink") } ch <- uplink } }
func (h *handlerManager) DeleteApplication(ctx context.Context, in *pb.ApplicationIdentifier) (*empty.Empty, error) { if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Application Identifier") } ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId) if err != nil { return nil, err } if !claims.AppRight(in.AppId, rights.AppSettings) { return nil, errors.NewErrPermissionDenied(`No "settings" rights to application`) } _, err = h.handler.applications.Get(in.AppId) if err != nil { return nil, err } // Get and delete all devices for this application devices, err := h.handler.devices.ListForApp(in.AppId) if err != nil { return nil, err } for _, dev := range devices { _, err = h.deviceManager.DeleteDevice(ctx, &pb_lorawan.DeviceIdentifier{AppEui: &dev.AppEUI, DevEui: &dev.DevEUI}) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "Broker did not delete device") } err = h.handler.devices.Delete(dev.AppID, dev.DevID) if err != nil { return nil, err } } // Delete the Application err = h.handler.applications.Delete(in.AppId) if err != nil { return nil, err } token, _ := api.TokenFromContext(ctx) err = h.handler.Discovery.RemoveAppID(in.AppId, token) if err != nil { h.handler.Ctx.WithField("AppID", in.AppId).WithError(errors.FromGRPCError(err)).Warn("Could not unregister Application from Discovery") } return &empty.Empty{}, nil }
// NotNilAndValid checks if the given interface is not nil AND validates it func NotNilAndValid(in interface{}, argument string) error { // Structs can not be nil and reflect.ValueOf(in).IsNil() would panic if reflect.ValueOf(in).Kind() == reflect.Struct { return errors.Wrap(Validate(in), "Invalid "+argument) } // We need to check for the interface to be nil and the value of the interface // See: https://stackoverflow.com/questions/13476349/check-for-nil-and-nil-interface-in-go if in == nil || reflect.ValueOf(in).IsNil() { return errors.NewErrInvalidArgument(argument, "can not be empty") } if err := Validate(in); err != nil { return errors.Wrap(Validate(in), "Invalid "+argument) } return nil }
func (b *brokerManager) DeleteDevice(ctx context.Context, in *lorawan.DeviceIdentifier) (*empty.Empty, error) { if _, err := b.validateClient(ctx); err != nil { return nil, err } res, err := b.deviceManager.DeleteDevice(ctx, in) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "NetworkServer did not delete device") } return res, nil }
func (n *networkServerManager) GetStatus(ctx context.Context, in *pb.StatusRequest) (*pb.Status, error) { if n.networkServer.Identity.Id != "dev" { _, err := n.networkServer.ValidateTTNAuthContext(ctx) if err != nil { return nil, errors.Wrap(err, "No access") } } status := n.networkServer.GetStatus() if status == nil { return new(pb.Status), nil } return status, nil }
func (h *handlerManager) GetDevicesForApplication(ctx context.Context, in *pb.ApplicationIdentifier) (*pb.DeviceList, error) { if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Application Identifier") } ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId) if err != nil { return nil, err } if !claims.AppRight(in.AppId, rights.Devices) { return nil, errors.NewErrPermissionDenied(fmt.Sprintf(`No "devices" rights to application "%s"`, in.AppId)) } if _, err := h.handler.applications.Get(in.AppId); err != nil { return nil, errors.Wrap(err, "Application not registered to this Handler") } devices, err := h.handler.devices.ListForApp(in.AppId) if err != nil { return nil, err } res := &pb.DeviceList{Devices: []*pb.Device{}} for _, dev := range devices { res.Devices = append(res.Devices, &pb.Device{ AppId: dev.AppID, DevId: dev.DevID, Device: &pb.Device_LorawanDevice{LorawanDevice: &pb_lorawan.Device{ AppId: dev.AppID, AppEui: &dev.AppEUI, DevId: dev.DevID, DevEui: &dev.DevEUI, DevAddr: &dev.DevAddr, NwkSKey: &dev.NwkSKey, AppSKey: &dev.AppSKey, AppKey: &dev.AppKey, }}, }) } return res, nil }
func (s *networkServerRPC) PrepareActivation(ctx context.Context, activation *broker.DeduplicatedDeviceActivationRequest) (*broker.DeduplicatedDeviceActivationRequest, error) { if err := s.ValidateContext(ctx); err != nil { return nil, err } if err := activation.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Activation Request") } res, err := s.networkServer.HandlePrepareActivation(activation) if err != nil { return nil, err } return res, nil }
// Activate implements RouterServer interface (github.com/TheThingsNetwork/ttn/api/router) func (r *routerRPC) Activate(ctx context.Context, req *pb.DeviceActivationRequest) (*pb.DeviceActivationResponse, error) { gateway, err := r.gatewayFromContext(ctx) if err != nil { return nil, err } if err := req.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Activation Request") } if r.uplinkRate.Limit(gateway.ID) { return nil, grpc.Errorf(codes.ResourceExhausted, "Gateway reached uplink rate limit") } return r.router.HandleActivation(gateway.ID, req) }
func (s *networkServerRPC) Uplink(ctx context.Context, message *broker.DeduplicatedUplinkMessage) (*broker.DeduplicatedUplinkMessage, error) { if err := s.ValidateContext(ctx); err != nil { return nil, err } if err := message.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Uplink") } res, err := s.networkServer.HandleUplink(message) if err != nil { return nil, err } return res, nil }
func (s *networkServerRPC) Activate(ctx context.Context, activation *handler.DeviceActivationResponse) (*handler.DeviceActivationResponse, error) { if err := s.ValidateContext(ctx); err != nil { return nil, err } if err := activation.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Activation Request") } res, err := s.networkServer.HandleActivate(activation) if err != nil { return nil, err } return res, nil }
func (s *networkServerRPC) GetDevices(ctx context.Context, req *pb.DevicesRequest) (*pb.DevicesResponse, error) { if err := s.ValidateContext(ctx); err != nil { return nil, err } if err := req.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Devices Request") } res, err := s.networkServer.HandleGetDevices(req) if err != nil { return nil, err } return res, nil }
func (h *handlerRPC) ActivationChallenge(ctx context.Context, challenge *pb_broker.ActivationChallengeRequest) (*pb_broker.ActivationChallengeResponse, error) { _, err := h.handler.ValidateNetworkContext(ctx) if err != nil { return nil, err } if err := challenge.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Activation Challenge Request") } res, err := h.handler.HandleActivationChallenge(challenge) if err != nil { return nil, err } return res, nil }
func (h *handlerRPC) Activate(ctx context.Context, activation *pb_broker.DeduplicatedDeviceActivationRequest) (*pb.DeviceActivationResponse, error) { _, err := h.handler.ValidateNetworkContext(ctx) if err != nil { return nil, err } if err := activation.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Activation Request") } res, err := h.handler.HandleActivation(activation) if err != nil { return nil, err } return res, nil }
func (n *networkServerManager) SetDevice(ctx context.Context, in *pb_lorawan.Device) (*empty.Empty, error) { dev, err := n.getDevice(ctx, &pb_lorawan.DeviceIdentifier{AppEui: in.AppEui, DevEui: in.DevEui}) if err != nil && errors.GetErrType(err) != errors.NotFound { return nil, err } if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Device") } claims, err := n.networkServer.Component.ValidateTTNAuthContext(ctx) if err != nil { return nil, err } if !claims.AppRight(in.AppId, rights.AppSettings) { return nil, errors.NewErrPermissionDenied(fmt.Sprintf("No access to Application %s", dev.AppID)) } if dev == nil { dev = new(device.Device) } else { dev.StartUpdate() } dev.AppID = in.AppId dev.AppEUI = *in.AppEui dev.DevID = in.DevId dev.DevEUI = *in.DevEui dev.FCntUp = in.FCntUp dev.FCntDown = in.FCntDown dev.Options = device.Options{ DisableFCntCheck: in.DisableFCntCheck, Uses32BitFCnt: in.Uses32BitFCnt, ActivationConstraints: in.ActivationConstraints, } if in.NwkSKey != nil && in.DevAddr != nil { dev.DevAddr = *in.DevAddr dev.NwkSKey = *in.NwkSKey } err = n.networkServer.devices.Set(dev) if err != nil { return nil, err } return &empty.Empty{}, nil }
func (h *handlerManager) GetStatus(ctx context.Context, in *pb.StatusRequest) (*pb.Status, error) { if h.handler.Identity.Id != "dev" { claims, err := h.handler.ValidateTTNAuthContext(ctx) if err != nil { return nil, errors.Wrap(err, "No access") } if !claims.ComponentAccess(h.handler.Identity.Id) { return nil, errors.NewErrPermissionDenied(fmt.Sprintf("Claims do not grant access to %s", h.handler.Identity.Id)) } } status := h.handler.GetStatus() if status == nil { return new(pb.Status), nil } return status, nil }
func (b *brokerRPC) Activate(ctx context.Context, req *pb.DeviceActivationRequest) (res *pb.DeviceActivationResponse, err error) { _, err = b.broker.ValidateNetworkContext(ctx) if err != nil { return nil, err } if err := req.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Activation Request") } res, err = b.broker.HandleActivation(req) if err == errDuplicateActivation { return nil, grpc.Errorf(codes.OutOfRange, err.Error()) } if err != nil { return nil, err } return }
func (h *handlerManager) RegisterApplication(ctx context.Context, in *pb.ApplicationIdentifier) (*empty.Empty, error) { if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Application Identifier") } ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId) if err != nil { return nil, err } if !claims.AppRight(in.AppId, rights.AppSettings) { return nil, errors.NewErrPermissionDenied(`No "settings" rights to application`) } app, err := h.handler.applications.Get(in.AppId) if err != nil && errors.GetErrType(err) != errors.NotFound { return nil, err } if app != nil { return nil, errors.NewErrAlreadyExists("Application") } err = h.handler.applications.Set(&application.Application{ AppID: in.AppId, }) if err != nil { return nil, err } token, _ := api.TokenFromContext(ctx) err = h.handler.Discovery.AddAppID(in.AppId, token) if err != nil { h.handler.Ctx.WithField("AppID", in.AppId).WithError(err).Warn("Could not register Application with Discovery") } _, err = h.handler.ttnBrokerManager.RegisterApplicationHandler(ctx, &pb_broker.ApplicationHandlerRegistration{ AppId: in.AppId, HandlerId: h.handler.Identity.Id, }) if err != nil { h.handler.Ctx.WithField("AppID", in.AppId).WithError(err).Warn("Could not register Application with Broker") } return &empty.Empty{}, nil }
func (n *networkServerManager) getDevice(ctx context.Context, in *pb_lorawan.DeviceIdentifier) (*device.Device, error) { if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Device Identifier") } claims, err := n.networkServer.Component.ValidateTTNAuthContext(ctx) if err != nil { return nil, err } if n.clientRate.Limit(claims.Subject) { return nil, grpc.Errorf(codes.ResourceExhausted, "Rate limit for client reached") } dev, err := n.networkServer.devices.Get(*in.AppEui, *in.DevEui) if err != nil { return nil, err } if !claims.AppRight(dev.AppID, rights.AppSettings) { return nil, errors.NewErrPermissionDenied(fmt.Sprintf("No access to Application %s", dev.AppID)) } return dev, nil }
func (b *brokerManager) RegisterApplicationHandler(ctx context.Context, in *pb.ApplicationHandlerRegistration) (*empty.Empty, error) { claims, err := b.broker.Component.ValidateTTNAuthContext(ctx) if err != nil { return nil, err } if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Application Handler Registration") } if !claims.AppRight(in.AppId, rights.AppSettings) { return nil, errors.NewErrPermissionDenied("No access to this application") } // Add Handler in local cache handler, err := b.broker.Discovery.Get("handler", in.HandlerId) if err != nil { return nil, errors.NewErrInternal("Could not get Handler Announcement") } handler.Metadata = append(handler.Metadata, &discovery.Metadata{Metadata: &discovery.Metadata_AppId{ AppId: in.AppId, }}) return &empty.Empty{}, nil }
func (b *broker) HandleDownlink(downlink *pb.DownlinkMessage) error { ctx := b.Ctx.WithFields(log.Fields{ "DevEUI": *downlink.DevEui, "AppEUI": *downlink.AppEui, }) var err error start := time.Now() defer func() { if err != nil { ctx.WithError(err).Warn("Could not handle downlink") } else { ctx.WithField("Duration", time.Now().Sub(start)).Info("Handled downlink") } }() b.status.downlink.Mark(1) downlink, err = b.ns.Downlink(b.Component.GetContext(b.nsToken), downlink) if err != nil { return errors.Wrap(errors.FromGRPCError(err), "NetworkServer did not handle downlink") } var routerID string if id := strings.Split(downlink.DownlinkOption.Identifier, ":"); len(id) == 2 { routerID = id[0] } else { return errors.NewErrInvalidArgument("DownlinkOption Identifier", "invalid format") } ctx = ctx.WithField("RouterID", routerID) var router chan<- *pb.DownlinkMessage router, err = b.getRouter(routerID) if err != nil { return err } router <- downlink return nil }
func (b *broker) checkPrefixAnnouncements() error { // Get prefixes from NS nsPrefixes := map[types.DevAddrPrefix]string{} devAddrClient := pb_lorawan.NewDevAddrManagerClient(b.nsConn) resp, err := devAddrClient.GetPrefixes(b.GetContext(""), &pb_lorawan.PrefixesRequest{}) if err != nil { return errors.Wrap(errors.FromGRPCError(err), "NetworkServer did not return prefixes") } for _, mapping := range resp.Prefixes { prefix, err := types.ParseDevAddrPrefix(mapping.Prefix) if err != nil { continue } nsPrefixes[prefix] = strings.Join(mapping.Usage, ",") } // Get self from Discovery self, err := b.Component.Discover("broker", b.Component.Identity.Id) if err != nil { return err } announcedPrefixes := self.DevAddrPrefixes() nextPrefix: for nsPrefix, usage := range nsPrefixes { if !strings.Contains(usage, "world") && !strings.Contains(usage, "local") { continue } for _, announcedPrefix := range announcedPrefixes { if nsPrefix.DevAddr == announcedPrefix.DevAddr && nsPrefix.Length == announcedPrefix.Length { b.Ctx.WithField("NSPrefix", nsPrefix).WithField("DPrefix", announcedPrefix).Info("Prefix found in Discovery") continue nextPrefix } } b.Ctx.WithField("Prefix", nsPrefix).Warn("Prefix not announced in Discovery") } return nil }
func (h *handlerManager) GetDevice(ctx context.Context, in *pb.DeviceIdentifier) (*pb.Device, error) { if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Device Identifier") } ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId) if err != nil { return nil, err } if !claims.AppRight(in.AppId, rights.Devices) { return nil, errors.NewErrPermissionDenied(fmt.Sprintf(`No "devices" rights to application "%s"`, in.AppId)) } if _, err := h.handler.applications.Get(in.AppId); err != nil { return nil, errors.Wrap(err, "Application not registered to this Handler") } dev, err := h.handler.devices.Get(in.AppId, in.DevId) if err != nil { return nil, err } pbDev := &pb.Device{ AppId: dev.AppID, DevId: dev.DevID, Device: &pb.Device_LorawanDevice{LorawanDevice: &pb_lorawan.Device{ AppId: dev.AppID, AppEui: &dev.AppEUI, DevId: dev.DevID, DevEui: &dev.DevEUI, DevAddr: &dev.DevAddr, NwkSKey: &dev.NwkSKey, AppSKey: &dev.AppSKey, AppKey: &dev.AppKey, DisableFCntCheck: dev.Options.DisableFCntCheck, Uses32BitFCnt: dev.Options.Uses32BitFCnt, ActivationConstraints: dev.Options.ActivationConstraints, }}, } nsDev, err := h.deviceManager.GetDevice(ctx, &pb_lorawan.DeviceIdentifier{ AppEui: &dev.AppEUI, DevEui: &dev.DevEUI, }) if errors.GetErrType(errors.FromGRPCError(err)) == errors.NotFound { // Re-register the device in the Broker (NetworkServer) h.handler.Ctx.WithFields(log.Fields{ "AppID": dev.AppID, "DevID": dev.DevID, "AppEUI": dev.AppEUI, "DevEUI": dev.DevEUI, }).Warn("Re-registering missing device to Broker") nsDev = dev.GetLoRaWAN() _, err = h.deviceManager.SetDevice(ctx, nsDev) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "Could not re-register missing device to Broker") } } else if err != nil { return pbDev, errors.Wrap(errors.FromGRPCError(err), "Broker did not return device") } pbDev.GetLorawanDevice().FCntUp = nsDev.FCntUp pbDev.GetLorawanDevice().FCntDown = nsDev.FCntDown pbDev.GetLorawanDevice().LastSeen = nsDev.LastSeen return pbDev, nil }
func (b *broker) HandleActivation(activation *pb.DeviceActivationRequest) (res *pb.DeviceActivationResponse, err error) { ctx := b.Ctx.WithFields(log.Fields{ "GatewayID": activation.GatewayMetadata.GatewayId, "AppEUI": *activation.AppEui, "DevEUI": *activation.DevEui, }) start := time.Now() defer func() { if err != nil { ctx.WithError(err).Warn("Could not handle activation") } else { ctx.WithField("Duration", time.Now().Sub(start)).Info("Handled activation") } }() time := time.Now() b.status.activations.Mark(1) // De-duplicate uplink messages duplicates := b.deduplicateActivation(activation) if len(duplicates) == 0 { return nil, errDuplicateActivation } b.status.activationsUnique.Mark(1) base := duplicates[0] // Collect GatewayMetadata and DownlinkOptions var gatewayMetadata []*gateway.RxMetadata var downlinkOptions []*pb.DownlinkOption var deviceActivationResponse *pb.DeviceActivationResponse for _, duplicate := range duplicates { gatewayMetadata = append(gatewayMetadata, duplicate.GatewayMetadata) downlinkOptions = append(downlinkOptions, duplicate.DownlinkOptions...) } // Select best DownlinkOption if len(downlinkOptions) > 0 { deviceActivationResponse = &pb.DeviceActivationResponse{ DownlinkOption: selectBestDownlink(downlinkOptions), } } // Build Uplink deduplicatedActivationRequest := &pb.DeduplicatedDeviceActivationRequest{ Payload: base.Payload, DevEui: base.DevEui, AppEui: base.AppEui, ProtocolMetadata: base.ProtocolMetadata, GatewayMetadata: gatewayMetadata, ActivationMetadata: base.ActivationMetadata, ServerTime: time.UnixNano(), ResponseTemplate: deviceActivationResponse, } // Send Activate to NS deduplicatedActivationRequest, err = b.ns.PrepareActivation(b.Component.GetContext(b.nsToken), deduplicatedActivationRequest) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "NetworkServer refused to prepare activation") } ctx = ctx.WithFields(log.Fields{ "AppID": deduplicatedActivationRequest.AppId, "DevID": deduplicatedActivationRequest.DevId, }) // Find Handler (based on AppEUI) var announcements []*pb_discovery.Announcement announcements, err = b.Discovery.GetAllHandlersForAppID(deduplicatedActivationRequest.AppId) if err != nil { return nil, err } if len(announcements) == 0 { return nil, errors.NewErrNotFound(fmt.Sprintf("Handler for AppID %s", deduplicatedActivationRequest.AppId)) } ctx = ctx.WithField("NumHandlers", len(announcements)) // LoRaWAN: Unmarshal and prepare version without MIC var phyPayload lorawan.PHYPayload err = phyPayload.UnmarshalBinary(deduplicatedActivationRequest.Payload) if err != nil { return nil, err } correctMIC := phyPayload.MIC phyPayload.MIC = [4]byte{0, 0, 0, 0} phyPayloadWithoutMIC, err := phyPayload.MarshalBinary() if err != nil { return nil, err } // Build Challenge challenge := &pb.ActivationChallengeRequest{ Payload: phyPayloadWithoutMIC, AppId: deduplicatedActivationRequest.AppId, DevId: deduplicatedActivationRequest.DevId, AppEui: deduplicatedActivationRequest.AppEui, DevEui: deduplicatedActivationRequest.DevEui, } // Send Challenge to all handlers and collect responses var wg sync.WaitGroup responses := make(chan *challengeResponseWithHandler, len(announcements)) for _, announcement := range announcements { conn, err := b.getHandlerConn(announcement.Id) if err != nil { ctx.WithError(err).Warn("Could not dial handler for Activation") continue } client := pb_handler.NewHandlerClient(conn) // Do async request wg.Add(1) go func(announcement *pb_discovery.Announcement) { res, err := client.ActivationChallenge(b.Component.GetContext(""), challenge) if err == nil && res != nil { responses <- &challengeResponseWithHandler{ handler: announcement, client: client, response: res, } } wg.Done() }(announcement) } // Make sure to close channel when all requests are done go func() { wg.Wait() close(responses) }() var gotFirst bool var joinHandler *pb_discovery.Announcement var joinHandlerClient pb_handler.HandlerClient for res := range responses { var phyPayload lorawan.PHYPayload err = phyPayload.UnmarshalBinary(res.response.Payload) if err != nil { continue } if phyPayload.MIC != correctMIC { continue } if gotFirst { ctx.Warn("Duplicate Activation Response") } else { gotFirst = true joinHandler = res.handler joinHandlerClient = res.client } } // Activation not accepted by any broker if !gotFirst { ctx.Debug("Activation not accepted by any Handler") return nil, errors.New("Activation not accepted by any Handler") } ctx.WithField("HandlerID", joinHandler.Id).Debug("Forward Activation") handlerResponse, err := joinHandlerClient.Activate(b.Component.GetContext(""), deduplicatedActivationRequest) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "Handler refused activation") } handlerResponse, err = b.ns.Activate(b.Component.GetContext(b.nsToken), handlerResponse) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "NetworkServer refused activation") } res = &pb.DeviceActivationResponse{ Payload: handlerResponse.Payload, Message: handlerResponse.Message, DownlinkOption: handlerResponse.DownlinkOption, } return res, nil }
func (b *broker) HandleUplink(uplink *pb.UplinkMessage) (err error) { ctx := b.Ctx.WithField("GatewayID", uplink.GatewayMetadata.GatewayId) start := time.Now() defer func() { if err != nil { ctx.WithError(err).Warn("Could not handle uplink") } else { ctx.WithField("Duration", time.Now().Sub(start)).Info("Handled uplink") } }() time := time.Now() b.status.uplink.Mark(1) // De-duplicate uplink messages duplicates := b.deduplicateUplink(uplink) if len(duplicates) == 0 { return nil } b.status.uplinkUnique.Mark(1) ctx = ctx.WithField("Duplicates", len(duplicates)) base := duplicates[0] if base.ProtocolMetadata.GetLorawan() == nil { return errors.NewErrInvalidArgument("Uplink", "does not contain LoRaWAN metadata") } // LoRaWAN: Unmarshal var phyPayload lorawan.PHYPayload err = phyPayload.UnmarshalBinary(base.Payload) if err != nil { return err } macPayload, ok := phyPayload.MACPayload.(*lorawan.MACPayload) if !ok { return errors.NewErrInvalidArgument("Uplink", "does not contain a MAC payload") } // Request devices from NS devAddr := types.DevAddr(macPayload.FHDR.DevAddr) ctx = ctx.WithFields(log.Fields{ "DevAddr": devAddr, "FCnt": macPayload.FHDR.FCnt, }) var getDevicesResp *networkserver.DevicesResponse getDevicesResp, err = b.ns.GetDevices(b.Component.GetContext(b.nsToken), &networkserver.DevicesRequest{ DevAddr: &devAddr, FCnt: macPayload.FHDR.FCnt, }) if err != nil { return errors.Wrap(errors.FromGRPCError(err), "NetworkServer did not return devices") } b.status.deduplication.Update(int64(len(getDevicesResp.Results))) if len(getDevicesResp.Results) == 0 { return errors.NewErrNotFound(fmt.Sprintf("Device with DevAddr %s and FCnt <= %d", devAddr, macPayload.FHDR.FCnt)) } ctx = ctx.WithField("DevAddrResults", len(getDevicesResp.Results)) // Sort by FCntUp to optimize the number of MIC checks sort.Sort(ByFCntUp(getDevicesResp.Results)) // Find AppEUI/DevEUI through MIC check var device *pb_lorawan.Device var micChecks int var originalFCnt uint32 for _, candidate := range getDevicesResp.Results { nwkSKey := lorawan.AES128Key(*candidate.NwkSKey) // First check with the 16 bit counter micChecks++ ok, err = phyPayload.ValidateMIC(nwkSKey) if err != nil { return err } if ok { device = candidate break } originalFCnt = macPayload.FHDR.FCnt if candidate.Uses32BitFCnt { macPayload.FHDR.FCnt = fcnt.GetFull(candidate.FCntUp, uint16(originalFCnt)) // If 32 bit counter has different value, perform another MIC check if macPayload.FHDR.FCnt != originalFCnt { micChecks++ ok, err = phyPayload.ValidateMIC(nwkSKey) if err != nil { return err } if ok { device = candidate break } } } return errors.NewErrNotFound("device that validates MIC") } ctx = ctx.WithFields(log.Fields{ "MICChecks": micChecks, "DevEUI": device.DevEui, "AppEUI": device.AppEui, "AppID": device.AppId, "DevID": device.DevId, "FCnt": originalFCnt, }) if macPayload.FHDR.FCnt != originalFCnt { ctx = ctx.WithField("RealFCnt", macPayload.FHDR.FCnt) } if device.DisableFCntCheck { // TODO: Add warning to message? } else if device.FCntUp == 0 { } else if macPayload.FHDR.FCnt <= device.FCntUp || macPayload.FHDR.FCnt-device.FCntUp > maxFCntGap { // Replay attack or FCnt gap too big return errors.NewErrNotFound("device with matching FCnt") } // Add FCnt to Metadata (because it's not marshaled in lorawan payload) base.ProtocolMetadata.GetLorawan().FCnt = macPayload.FHDR.FCnt // Collect GatewayMetadata and DownlinkOptions var gatewayMetadata []*gateway.RxMetadata var downlinkOptions []*pb.DownlinkOption var downlinkMessage *pb.DownlinkMessage for _, duplicate := range duplicates { gatewayMetadata = append(gatewayMetadata, duplicate.GatewayMetadata) downlinkOptions = append(downlinkOptions, duplicate.DownlinkOptions...) } // Select best DownlinkOption if len(downlinkOptions) > 0 { downlinkMessage = &pb.DownlinkMessage{ DevEui: device.DevEui, AppEui: device.AppEui, AppId: device.AppId, DevId: device.DevId, DownlinkOption: selectBestDownlink(downlinkOptions), } } // Build Uplink deduplicatedUplink := &pb.DeduplicatedUplinkMessage{ Payload: base.Payload, DevEui: device.DevEui, DevId: device.DevId, AppEui: device.AppEui, AppId: device.AppId, ProtocolMetadata: base.ProtocolMetadata, GatewayMetadata: gatewayMetadata, ServerTime: time.UnixNano(), ResponseTemplate: downlinkMessage, } // Pass Uplink through NS deduplicatedUplink, err = b.ns.Uplink(b.Component.GetContext(b.nsToken), deduplicatedUplink) if err != nil { return errors.Wrap(errors.FromGRPCError(err), "NetworkServer did not handle uplink") } var announcements []*pb_discovery.Announcement announcements, err = b.Discovery.GetAllHandlersForAppID(device.AppId) if err != nil { return err } if len(announcements) == 0 { return errors.NewErrNotFound(fmt.Sprintf("Handler for AppID %s", device.AppId)) } if len(announcements) > 1 { return errors.NewErrInternal(fmt.Sprintf("Multiple Handlers for AppID %s", device.AppId)) } var handler chan<- *pb.DeduplicatedUplinkMessage handler, err = b.getHandlerUplink(announcements[0].Id) if err != nil { return err } handler <- deduplicatedUplink return nil }
func (h *handlerManager) SetDevice(ctx context.Context, in *pb.Device) (*empty.Empty, error) { if err := in.Validate(); err != nil { return nil, errors.Wrap(err, "Invalid Device") } ctx, claims, err := h.validateTTNAuthAppContext(ctx, in.AppId) if err != nil { return nil, err } if !claims.AppRight(in.AppId, rights.Devices) { return nil, errors.NewErrPermissionDenied(fmt.Sprintf(`No "devices" rights to application "%s"`, in.AppId)) } if _, err := h.handler.applications.Get(in.AppId); err != nil { return nil, errors.Wrap(err, "Application not registered to this Handler") } dev, err := h.handler.devices.Get(in.AppId, in.DevId) if err != nil && errors.GetErrType(err) != errors.NotFound { return nil, err } lorawan := in.GetLorawanDevice() if lorawan == nil { return nil, errors.NewErrInvalidArgument("Device", "No LoRaWAN Device") } if dev != nil { // When this is an update if dev.AppEUI != *lorawan.AppEui || dev.DevEUI != *lorawan.DevEui { // If the AppEUI or DevEUI is changed, we should remove the device from the NetworkServer and re-add it later _, err = h.deviceManager.DeleteDevice(ctx, &pb_lorawan.DeviceIdentifier{ AppEui: &dev.AppEUI, DevEui: &dev.DevEUI, }) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "Broker did not delete device") } } dev.StartUpdate() } else { // When this is a create existingDevices, err := h.handler.devices.ListForApp(in.AppId) if err != nil { return nil, err } for _, existingDevice := range existingDevices { if existingDevice.AppEUI == *lorawan.AppEui && existingDevice.DevEUI == *lorawan.DevEui { return nil, errors.NewErrAlreadyExists("Device with AppEUI and DevEUI") } } dev = new(device.Device) } dev.AppID = in.AppId dev.AppEUI = *lorawan.AppEui dev.DevID = in.DevId dev.DevEUI = *lorawan.DevEui dev.Options = device.Options{ DisableFCntCheck: lorawan.DisableFCntCheck, Uses32BitFCnt: lorawan.Uses32BitFCnt, ActivationConstraints: lorawan.ActivationConstraints, } if dev.Options.ActivationConstraints == "" { dev.Options.ActivationConstraints = "local" } if lorawan.DevAddr != nil { dev.DevAddr = *lorawan.DevAddr } if lorawan.NwkSKey != nil { dev.NwkSKey = *lorawan.NwkSKey } if lorawan.AppSKey != nil { dev.AppSKey = *lorawan.AppSKey } if lorawan.AppKey != nil { if dev.AppKey != *lorawan.AppKey { // When the AppKey of an existing device is changed dev.UsedAppNonces = []device.AppNonce{} dev.UsedDevNonces = []device.DevNonce{} } dev.AppKey = *lorawan.AppKey } // Update the device in the Broker (NetworkServer) nsUpdated := dev.GetLoRaWAN() nsUpdated.FCntUp = lorawan.FCntUp nsUpdated.FCntDown = lorawan.FCntDown _, err = h.deviceManager.SetDevice(ctx, nsUpdated) if err != nil { return nil, errors.Wrap(errors.FromGRPCError(err), "Broker did not set device") } err = h.handler.devices.Set(dev) if err != nil { return nil, err } return &empty.Empty{}, nil }