func (n *NetworkServerAPI) CreateMACCommandQueueItem(ctx context.Context, req *ns.CreateMACCommandQueueItemRequest) (*empty.Empty, error) {
	var commands []lorawan.MACCommand
	var devEUI lorawan.EUI64
	copy(devEUI[:], req.DevEui)
	for _, b := range req.Commands {
		var mac lorawan.MACCommand
		if err := mac.UnmarshalBinary(false, b); err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, err.Error())
		}
		commands = append(commands, mac)
	}
	block := storage.MACCommandBlock{
		CID:         lorawan.CID(req.Cid),
		External:    true,
		MACCommands: commands,
	}
	if err := storage.CreateMACCommandQueueItem(ctx, devEUI, block); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
CreateMACCommandQueueItem adds a data down MAC command to the queue.
It replaces already enqueued mac-commands with the same CID.
package ns
import (
	"strings"
	"time"
	"github.com/gofrs/uuid"
	"github.com/golang/protobuf/ptypes"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/jmoiron/sqlx"
	log "github.com/sirupsen/logrus"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"github.com/brocaar/chirpstack-api/go/v3/common"
	"github.com/brocaar/chirpstack-api/go/v3/ns"
	"github.com/brocaar/chirpstack-network-server/v3/internal/adr"
	"github.com/brocaar/chirpstack-network-server/v3/internal/band"
	"github.com/brocaar/chirpstack-network-server/v3/internal/config"
	"github.com/brocaar/chirpstack-network-server/v3/internal/downlink/multicast"
	proprietarydown "github.com/brocaar/chirpstack-network-server/v3/internal/downlink/proprietary"
	"github.com/brocaar/chirpstack-network-server/v3/internal/framelog"
	"github.com/brocaar/chirpstack-network-server/v3/internal/gateway"
	"github.com/brocaar/chirpstack-network-server/v3/internal/helpers"
	"github.com/brocaar/chirpstack-network-server/v3/internal/storage"
	"github.com/brocaar/lorawan"
	"github.com/brocaar/lorawan/backend"
)
const defaultCodeRate = "4/5"
const classBScheduleMargin = 5 * time.Second
type NetworkServerAPI struct{}
func NewNetworkServerAPI() *NetworkServerAPI {
	return &NetworkServerAPI{}
}
func (n *NetworkServerAPI) CreateServiceProfile(ctx context.Context, req *ns.CreateServiceProfileRequest) (*ns.CreateServiceProfileResponse, error) {
	if req.ServiceProfile == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "service_profile must not be nil")
	}
	var spID uuid.UUID
	copy(spID[:], req.ServiceProfile.Id)
	sp := storage.ServiceProfile{
		ID:                     spID,
		ULRate:                 int(req.ServiceProfile.UlRate),
		ULBucketSize:           int(req.ServiceProfile.UlBucketSize),
		DLRate:                 int(req.ServiceProfile.DlRate),
		DLBucketSize:           int(req.ServiceProfile.DlBucketSize),
		AddGWMetadata:          req.ServiceProfile.AddGwMetadata,
		DevStatusReqFreq:       int(req.ServiceProfile.DevStatusReqFreq),
		ReportDevStatusBattery: req.ServiceProfile.ReportDevStatusBattery,
		ReportDevStatusMargin:  req.ServiceProfile.ReportDevStatusMargin,
		DRMin:                  int(req.ServiceProfile.DrMin),
		DRMax:                  int(req.ServiceProfile.DrMax),
		ChannelMask:            req.ServiceProfile.ChannelMask,
		PRAllowed:              req.ServiceProfile.PrAllowed,
		HRAllowed:              req.ServiceProfile.HrAllowed,
		RAAllowed:              req.ServiceProfile.RaAllowed,
		NwkGeoLoc:              req.ServiceProfile.NwkGeoLoc,
		TargetPER:              int(req.ServiceProfile.TargetPer),
		MinGWDiversity:         int(req.ServiceProfile.MinGwDiversity),
		GwsPrivate:             req.ServiceProfile.GwsPrivate,
	}
	switch req.ServiceProfile.UlRatePolicy {
	case ns.RatePolicy_MARK:
		sp.ULRatePolicy = storage.Mark
	case ns.RatePolicy_DROP:
		sp.ULRatePolicy = storage.Drop
	}
	switch req.ServiceProfile.DlRatePolicy {
	case ns.RatePolicy_MARK:
		sp.DLRatePolicy = storage.Mark
	case ns.RatePolicy_DROP:
		sp.DLRatePolicy = storage.Drop
	}
	if err := storage.CreateServiceProfile(ctx, storage.DB(), &sp); err != nil {
		return nil, errToRPCError(err)
	}
	return &ns.CreateServiceProfileResponse{
		Id: sp.ID.Bytes(),
	}, nil
}
func (n *NetworkServerAPI) GetServiceProfile(ctx context.Context, req *ns.GetServiceProfileRequest) (*ns.GetServiceProfileResponse, error) {
	var spID uuid.UUID
	copy(spID[:], req.Id)
	sp, err := storage.GetServiceProfile(ctx, storage.DB(), spID)
	if err != nil {
		return nil, errToRPCError(err)
	}
	resp := ns.GetServiceProfileResponse{
		ServiceProfile: &ns.ServiceProfile{
			Id:                     sp.ID.Bytes(),
			UlRate:                 uint32(sp.ULRate),
			UlBucketSize:           uint32(sp.ULBucketSize),
			DlRate:                 uint32(sp.DLRate),
			DlBucketSize:           uint32(sp.DLBucketSize),
			AddGwMetadata:          sp.AddGWMetadata,
			DevStatusReqFreq:       uint32(sp.DevStatusReqFreq),
			ReportDevStatusBattery: sp.ReportDevStatusBattery,
			ReportDevStatusMargin:  sp.ReportDevStatusMargin,
			DrMin:                  uint32(sp.DRMin),
			DrMax:                  uint32(sp.DRMax),
			ChannelMask:            sp.ChannelMask,
			PrAllowed:              sp.PRAllowed,
			HrAllowed:              sp.HRAllowed,
			RaAllowed:              sp.RAAllowed,
			NwkGeoLoc:              sp.NwkGeoLoc,
			TargetPer:              uint32(sp.TargetPER),
			MinGwDiversity:         uint32(sp.MinGWDiversity),
			GwsPrivate:             sp.GwsPrivate,
		},
	}
	resp.CreatedAt, err = ptypes.TimestampProto(sp.CreatedAt)
	if err != nil {
		return nil, errToRPCError(err)
	}
	resp.UpdatedAt, err = ptypes.TimestampProto(sp.UpdatedAt)
	if err != nil {
		return nil, errToRPCError(err)
	}
	switch sp.ULRatePolicy {
	case storage.Mark:
		resp.ServiceProfile.UlRatePolicy = ns.RatePolicy_MARK
	case storage.Drop:
		resp.ServiceProfile.UlRatePolicy = ns.RatePolicy_DROP
	}
	switch sp.DLRatePolicy {
	case storage.Mark:
		resp.ServiceProfile.DlRatePolicy = ns.RatePolicy_MARK
	case storage.Drop:
		resp.ServiceProfile.DlRatePolicy = ns.RatePolicy_DROP
	}
	return &resp, nil
}
func (n *NetworkServerAPI) UpdateServiceProfile(ctx context.Context, req *ns.UpdateServiceProfileRequest) (*empty.Empty, error) {
	if req.ServiceProfile == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "service_profile must not be nil")
	}
	var spID uuid.UUID
	copy(spID[:], req.ServiceProfile.Id)
	sp, err := storage.GetServiceProfile(ctx, storage.DB(), spID)
	if err != nil {
		return nil, errToRPCError(err)
	}
	sp.ULRate = int(req.ServiceProfile.UlRate)
	sp.ULBucketSize = int(req.ServiceProfile.UlBucketSize)
	sp.DLRate = int(req.ServiceProfile.DlRate)
	sp.DLBucketSize = int(req.ServiceProfile.DlBucketSize)
	sp.AddGWMetadata = req.ServiceProfile.AddGwMetadata
	sp.DevStatusReqFreq = int(req.ServiceProfile.DevStatusReqFreq)
	sp.ReportDevStatusBattery = req.ServiceProfile.ReportDevStatusBattery
	sp.ReportDevStatusMargin = req.ServiceProfile.ReportDevStatusMargin
	sp.DRMin = int(req.ServiceProfile.DrMin)
	sp.DRMax = int(req.ServiceProfile.DrMax)
	sp.ChannelMask = backend.HEXBytes(req.ServiceProfile.ChannelMask)
	sp.PRAllowed = req.ServiceProfile.PrAllowed
	sp.HRAllowed = req.ServiceProfile.HrAllowed
	sp.RAAllowed = req.ServiceProfile.RaAllowed
	sp.NwkGeoLoc = req.ServiceProfile.NwkGeoLoc
	sp.TargetPER = int(req.ServiceProfile.TargetPer)
	sp.MinGWDiversity = int(req.ServiceProfile.MinGwDiversity)
	sp.GwsPrivate = req.ServiceProfile.GwsPrivate
	switch req.ServiceProfile.UlRatePolicy {
	case ns.RatePolicy_MARK:
		sp.ULRatePolicy = storage.Mark
	case ns.RatePolicy_DROP:
		sp.ULRatePolicy = storage.Drop
	}
	switch req.ServiceProfile.DlRatePolicy {
	case ns.RatePolicy_MARK:
		sp.DLRatePolicy = storage.Mark
	case ns.RatePolicy_DROP:
		sp.DLRatePolicy = storage.Drop
	}
	if err := storage.FlushServiceProfileCache(ctx, sp.ID); err != nil {
		return nil, errToRPCError(err)
	}
	if err := storage.UpdateServiceProfile(ctx, storage.DB(), &sp); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) DeleteServiceProfile(ctx context.Context, req *ns.DeleteServiceProfileRequest) (*empty.Empty, error) {
	var spID uuid.UUID
	copy(spID[:], req.Id)
	if err := storage.FlushServiceProfileCache(ctx, spID); err != nil {
		return nil, errToRPCError(err)
	}
	if err := storage.DeleteServiceProfile(ctx, storage.DB(), spID); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) CreateRoutingProfile(ctx context.Context, req *ns.CreateRoutingProfileRequest) (*ns.CreateRoutingProfileResponse, error) {
	if req.RoutingProfile == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "routing_profile must not be nil")
	}
	var rpID uuid.UUID
	copy(rpID[:], req.RoutingProfile.Id)
	rp := storage.RoutingProfile{
		ID:      rpID,
		ASID:    req.RoutingProfile.AsId,
		CACert:  req.RoutingProfile.CaCert,
		TLSCert: req.RoutingProfile.TlsCert,
		TLSKey:  req.RoutingProfile.TlsKey,
	}
	if err := storage.CreateRoutingProfile(ctx, storage.DB(), &rp); err != nil {
		return nil, errToRPCError(err)
	}
	return &ns.CreateRoutingProfileResponse{
		Id: rp.ID.Bytes(),
	}, nil
}
func (n *NetworkServerAPI) GetRoutingProfile(ctx context.Context, req *ns.GetRoutingProfileRequest) (*ns.GetRoutingProfileResponse, error) {
	var rpID uuid.UUID
	copy(rpID[:], req.Id)
	rp, err := storage.GetRoutingProfile(ctx, storage.DB(), rpID)
	if err != nil {
		return nil, errToRPCError(err)
	}
	resp := ns.GetRoutingProfileResponse{
		RoutingProfile: &ns.RoutingProfile{
			Id:      rp.ID.Bytes(),
			AsId:    rp.ASID,
			CaCert:  rp.CACert,
			TlsCert: rp.TLSCert,
		},
	}
	resp.CreatedAt, err = ptypes.TimestampProto(rp.CreatedAt)
	if err != nil {
		return nil, errToRPCError(err)
	}
	resp.UpdatedAt, err = ptypes.TimestampProto(rp.UpdatedAt)
	if err != nil {
		return nil, errToRPCError(err)
	}
	return &resp, nil
}
func (n *NetworkServerAPI) UpdateRoutingProfile(ctx context.Context, req *ns.UpdateRoutingProfileRequest) (*empty.Empty, error) {
	if req.RoutingProfile == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "routing_profile must not be nil")
	}
	var rpID uuid.UUID
	copy(rpID[:], req.RoutingProfile.Id)
	rp, err := storage.GetRoutingProfile(ctx, storage.DB(), rpID)
	if err != nil {
		return nil, errToRPCError(err)
	}
	rp.ASID = req.RoutingProfile.AsId
	rp.CACert = req.RoutingProfile.CaCert
	rp.TLSCert = req.RoutingProfile.TlsCert
	if req.RoutingProfile.TlsKey != "" {
		rp.TLSKey = req.RoutingProfile.TlsKey
	}
	if rp.TLSCert == "" {
		rp.TLSKey = ""
	}
	if err := storage.UpdateRoutingProfile(ctx, storage.DB(), &rp); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) DeleteRoutingProfile(ctx context.Context, req *ns.DeleteRoutingProfileRequest) (*empty.Empty, error) {
	var rpID uuid.UUID
	copy(rpID[:], req.Id)
	if err := storage.DeleteRoutingProfile(ctx, storage.DB(), rpID); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) CreateDeviceProfile(ctx context.Context, req *ns.CreateDeviceProfileRequest) (*ns.CreateDeviceProfileResponse, error) {
	if req.DeviceProfile == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "device_profile must not be nil")
	}
	var dpID uuid.UUID
	copy(dpID[:], req.DeviceProfile.Id)
	dp := storage.DeviceProfile{
		ID:                 dpID,
		SupportsClassB:     req.DeviceProfile.SupportsClassB,
		ClassBTimeout:      int(req.DeviceProfile.ClassBTimeout),
		PingSlotPeriod:     int(req.DeviceProfile.PingSlotPeriod),
		PingSlotDR:         int(req.DeviceProfile.PingSlotDr),
		PingSlotFreq:       req.DeviceProfile.PingSlotFreq,
		SupportsClassC:     req.DeviceProfile.SupportsClassC,
		ClassCTimeout:      int(req.DeviceProfile.ClassCTimeout),
		MACVersion:         req.DeviceProfile.MacVersion,
		RegParamsRevision:  req.DeviceProfile.RegParamsRevision,
		RXDelay1:           int(req.DeviceProfile.RxDelay_1),
		RXDROffset1:        int(req.DeviceProfile.RxDrOffset_1),
		RXDataRate2:        int(req.DeviceProfile.RxDatarate_2),
		RXFreq2:            req.DeviceProfile.RxFreq_2,
		FactoryPresetFreqs: req.DeviceProfile.FactoryPresetFreqs,
		MaxEIRP:            int(req.DeviceProfile.MaxEirp),
		MaxDutyCycle:       int(req.DeviceProfile.MaxDutyCycle),
		SupportsJoin:       req.DeviceProfile.SupportsJoin,
		Supports32bitFCnt:  req.DeviceProfile.Supports_32BitFCnt,
		RFRegion:           band.Band().Name(),
		ADRAlgorithmID:     req.DeviceProfile.AdrAlgorithmId,
	}
	if err := storage.CreateDeviceProfile(ctx, storage.DB(), &dp); err != nil {
		return nil, errToRPCError(err)
	}
	return &ns.CreateDeviceProfileResponse{
		Id: dp.ID.Bytes(),
	}, nil
}
func (n *NetworkServerAPI) GetDeviceProfile(ctx context.Context, req *ns.GetDeviceProfileRequest) (*ns.GetDeviceProfileResponse, error) {
	var dpID uuid.UUID
	copy(dpID[:], req.Id)
	dp, err := storage.GetDeviceProfile(ctx, storage.DB(), dpID)
	if err != nil {
		return nil, errToRPCError(err)
	}
	var factoryPresetFreqs []uint32
	for _, f := range dp.FactoryPresetFreqs {
		factoryPresetFreqs = append(factoryPresetFreqs, uint32(f))
	}
	resp := ns.GetDeviceProfileResponse{
		DeviceProfile: &ns.DeviceProfile{
			Id:                 dp.ID.Bytes(),
			SupportsClassB:     dp.SupportsClassB,
			ClassBTimeout:      uint32(dp.ClassBTimeout),
			PingSlotPeriod:     uint32(dp.PingSlotPeriod),
			PingSlotDr:         uint32(dp.PingSlotDR),
			PingSlotFreq:       uint32(dp.PingSlotFreq),
			SupportsClassC:     dp.SupportsClassC,
			ClassCTimeout:      uint32(dp.ClassCTimeout),
			MacVersion:         dp.MACVersion,
			RegParamsRevision:  dp.RegParamsRevision,
			RxDelay_1:          uint32(dp.RXDelay1),
			RxDrOffset_1:       uint32(dp.RXDROffset1),
			RxDatarate_2:       uint32(dp.RXDataRate2),
			RxFreq_2:           uint32(dp.RXFreq2),
			FactoryPresetFreqs: factoryPresetFreqs,
			MaxEirp:            uint32(dp.MaxEIRP),
			MaxDutyCycle:       uint32(dp.MaxDutyCycle),
			SupportsJoin:       dp.SupportsJoin,
			RfRegion:           string(dp.RFRegion),
			Supports_32BitFCnt: dp.Supports32bitFCnt,
			AdrAlgorithmId:     dp.ADRAlgorithmID,
		},
	}
	resp.CreatedAt, err = ptypes.TimestampProto(dp.CreatedAt)
	if err != nil {
		return nil, errToRPCError(err)
	}
	resp.UpdatedAt, err = ptypes.TimestampProto(dp.UpdatedAt)
	if err != nil {
		return nil, errToRPCError(err)
	}
	return &resp, nil
}
func (n *NetworkServerAPI) UpdateDeviceProfile(ctx context.Context, req *ns.UpdateDeviceProfileRequest) (*empty.Empty, error) {
	if req.DeviceProfile == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "device_profile must not be nil")
	}
	var dpID uuid.UUID
	copy(dpID[:], req.DeviceProfile.Id)
	dp, err := storage.GetDeviceProfile(ctx, storage.DB(), dpID)
	if err != nil {
		return nil, errToRPCError(err)
	}
	dp.SupportsClassB = req.DeviceProfile.SupportsClassB
	dp.ClassBTimeout = int(req.DeviceProfile.ClassBTimeout)
	dp.PingSlotPeriod = int(req.DeviceProfile.PingSlotPeriod)
	dp.PingSlotDR = int(req.DeviceProfile.PingSlotDr)
	dp.PingSlotFreq = req.DeviceProfile.PingSlotFreq
	dp.SupportsClassC = req.DeviceProfile.SupportsClassC
	dp.ClassCTimeout = int(req.DeviceProfile.ClassCTimeout)
	dp.MACVersion = req.DeviceProfile.MacVersion
	dp.RegParamsRevision = req.DeviceProfile.RegParamsRevision
	dp.RXDelay1 = int(req.DeviceProfile.RxDelay_1)
	dp.RXDROffset1 = int(req.DeviceProfile.RxDrOffset_1)
	dp.RXDataRate2 = int(req.DeviceProfile.RxDatarate_2)
	dp.RXFreq2 = req.DeviceProfile.RxFreq_2
	dp.FactoryPresetFreqs = req.DeviceProfile.FactoryPresetFreqs
	dp.MaxEIRP = int(req.DeviceProfile.MaxEirp)
	dp.MaxDutyCycle = int(req.DeviceProfile.MaxDutyCycle)
	dp.SupportsJoin = req.DeviceProfile.SupportsJoin
	dp.Supports32bitFCnt = req.DeviceProfile.Supports_32BitFCnt
	dp.RFRegion = band.Band().Name()
	dp.ADRAlgorithmID = req.DeviceProfile.AdrAlgorithmId
	if err := storage.FlushDeviceProfileCache(ctx, dp.ID); err != nil {
		return nil, errToRPCError(err)
	}
	if err := storage.UpdateDeviceProfile(ctx, storage.DB(), &dp); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) DeleteDeviceProfile(ctx context.Context, req *ns.DeleteDeviceProfileRequest) (*empty.Empty, error) {
	var dpID uuid.UUID
	copy(dpID[:], req.Id)
	if err := storage.FlushDeviceProfileCache(ctx, dpID); err != nil {
		return nil, errToRPCError(err)
	}
	if err := storage.DeleteDeviceProfile(ctx, storage.DB(), dpID); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) CreateDevice(ctx context.Context, req *ns.CreateDeviceRequest) (*empty.Empty, error) {
	if req.Device == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "device must not be nil")
	}
	var devEUI lorawan.EUI64
	var dpID, spID, rpID uuid.UUID
	copy(devEUI[:], req.Device.DevEui)
	copy(dpID[:], req.Device.DeviceProfileId)
	copy(rpID[:], req.Device.RoutingProfileId)
	copy(spID[:], req.Device.ServiceProfileId)
	d := storage.Device{
		DevEUI:            devEUI,
		DeviceProfileID:   dpID,
		ServiceProfileID:  spID,
		RoutingProfileID:  rpID,
		SkipFCntCheck:     req.Device.SkipFCntCheck,
		ReferenceAltitude: req.Device.ReferenceAltitude,
		IsDisabled:        req.Device.IsDisabled,
	}
	if err := storage.CreateDevice(ctx, storage.DB(), &d); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) GetDevice(ctx context.Context, req *ns.GetDeviceRequest) (*ns.GetDeviceResponse, error) {
	var devEUI lorawan.EUI64
	copy(devEUI[:], req.DevEui)
	d, err := storage.GetDevice(ctx, storage.DB(), devEUI, false)
	if err != nil {
		return nil, errToRPCError(err)
	}
	resp := ns.GetDeviceResponse{
		Device: &ns.Device{
			DevEui:            d.DevEUI[:],
			SkipFCntCheck:     d.SkipFCntCheck,
			DeviceProfileId:   d.DeviceProfileID[:],
			ServiceProfileId:  d.ServiceProfileID[:],
			RoutingProfileId:  d.RoutingProfileID[:],
			ReferenceAltitude: d.ReferenceAltitude,
			IsDisabled:        d.IsDisabled,
		},
	}
	resp.CreatedAt, err = ptypes.TimestampProto(d.CreatedAt)
	if err != nil {
		return nil, errToRPCError(err)
	}
	resp.UpdatedAt, err = ptypes.TimestampProto(d.UpdatedAt)
	if err != nil {
		return nil, errToRPCError(err)
	}
	return &resp, nil
}
func (n *NetworkServerAPI) UpdateDevice(ctx context.Context, req *ns.UpdateDeviceRequest) (*empty.Empty, error) {
	if req.Device == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "device must not be nil")
	}
	var devEUI lorawan.EUI64
	var dpID, spID, rpID uuid.UUID
	copy(devEUI[:], req.Device.DevEui)
	copy(dpID[:], req.Device.DeviceProfileId)
	copy(rpID[:], req.Device.RoutingProfileId)
	copy(spID[:], req.Device.ServiceProfileId)
	d, err := storage.GetDevice(ctx, storage.DB(), devEUI, false)
	if err != nil {
		return nil, errToRPCError(err)
	}
	d.DeviceProfileID = dpID
	d.ServiceProfileID = spID
	d.RoutingProfileID = rpID
	d.SkipFCntCheck = req.Device.SkipFCntCheck
	d.ReferenceAltitude = req.Device.ReferenceAltitude
	d.IsDisabled = req.Device.IsDisabled
	err = storage.Transaction(func(tx sqlx.Ext) error {
		if err := storage.UpdateDevice(ctx, tx, &d); err != nil {
			return err
		}
		ds, err := storage.GetDeviceSession(ctx, devEUI)
		if err == nil {
			ds.IsDisabled = req.Device.IsDisabled
			return storage.SaveDeviceSession(ctx, ds)
		} else if err != storage.ErrDoesNotExist {
			return err
		}
		return nil
	})
	if err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) DeleteDevice(ctx context.Context, req *ns.DeleteDeviceRequest) (*empty.Empty, error) {
	var devEUI lorawan.EUI64
	copy(devEUI[:], req.DevEui)
	err := storage.Transaction(func(tx sqlx.Ext) error {
		if err := storage.DeleteDevice(ctx, tx, devEUI); err != nil {
			return errToRPCError(err)
		}
		if err := storage.DeleteDeviceSession(ctx, devEUI); err != nil && err != storage.ErrDoesNotExist {
			return errToRPCError(err)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) ActivateDevice(ctx context.Context, req *ns.ActivateDeviceRequest) (*empty.Empty, error) {
	if req.DeviceActivation == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "device_activation must not be nil")
	}
	var devEUI lorawan.EUI64
	var devAddr lorawan.DevAddr
	var sNwkSIntKey, fNwkSIntKey, nwkSEncKey lorawan.AES128Key
	copy(devEUI[:], req.DeviceActivation.DevEui)
	copy(devAddr[:], req.DeviceActivation.DevAddr)
	copy(sNwkSIntKey[:], req.DeviceActivation.SNwkSIntKey)
	copy(fNwkSIntKey[:], req.DeviceActivation.FNwkSIntKey)
	copy(nwkSEncKey[:], req.DeviceActivation.NwkSEncKey)
	d, err := storage.GetDevice(ctx, storage.DB(), devEUI, false)
	if err != nil {
		return nil, errToRPCError(err)
	}
	dp, err := storage.GetDeviceProfile(ctx, storage.DB(), d.DeviceProfileID)
	if err != nil {
		return nil, errToRPCError(err)
	}
	ds := storage.DeviceSession{
		DeviceProfileID:  d.DeviceProfileID,
		ServiceProfileID: d.ServiceProfileID,
		RoutingProfileID: d.RoutingProfileID,
		DevEUI:             devEUI,
		DevAddr:            devAddr,
		SNwkSIntKey:        sNwkSIntKey,
		FNwkSIntKey:        fNwkSIntKey,
		NwkSEncKey:         nwkSEncKey,
		FCntUp:             req.DeviceActivation.FCntUp,
		NFCntDown:          req.DeviceActivation.NFCntDown,
		AFCntDown:          req.DeviceActivation.AFCntDown,
		SkipFCntValidation: req.DeviceActivation.SkipFCntCheck || d.SkipFCntCheck,
		RXWindow: storage.RX1,
		MACVersion: dp.MACVersion,
		IsDisabled: d.IsDisabled,
	}
	if dp.SupportsClassC {
		d.Mode = storage.DeviceModeC
	} else {
		d.Mode = storage.DeviceModeA
	}
	if err := storage.UpdateDevice(ctx, storage.DB(), &d); err != nil {
		return nil, errToRPCError(err)
	}
	ds.ResetToBootParameters(dp)
	if err := storage.SaveDeviceSession(ctx, ds); err != nil {
		return nil, errToRPCError(err)
	}
	if err := storage.FlushDeviceQueueForDevEUI(ctx, storage.DB(), d.DevEUI); err != nil {
		return nil, errToRPCError(err)
	}
	if err := storage.FlushMACCommandQueue(ctx, ds.DevEUI); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) DeactivateDevice(ctx context.Context, req *ns.DeactivateDeviceRequest) (*empty.Empty, error) {
	var devEUI lorawan.EUI64
	copy(devEUI[:], req.DevEui)
	if err := storage.DeleteDeviceSession(ctx, devEUI); err != nil {
		return nil, errToRPCError(err)
	}
	if err := storage.FlushDeviceQueueForDevEUI(ctx, storage.DB(), devEUI); err != nil {
		return nil, errToRPCError(err)
	}
	return &empty.Empty{}, nil
}
func (n *NetworkServerAPI) GetDeviceActivation(ctx context.Context, req *ns.GetDeviceActivationRequest) (*ns.GetDeviceActivationResponse, error) {
	var devEUI lorawan.EUI64
	copy(devEUI[:], req.DevEui)
	ds, err := storage.GetDeviceSession(ctx, devEUI)
	if err != nil {
		return nil, errToRPCError(err)
	}
	return &ns.GetDeviceActivationResponse{
		DeviceActivation: &ns.DeviceActivation{
			DevEui:        ds.DevEUI[:],
			DevAddr:       ds.DevAddr[:],
			SNwkSIntKey:   ds.SNwkSIntKey[:],
			FNwkSIntKey:   ds.FNwkSIntKey[:],
			NwkSEncKey:    ds.NwkSEncKey[:],
			FCntUp:        ds.FCntUp,
			NFCntDown:     ds.NFCntDown,
			AFCntDown:     ds.AFCntDown,
			SkipFCntCheck: ds.SkipFCntValidation,
		},
	}, nil
}
func (n *NetworkServerAPI) GetRandomDevAddr(ctx context.Context, req *empty.Empty) (*ns.GetRandomDevAddrResponse, error) {
	devAddr, err := storage.GetRandomDevAddr(config.C.NetworkServer.NetID)
	if err != nil {
		return nil, errToRPCError(err)
	}
	return &ns.GetRandomDevAddrResponse{
		DevAddr: devAddr[:],
	}, nil
}