Modify the packet parameters with “Security Mode Command”
Modify the packet parameters with “Initial Context Setup Request”
Solution
Solution
nano /home/ubuntu/free5gc/run.sh
nano /home/ubuntu/free5gc/Makefile
Solution
Problem
Solution
if needSliceSelection {
if ue.NssfUri == "" {
for {
err := consumer.SearchNssfNSSelectionInstance(ue, amfSelf.NrfUri, models.NfType_NSSF, models.NfType_AMF, nil)
if err != nil {
//ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", err)
//time.Sleep(2 * time.Second)
} else {
break
}
}
}
func SelectSmf(
ue *amf_context.AmfUe,
anType models.AccessType,
pduSessionID int32,
snssai models.Snssai,
dnn string,
) (*amf_context.SmContext, uint8, error) {
var (
smfID string
smfUri string
)
ue.GmmLog.Infof("Select SMF [snssai: %+v, dnn: %+v]", snssai, dnn)
nrfUri := ue.ServingAMF().NrfUri // default NRF URI is pre-configured by AMF
ue.GmmLog.Errorf("/////////////////TEST01////////////////")
nsiInformation := ue.GetNsiInformationFromSnssai(anType, snssai)
ue.GmmLog.Errorf("/////////////////TEST02////////////////")
if nsiInformation == nil {
if ue.NssfUri == "" {
// TODO: Set a timeout of NSSF Selection or will starvation here
for {
ue.GmmLog.Errorf("/////////////////TEST03////////////////")
if err := SearchNssfNSSelectionInstance(ue, nrfUri, models.NfType_NSSF,
models.NfType_AMF, nil); err != nil {
ue.GmmLog.Errorf("/////////////////TEST04////////////////")
//ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", err)
//time.Sleep(2 * time.Second)
break
} else {
break
}
}
}
response, problemDetails, err := NSSelectionGetForPduSession(ue, snssai)
if err != nil {
err = fmt.Errorf("NSSelection Get Error[%+v]", err)
return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err
} else if problemDetails != nil {
err = fmt.Errorf("NSSelection Get Failed Problem[%+v]", problemDetails)
return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err
}
nsiInformation = response.NsiInformation
}
.
.
.
func SendSearchNFInstances(nrfUri string, targetNfType, requestNfType models.NfType,
param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts,
) (models.SearchResult, error) {
// Set client and set url
fmt.Println("////TEST A////")
configuration := Nnrf_NFDiscovery.NewConfiguration()
fmt.Println("////TEST B////")
configuration.SetBasePath(nrfUri)
client := Nnrf_NFDiscovery.NewAPIClient(configuration)
fmt.Println("////TEST C////")
result, res, err := client.NFInstancesStoreApi.SearchNFInstances(context.TODO(), targetNfType, requestNfType, param)
// 從這行印出 Handle NFDiscoveryRequest 和 200 GET,然後就到下面return回去了。
fmt.Println("////TEST D////")
if res != nil && res.StatusCode == http.StatusTemporaryRedirect {
err = fmt.Errorf("Temporary Redirect For Non NRF Consumer")
}
if res == nil || res.Body == nil {
return result, err
}
defer func() {
if res != nil {
if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil {
err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr)
}
}
}()
return result, err
}
func CreatePDUSession(ulNasTransport *nasMessage.ULNASTransport,
ue *context.AmfUe,
anType models.AccessType,
pduSessionID int32,
smMessage []uint8,
) (setNewSmContext bool, err error) {
var (
snssai models.Snssai
dnn string
)
// A) AMF shall select an SMF
// If the S-NSSAI IE is not included and the user's subscription context obtained from UDM. AMF shall
// select a default snssai
if ulNasTransport.SNSSAI != nil {
snssai = nasConvert.SnssaiToModels(ulNasTransport.SNSSAI)
} else {
if allowedNssai, ok := ue.AllowedNssai[anType]; ok {
snssai = *allowedNssai[0].AllowedSnssai
} else {
return false, errors.New("Ue doesn't have allowedNssai")
}
}
if ulNasTransport.DNN != nil {
dnn = ulNasTransport.DNN.GetDNN()
} else {
// if user's subscription context obtained from UDM does not contain the default DNN for the,
// S-NSSAI, the AMF shall use a locally configured DNN as the DNN
dnn = ue.ServingAMF().SupportDnnLists[0]
if ue.SmfSelectionData != nil {
snssaiStr := util.SnssaiModelsToHex(snssai)
if snssaiInfo, ok := ue.SmfSelectionData.SubscribedSnssaiInfos[snssaiStr]; ok {
for _, dnnInfo := range snssaiInfo.DnnInfos {
if dnnInfo.DefaultDnnIndicator {
dnn = dnnInfo.Dnn
}
}
}
}
}
if newSmContext, cause, err := consumer.SelectSmf(ue, anType, pduSessionID, snssai, dnn); err != nil {
ue.GmmLog.Errorf("Select SMF failed: %+v", err)
gmm_message.SendDLNASTransport(ue.RanUe[anType], nasMessage.PayloadContainerTypeN1SMInfo,
smMessage, pduSessionID, cause, nil, 0)
} else {
_, smContextRef, errResponse, problemDetail, err := consumer.SendCreateSmContextRequest(
ue, newSmContext, nil, smMessage)
if err != nil {
ue.GmmLog.Errorf("CreateSmContextRequest Error: %+v", err)
return false, nil
} else if problemDetail != nil {
// TODO: error handling
return false, fmt.Errorf("Failed to Create smContext[pduSessionID: %d], Error[%v]", pduSessionID, problemDetail)
} else if errResponse != nil {
ue.GmmLog.Warnf("PDU Session Establishment Request is rejected by SMF[pduSessionId:%d]",
pduSessionID)
gmm_message.SendDLNASTransport(ue.RanUe[anType], nasMessage.PayloadContainerTypeN1SMInfo,
errResponse.BinaryDataN1SmMessage, pduSessionID, 0, nil, 0)
} else {
newSmContext.SetSmContextRef(smContextRef)
newSmContext.SetUserLocation(deepcopy.Copy(ue.Location).(models.UserLocation))
ue.StoreSmContext(pduSessionID, newSmContext)
ue.GmmLog.Infof("create smContext[pduSessionID: %d] Success", pduSessionID)
// TODO: handle response(response N2SmInfo to RAN if exists)
return true, nil
}
}
return false, nil
}
.
.
.
smContext := amf_context.NewSmContext(pduSessionID)
smContext.SetSnssai(snssai)
smContext.SetDnn(dnn)
smContext.SetAccessType(anType)
if nsiInformation == nil {
ue.GmmLog.Warnf("nsiInformation is still nil, use default NRF[%s]", nrfUri)
} else {
smContext.SetNsInstance(nsiInformation.NsiId)
nrfApiUri, err := url.Parse(nsiInformation.NrfId)
if err != nil {
ue.GmmLog.Errorf("Parse NRF URI error, use default NRF[%s]", nrfUri)
} else {
nrfUri = fmt.Sprintf("%s://%s", nrfApiUri.Scheme, nrfApiUri.Host)
}
}
param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{
ServiceNames: optional.NewInterface([]models.ServiceName{models.ServiceName_NSMF_PDUSESSION}),
Dnn: optional.NewString(dnn),
Snssais: optional.NewInterface(openapi.MarshToJsonString([]models.Snssai{snssai})),
}
if ue.PlmnId.Mcc != "" {
param.TargetPlmnList = optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId))
}
if amf_context.GetSelf().Locality != "" {
param.PreferredLocality = optional.NewString(amf_context.GetSelf().Locality)
}
ue.GmmLog.Debugf("Search SMF from NRF[%s]", nrfUri)
result, err := SendSearchNFInstances(nrfUri, models.NfType_SMF, models.NfType_AMF, ¶m)
if err != nil {
ue.GmmLog.Errorf("////return03////")
return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err
}
if len(result.NfInstances) == 0 {
err = fmt.Errorf("DNN[%s] is not supported or not subscribed in the slice[Snssai: %+v]", dnn, snssai)
ue.GmmLog.Errorf("////return04////")
return nil, nasMessage.Cause5GMMDNNNotSupportedOrNotSubscribedInTheSlice, err
}
// select the first SMF, TODO: select base on other info
for _, nfProfile := range result.NfInstances {
smfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NSMF_PDUSESSION, models.NfServiceStatus_REGISTERED)
if smfUri != "" {
break
}
}
smContext.SetSmfID(smfID)
smContext.SetSmfUri(smfUri)
ue.GmmLog.Errorf("////return05////")
return smContext, 0, nil
}
Core side
gnb side
UE side
func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) error {
ue.GmmLog.Infoln("Handle InitialRegistration")
amfSelf := context.GetSelf()
// update Kgnb/Kn3iwf
ue.UpdateSecurityContext(anType)
// Registration with AMF re-allocation (TS 23.502 4.2.2.2.3)
if len(ue.SubscribedNssai) == 0 {
getSubscribedNssai(ue)
}
if err := handleRequestedNssai(ue, anType); err != nil {
return err
}
if ue.RegistrationRequest.Capability5GMM != nil {
ue.Capability5GMM = *ue.RegistrationRequest.Capability5GMM
} else {
gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "")
return fmt.Errorf("Capability5GMM is nil")
}
storeLastVisitedRegisteredTAI(ue, ue.RegistrationRequest.LastVisitedRegisteredTAI)
if ue.RegistrationRequest.MICOIndication != nil {
ue.GmmLog.Warnf("Receive MICO Indication[RAAI: %d], Not Supported",
ue.RegistrationRequest.MICOIndication.GetRAAI())
}
// TODO: Negotiate DRX value if need (TS 23.501 5.4.5)
negotiateDRXParameters(ue, ue.RegistrationRequest.RequestedDRXParameters)
// TODO (step 10 optional): send Namf_Communication_RegistrationCompleteNotify to old AMF if need
if ue.ServingAmfChanged {
// If the AMF has changed the new AMF notifies the old AMF that the registration of the UE in the new AMF is completed
req := models.UeRegStatusUpdateReqData{
TransferStatus: models.UeContextTransferStatus_TRANSFERRED,
}
// TODO: based on locol policy, decide if need to change serving PCF for UE
regStatusTransferComplete, problemDetails, err := consumer.RegistrationStatusUpdate(ue, req)
if problemDetails != nil {
ue.GmmLog.Errorf("Registration Status Update Failed Problem[%+v]", problemDetails)
} else if err != nil {
ue.GmmLog.Errorf("Registration Status Update Error[%+v]", err)
} else {
if regStatusTransferComplete {
ue.GmmLog.Infof("Registration Status Transfer complete")
}
}
}
if len(ue.Pei) == 0 {
gmm_message.SendIdentityRequest(ue.RanUe[anType], anType, nasMessage.MobileIdentity5GSTypeImei)
return nil
}
// TODO (step 12 optional): the new AMF initiates ME identity check by invoking the
// N5g-eir_EquipmentIdentityCheck_Get service operation
if ue.ServingAmfChanged || ue.State[models.AccessType_NON_3_GPP_ACCESS].Is(context.Registered) ||
!ue.ContextValid {
if err := communicateWithUDM(ue, anType); err != nil {
ue.GmmLog.Errorf("communicateWithUDM error: %v", err)
gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMPLMNNotAllowed, "")
return errors.Wrap(err, "communicateWithUDM failed")
}
}
param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{
Supi: optional.NewString(ue.Supi),
}
if amfSelf.Locality != "" {
param.PreferredLocality = optional.NewString(amfSelf.Locality)
}
for {
resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, ¶m)
if err != nil {
ue.GmmLog.Error("AMF can not select an PCF by NRF")
} else {
// select the first PCF, TODO: select base on other info
var pcfUri string
for _, nfProfile := range resp.NfInstances {
pcfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NPCF_AM_POLICY_CONTROL,
models.NfServiceStatus_REGISTERED)
if pcfUri != "" {
ue.PcfId = nfProfile.NfInstanceId
break
}
}
if ue.PcfUri = pcfUri; ue.PcfUri == "" {
ue.GmmLog.Error("AMF can not select an PCF by NRF")
} else {
break
}
}
time.Sleep(500 * time.Millisecond) // sleep a while when search NF Instance fail
}
problemDetails, err := consumer.AMPolicyControlCreate(ue, anType)
if problemDetails != nil {
ue.GmmLog.Errorf("AM Policy Control Create Failed Problem[%+v]", problemDetails)
} else if err != nil {
ue.GmmLog.Errorf("AM Policy Control Create Error[%+v]", err)
}
// Service Area Restriction are applicable only to 3GPP access
if anType == models.AccessType__3_GPP_ACCESS {
if ue.AmPolicyAssociation != nil && ue.AmPolicyAssociation.ServAreaRes != nil {
servAreaRes := ue.AmPolicyAssociation.ServAreaRes
if servAreaRes.RestrictionType == models.RestrictionType_ALLOWED_AREAS {
numOfallowedTAs := 0
for _, area := range servAreaRes.Areas {
numOfallowedTAs += len(area.Tacs)
}
// if numOfallowedTAs < int(servAreaRes.MaxNumOfTAs) {
// TODO: based on AMF Policy, assign additional allowed area for UE,
// and the upper limit is servAreaRes.MaxNumOfTAs (TS 29.507 4.2.2.3)
// }
}
}
}
// TODO (step 18 optional):
// If the AMF has changed and the old AMF has indicated an existing NGAP UE association towards a N3IWF, the new AMF
// creates an NGAP UE association towards the N3IWF to which the UE is connectedsend N2 AMF mobility request to N3IWF
// if anType == models.AccessType_NON_3_GPP_ACCESS && ue.ServingAmfChanged {
// TODO: send N2 AMF Mobility Request
// }
amfSelf.AllocateRegistrationArea(ue, anType)
ue.GmmLog.Debugf("Use original GUTI[%s]", ue.Guti)
assignLadnInfo(ue, anType)
amfSelf.AddAmfUeToUePool(ue, ue.Supi)
ue.T3502Value = amfSelf.T3502Value
if anType == models.AccessType__3_GPP_ACCESS {
ue.T3512Value = amfSelf.T3512Value
} else {
ue.Non3gppDeregTimerValue = amfSelf.Non3gppDeregTimerValue
}
gmm_message.SendRegistrationAccept(ue, anType, nil, nil, nil, nil, nil)
return nil
}
.
.
.
for {
resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, ¶m)
if err != nil {
ue.GmmLog.Error("AMF can not select an PCF by NRF")
//break
} else {
// select the first PCF, TODO: select base on other info
var pcfUri string
for _, nfProfile := range resp.NfInstances {
pcfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NPCF_AM_POLICY_CONTROL,
models.NfServiceStatus_REGISTERED)
if pcfUri != "" {
ue.PcfId = nfProfile.NfInstanceId
break
}
}
if ue.PcfUri = pcfUri; ue.PcfUri == "" {
ue.GmmLog.Error("AMF can not select an PCF by NRF")
break
} else {
break
}
}
time.Sleep(500 * time.Millisecond) // sleep a while when search NF Instance fail
}
problemDetails, err := consumer.AMPolicyControlCreate(ue, anType)
if problemDetails != nil {
ue.GmmLog.Errorf("AM Policy Control Create Failed Problem[%+v]", problemDetails)
} else if err != nil {
ue.GmmLog.Errorf("AM Policy Control Create Error[%+v]", err)
}
.
.
.
Core side
gnb side
UE side
Because the log result has already on the stage of SMcontext and PDUsession creaing, so if I keep commenting out something, it may influence the whole process.