// Create creates the given node-session. The DevAddr must contain the same NwkID as the configured NetID. Node-sessions will expire automatically after the configured TTL. func (a *NodeSessionAPI) Create(ctx context.Context, req *pb.CreateNodeSessionRequest) (*pb.CreateNodeSessionResponse, error) { var appEUI, devEUI lorawan.EUI64 var appSKey, nwkSKey lorawan.AES128Key var devAddr lorawan.DevAddr if err := appEUI.UnmarshalText([]byte(req.AppEUI)); err != nil { return nil, err } if err := devEUI.UnmarshalText([]byte(req.DevEUI)); err != nil { return nil, err } if err := appSKey.UnmarshalText([]byte(req.AppSKey)); err != nil { return nil, err } if err := nwkSKey.UnmarshalText([]byte(req.NwkSKey)); err != nil { return nil, err } if err := devAddr.UnmarshalText([]byte(req.DevAddr)); err != nil { return nil, err } var cFList *lorawan.CFList if len(req.CFList) > len(cFList) { return nil, fmt.Errorf("max CFList channels is %d", len(cFList)) } if len(req.CFList) > 0 { cFList = &lorawan.CFList{} for i, f := range req.CFList { cFList[i] = f } } ns := models.NodeSession{ DevAddr: devAddr, AppEUI: appEUI, DevEUI: devEUI, AppSKey: appSKey, NwkSKey: nwkSKey, FCntUp: req.FCntUp, FCntDown: req.FCntDown, RXDelay: uint8(req.RxDelay), RX1DROffset: uint8(req.Rx1DROffset), CFList: cFList, } if err := a.validateNodeSession(ns); err != nil { return nil, err } if err := storage.CreateNodeSession(a.ctx.RedisPool, ns); err != nil { return nil, err } return &pb.CreateNodeSessionResponse{}, nil }
// Delete deletes the node-session matching the given DevAddr. func (a *NodeSessionAPI) Delete(ctx context.Context, req *pb.DeleteNodeSessionRequest) (*pb.DeleteNodeSessionResponse, error) { var devAddr lorawan.DevAddr if err := devAddr.UnmarshalText([]byte(req.DevAddr)); err != nil { return nil, err } if err := storage.DeleteNodeSession(a.ctx.RedisPool, devAddr); err != nil { return nil, err } return &pb.DeleteNodeSessionResponse{}, nil }
// Get returns the node-session matching the given DevAddr. func (a *NodeSessionAPI) Get(ctx context.Context, req *pb.GetNodeSessionRequest) (*pb.GetNodeSessionResponse, error) { var devAddr lorawan.DevAddr if err := devAddr.UnmarshalText([]byte(req.DevAddr)); err != nil { return nil, err } ns, err := storage.GetNodeSession(a.ctx.RedisPool, devAddr) if err != nil { return nil, err } return a.nodeSessionToResponse(ns) }
// getRandomDevAddr returns a random free DevAddr. Note that the 7 MSB will be // set to the NwkID (based on the configured NetID). // TODO: handle collission with retry? func getRandomDevAddr(p *redis.Pool, netID lorawan.NetID) (lorawan.DevAddr, error) { var d lorawan.DevAddr b := make([]byte, len(d)) if _, err := rand.Read(b); err != nil { return d, fmt.Errorf("could not read from random reader: %s", err) } copy(d[:], b) d[0] = d[0] & 1 // zero out 7 msb d[0] = d[0] ^ (netID.NwkID() << 1) // set 7 msb to NwkID c := p.Get() defer c.Close() key := "node_session_" + d.String() val, err := redis.Int(c.Do("EXISTS", key)) if err != nil { return lorawan.DevAddr{}, fmt.Errorf("test DevAddr %s exist error: %s", d, err) } if val == 1 { return lorawan.DevAddr{}, fmt.Errorf("DevAddr %s already exists", d) } return d, nil }