Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow registration to PLMNID other than 208-93 #119

Merged
merged 1 commit into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions gnodeb/ngap/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
package ngap

import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"strconv"

"github.com/omec-project/aper"
gnbctx "github.com/omec-project/gnbsim/gnodeb/context"
"github.com/omec-project/gnbsim/util/ngapTestpacket"

Expand Down Expand Up @@ -65,6 +69,36 @@ func GetNGSetupRequest(gnb *gnbctx.GNodeB) ([]byte, error) {
return ngap.Encoder(message)
}

// GetInitialUEMessage encodes NGAP InitialUEMessage for the given UE.
//
// gnbue: gNB-UE context.
// nasPdu: value of id-NAS-PDU from the UE.
func GetInitialUEMessage(gnbue *gnbctx.GnbCpUe, nasPdu []byte) ([]byte, error) {
message := ngapTestpacket.BuildInitialUEMessage(gnbue.GnbUeNgapId, nasPdu, "")
ies := message.InitiatingMessage.Value.InitialUEMessage.ProtocolIEs.List

if e := updateUserLocationInformation(gnbue.Gnb, ies[2].Value.UserLocationInformation); e != nil {
return nil, e
}

return ngap.Encoder(message)
}

// GetUplinkNASTransport encodes NGAP UplinkNASTransport for the given UE.
//
// gnbue: gNB-UE context.
// nasPdu: value of id-NAS-PDU from the UE.
func GetUplinkNASTransport(gnbue *gnbctx.GnbCpUe, nasPdu []byte) ([]byte, error) {
message := ngapTestpacket.BuildUplinkNasTransport(gnbue.AmfUeNgapId, gnbue.GnbUeNgapId, nasPdu)
ies := message.InitiatingMessage.Value.UplinkNASTransport.ProtocolIEs.List

if e := updateUserLocationInformation(gnbue.Gnb, ies[3].Value.UserLocationInformation); e != nil {
return nil, e
}

return ngap.Encoder(message)
}

func GetUEContextReleaseRequest(gnbue *gnbctx.GnbCpUe) ([]byte, error) {
var pduSessIds []int64
f := func(k interface{}, v interface{}) bool {
Expand All @@ -85,3 +119,56 @@ func GetUEContextReleaseRequest(gnbue *gnbctx.GnbCpUe) ([]byte, error) {

return ngap.Encoder(message)
}

// GetUplinkNASTransport encodes NGAP UEContextReleaseComplete for the given UE.
//
// gnbue: gNB-UE context.
// nasPdu: value of id-NAS-PDU from the UE.
func GetUEContextReleaseComplete(gnbue *gnbctx.GnbCpUe) ([]byte, error) {
var pduSessIds []int64
gnbue.GnbUpUes.Range(func(k interface{}, v interface{}) bool {
pduSessIds = append(pduSessIds, k.(int64))
return true
})

message := ngapTestpacket.BuildUEContextReleaseComplete(gnbue.AmfUeNgapId, gnbue.GnbUeNgapId, pduSessIds)
ies := message.SuccessfulOutcome.Value.UEContextReleaseComplete.ProtocolIEs.List

if e := updateUserLocationInformation(gnbue.Gnb, ies[2].Value.UserLocationInformation); e != nil {
return nil, e
}

return ngap.Encoder(message)
}

// updateUserLocationInformation updates UserLocationInformation element to match gNB information.
//
// gnb: gNB context.
// uli: UserLocationInformation prepared by ngapTestpacket package.
func updateUserLocationInformation(gnb *gnbctx.GNodeB, uli *ngapType.UserLocationInformation) error {
nr := uli.UserLocationInformationNR

nr.NRCGI.PLMNIdentity = ngapConvert.PlmnIdToNgap(*gnb.RanId.PlmnId)
nr.TAI.PLMNIdentity = nr.NRCGI.PLMNIdentity

gnbID, e := strconv.ParseUint(gnb.RanId.GNbId.GNBValue, 16, 64)
if e != nil {
return fmt.Errorf("invalid GNB ID: %w", e)
}
// NRCI contains gnbID and cellID, here we assume cellID is zero
nrci := gnbID << uint64(36-gnb.RanId.GNbId.BitLength)
nrciBuf := [8]byte{}
binary.BigEndian.PutUint64(nrciBuf[:], nrci)
nr.NRCGI.NRCellIdentity.Value.Bytes = nrciBuf[3:]

if len(gnb.SupportedTaList) < 1 {
return errors.New("unexpected empty SupportedTaList")
}
tac, e := hex.DecodeString(gnb.SupportedTaList[0].Tac)
if e != nil {
return fmt.Errorf("invalid TAC: %w", e)
}
nr.TAI.TAC.Value = aper.OctetString(tac)

return nil
}
14 changes: 3 additions & 11 deletions gnodeb/worker/gnbcpueworker/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func HandleInitialUEMessage(gnbue *gnbctx.GnbCpUe,
}
gnbue.Log.Traceln("Sent Uplink NAS Message to AMF")
} else {
sendMsg, err := test.GetInitialUEMessage(gnbue.GnbUeNgapId, msg.NasPdus[0], "")
sendMsg, err := ngap.GetInitialUEMessage(gnbue, msg.NasPdus[0])
if err != nil {
gnbue.Log.Errorln("GetInitialUEMessage failed:", err)
return
Expand Down Expand Up @@ -113,7 +113,7 @@ func HandleUlInfoTransfer(gnbue *gnbctx.GnbCpUe,

msg := intfcMsg.(*common.UuMessage)
gnbue.Log.Traceln("Creating Uplink NAS Transport Message")
sendMsg, err := test.GetUplinkNASTransport(gnbue.AmfUeNgapId, gnbue.GnbUeNgapId, msg.NasPdus[0])
sendMsg, err := ngap.GetUplinkNASTransport(gnbue, msg.NasPdus[0])
if err != nil {
gnbue.Log.Errorln("GetUplinkNASTransport failed:", err)
return
Expand Down Expand Up @@ -427,15 +427,7 @@ func HandleUeCtxReleaseCommand(gnbue *gnbctx.GnbCpUe,
}
}

var pduSessIds []int64
f := func(k interface{}, v interface{}) bool {
pduSessIds = append(pduSessIds, k.(int64))
return true
}
gnbue.GnbUpUes.Range(f)

ngapPdu, err := test.GetUEContextReleaseComplete(gnbue.AmfUeNgapId,
gnbue.GnbUeNgapId, pduSessIds)
ngapPdu, err := ngap.GetUEContextReleaseComplete(gnbue)
if err != nil {
fmt.Println("Failed to create UE Context Release Complete message")
return
Expand Down
13 changes: 10 additions & 3 deletions profile/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"log"
"strconv"
"strings"
"sync"

"github.com/omec-project/gnbsim/common"
Expand Down Expand Up @@ -62,12 +63,18 @@ func InitProfile(profile *profctx.Profile, summaryChan chan common.InterfaceMess
}

for count := 1; count <= profile.UeCount; count++ {
imsiStr := IMSI_PREFIX + strconv.Itoa(startImsi)
imsiStr := makeImsiStr(profile, startImsi)
initImsi(profile, gnb, imsiStr)
startImsi++
}
}

// makeImsiStr constructs IMSI string with specified integer value and proper length.
func makeImsiStr(profile *profctx.Profile, imsi int) string {
s := strconv.Itoa(imsi)
return IMSI_PREFIX + strings.Repeat("0", max(0, len(profile.StartImsi)-len(s))) + s
}

func initImsi(profile *profctx.Profile, gnb *gnbctx.GNodeB, imsiStr string) {
readChan := make(chan *common.ProfileMessage)
c := simue.InitUE(imsiStr, gnb, profile, readChan)
Expand Down Expand Up @@ -127,7 +134,7 @@ func ExecuteProfile(profile *profctx.Profile, summaryChan chan common.InterfaceM
plock.Lock()
profile.UeCount = profile.UeCount + 1
imsi := profile.Imsi + profile.UeCount
imsiStr := IMSI_PREFIX + strconv.Itoa(imsi)
imsiStr := makeImsiStr(profile, imsi)
initImsi(profile, gnb, imsiStr)
pCtx := profile.PSimUe[imsiStr]
profile.Log.Infoln("pCtx ", pCtx)
Expand All @@ -151,7 +158,7 @@ func ExecuteProfile(profile *profctx.Profile, summaryChan chan common.InterfaceM
}()
imsi := profile.Imsi
for count := 1; count <= profile.UeCount; count++ {
imsiStr := IMSI_PREFIX + strconv.Itoa(imsi)
imsiStr := makeImsiStr(profile, imsi)
imsi++
wg.Add(1)
pCtx := profile.PSimUe[imsiStr]
Expand Down
12 changes: 8 additions & 4 deletions realue/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package realue
import (
"fmt"
"net"
"strconv"

"github.com/omec-project/gnbsim/common"
realuectx "github.com/omec-project/gnbsim/realue/context"
Expand All @@ -25,9 +26,8 @@ import (

// TODO Remove the hardcoding
const (
SN_NAME string = "5G:mnc093.mcc208.3gppnetwork.org"
SWITCH_OFF uint8 = 0
REQUEST_TYPE_EXISTING_PDU_SESS uint8 = 0x02
SWITCH_OFF uint8 = 0
REQUEST_TYPE_EXISTING_PDU_SESS uint8 = 0x02
)

func HandleRegRequestEvent(ue *realuectx.RealUe,
Expand Down Expand Up @@ -64,9 +64,13 @@ func HandleAuthResponseEvent(ue *realuectx.RealUe,

ue.NgKsi = nasConvert.SpareHalfOctetAndNgksiToModels(authReq.SpareHalfOctetAndNgksi)

mcc, _ := strconv.Atoi(ue.Plmn.Mcc)
mnc, _ := strconv.Atoi(ue.Plmn.Mnc)
snName := fmt.Sprintf("5G:mnc%03d.mcc%03d.3gppnetwork.org", mnc, mcc)

rand := authReq.GetRANDValue()
autn := authReq.GetAUTN()
resStat := ue.DeriveRESstarAndSetKey(autn[:], rand[:], SN_NAME)
resStat := ue.DeriveRESstarAndSetKey(autn[:], rand[:], snName)

// TODO: Parse Auth Request IEs and update the RealUE Context

Expand Down
23 changes: 5 additions & 18 deletions realue/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,12 @@ const (
var ROUTING_INDICATOR []uint8 = []uint8{0xf0, 0xff}

func SupiToSuci(supi string, plmnid *models.PlmnId) ([]byte, error) {
index := strings.Index(supi, "-")
if index < 0 {
return nil, fmt.Errorf(`invalid supi format, should start with "imsi-"`)
supiExpectedPrefix := "imsi-" + plmnid.Mcc + plmnid.Mnc
if !strings.HasPrefix(supi, supiExpectedPrefix) {
return nil, fmt.Errorf(`invalid supi format, should start with "imsi-" + MCC + MNC`)
}

// extracting imsi part after "imsi-"
imsi := supi[(index + 1):]

if !strings.Contains(imsi, plmnid.Mcc) {
return nil, fmt.Errorf("mcc not found in imsi")
}

index = strings.Index(imsi, plmnid.Mnc)
if index < 0 {
return nil, fmt.Errorf("mnc not found in imsi")
}
index += len(plmnid.Mnc)
// extracting msin from imsi
msin := imsi[index:]
// extracting msin from supi
msin := supi[len(supiExpectedPrefix):]

suci := make([]uint8, 0, SUCI_LEN)
// creating octet 4 of 5GS mobile identity info
Expand Down