Ejemplo n.º 1
0
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
}
Ejemplo n.º 2
0
func (cl *gatewayClient) monitorUplink() {
	var retries int
newStream:
	for {
		ctx, cancel := context.WithCancel(cl.Context())
		cl.uplink.Lock()
		cl.uplink.cancel = cancel
		cl.uplink.Unlock()

		stream, err := cl.client.client.GatewayUplink(ctx)
		if err != nil {
			cl.Ctx.WithError(errors.FromGRPCError(err)).Warn("Failed to open new monitor uplink stream")

			retries++
			time.Sleep(backoff.Backoff(retries))

			continue
		}
		retries = 0
		cl.Ctx.Debug("Opened new monitor uplink stream")

		// The actual stream
		go func() {
			for {
				select {
				case <-ctx.Done():
					return
				case uplink, ok := <-cl.uplink.ch:
					if ok {
						stream.Send(uplink)
						cl.Ctx.Debug("Sent uplink to monitor")
					}
				}
			}
		}()

		msg := new(empty.Empty)
		for {
			if err := stream.RecvMsg(&msg); err != nil {
				cl.Ctx.WithError(errors.FromGRPCError(err)).Warn("Received error on monitor uplink stream, closing...")
				stream.CloseSend()
				cl.Ctx.Debug("Closed monitor uplink stream")

				cl.uplink.Lock()
				cl.uplink.cancel()
				cl.uplink.cancel = nil
				cl.uplink.Unlock()

				retries++
				time.Sleep(backoff.Backoff(retries))

				continue newStream
			}
		}
	}
}
Ejemplo n.º 3
0
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
}
Ejemplo n.º 4
0
// GetHandlerManager gets a new HandlerManager for ttnctl
func GetHandlerManager(ctx log.Interface, appID string) (*grpc.ClientConn, *handler.ManagerClient) {
	ctx.WithField("Handler", viper.GetString("handler-id")).Info("Discovering Handler...")
	dscConn, client := GetDiscovery(ctx)
	defer dscConn.Close()
	handlerAnnouncement, err := client.Get(GetContext(ctx), &discovery.GetRequest{
		ServiceName: "handler",
		Id:          viper.GetString("handler-id"),
	})
	if err != nil {
		ctx.WithError(errors.FromGRPCError(err)).Fatal("Could not find Handler")
	}

	token := TokenForScope(ctx, scope.App(appID))

	ctx.WithField("Handler", handlerAnnouncement.NetAddress).Info("Connecting with Handler...")
	hdlConn, err := handlerAnnouncement.Dial()
	if err != nil {
		ctx.WithError(err).Fatal("Could not connect to Handler")
	}
	managerClient, err := handler.NewManagerClient(hdlConn, token)
	if err != nil {
		ctx.WithError(err).Fatal("Could not create Handler Manager")
	}
	return hdlConn, managerClient
}
Ejemplo n.º 5
0
// Discover is used to discover another component
func (c *Component) Discover(serviceName, id string) (*pb_discovery.Announcement, error) {
	res, err := c.Discovery.Get(serviceName, id)
	if err != nil {
		return nil, errors.Wrapf(errors.FromGRPCError(err), "Failed to discover %s/%s", serviceName, id)
	}
	return res, nil
}
Ejemplo n.º 6
0
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
}
Ejemplo n.º 7
0
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
}
Ejemplo n.º 8
0
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
}
Ejemplo n.º 9
0
// Announce the component to TTN discovery
func (c *Component) Announce() error {
	if c.Identity.Id == "" {
		return errors.NewErrInvalidArgument("Component ID", "can not be empty")
	}
	err := c.Discovery.Announce(c.AccessToken)
	if err != nil {
		return errors.Wrapf(errors.FromGRPCError(err), "Failed to announce this component to TTN discovery: %s", err.Error())
	}
	c.Ctx.Info("ttn: Announced to TTN discovery")

	return nil
}
Ejemplo n.º 10
0
// GetRouter starts a connection with the router
func GetRouter(ctx log.Interface) (*grpc.ClientConn, router.RouterClient) {
	ctx.Info("Discovering Router...")
	dscConn, client := GetDiscovery(ctx)
	defer dscConn.Close()
	routerAnnouncement, err := client.Get(GetContext(ctx), &discovery.GetRequest{
		ServiceName: "router",
		Id:          viper.GetString("router-id"),
	})
	if err != nil {
		ctx.WithError(errors.FromGRPCError(err)).Fatal("Could not get Router from Discovery")
	}
	ctx.Info("Connecting with Router...")
	rtrConn, err := routerAnnouncement.Dial()
	ctx.Info("Connected to Router")
	rtrClient := router.NewRouterClient(rtrConn)
	return rtrConn, rtrClient
}
Ejemplo n.º 11
0
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
}
Ejemplo n.º 12
0
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
}
Ejemplo n.º 13
0
func (cl *Client) open() (err error) {
	addr := cl.addr
	ctx := cl.Ctx.WithField("addr", addr)

	defer func() {
		if err != nil {
			ctx.Warn("Failed to open monitor connection")
		} else {
			ctx.Info("Monitor connection opened")
		}
	}()

	ctx.Debug("Opening monitor connection...")

	cl.conn, err = api.Dial(addr)
	if err != nil {
		ctx.WithError(errors.FromGRPCError(err)).Warn("Failed to establish connection to gRPC service")
		return err
	}

	cl.client = NewMonitorClient(cl.conn)
	return nil
}
Ejemplo n.º 14
0
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
}
Ejemplo n.º 15
0
		case "broker":
			ctx.Info("Discovering brokers and their prefixes...")
		case "handler":
			ctx.Info("Discovering handlers and their apps...")
		default:
			ctx.Fatalf("Service type %s unknown", serviceType)
		}

		conn, client := util.GetDiscovery(ctx)
		defer conn.Close()

		res, err := client.GetAll(util.GetContext(ctx), &discovery.GetServiceRequest{
			ServiceName: serviceType,
		})
		if err != nil {
			ctx.WithError(errors.FromGRPCError(err)).Fatalf("Could not get %ss", serviceType)
		}

		ctx.Infof("Discovered %d %ss", len(res.Services), serviceType)

		fmt.Printf(serviceFmt, "ID", "ADDRESS", "VERSION", "PUBLIC")
		fmt.Printf(serviceFmt, "==", "=======", "=======", "======")
		fmt.Println()
		for _, service := range res.Services {
			fmt.Printf(serviceFmt, service.Id, crop(service.NetAddress, 36), crop(service.ServiceVersion, 20), fmt.Sprintf("%v", service.Public))
			if showMetadata, _ := cmd.Flags().GetBool("metadata"); showMetadata {
				switch serviceType {
				case "broker":
					fmt.Println("  DevAddr Prefixes:")
					for _, prefix := range service.DevAddrPrefixes() {
						min := types.DevAddr{0x00, 0x00, 0x00, 0x00}.WithPrefix(prefix)
Ejemplo n.º 16
0
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
}
Ejemplo n.º 17
0
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
}
Ejemplo n.º 18
0
		}

		serviceID := args[1]
		if !api.ValidID(serviceID) {
			ctx.Fatalf("Service ID %s invalid", serviceID)
		}

		dscConn, client := util.GetDiscovery(ctx)
		defer dscConn.Close()

		res, err := client.Get(util.GetContext(ctx), &discovery.GetRequest{
			ServiceName: serviceType,
			Id:          serviceID,
		})
		if err != nil {
			ctx.WithError(errors.FromGRPCError(err)).Fatalf("Could not get %s %s", serviceType, serviceID)
		}

		conn, err := res.Dial()
		if err != nil {
			ctx.WithError(errors.FromGRPCError(err)).Fatalf("Could not dial %s %s", serviceType, serviceID)
		}
		defer conn.Close()

		start := time.Now()
		ok, err := health.Check(conn)
		if err != nil {
			ctx.WithError(errors.FromGRPCError(err)).Fatalf("Could not check %s %s", serviceType, serviceID)
		}
		ctx = ctx.WithField("Duration", time.Now().Sub(start))
Ejemplo n.º 19
0
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
}
Ejemplo n.º 20
0
		gtwID := args[0]
		if !api.ValidID(gtwID) {
			ctx.Fatal("Invalid Gateway ID")
		}

		conn, manager := util.GetRouterManager(ctx)
		defer conn.Close()

		ctx = ctx.WithField("GatewayID", gtwID)

		resp, err := manager.GatewayStatus(util.GetContext(ctx), &router.GatewayStatusRequest{
			GatewayId: gtwID,
		})
		if err != nil {
			ctx.WithError(errors.FromGRPCError(err)).Fatal("Could not get status of gateway.")
		}

		ctx.Infof("Received status")
		fmt.Println()
		printKV("Last seen", time.Unix(0, resp.LastSeen))
		printKV("Timestamp", resp.Status.Timestamp)
		if t := resp.Status.Time; t != 0 {
			printKV("Reported time", time.Unix(0, t))
		}
		printKV("Description", resp.Status.Description)
		printKV("Platform", resp.Status.Platform)
		printKV("Contact email", resp.Status.ContactEmail)
		printKV("Region", resp.Status.Region)
		printKV("IP Address", strings.Join(resp.Status.Ip, ", "))
		printKV("GPS coordinates", func() interface{} {