diff --git a/internal/common/tools/tools.go b/internal/common/tools/tools.go index bc4364ac..aba8efda 100644 --- a/internal/common/tools/tools.go +++ b/internal/common/tools/tools.go @@ -117,14 +117,6 @@ func SimulateSingleUE(simConfig UESimulationConfig, wg *sync.WaitGroup) { ueCfg.GNodeB.PlmnList.GnbId = gnbIdGenerator(simConfig.UeId%numGnb + 1) - // If there is currently a coroutine handling current UE - // kill it, before creating a new coroutine with same UE - // Use case: Registration of N UEs in loop, when loop = true - if simConfig.ScenarioChan != nil { - simConfig.ScenarioChan <- procedures.UeTesterMessage{Type: procedures.Kill} - close(simConfig.ScenarioChan) - } - // Launch a coroutine to handle UE's individual scenario go func(scenarioChan chan procedures.UeTesterMessage, ueId int) { wg.Add(1) @@ -152,8 +144,10 @@ func SimulateSingleUE(simConfig UESimulationConfig, wg *sync.WaitGroup) { for loop { select { case <-deregistrationChannel: - ueRx <- procedures.UeTesterMessage{Type: procedures.Terminate} - ueRx = nil + if ueRx != nil { + ueRx <- procedures.UeTesterMessage{Type: procedures.Terminate} + ueRx = nil + } case <-handoverChannel: if ueRx != nil { ueRx <- procedures.UeTesterMessage{Type: procedures.Handover, GnbChan: simConfig.Gnbs[gnbIdGenerator((ueId+1)%numGnb+1)].GetInboundChannel()} @@ -161,6 +155,9 @@ func SimulateSingleUE(simConfig UESimulationConfig, wg *sync.WaitGroup) { case msg := <-scenarioChan: if ueRx != nil { ueRx <- msg + if msg.Type == procedures.Terminate || msg.Type == procedures.Kill { + ueRx = nil + } } case msg := <-ueTx: log.Info("[UE] Switched from state ", state, " to state ", msg.StateChange) diff --git a/internal/control_test_engine/gnb/context/context.go b/internal/control_test_engine/gnb/context/context.go index 2dcde594..53639cd9 100644 --- a/internal/control_test_engine/gnb/context/context.go +++ b/internal/control_test_engine/gnb/context/context.go @@ -134,8 +134,10 @@ func (gnb *GNBContext) DeleteGnBUe(ue *GNBUe) { } } ue.Lock() - close(ue.gnbTx) - ue.gnbTx = nil + if ue.gnbTx != nil { + close(ue.gnbTx) + ue.gnbTx = nil + } ue.Unlock() } diff --git a/internal/control_test_engine/gnb/nas/service/service.go b/internal/control_test_engine/gnb/nas/service/service.go index 6ab3bb0f..8841cfe7 100644 --- a/internal/control_test_engine/gnb/nas/service/service.go +++ b/internal/control_test_engine/gnb/nas/service/service.go @@ -65,7 +65,7 @@ func processingConn(ue *context.GNBUe, gnb *context.GNBContext) { gnbUeContext.SetStateDown() gnb.DeleteGnBUe(ue) } else if message.IsNas { - go nas.Dispatch(ue, message.Nas, gnb) + nas.Dispatch(ue, message.Nas, gnb) } else if message.AmfId >= 0 { log.Info("[GNB] Received incoming handover for UE") gnbUeContext.SetStateReady() diff --git a/internal/control_test_engine/gnb/ngap/dispatcher.go b/internal/control_test_engine/gnb/ngap/dispatcher.go index 719212fe..5eac0d0d 100644 --- a/internal/control_test_engine/gnb/ngap/dispatcher.go +++ b/internal/control_test_engine/gnb/ngap/dispatcher.go @@ -62,7 +62,7 @@ func Dispatch(amf *context.GNBAmf, gnb *context.GNBContext, message []byte) { case ngapType.ProcedureCodeAMFConfigurationUpdate: // handler NGAP AMF Configuration Update log.Info("[GNB][NGAP] Receive AMF Configuration Update") - handler.HandlerAmfConfiguratonUpdate(amf, gnb, ngapMsg) + handler.HandlerAmfConfigurationUpdate(amf, gnb, ngapMsg) case ngapType.ProcedureCodeErrorIndication: // handler Error Indicator diff --git a/internal/control_test_engine/gnb/ngap/handler/handler.go b/internal/control_test_engine/gnb/ngap/handler/handler.go index d78b2d76..b69a8110 100644 --- a/internal/control_test_engine/gnb/ngap/handler/handler.go +++ b/internal/control_test_engine/gnb/ngap/handler/handler.go @@ -606,7 +606,7 @@ func HandlerUeContextReleaseCommand(gnb *context.GNBContext, message *ngapType.N log.Info("[GNB][NGAP] Releasing UE Context, cause: ", causeToString(cause)) } -func HandlerAmfConfiguratonUpdate(amf *context.GNBAmf, gnb *context.GNBContext, message *ngapType.NGAPPDU) { +func HandlerAmfConfigurationUpdate(amf *context.GNBAmf, gnb *context.GNBContext, message *ngapType.NGAPPDU) { // TODO: Implement update AMF Context from AMFConfigurationUpdate _ = message.InitiatingMessage.Value.AMFConfigurationUpdate diff --git a/internal/control_test_engine/gnb/ngap/message/ngap_control/pdu_session_management/pdu-session-release-response.go b/internal/control_test_engine/gnb/ngap/message/ngap_control/pdu_session_management/pdu-session-release-response.go index 1af135e8..004b417f 100644 --- a/internal/control_test_engine/gnb/ngap/message/ngap_control/pdu_session_management/pdu-session-release-response.go +++ b/internal/control_test_engine/gnb/ngap/message/ngap_control/pdu_session_management/pdu-session-release-response.go @@ -68,6 +68,7 @@ func buildPDUSessionReleaseResponse(amfUeNgapID, ranUeNgapID int64, pduSessionId pDUSessionResourceReleasedItemRelRes := ngapType.PDUSessionResourceReleasedItemRelRes{} pDUSessionResourceReleasedItemRelRes.PDUSessionID = pduSessionId + pDUSessionResourceReleasedItemRelRes.PDUSessionResourceReleaseResponseTransfer = []byte{00} pDUSessionResourceReleasedListRelRes.List = append(pDUSessionResourceReleasedListRelRes.List, pDUSessionResourceReleasedItemRelRes) } diff --git a/internal/control_test_engine/ue/context/context.go b/internal/control_test_engine/ue/context/context.go index 9f15dade..5d43ef75 100644 --- a/internal/control_test_engine/ue/context/context.go +++ b/internal/control_test_engine/ue/context/context.go @@ -1,3 +1,8 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * © Copyright 2023 Hewlett Packard Enterprise Development LP + */ + package context import ( @@ -700,9 +705,11 @@ func (ue *UEContext) Terminate() { } ue.Lock() - close(ue.gnbRx) - ue.gnbRx = nil - ue.Unlock() + if ue.gnbRx != nil { + close(ue.gnbRx) + ue.gnbRx = nil + ue.Unlock() + } close(ue.scenarioChan) log.Info("[UE] UE Terminated") diff --git a/internal/control_test_engine/ue/nas/dispatcher.go b/internal/control_test_engine/ue/nas/dispatcher.go index a3c89165..3f76c929 100644 --- a/internal/control_test_engine/ue/nas/dispatcher.go +++ b/internal/control_test_engine/ue/nas/dispatcher.go @@ -142,6 +142,7 @@ func DispatchNas(ue *context.UEContext, message []byte) { case nas.MsgTypeIdentityRequest: log.Info("[UE][NAS] Receive Identify Request") // handler identity request. + handler.HandlerIdentityRequest(ue, m) case nas.MsgTypeSecurityModeCommand: // handler security mode command. @@ -155,7 +156,7 @@ func DispatchNas(ue *context.UEContext, message []byte) { case nas.MsgTypeConfigurationUpdateCommand: log.Info("[UE][NAS] Receive Configuration Update Command") - log.Info("[UE][NAS] ", ue.GetSupi(), " was succesfully registered") + handler.HandlerConfigurationUpdateCommand(ue, m) case nas.MsgTypeDLNASTransport: // handler DL NAS Transport. diff --git a/internal/control_test_engine/ue/nas/handler/handler.go b/internal/control_test_engine/ue/nas/handler/handler.go index 352b161b..045b86b4 100644 --- a/internal/control_test_engine/ue/nas/handler/handler.go +++ b/internal/control_test_engine/ue/nas/handler/handler.go @@ -12,6 +12,7 @@ import ( "my5G-RANTester/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs" "my5G-RANTester/internal/control_test_engine/ue/nas/message/sender" "my5G-RANTester/internal/control_test_engine/ue/nas/trigger" + "reflect" "time" "github.com/free5gc/nas" @@ -30,6 +31,47 @@ func HandlerAuthenticationReject(ue *context.UEContext, message *nas.Message) { func HandlerAuthenticationRequest(ue *context.UEContext, message *nas.Message) { var authenticationResponse []byte + // check the mandatory fields + if reflect.ValueOf(message.AuthenticationRequest.ExtendedProtocolDiscriminator).IsZero() { + log.Fatal("[UE][NAS] Error in Authentication Request, Extended Protocol is missing") + } + + if message.AuthenticationRequest.ExtendedProtocolDiscriminator.GetExtendedProtocolDiscriminator() != 126 { + log.Fatal("[UE][NAS] Error in Authentication Request, Extended Protocol not the expected value") + } + + if message.AuthenticationRequest.SpareHalfOctetAndSecurityHeaderType.GetSpareHalfOctet() != 0 { + log.Fatal("[UE][NAS] Error in Authentication Request, Spare Half Octet not the expected value") + } + + if message.AuthenticationRequest.SpareHalfOctetAndSecurityHeaderType.GetSecurityHeaderType() != 0 { + log.Fatal("[UE][NAS] Error in Authentication Request, Security Header Type not the expected value") + } + + if reflect.ValueOf(message.AuthenticationRequest.AuthenticationRequestMessageIdentity).IsZero() { + log.Fatal("[UE][NAS] Error in Authentication Request, Message Type is missing") + } + + if message.AuthenticationRequest.AuthenticationRequestMessageIdentity.GetMessageType() != 86 { + log.Fatal("[UE][NAS] Error in Authentication Request, Message Type not the expected value") + } + + if message.AuthenticationRequest.SpareHalfOctetAndNgksi.GetSpareHalfOctet() != 0 { + log.Fatal("[UE][NAS] Error in Authentication Request, Spare Half Octet not the expected value") + } + + if message.AuthenticationRequest.SpareHalfOctetAndNgksi.GetNasKeySetIdentifiler() == 7 { + log.Fatal("[UE][NAS] Error in Authentication Request, ngKSI not the expected value") + } + + if reflect.ValueOf(message.AuthenticationRequest.ABBA).IsZero() { + log.Fatal("[UE][NAS] Error in Authentication Request, ABBA is missing") + } + + if message.AuthenticationRequest.GetABBAContents() == nil { + log.Fatal("[UE][NAS] Error in Authentication Request, ABBA Content is missing") + } + // getting RAND and AUTN from the message. rand := message.AuthenticationRequest.GetRANDValue() autn := message.AuthenticationRequest.GetAUTN() @@ -67,8 +109,47 @@ func HandlerAuthenticationRequest(ue *context.UEContext, message *nas.Message) { sender.SendToGnb(ue, authenticationResponse) } -func HandlerSecurityModeCommand(ue *context.UEContext, message *nas.Message) { +func HandlerSecurityModeCommand(ue *context.UEContext, message *nas.Message) { // check the mandatory fields + if reflect.ValueOf(message.SecurityModeCommand.ExtendedProtocolDiscriminator).IsZero() { + log.Fatal("[UE][NAS] Error in Security Mode Command, Extended Protocol is missing") + } + + if message.SecurityModeCommand.ExtendedProtocolDiscriminator.GetExtendedProtocolDiscriminator() != 126 { + log.Fatal("[UE][NAS] Error in Security Mode Command, Extended Protocol not the expected value") + } + + if message.SecurityModeCommand.SpareHalfOctetAndSecurityHeaderType.GetSecurityHeaderType() != 0 { + log.Fatal("[UE][NAS] Error in Security Mode Command, Security Header Type not the expected value") + } + + if message.SecurityModeCommand.SpareHalfOctetAndSecurityHeaderType.GetSpareHalfOctet() != 0 { + log.Fatal("[UE][NAS] Error in Security Mode Command, Spare Half Octet not the expected value") + } + + if reflect.ValueOf(message.SecurityModeCommand.SecurityModeCommandMessageIdentity).IsZero() { + log.Fatal("[UE][NAS] Error in Security Mode Command, Message Type is missing") + } + + if message.SecurityModeCommand.SecurityModeCommandMessageIdentity.GetMessageType() != 93 { + log.Fatal("[UE][NAS] Error in Security Mode Command, Message Type not the expected value") + } + + if reflect.ValueOf(message.SecurityModeCommand.SelectedNASSecurityAlgorithms).IsZero() { + log.Fatal("[UE][NAS] Error in Security Mode Command, NAS Security Algorithms is missing") + } + if message.SecurityModeCommand.SpareHalfOctetAndNgksi.GetSpareHalfOctet() != 0 { + log.Fatal("[UE][NAS] Error in Security Mode Command, Spare Half Octet is missing") + } + + if message.SecurityModeCommand.SpareHalfOctetAndNgksi.GetNasKeySetIdentifiler() == 7 { + log.Fatal("[UE][NAS] Error in Security Mode Command, ngKSI not the expected value") + } + + if reflect.ValueOf(message.SecurityModeCommand.ReplayedUESecurityCapabilities).IsZero() { + log.Fatal("[UE][NAS] Error in Security Mode Command, Replayed UE Security Capabilities is missing") + } + ue.UeSecurity.CipheringAlg = message.SecurityModeCommand.SelectedNASSecurityAlgorithms.GetTypeOfCipheringAlgorithm() switch ue.UeSecurity.CipheringAlg { case 0: @@ -105,6 +186,38 @@ func HandlerSecurityModeCommand(ue *context.UEContext, message *nas.Message) { } func HandlerRegistrationAccept(ue *context.UEContext, message *nas.Message) { + // check the mandatory fields + if reflect.ValueOf(message.RegistrationAccept.ExtendedProtocolDiscriminator).IsZero() { + log.Fatal("[UE][NAS] Error in Registration Accept, Extended Protocol is missing") + } + + if message.RegistrationAccept.ExtendedProtocolDiscriminator.GetExtendedProtocolDiscriminator() != 126 { + log.Fatal("[UE][NAS] Error in Registration Accept, Extended Protocol not the expected value") + } + + if message.RegistrationAccept.SpareHalfOctetAndSecurityHeaderType.GetSpareHalfOctet() != 0 { + log.Fatal("[UE][NAS] Error in Registration Accept, Spare Half not the expected value") + } + + if message.RegistrationAccept.SpareHalfOctetAndSecurityHeaderType.GetSecurityHeaderType() != 0 { + log.Fatal("[UE][NAS] Error in Registration Accept, Security Header not the expected value") + } + + if reflect.ValueOf(message.RegistrationAccept.RegistrationAcceptMessageIdentity).IsZero() { + log.Fatal("[UE][NAS] Error in Registration Accept, Message Type is missing") + } + + if message.RegistrationAccept.RegistrationAcceptMessageIdentity.GetMessageType() != 66 { + log.Fatal("[UE][NAS] Error in Registration Accept, Message Type not the expected value") + } + + if reflect.ValueOf(message.RegistrationAccept.RegistrationResult5GS).IsZero() { + log.Fatal("[UE][NAS] Error in Registration Accept, Registration Result 5GS is missing") + } + + if message.RegistrationAccept.RegistrationResult5GS.GetRegistrationResultValue5GS() != 1 { + log.Fatal("[UE][NAS] Error in Registration Accept, Registration Result 5GS not the expected value") + } // change the state of ue for registered ue.SetStateMM_REGISTERED() @@ -139,14 +252,51 @@ func HandlerRegistrationAccept(ue *context.UEContext, message *nas.Message) { // sending to GNB sender.SendToGnb(ue, registrationComplete) - - // waiting receive Configuration Update Command. - // TODO: Wait more properly for Configuration Update Command - time.Sleep(50 * time.Millisecond) } func HandlerDlNasTransportPduaccept(ue *context.UEContext, message *nas.Message) { + // check the mandatory fields + if reflect.ValueOf(message.DLNASTransport.ExtendedProtocolDiscriminator).IsZero() { + log.Fatal("[UE][NAS] Error in DL NAS Transport, Extended Protocol is missing") + } + + if message.DLNASTransport.ExtendedProtocolDiscriminator.GetExtendedProtocolDiscriminator() != 126 { + log.Fatal("[UE][NAS] Error in DL NAS Transport, Extended Protocol not expected value") + } + + if message.DLNASTransport.SpareHalfOctetAndSecurityHeaderType.GetSpareHalfOctet() != 0 { + log.Fatal("[UE][NAS] Error in DL NAS Transport, Spare Half not expected value") + } + + if message.DLNASTransport.SpareHalfOctetAndSecurityHeaderType.GetSecurityHeaderType() != 0 { + log.Fatal("[UE][NAS] Error in DL NAS Transport, Security Header not expected value") + } + + if message.DLNASTransport.DLNASTRANSPORTMessageIdentity.GetMessageType() != 104 { + log.Fatal("[UE][NAS] Error in DL NAS Transport, Message Type is missing or not expected value") + } + + if reflect.ValueOf(message.DLNASTransport.SpareHalfOctetAndPayloadContainerType).IsZero() { + log.Fatal("[UE][NAS] Error in DL NAS Transport, Payload Container Type is missing") + } + + if message.DLNASTransport.SpareHalfOctetAndPayloadContainerType.GetPayloadContainerType() != 1 { + log.Fatal("[UE][NAS] Error in DL NAS Transport, Payload Container Type not expected value") + } + + if reflect.ValueOf(message.DLNASTransport.PayloadContainer).IsZero() || message.DLNASTransport.PayloadContainer.GetPayloadContainerContents() == nil { + log.Fatal("[UE][NAS] Error in DL NAS Transport, Payload Container is missing") + } + + if reflect.ValueOf(message.DLNASTransport.PduSessionID2Value).IsZero() { + log.Fatal("[UE][NAS] Error in DL NAS Transport, PDU Session ID is missing") + } + + if message.DLNASTransport.PduSessionID2Value.GetIei() != 18 { + log.Fatal("[UE][NAS] Error in DL NAS Transport, PDU Session ID not expected value") + } + //getting PDU Session establishment accept. payloadContainer := nas_control.GetNasPduFromPduAccept(message) @@ -157,6 +307,47 @@ func HandlerDlNasTransportPduaccept(ue *context.UEContext, message *nas.Message) // get UE ip pduSessionEstablishmentAccept := payloadContainer.PDUSessionEstablishmentAccept + // check the mandatory fields + if reflect.ValueOf(pduSessionEstablishmentAccept.ExtendedProtocolDiscriminator).IsZero() { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, Extended Protocol Discriminator is missing") + } + + if pduSessionEstablishmentAccept.GetExtendedProtocolDiscriminator() != 46 { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, Extended Protocol Discriminator not expected value") + } + + if reflect.ValueOf(pduSessionEstablishmentAccept.PDUSessionID).IsZero() { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, PDU Session ID is missing or not expected value") + } + + if reflect.ValueOf(pduSessionEstablishmentAccept.PTI).IsZero() { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, PTI is missing") + } + + if pduSessionEstablishmentAccept.PTI.GetPTI() != 1 { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, PTI not the expected value") + } + + if pduSessionEstablishmentAccept.PDUSESSIONESTABLISHMENTACCEPTMessageIdentity.GetMessageType() != 194 { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, Message Type is missing or not expected value") + } + + if reflect.ValueOf(pduSessionEstablishmentAccept.SelectedSSCModeAndSelectedPDUSessionType).IsZero() { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, SSC Mode or PDU Session Type is missing") + } + + if pduSessionEstablishmentAccept.SelectedSSCModeAndSelectedPDUSessionType.GetPDUSessionType() != 1 { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, PDU Session Type not the expected value") + } + + if reflect.ValueOf(pduSessionEstablishmentAccept.AuthorizedQosRules).IsZero() { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, Authorized QoS Rules is missing") + } + + if reflect.ValueOf(pduSessionEstablishmentAccept.SessionAMBR).IsZero() { + log.Fatal("[UE][NAS] Error in PDU Session Establishment Accept, Session AMBR is missing") + } + // update PDU Session information. pduSessionId := pduSessionEstablishmentAccept.GetPDUSessionID() pduSession, err := ue.GetPduSession(pduSessionId) @@ -167,9 +358,23 @@ func HandlerDlNasTransportPduaccept(ue *context.UEContext, message *nas.Message) return } + // get UE IP UeIp := pduSessionEstablishmentAccept.GetPDUAddressInformation() pduSession.SetIp(UeIp) + // get QoS Rules + QosRule := pduSessionEstablishmentAccept.AuthorizedQosRules.GetQosRule() + // get DNN + dnn := pduSessionEstablishmentAccept.DNN.GetDNN() + // get SNSSAI + sst := pduSessionEstablishmentAccept.SNSSAI.GetSST() + sd := pduSessionEstablishmentAccept.SNSSAI.GetSD() + + log.Info("[UE][NAS] PDU session QoS RULES: ", QosRule) + log.Info("[UE][NAS] PDU session DNN: ", string(dnn)) + log.Info("[UE][NAS] PDU session NSSAI -- sst: ", sst, " sd: ", + fmt.Sprintf("%x%x%x", sd[0], sd[1], sd[2])) + log.Info("[UE][NAS] PDU address received: ", pduSession.GetIp()) case nas.MsgTypePDUSessionReleaseCommand: log.Info("[UE][NAS] Receiving PDU Session Release Command") @@ -182,6 +387,7 @@ func HandlerDlNasTransportPduaccept(ue *context.UEContext, message *nas.Message) } ue.DeletePduSession(pduSessionId) log.Info("[UE][NAS] Successfully released PDU Session ", pduSessionId, " from UE Context") + trigger.InitPduSessionReleaseComplete(ue, pduSession) case nas.MsgTypePDUSessionEstablishmentReject: log.Error("[UE][NAS] Receiving PDU Session Establishment Reject") @@ -214,6 +420,79 @@ func HandlerDlNasTransportPduaccept(ue *context.UEContext, message *nas.Message) } } +func HandlerIdentityRequest(ue *context.UEContext, message *nas.Message) { + + // check the mandatory fields + if reflect.ValueOf(message.IdentityRequest.ExtendedProtocolDiscriminator).IsZero() { + log.Fatal("[UE][NAS] Error in Identity Request, Extended Protocol is missing") + } + + if message.IdentityRequest.ExtendedProtocolDiscriminator.GetExtendedProtocolDiscriminator() != 126 { + log.Fatal("[UE][NAS] Error in Identity Request, Extended Protocol not the expected value") + } + + if message.IdentityRequest.SpareHalfOctetAndSecurityHeaderType.GetSpareHalfOctet() != 0 { + log.Fatal("[UE][NAS] Error in Identity Request, Spare Half Octet not the expected value") + } + + if message.IdentityRequest.SpareHalfOctetAndSecurityHeaderType.GetSecurityHeaderType() != 0 { + log.Fatal("[UE][NAS] Error in Identity Request, Security Header Type not the expected value") + } + + if reflect.ValueOf(message.IdentityRequest.IdentityRequestMessageIdentity).IsZero() { + log.Fatal("[UE][NAS] Error in Identity Request, Message Type is missing") + } + + if message.IdentityRequest.IdentityRequestMessageIdentity.GetMessageType() != 91 { + log.Fatal("[UE][NAS] Error in Identity Request, Message Type not the expected value") + } + + if reflect.ValueOf(message.IdentityRequest.SpareHalfOctetAndIdentityType).IsZero() { + log.Fatal("[UE][NAS] Error in Identity Request, Spare Half Octet And Identity Type is missing") + } + + + switch message.IdentityRequest.GetTypeOfIdentity() { + case 1: + log.Info("[UE][NAS] Requested SUCI 5GS type") + default: + log.Fatal("[UE][NAS] Only SUCI identity is supported for now inside PacketRusher") + } + + trigger.InitIdentifyResponse(ue) +} + +func HandlerConfigurationUpdateCommand(ue *context.UEContext, message *nas.Message) { + + // check the mandatory fields + if reflect.ValueOf(message.ConfigurationUpdateCommand.ExtendedProtocolDiscriminator).IsZero() { + log.Fatal("[UE][NAS] Error in Configuration Update Command, Extended Protocol Discriminator is missing") + } + + if message.ConfigurationUpdateCommand.ExtendedProtocolDiscriminator.GetExtendedProtocolDiscriminator() != 126 { + log.Fatal("[UE][NAS] Error in Configuration Update Command, Extended Protocol Discriminator not the expected value") + } + + if message.ConfigurationUpdateCommand.SpareHalfOctetAndSecurityHeaderType.GetSpareHalfOctet() != 0 { + log.Fatal("[UE][NAS] Error in Configuration Update Command, Spare Half not the expected value") + } + + if message.ConfigurationUpdateCommand.SpareHalfOctetAndSecurityHeaderType.GetSecurityHeaderType() != 0 { + log.Fatal("[UE][NAS] Error in Configuration Update Command, Security Header not the expected value") + } + + if reflect.ValueOf(message.ConfigurationUpdateCommand.ConfigurationUpdateCommandMessageIdentity).IsZero() { + log.Fatal("[UE][NAS] Error in Configuration Update Command, Message type not the expected value") + } + + if message.ConfigurationUpdateCommand.ConfigurationUpdateCommandMessageIdentity.GetMessageType() != 84 { + log.Fatal("[UE][NAS] Error in Configuration Update Command, Message Type not the expected value") + } + + // return configuration update complete + trigger.InitConfigurationUpdateComplete(ue) +} + func cause5GSMToString(causeValue uint8) string { switch causeValue { case nasMessage.Cause5GSMInsufficientResources: diff --git a/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/configuration-update-complete.go b/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/configuration-update-complete.go new file mode 100644 index 00000000..c3bd86cf --- /dev/null +++ b/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/configuration-update-complete.go @@ -0,0 +1,36 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * © Copyright 2023 Hewlett Packard Enterprise Development LP + */ +package mm_5gs + +import ( + "bytes" + "fmt" + "github.com/free5gc/nas" + "github.com/free5gc/nas/nasMessage" + "my5G-RANTester/internal/control_test_engine/ue/context" +) + +func ConfigurationUpdateComplete(ue *context.UEContext) (nasPdu []byte) { + m := nas.NewMessage() + m.GmmMessage = nas.NewGmmMessage() + m.GmmHeader.SetMessageType(nas.MsgTypeConfigurationUpdateComplete) + + configurationUpdateComplete := nasMessage.NewConfigurationUpdateComplete(0) + configurationUpdateComplete.SetExtendedProtocolDiscriminator(nasMessage.Epd5GSMobilityManagementMessage) + configurationUpdateComplete.SetSecurityHeaderType(0x00) + configurationUpdateComplete.SetSpareHalfOctet(0x00) + configurationUpdateComplete.SetMessageType(nas.MsgTypeConfigurationUpdateComplete) + + m.GmmMessage.ConfigurationUpdateComplete = configurationUpdateComplete + + data := new(bytes.Buffer) + err := m.GmmMessageEncode(data) + if err != nil { + fmt.Println(err.Error()) + } + + nasPdu = data.Bytes() + return +} \ No newline at end of file diff --git a/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/identity-response.go b/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/identity-response.go new file mode 100644 index 00000000..80bd15a7 --- /dev/null +++ b/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/identity-response.go @@ -0,0 +1,39 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * © Copyright 2023 Hewlett Packard Enterprise Development LP + */ +package mm_5gs + +import ( + "bytes" + "fmt" + "github.com/free5gc/nas/nasType" + "my5G-RANTester/internal/control_test_engine/ue/context" + "github.com/free5gc/nas" + "github.com/free5gc/nas/nasMessage" +) + +func IdentityResponse(ue *context.UEContext) (nasPdu []byte) { + + m := nas.NewMessage() + m.GmmMessage = nas.NewGmmMessage() + m.GmmHeader.SetMessageType(nas.MsgTypeIdentityResponse) + + identityResponse := nasMessage.NewIdentityResponse(0) + identityResponse.SetExtendedProtocolDiscriminator(nasMessage.Epd5GSMobilityManagementMessage) + identityResponse.SpareHalfOctetAndSecurityHeaderType.SetSecurityHeaderType(nas.SecurityHeaderTypePlainNas) + identityResponse.SpareHalfOctetAndSecurityHeaderType.SetSpareHalfOctet(0x00) + identityResponse.IdentityResponseMessageIdentity.SetMessageType(nas.MsgTypeIdentityResponse) + identityResponse.MobileIdentity = nasType.MobileIdentity(ue.GetSuci()) + + m.GmmMessage.IdentityResponse = identityResponse + + data := new(bytes.Buffer) + err := m.GmmMessageEncode(data) + if err != nil { + fmt.Println(err.Error()) + } + + nasPdu = data.Bytes() + return +} \ No newline at end of file diff --git a/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/ul-nas-transport.go b/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/ul-nas-transport.go index f6cb6a2a..071501f3 100644 --- a/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/ul-nas-transport.go +++ b/internal/control_test_engine/ue/nas/message/nas_control/mm_5gs/ul-nas-transport.go @@ -47,6 +47,20 @@ func Release_UlNasTransport(pduSession *context.UEPDUSession, ue *context.UECont return pdu, nil } +func ReleasComplete_UlNasTransport(pduSession *context.UEPDUSession, ue *context.UEContext) ([]byte, error) { + + pdu := getUlNasTransport_PduSessionReleaseComplete(pduSession.Id, ue.Dnn, &ue.Snssai) + if pdu == nil { + return nil, fmt.Errorf("Error encoding %s IMSI UE PduSession Establishment Request Msg", ue.UeSecurity.Supi) + } + pdu, err := nas_control.EncodeNasPduWithSecurity(ue, pdu, nas.SecurityHeaderTypeIntegrityProtectedAndCiphered, true, false) + if err != nil { + return nil, fmt.Errorf("Error encoding %s IMSI UE PduSession Establishment Request Msg", ue.UeSecurity.Supi) + } + + return pdu, nil +} + func getUlNasTransport_PduSessionEstablishmentRequest(pduSessionId uint8, dnn string, sNssai *models.Snssai) (nasPdu []byte) { pduSessionEstablishmentRequest := sm_5gs.GetPduSessionEstablishmentRequest(pduSessionId) @@ -134,3 +148,58 @@ func getUlNasTransport_PduSessionEstablishmentRelease(pduSessionId uint8) (nasPd nasPdu = data.Bytes() return } + +func getUlNasTransport_PduSessionReleaseComplete(pduSessionId uint8, dnn string, sNssai *models.Snssai) (nasPdu []byte) { + pduSessionReleaseRequest := sm_5gs.GetPduSessionReleaseComplete(pduSessionId) + + m := nas.NewMessage() + m.GmmMessage = nas.NewGmmMessage() + m.GmmHeader.SetMessageType(nas.MsgTypeULNASTransport) + + ulNasTransport := nasMessage.NewULNASTransport(0) + ulNasTransport.SpareHalfOctetAndSecurityHeaderType.SetSecurityHeaderType(nas.SecurityHeaderTypePlainNas) + ulNasTransport.SetMessageType(nas.MsgTypeULNASTransport) + ulNasTransport.ExtendedProtocolDiscriminator.SetExtendedProtocolDiscriminator(nasMessage.Epd5GSMobilityManagementMessage) + ulNasTransport.PduSessionID2Value = new(nasType.PduSessionID2Value) + ulNasTransport.PduSessionID2Value.SetIei(nasMessage.ULNASTransportPduSessionID2ValueType) + ulNasTransport.PduSessionID2Value.SetPduSessionID2Value(pduSessionId) + ulNasTransport.RequestType = new(nasType.RequestType) + ulNasTransport.RequestType.SetIei(nasMessage.ULNASTransportRequestTypeType) + ulNasTransport.RequestType.SetRequestTypeValue(nasMessage.ULNASTransportRequestTypeExistingPduSession) + + if dnn != "" { + ulNasTransport.DNN = new(nasType.DNN) + ulNasTransport.DNN.SetIei(nasMessage.ULNASTransportDNNType) + ulNasTransport.DNN.SetLen(uint8(len(dnn))) + ulNasTransport.DNN.SetDNN(dnn) + } + + if sNssai != nil { + ulNasTransport.SNSSAI = nasType.NewSNSSAI(nasMessage.ULNASTransportSNSSAIType) + if sNssai.Sd == "" { + ulNasTransport.SNSSAI.SetLen(1) + } else { + ulNasTransport.SNSSAI.SetLen(4) + var sdTemp [3]uint8 + sd, _ := hex.DecodeString(sNssai.Sd) + copy(sdTemp[:], sd) + ulNasTransport.SNSSAI.SetSD(sdTemp) + } + ulNasTransport.SNSSAI.SetSST(uint8(sNssai.Sst)) + } + + ulNasTransport.SpareHalfOctetAndPayloadContainerType.SetPayloadContainerType(nasMessage.PayloadContainerTypeN1SMInfo) + ulNasTransport.PayloadContainer.SetLen(uint16(len(pduSessionReleaseRequest))) + ulNasTransport.PayloadContainer.SetPayloadContainerContents(pduSessionReleaseRequest) + + m.GmmMessage.ULNASTransport = ulNasTransport + + data := new(bytes.Buffer) + err := m.GmmMessageEncode(data) + if err != nil { + fmt.Println(err.Error()) + } + + nasPdu = data.Bytes() + return +} \ No newline at end of file diff --git a/internal/control_test_engine/ue/nas/message/nas_control/sm_5gs/pdu-session-release-complete.go b/internal/control_test_engine/ue/nas/message/nas_control/sm_5gs/pdu-session-release-complete.go new file mode 100644 index 00000000..38588bfb --- /dev/null +++ b/internal/control_test_engine/ue/nas/message/nas_control/sm_5gs/pdu-session-release-complete.go @@ -0,0 +1,35 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * © Copyright 2023 Hewlett Packard Enterprise Development LP + */ +package sm_5gs + +import ( + "bytes" + "fmt" + "github.com/free5gc/nas" + "github.com/free5gc/nas/nasMessage" +) + +func GetPduSessionReleaseComplete(pduSessionId uint8) (nasPdu []byte) { + m := nas.NewMessage() + m.GsmMessage = nas.NewGsmMessage() + m.GsmHeader.SetMessageType(nas.MsgTypePDUSessionReleaseComplete) + + pduSessionReleaseComplete := nasMessage.NewPDUSessionReleaseComplete(0) + pduSessionReleaseComplete.ExtendedProtocolDiscriminator.SetExtendedProtocolDiscriminator(nasMessage.Epd5GSSessionManagementMessage) + pduSessionReleaseComplete.SetMessageType(nas.MsgTypePDUSessionReleaseComplete) + pduSessionReleaseComplete.PDUSessionID.SetPDUSessionID(pduSessionId) + pduSessionReleaseComplete.PTI.SetPTI(0x01) + + m.GsmMessage.PDUSessionReleaseComplete = pduSessionReleaseComplete + + data := new(bytes.Buffer) + err := m.GsmMessageEncode(data) + if err != nil { + fmt.Println(err.Error()) + } + + nasPdu = data.Bytes() + return +} \ No newline at end of file diff --git a/internal/control_test_engine/ue/nas/trigger/trigger.go b/internal/control_test_engine/ue/nas/trigger/trigger.go index c626ef19..2a39d45a 100644 --- a/internal/control_test_engine/ue/nas/trigger/trigger.go +++ b/internal/control_test_engine/ue/nas/trigger/trigger.go @@ -84,6 +84,23 @@ func InitPduSessionRelease(ue *context.UEContext, pduSession *context.UEPDUSessi sender.SendToGnb(ue, ulNasTransport) } +func InitPduSessionReleaseComplete(ue *context.UEContext, pduSession *context.UEPDUSession) { + log.Info("[UE] Initiating PDU Session Release Complete for PDU Session", pduSession.Id) + + if pduSession.GetStateSM() != context.SM5G_PDU_SESSION_INACTIVE { + log.Warn("[UE][NAS] Unable to send PDU Session Release Complete for a PDU Session which is not inactive") + return + } + + ulNasTransport, err := mm_5gs.ReleasComplete_UlNasTransport(pduSession, ue) + if err != nil { + log.Fatal("[UE][NAS] Error sending ul nas transport and pdu session establishment request: ", err) + } + + // sending to GNB + sender.SendToGnb(ue, ulNasTransport) +} + func InitDeregistration(ue *context.UEContext) { log.Info("[UE] Initiating Deregistration") @@ -117,3 +134,23 @@ func InitHandover(ue *context.UEContext, gnbChan chan gnbContext.UEMessage) { previousGnbRx <- gnbContext.UEMessage{ConnectionClosed: true} close(previousGnbRx) } + +func InitIdentifyResponse(ue *context.UEContext) { + log.Info("[UE] Initiating Identify Response") + + // trigger identity response. + identityResponse := mm_5gs.IdentityResponse(ue) + + // send to GNB. + sender.SendToGnb(ue, identityResponse) +} + +func InitConfigurationUpdateComplete(ue *context.UEContext) { + log.Info("[UE] Initiating Configuration Update Complete") + + // trigger identity response. + identityResponse := mm_5gs.ConfigurationUpdateComplete(ue) + + // send to GNB. + sender.SendToGnb(ue, identityResponse) +} \ No newline at end of file diff --git a/internal/control_test_engine/ue/ue.go b/internal/control_test_engine/ue/ue.go index f0d9127d..94b1f94a 100644 --- a/internal/control_test_engine/ue/ue.go +++ b/internal/control_test_engine/ue/ue.go @@ -58,7 +58,7 @@ func NewUE(conf config.Config, id uint8, ueMgrChannel chan procedures.UeTesterMe case msg, open := <-ue.GetGnbTx(): if !open { log.Error("[UE][", ue.GetMsin(), "] Stopping UE as communication with gNB was closed") - loop = false + ue.SetGnbTx(nil) break } gnbMsgHandler(msg, ue) @@ -69,10 +69,6 @@ func NewUE(conf config.Config, id uint8, ueMgrChannel chan procedures.UeTesterMe break } loop = ueMgrHandler(msg, ue) - case <-sigStop: - log.Info("[UE][", ue.GetMsin(), "] Stopping UE as CTRL-C was received") - ueMgrHandler(procedures.UeTesterMessage{Type: procedures.Terminate}, ue) - loop = false } } ue.Terminate() diff --git a/internal/templates/test-multi-ues-in-queue.go b/internal/templates/test-multi-ues-in-queue.go index dd8122ab..7fc0efc1 100644 --- a/internal/templates/test-multi-ues-in-queue.go +++ b/internal/templates/test-multi-ues-in-queue.go @@ -71,6 +71,15 @@ func TestMultiUesInQueue(numUes int, tunnelEnabled bool, dedicatedGnb bool, loop // If CTRL-C signal has been received, // stop creating new UEs, else we create numUes UEs for ueSimCfg.UeId = 1; stopSignal && ueSimCfg.UeId <= numUes; ueSimCfg.UeId++ { + // If there is currently a coroutine handling current UE + // kill it, before creating a new coroutine with same UE + // Use case: Registration of N UEs in loop, when loop = true + if scenarioChans[ueSimCfg.UeId] != nil { + scenarioChans[ueSimCfg.UeId] <- procedures.UeTesterMessage{Type: procedures.Kill} + close(scenarioChans[ueSimCfg.UeId]) + scenarioChans[ueSimCfg.UeId] = nil + } + scenarioChans[ueSimCfg.UeId] = make(chan procedures.UeTesterMessage) ueSimCfg.ScenarioChan = scenarioChans[ueSimCfg.UeId] tools.SimulateSingleUE(ueSimCfg, &wg) @@ -91,5 +100,14 @@ func TestMultiUesInQueue(numUes int, tunnelEnabled bool, dedicatedGnb bool, loop } } - wg.Wait() + if stopSignal { + <-sigStop + } + for _, scenarioChan := range scenarioChans { + if scenarioChan != nil { + scenarioChan <- procedures.UeTesterMessage{Type: procedures.Terminate} + } + } + + time.Sleep(time.Second*2) }