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

Hotfix https://github.com/free5gc/free5gc/issues/84 free5gc issue#84 #1

Merged
merged 1 commit into from
Aug 24, 2020
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
4 changes: 4 additions & 0 deletions context/ue.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ type N3IWFUe struct {

/* PDU Session Setup Temporary Data */
TemporaryPDUSessionSetupData *PDUSessionSetupTemporaryData
/* Temporary cached NAS message */
// Used when NAS registration accept arrived before
// UE setup NAS TCP connection with N3IWF
TemporaryCachedNASMessage []byte

/* Security */
Kn3iwf []uint8 // 32 bytes (256 bits), value is from NGAP IE "Security Key"
Expand Down
83 changes: 15 additions & 68 deletions ike/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
ike_message "free5gc/src/n3iwf/ike/message"
"free5gc/src/n3iwf/logger"
ngap_message "free5gc/src/n3iwf/ngap/message"
"free5gc/src/n3iwf/relay"

"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
Expand Down Expand Up @@ -211,6 +210,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa
// Create new IKE security association
ikeSecurityAssociation := n3iwfSelf.NewIKESecurityAssociation()
ikeSecurityAssociation.RemoteSPI = message.InitiatorSPI
ikeSecurityAssociation.MessageID = message.MessageID

// Record algorithm in context
ikeSecurityAssociation.EncryptionAlgorithm = responseSecurityAssociation.Proposals[0].EncryptionAlgorithm[0]
Expand Down Expand Up @@ -391,6 +391,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message

// NOTE: tune it
transformPseudorandomFunction := ikeSecurityAssociation.PseudorandomFunction
ikeSecurityAssociation.MessageID = message.MessageID

switch ikeSecurityAssociation.State {
case PreSignalling:
Expand Down Expand Up @@ -634,12 +635,12 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message
return
}

// Send IKE message to UE
SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage)

// Shift state
ikeSecurityAssociation.State++

// Send IKE message to UE
SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage)

case EAPSignalling:
// If success, N3IWF will send an UPLinkNASTransport to AMF
if eap != nil {
Expand Down Expand Up @@ -1252,6 +1253,9 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m
}
}

// Record message ID
ikeSecurityAssociation.MessageID = message.MessageID

// UE context
thisUE := ikeSecurityAssociation.ThisUE
if thisUE == nil {
Expand Down Expand Up @@ -1326,72 +1330,15 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m
return
}

// Setup GTP tunnel for UE
ueAssociatedGTPConnection := pduSession.GTPConnection
if userPlaneConnection, ok := n3iwfSelf.GTPConnectionWithUPFLoad(ueAssociatedGTPConnection.UPFIPAddr); ok {
// UPF UDP address
upfUDPAddr, err := net.ResolveUDPAddr("udp", ueAssociatedGTPConnection.UPFIPAddr+":2152")
if err != nil {
ikeLog.Errorf("Resolve UDP address failed: %+v", err)
return
}

// UE TEID
ueTEID := n3iwfSelf.NewTEID(thisUE)
if ueTEID == 0 {
ikeLog.Error("Invalid TEID (0).")
return
}

// Set UE associated GTP connection
ueAssociatedGTPConnection.UPFUDPAddr = upfUDPAddr
ueAssociatedGTPConnection.IncomingTEID = ueTEID
ueAssociatedGTPConnection.UserPlaneConnection = userPlaneConnection

// Append NGAP PDU session resource setup response transfer
transfer, err := ngap_message.BuildPDUSessionResourceSetupResponseTransfer(pduSession)
if err != nil {
ikeLog.Errorf("Build PDU session resource setup response transfer failed: %+v", err)
return
}
ngap_message.AppendPDUSessionResourceSetupListSURes(temporaryPDUSessionSetupData.SetupListSURes, pduSessionID, transfer)
} else {
// Setup GTP connection with UPF
userPlaneConnection, upfUDPAddr, err := relay.SetupGTPTunnelWithUPF(ueAssociatedGTPConnection.UPFIPAddr)
if err != nil {
ikeLog.Errorf("Setup GTP connection with UPF failed: %+v", err)
return
}
// Listen GTP tunnel
if err := relay.ListenGTP(userPlaneConnection); err != nil {
ikeLog.Errorf("Listening GTP tunnel failed: %+v", err)
return
}

// UE TEID
ueTEID := n3iwfSelf.NewTEID(thisUE)
if ueTEID == 0 {
ikeLog.Error("Invalid TEID (0).")
return
}

// Setup GTP connection with UPF
ueAssociatedGTPConnection.UPFUDPAddr = upfUDPAddr
ueAssociatedGTPConnection.IncomingTEID = ueTEID
ueAssociatedGTPConnection.UserPlaneConnection = userPlaneConnection

// Store GTP connection with UPF into N3IWF context
n3iwfSelf.GTPConnectionWithUPFStore(ueAssociatedGTPConnection.UPFIPAddr, userPlaneConnection)

// Append NGAP PDU session resource setup response transfer
transfer, err := ngap_message.BuildPDUSessionResourceSetupResponseTransfer(pduSession)
if err != nil {
ikeLog.Errorf("Build PDU session resource setup response transfer failed: %+v", err)
return
}
ngap_message.AppendPDUSessionResourceSetupListSURes(temporaryPDUSessionSetupData.SetupListSURes, pduSessionID, transfer)
// Append NGAP PDU session resource setup response transfer
transfer, err := ngap_message.BuildPDUSessionResourceSetupResponseTransfer(pduSession)
if err != nil {
ikeLog.Errorf("Build PDU session resource setup response transfer failed: %+v", err)
return
}
ngap_message.AppendPDUSessionResourceSetupListSURes(temporaryPDUSessionSetupData.SetupListSURes, pduSessionID, transfer)

// Remove handled PDU session setup request from queue
temporaryPDUSessionSetupData.UnactivatedPDUSession = temporaryPDUSessionSetupData.UnactivatedPDUSession[1:]

for {
Expand Down
130 changes: 106 additions & 24 deletions ngap/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
ike_message "free5gc/src/n3iwf/ike/message"
"free5gc/src/n3iwf/logger"
ngap_message "free5gc/src/n3iwf/ngap/message"
"free5gc/src/n3iwf/relay"
"math/rand"
"net"
"time"
Expand Down Expand Up @@ -709,17 +710,21 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N
return
}

n3iwfUe.N3IWFIKESecurityAssociation.State++

// Send IKE message to UE
handler.SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, n3iwfUe.IKEConnection.UEAddr, responseIKEMessage)

n3iwfUe.N3IWFIKESecurityAssociation.State++
}

// handlePDUSessionResourceSetupRequestTransfer parse and store needed information
// for setup user plane connection for UE
// When success, it will return a status "success" set to "true" for indication and set
// unsuccessfulTransfer to nil, otherwise, return false and corresponding transfer
func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSession *context.PDUSession, transfer ngapType.PDUSessionResourceSetupRequestTransfer) (success bool, unsuccessfulTransfer []byte) {
// handlePDUSessionResourceSetupRequestTransfer parse and store needed information from NGAP
// and setup user plane connection for UE
// Parameters:
// UE context :: a pointer to the UE's pdusession data structure ::
// SMF PDU session resource setup request transfer
// Return value:
// a status value indicate whether the handlling is "success" ::
// if failed, an unsuccessfulTransfer is set, otherwise, set to nil
func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSession *context.PDUSession, transfer ngapType.PDUSessionResourceSetupRequestTransfer) (bool, []byte) {

var pduSessionAMBR *ngapType.PDUSessionAggregateMaximumBitRate
var ulNGUUPTNLInformation *ngapType.UPTransportLayerInformation
Expand Down Expand Up @@ -759,15 +764,13 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio
}

if len(iesCriticalityDiagnostics.List) > 0 {
success = false
cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorFalselyConstructedMessage)
criticalityDiagnostics := buildCriticalityDiagnostics(nil, nil, nil, &iesCriticalityDiagnostics)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, &criticalityDiagnostics)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
unsuccessfulTransfer = responseTransfer
return
return false, responseTransfer
}

pduSession.Ambr = pduSessionAMBR
Expand All @@ -785,14 +788,12 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio
pduSession.SecurityIntegrity = true
default:
ngapLog.Error("Unknown security integrity indication")
success = false
cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentSemanticError)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
unsuccessfulTransfer = responseTransfer
return
return false, responseTransfer
}

switch securityIndication.ConfidentialityProtectionIndication.Value {
Expand All @@ -804,14 +805,12 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio
pduSession.SecurityCipher = true
default:
ngapLog.Error("Unknown security confidentiality indication")
success = false
cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentSemanticError)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
unsuccessfulTransfer = responseTransfer
return
return false, responseTransfer
}
} else {
pduSession.SecurityIntegrity = false
Expand All @@ -833,16 +832,98 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio
// TODO: Support IPv6
upfIPv4, _ := ngapConvert.IPAddressToString(ulNGUUPTNLInformation.GTPTunnel.TransportLayerAddress)
if upfIPv4 != "" {
n3iwfSelf := context.N3IWFSelf()

gtpConnection := &context.GTPConnectionInfo{
UPFIPAddr: upfIPv4,
OutgoingTEID: binary.BigEndian.Uint32(ulNGUUPTNLInformation.GTPTunnel.GTPTEID.Value),
}

if userPlaneConnection, ok := n3iwfSelf.GTPConnectionWithUPFLoad(upfIPv4); ok {
// UPF UDP address
upfUDPAddr, err := net.ResolveUDPAddr("udp", upfIPv4+":2152")
if err != nil {
ngapLog.Errorf("Resolve UDP address failed: %+v", err)
cause := buildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
return false, responseTransfer
}

// UE TEID
ueTEID := n3iwfSelf.NewTEID(ue)
if ueTEID == 0 {
ngapLog.Error("Invalid TEID (0).")
cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
return false, responseTransfer
}

// Set UE associated GTP connection
gtpConnection.UPFUDPAddr = upfUDPAddr
gtpConnection.IncomingTEID = ueTEID
gtpConnection.UserPlaneConnection = userPlaneConnection
} else {
// Setup GTP connection with UPF
userPlaneConnection, upfUDPAddr, err := relay.SetupGTPTunnelWithUPF(upfIPv4)
if err != nil {
ngapLog.Errorf("Setup GTP connection with UPF failed: %+v", err)
cause := buildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
return false, responseTransfer
}
// Listen GTP tunnel
if err := relay.ListenGTP(userPlaneConnection); err != nil {
ngapLog.Errorf("Listening GTP tunnel failed: %+v", err)
cause := buildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
return false, responseTransfer
}

// UE TEID
ueTEID := n3iwfSelf.NewTEID(ue)
if ueTEID == 0 {
ngapLog.Error("Invalid TEID (0).")
cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
return false, responseTransfer
}

// Setup GTP connection with UPF
gtpConnection.UPFUDPAddr = upfUDPAddr
gtpConnection.IncomingTEID = ueTEID
gtpConnection.UserPlaneConnection = userPlaneConnection

// Store GTP connection with UPF into N3IWF context
n3iwfSelf.GTPConnectionWithUPFStore(upfIPv4, userPlaneConnection)
}

pduSession.GTPConnection = gtpConnection
} else {
ngapLog.Error("Cannot parse \"PDU session resource setup request transfer\" message \"UL NG-U UP TNL Information\"")
cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject)
responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil)
if err != nil {
ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err)
}
return false, responseTransfer
}

success = true
unsuccessfulTransfer = nil
return
return true, nil
}

func HandleUEContextModificationRequest(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) {
Expand Down Expand Up @@ -1075,7 +1156,7 @@ func HandleDownlinkNASTransport(amf *context.N3IWFAMF, message *ngapType.NGAPPDU
var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList

var n3iwfUe *context.N3IWFUe
var n3iwfSelf = context.N3IWFSelf()
var n3iwfSelf *context.N3IWFContext = context.N3IWFSelf()

if message == nil {
ngapLog.Error("NGAP Message is nil")
Expand Down Expand Up @@ -1152,7 +1233,6 @@ func HandleDownlinkNASTransport(amf *context.N3IWFAMF, message *ngapType.NGAPPDU
if n3iwfUe.AmfUeNgapId == context.AmfUeNgapIdUnspecified {
ngapLog.Tracef("Create new logical UE-associated NG-connection")
n3iwfUe.AmfUeNgapId = amfUeNgapID.Value
// n3iwfUe.SCTPAddr = amf.SCTPAddr
} else {
if n3iwfUe.AmfUeNgapId != amfUeNgapID.Value {
ngapLog.Warn("AMFUENGAPID unmatched")
Expand Down Expand Up @@ -1213,10 +1293,12 @@ func HandleDownlinkNASTransport(amf *context.N3IWFAMF, message *ngapType.NGAPPDU
handler.SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, n3iwfUe.IKEConnection.UEAddr, responseIKEMessage)
} else {
// Check ue.TCPConnection. If failed, retry 2 times.
for i := 0; i < 3; i++ {
maxRetryTimes := 3
for i := 0; i < maxRetryTimes; i++ {
if n3iwfUe.TCPConnection == nil {
if i == 2 {
ngapLog.Warn("No connection found for UE to send NAS message.")
if i == (maxRetryTimes - 1) {
ngapLog.Warn("No connection found for UE to send NAS message. This message will be cached in N3IWF")
n3iwfUe.TemporaryCachedNASMessage = nasPDU.Value
return
} else {
ngapLog.Warn("No NAS signalling session found, retry...")
Expand Down
5 changes: 4 additions & 1 deletion ngap/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,10 @@ func listenAndServe(localAddr, remoteAddr *sctp.SCTPAddr, errChan chan<- error)
continue
}

go ngap.Dispatch(conn, data[:n])
forwardData := make([]byte, n)
copy(forwardData, data[:n])

go ngap.Dispatch(conn, forwardData)
}
}
}
Loading