diff --git a/cmd/main.go b/cmd/main.go index 59417c1..3dcf04b 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,25 +1,26 @@ package main import ( - "fmt" "os" + "path/filepath" "runtime/debug" - "github.com/asaskevich/govalidator" "github.com/urfave/cli" "github.com/free5gc/n3iwf/internal/logger" + "github.com/free5gc/n3iwf/pkg/factory" "github.com/free5gc/n3iwf/pkg/service" + logger_util "github.com/free5gc/util/logger" "github.com/free5gc/util/version" ) -var N3IWF = &service.N3IWF{} +var N3IWF *service.N3iwfApp func main() { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. - logger.AppLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + logger.MainLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } }() @@ -27,43 +28,67 @@ func main() { app.Name = "n3iwf" app.Usage = "Non-3GPP Interworking Function (N3IWF)" app.Action = action - app.Flags = N3IWF.GetCliCmd() + app.Flags = []cli.Flag{ + cli.StringFlag{ + Name: "config, c", + Usage: "Load configuration from `FILE`", + }, + cli.StringSliceFlag{ + Name: "log, l", + Usage: "Output NF log to `FILE`", + }, + } if err := app.Run(os.Args); err != nil { - logger.AppLog.Errorf("N3IWF Run Error: %v\n", err) + logger.MainLog.Errorf("N3IWF Run Error: %v\n", err) } } -func action(c *cli.Context) error { - if err := initLogFile(c.String("log"), c.String("log5gc")); err != nil { - logger.AppLog.Errorf("%+v", err) +func action(cliCtx *cli.Context) error { + tlsKeyLogPath, err := initLogFile(cliCtx.StringSlice("log")) + if err != nil { return err } - if err := N3IWF.Initialize(c); err != nil { - switch errType := err.(type) { - case govalidator.Errors: - validErrs := err.(govalidator.Errors).Errors() - for _, validErr := range validErrs { - logger.CfgLog.Errorf("%+v", validErr) - } - default: - logger.CfgLog.Errorf("%+v", errType) - } - logger.CfgLog.Errorf("[-- PLEASE REFER TO SAMPLE CONFIG FILE COMMENTS --]") - return fmt.Errorf("Failed to initialize !!") + logger.MainLog.Infoln("N3IWF version: ", version.GetVersion()) + + cfg, err := factory.ReadConfig(cliCtx.String("config")) + if err != nil { + return err } + factory.N3iwfConfig = cfg - logger.AppLog.Infoln(c.App.Name) - logger.AppLog.Infoln("N3IWF version: ", version.GetVersion()) + n3iwf, err := service.NewApp(cfg) + if err != nil { + return err + } + N3IWF = n3iwf - N3IWF.Start() + n3iwf.Start(tlsKeyLogPath) return nil } -func initLogFile(logNfPath, log5gcPath string) error { - if err := logger.LogFileHook(logNfPath, log5gcPath); err != nil { - return err +func initLogFile(logNfPath []string) (string, error) { + logTlsKeyPath := "" + + for _, path := range logNfPath { + if err := logger_util.LogFileHook(logger.Log, path); err != nil { + return "", err + } + + if logTlsKeyPath != "" { + continue + } + + nfDir, _ := filepath.Split(path) + tmpDir := filepath.Join(nfDir, "key") + if err := os.MkdirAll(tmpDir, 0o775); err != nil { + logger.InitLog.Errorf("Make directory %s failed: %+v", tmpDir, err) + return "", err + } + _, name := filepath.Split(factory.N3iwfDefaultTLSKeyLogPath) + logTlsKeyPath = filepath.Join(tmpDir, name) } - return nil + + return logTlsKeyPath, nil } diff --git a/go.mod b/go.mod index 5a0be55..09f68c8 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,13 @@ module github.com/free5gc/n3iwf -go 1.14 +go 1.17 require ( git.cs.nctu.edu.tw/calee/sctp v1.1.0 - github.com/antonfisher/nested-logrus-formatter v1.3.1 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/free5gc/aper v1.0.4 github.com/free5gc/ngap v1.0.6 - github.com/free5gc/util v1.0.3 + github.com/free5gc/util v1.0.5-0.20230306071612-a52909216bd2 github.com/sirupsen/logrus v1.8.1 github.com/urfave/cli v1.22.5 github.com/vishvananda/netlink v1.1.0 @@ -17,3 +16,29 @@ require ( golang.org/x/sys v0.5.0 gopkg.in/yaml.v2 v2.4.0 ) + +require ( + github.com/antonfisher/nested-logrus-formatter v1.3.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect + github.com/free5gc/openapi v1.0.4 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.7.7 // indirect + github.com/go-playground/locales v0.13.0 // indirect + github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-playground/validator/v10 v10.4.1 // indirect + github.com/golang-jwt/jwt v3.2.1+incompatible // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/json-iterator/go v1.1.11 // indirect + github.com/leodido/go-urn v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect + github.com/ugorji/go/codec v1.1.7 // indirect + github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect + golang.org/x/crypto v0.1.0 // indirect + google.golang.org/protobuf v1.26.0 // indirect +) diff --git a/go.sum b/go.sum index 3be1f17..5254869 100644 --- a/go.sum +++ b/go.sum @@ -71,12 +71,12 @@ github.com/free5gc/ngap v1.0.6 h1:f9sKqHMNrFZVo9Kp8hAyrCXSoI8l746N5O+DFn7vKHA= github.com/free5gc/ngap v1.0.6/go.mod h1:TG1kwwU/EyIlJ3bxY591rdxpD5ZeYnLZTzoWjcfvrBM= github.com/free5gc/openapi v1.0.4 h1:bC6oqXy8Z+3e532xLMFmrTHvdyv4sNGDPezQSslw5gQ= github.com/free5gc/openapi v1.0.4/go.mod h1:KRCnnp0GeK0Bl4gnrX79cQAidKXNENf8VRdG0y9R0Fc= -github.com/free5gc/util v1.0.3 h1:or/gqHCAi3j2YKd+nzViRnc/tl1tuuJAYxCao6IbOAU= -github.com/free5gc/util v1.0.3/go.mod h1:DL1Dnryh//Ps5B+hfXbhU1R07fVfrmPs4uuTO4g9yTg= +github.com/free5gc/util v1.0.5-0.20230306071612-a52909216bd2 h1:FG8KlJ46Epscj3F9XBAKuDGJD9kSKJdstCL9fttjUjE= +github.com/free5gc/util v1.0.5-0.20230306071612-a52909216bd2/go.mod h1:fgV0hXf5arxAWs8D9LfrrfNByZ1IDCWYlgBzncy5GtE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.7.3 h1:aMBzLJ/GMEYmv1UWs2FFTcPISLrQH2mRgL9Glz8xows= -github.com/gin-gonic/gin v1.7.3/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -187,6 +187,7 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -201,6 +202,7 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -240,6 +242,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tim-ywliu/nested-logrus-formatter v1.3.2 h1:jugNJ2/CNCI79SxOJCOhwUHeN3O7/7/bj+ZRGOFlCSw= +github.com/tim-ywliu/nested-logrus-formatter v1.3.2/go.mod h1:oGPmcxZB65j9Wo7mCnQKSrKEJtVDqyjD666SGmyStXI= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= @@ -273,8 +277,9 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -338,6 +343,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210501142056-aec3718b3fa0/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -397,11 +403,13 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -411,6 +419,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/gtp/handler/handler.go b/internal/gtp/handler/handler.go index 4040feb..9536df9 100644 --- a/internal/gtp/handler/handler.go +++ b/internal/gtp/handler/handler.go @@ -4,7 +4,6 @@ import ( "net" "runtime/debug" - "github.com/sirupsen/logrus" gtp "github.com/wmnsk/go-gtp/gtpv1" gtpMsg "github.com/wmnsk/go-gtp/gtpv1/message" "golang.org/x/net/ipv4" @@ -15,12 +14,6 @@ import ( n3iwfContext "github.com/free5gc/n3iwf/pkg/context" ) -var gtpLog *logrus.Entry - -func init() { - gtpLog = logger.GTPLog -} - // Parse the fields not supported by go-gtp and forward data to UE. func HandleQoSTPDU(c gtp.Conn, senderAddr net.Addr, msg gtpMsg.Message) error { pdu := gtpQoSMsg.QoSTPDUPacket{} @@ -37,7 +30,7 @@ func forward(packet gtpQoSMsg.QoSTPDUPacket) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. - gtpLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + logger.GTPLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } }() @@ -48,27 +41,34 @@ func forward(packet gtpQoSMsg.QoSTPDUPacket) { NWuConn := self.NWuIPv4PacketConn pktTEID := packet.GetTEID() - gtpLog.Tracef("pkt teid : %d", pktTEID) + logger.GTPLog.Tracef("pkt teid : %d", pktTEID) // Find UE information - ue, ok := self.AllocatedUETEIDLoad(packet.GetTEID()) + ranUe, ok := self.AllocatedUETEIDLoad(pktTEID) if !ok { - gtpLog.Error("UE context not found") + logger.GTPLog.Errorf("Cannot find RanUE context from QosPacket TEID : %+v", pktTEID) + return + } + + ikeUe, err := self.IkeUeLoadFromNgapId(ranUe.RanUeNgapId) + if err != nil { + logger.GTPLog.Errorf("Cannot find IkeUe context from RanUe , NgapID : %+v", ranUe.RanUeNgapId) return } // UE inner IP in IPSec - ueInnerIPAddr := ue.IPSecInnerIPAddr + ueInnerIPAddr := ikeUe.IPSecInnerIPAddr var cm *ipv4.ControlMessage - for _, childSA := range ue.N3IWFChildSecurityAssociation { - pdusession := ue.FindPDUSession(childSA.PDUSessionIds[0]) + for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { + pdusession := ranUe.FindPDUSession(childSA.PDUSessionIds[0]) if pdusession != nil && pdusession.GTPConnection.IncomingTEID == pktTEID { - gtpLog.Tracef("forwarding IPSec xfrm interfaceid : %d", childSA.XfrmIface.Attrs().Index) + logger.GTPLog.Tracef("forwarding IPSec xfrm interfaceid : %d", childSA.XfrmIface.Attrs().Index) cm = &ipv4.ControlMessage{ IfIndex: childSA.XfrmIface.Attrs().Index, } + break } } @@ -80,7 +80,7 @@ func forward(packet gtpQoSMsg.QoSTPDUPacket) { // QoS Related Parameter if packet.HasQoS() { qfi, rqi = packet.GetQoSParameters() - gtpLog.Tracef("QFI: %v, RQI: %v", qfi, rqi) + logger.GTPLog.Tracef("QFI: %v, RQI: %v", qfi, rqi) } // Encasulate IPv4 packet with GRE header before forward to UE through IPsec @@ -93,10 +93,10 @@ func forward(packet gtpQoSMsg.QoSTPDUPacket) { // Send to UE through Nwu if n, err := NWuConn.WriteTo(forwardData, cm, ueInnerIPAddr); err != nil { - gtpLog.Errorf("Write to UE failed: %+v", err) + logger.GTPLog.Errorf("Write to UE failed: %+v", err) return } else { - gtpLog.Trace("Forward NWu <- N3") - gtpLog.Tracef("Wrote %d bytes", n) + logger.GTPLog.Trace("Forward NWu <- N3") + logger.GTPLog.Tracef("Wrote %d bytes", n) } } diff --git a/internal/gtp/service/service.go b/internal/gtp/service/service.go index 49761bb..8b33842 100644 --- a/internal/gtp/service/service.go +++ b/internal/gtp/service/service.go @@ -5,7 +5,6 @@ import ( "errors" "net" - "github.com/sirupsen/logrus" gtp "github.com/wmnsk/go-gtp/gtpv1" gtpMsg "github.com/wmnsk/go-gtp/gtpv1/message" @@ -14,14 +13,7 @@ import ( n3iwfContext "github.com/free5gc/n3iwf/pkg/context" ) -var gtpLog *logrus.Entry - -var gtpContext context.Context - -func init() { - gtpLog = logger.GTPLog - gtpContext = context.TODO() -} +var gtpContext context.Context = context.TODO() // SetupGTPTunnelWithUPF set up GTP connection with UPF // return *gtp.UPlaneConn, net.Addr and error @@ -33,7 +25,7 @@ func SetupGTPTunnelWithUPF(upfIPAddr string) (*gtp.UPlaneConn, net.Addr, error) remoteUDPAddr, err := net.ResolveUDPAddr("udp", upfUDPAddr) if err != nil { - gtpLog.Errorf("Resolve UDP address %s failed: %+v", upfUDPAddr, err) + logger.GTPLog.Errorf("Resolve UDP address %s failed: %+v", upfUDPAddr, err) return nil, nil, errors.New("Resolve Address Failed") } @@ -41,14 +33,14 @@ func SetupGTPTunnelWithUPF(upfIPAddr string) (*gtp.UPlaneConn, net.Addr, error) localUDPAddr, err := net.ResolveUDPAddr("udp", n3iwfUDPAddr) if err != nil { - gtpLog.Errorf("Resolve UDP address %s failed: %+v", n3iwfUDPAddr, err) + logger.GTPLog.Errorf("Resolve UDP address %s failed: %+v", n3iwfUDPAddr, err) return nil, nil, errors.New("Resolve Address Failed") } // Dial to UPF userPlaneConnection, err := gtp.DialUPlane(gtpContext, localUDPAddr, remoteUDPAddr) if err != nil { - gtpLog.Errorf("Dial to UPF failed: %+v", err) + logger.GTPLog.Errorf("Dial to UPF failed: %+v", err) return nil, nil, errors.New("Dial failed") } diff --git a/internal/logger/logger.go b/internal/logger/logger.go index e6a401c..14f3cbc 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -1,92 +1,46 @@ package logger import ( - "os" - "time" - - formatter "github.com/antonfisher/nested-logrus-formatter" "github.com/sirupsen/logrus" - aperLogger "github.com/free5gc/aper/logger" - ngapLogger "github.com/free5gc/ngap/logger" logger_util "github.com/free5gc/util/logger" ) -var log *logrus.Logger - var ( - AppLog *logrus.Entry - InitLog *logrus.Entry - CfgLog *logrus.Entry - ContextLog *logrus.Entry - NgapLog *logrus.Entry - IKELog *logrus.Entry - GTPLog *logrus.Entry - NWuCPLog *logrus.Entry - NWuUPLog *logrus.Entry - RelayLog *logrus.Entry - UtilLog *logrus.Entry + Log *logrus.Logger + NfLog *logrus.Entry + MainLog *logrus.Entry + InitLog *logrus.Entry + CfgLog *logrus.Entry + CtxLog *logrus.Entry + GinLog *logrus.Entry + NgapLog *logrus.Entry + IKELog *logrus.Entry + GTPLog *logrus.Entry + NWuCPLog *logrus.Entry + NWuUPLog *logrus.Entry + RelayLog *logrus.Entry + UtilLog *logrus.Entry ) func init() { - log = logrus.New() - log.SetReportCaller(false) - - log.Formatter = &formatter.Formatter{ - TimestampFormat: time.RFC3339Nano, - TrimMessages: true, - NoFieldsSpace: true, - HideKeys: true, - FieldsOrder: []string{"component", "category"}, - } - - AppLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "App"}) - InitLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "Init"}) - CfgLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "CFG"}) - ContextLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "Context"}) - NgapLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "NGAP"}) - IKELog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "IKE"}) - GTPLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "GTP"}) - NWuCPLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "NWuCP"}) - NWuUPLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "NWuUP"}) - RelayLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "Relay"}) - UtilLog = log.WithFields(logrus.Fields{"component": "N3IWF", "category": "Util"}) -} - -func LogFileHook(logNfPath string, log5gcPath string) error { - if fullPath, err := logger_util.CreateFree5gcLogFile(log5gcPath); err == nil { - if fullPath != "" { - free5gcLogHook, hookErr := logger_util.NewFileHook(fullPath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0o666) - if hookErr != nil { - return hookErr - } - log.Hooks.Add(free5gcLogHook) - aperLogger.GetLogger().Hooks.Add(free5gcLogHook) - ngapLogger.GetLogger().Hooks.Add(free5gcLogHook) - } - } else { - return err + fieldsOrder := []string{ + logger_util.FieldNF, + logger_util.FieldCategory, } - if fullPath, err := logger_util.CreateNfLogFile(logNfPath, "n3iwf.log"); err == nil { - selfLogHook, hookErr := logger_util.NewFileHook(fullPath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0o666) - if hookErr != nil { - return hookErr - } - log.Hooks.Add(selfLogHook) - aperLogger.GetLogger().Hooks.Add(selfLogHook) - ngapLogger.GetLogger().Hooks.Add(selfLogHook) - } else { - return err - } - - return nil -} - -func SetLogLevel(level logrus.Level) { - log.SetLevel(level) -} - -func SetReportCaller(enable bool) { - log.SetReportCaller(enable) + Log = logger_util.New(fieldsOrder) + NfLog = Log.WithField(logger_util.FieldNF, "N3IWF") + MainLog = NfLog.WithField(logger_util.FieldCategory, "Main") + InitLog = NfLog.WithField(logger_util.FieldCategory, "Init") + CfgLog = NfLog.WithField(logger_util.FieldCategory, "CFG") + CtxLog = NfLog.WithField(logger_util.FieldCategory, "CTX") + GinLog = NfLog.WithField(logger_util.FieldCategory, "GIN") + NgapLog = NfLog.WithField(logger_util.FieldCategory, "NGAP") + IKELog = NfLog.WithField(logger_util.FieldCategory, "IKE") + GTPLog = NfLog.WithField(logger_util.FieldCategory, "GTP") + NWuCPLog = NfLog.WithField(logger_util.FieldCategory, "NWuCP") + NWuUPLog = NfLog.WithField(logger_util.FieldCategory, "NWuUP") + RelayLog = NfLog.WithField(logger_util.FieldCategory, "Relay") + UtilLog = NfLog.WithField(logger_util.FieldCategory, "Util") } diff --git a/internal/ngap/dispatcher.go b/internal/ngap/dispatcher.go index a3bf2a4..b953b47 100644 --- a/internal/ngap/dispatcher.go +++ b/internal/ngap/dispatcher.go @@ -4,7 +4,6 @@ import ( "runtime/debug" "git.cs.nctu.edu.tw/calee/sctp" - "github.com/sirupsen/logrus" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/internal/ngap/handler" @@ -13,13 +12,7 @@ import ( "github.com/free5gc/ngap/ngapType" ) -var Ngaplog *logrus.Entry - -func init() { - Ngaplog = logger.NgapLog -} - -func Dispatch(conn *sctp.SCTPConn, msg []byte) { +func NGAPDispatch(conn *sctp.SCTPConn, msg []byte) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. @@ -34,7 +27,7 @@ func Dispatch(conn *sctp.SCTPConn, msg []byte) { // Decode pdu, err := ngap.Decoder(msg) if err != nil { - Ngaplog.Errorf("NGAP decode error: %+v\n", err) + logger.NgapLog.Errorf("NGAP decode error: %+v\n", err) return } @@ -42,7 +35,7 @@ func Dispatch(conn *sctp.SCTPConn, msg []byte) { case ngapType.NGAPPDUPresentInitiatingMessage: initiatingMessage := pdu.InitiatingMessage if initiatingMessage == nil { - Ngaplog.Errorln("Initiating Message is nil") + logger.NgapLog.Errorln("Initiating Message is nil") return } @@ -84,13 +77,13 @@ func Dispatch(conn *sctp.SCTPConn, msg []byte) { case ngapType.ProcedureCodeOverloadStop: handler.HandleOverloadStop(amf, pdu) default: - Ngaplog.Warnf("Not implemented NGAP message(initiatingMessage), procedureCode:%d]\n", + logger.NgapLog.Warnf("Not implemented NGAP message(initiatingMessage), procedureCode:%d]\n", initiatingMessage.ProcedureCode.Value) } case ngapType.NGAPPDUPresentSuccessfulOutcome: successfulOutcome := pdu.SuccessfulOutcome if successfulOutcome == nil { - Ngaplog.Errorln("Successful Outcome is nil") + logger.NgapLog.Errorln("Successful Outcome is nil") return } @@ -104,13 +97,13 @@ func Dispatch(conn *sctp.SCTPConn, msg []byte) { case ngapType.ProcedureCodeRANConfigurationUpdate: handler.HandleRANConfigurationUpdateAcknowledge(amf, pdu) default: - Ngaplog.Warnf("Not implemented NGAP message(successfulOutcome), procedureCode:%d]\n", + logger.NgapLog.Warnf("Not implemented NGAP message(successfulOutcome), procedureCode:%d]\n", successfulOutcome.ProcedureCode.Value) } case ngapType.NGAPPDUPresentUnsuccessfulOutcome: unsuccessfulOutcome := pdu.UnsuccessfulOutcome if unsuccessfulOutcome == nil { - Ngaplog.Errorln("Unsuccessful Outcome is nil") + logger.NgapLog.Errorln("Unsuccessful Outcome is nil") return } @@ -120,7 +113,7 @@ func Dispatch(conn *sctp.SCTPConn, msg []byte) { case ngapType.ProcedureCodeRANConfigurationUpdate: handler.HandleRANConfigurationUpdateFailure(amf, pdu) default: - Ngaplog.Warnf("Not implemented NGAP message(unsuccessfulOutcome), procedureCode:%d]\n", + logger.NgapLog.Warnf("Not implemented NGAP message(unsuccessfulOutcome), procedureCode:%d]\n", unsuccessfulOutcome.ProcedureCode.Value) } } diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index ce19637..e136849 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -2,32 +2,22 @@ package handler import ( "encoding/binary" - "math/rand" "net" "time" "git.cs.nctu.edu.tw/calee/sctp" - "github.com/sirupsen/logrus" "github.com/free5gc/aper" gtp_service "github.com/free5gc/n3iwf/internal/gtp/service" "github.com/free5gc/n3iwf/internal/logger" ngap_message "github.com/free5gc/n3iwf/internal/ngap/message" "github.com/free5gc/n3iwf/pkg/context" - "github.com/free5gc/n3iwf/pkg/ike/handler" - ike_message "github.com/free5gc/n3iwf/pkg/ike/message" "github.com/free5gc/ngap/ngapConvert" "github.com/free5gc/ngap/ngapType" ) -var ngapLog *logrus.Entry - -func init() { - ngapLog = logger.NgapLog -} - func HandleNGSetupResponse(sctpAddr string, conn *sctp.SCTPConn, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle NG Setup Response") + logger.NgapLog.Infoln("[N3IWF] Handle NG Setup Response") var amfName *ngapType.AMFName var servedGUAMIList *ngapType.ServedGUAMIList @@ -40,62 +30,62 @@ func HandleNGSetupResponse(sctpAddr string, conn *sctp.SCTPConn, message *ngapTy n3iwfSelf := context.N3IWFSelf() if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } successfulOutcome := message.SuccessfulOutcome if successfulOutcome == nil { - ngapLog.Error("Successful Outcome is nil") + logger.NgapLog.Error("Successful Outcome is nil") return } ngSetupResponse := successfulOutcome.Value.NGSetupResponse if ngSetupResponse == nil { - ngapLog.Error("ngSetupResponse is nil") + logger.NgapLog.Error("ngSetupResponse is nil") return } for _, ie := range ngSetupResponse.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFName: - ngapLog.Traceln("[NGAP] Decode IE AMFName") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFName") amfName = ie.Value.AMFName if amfName == nil { - ngapLog.Errorf("AMFName is nil") + logger.NgapLog.Errorf("AMFName is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDServedGUAMIList: - ngapLog.Traceln("[NGAP] Decode IE ServedGUAMIList") + logger.NgapLog.Traceln("[NGAP] Decode IE ServedGUAMIList") servedGUAMIList = ie.Value.ServedGUAMIList if servedGUAMIList == nil { - ngapLog.Errorf("ServedGUAMIList is nil") + logger.NgapLog.Errorf("ServedGUAMIList is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRelativeAMFCapacity: - ngapLog.Traceln("[NGAP] Decode IE RelativeAMFCapacity") + logger.NgapLog.Traceln("[NGAP] Decode IE RelativeAMFCapacity") relativeAMFCapacity = ie.Value.RelativeAMFCapacity case ngapType.ProtocolIEIDPLMNSupportList: - ngapLog.Traceln("[NGAP] Decode IE PLMNSupportList") + logger.NgapLog.Traceln("[NGAP] Decode IE PLMNSupportList") plmnSupportList = ie.Value.PLMNSupportList if plmnSupportList == nil { - ngapLog.Errorf("PLMNSupportList is nil") + logger.NgapLog.Errorf("PLMNSupportList is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDCriticalityDiagnostics: - ngapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") + logger.NgapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") criticalityDiagnostics = ie.Value.CriticalityDiagnostics } } if len(iesCriticalityDiagnostics.List) != 0 { - ngapLog.Traceln("[NGAP] Sending error indication to AMF, because some mandatory IEs were not included") + logger.NgapLog.Traceln("[NGAP] Sending error indication to AMF, because some mandatory IEs were not included") cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) @@ -136,7 +126,7 @@ func HandleNGSetupResponse(sctpAddr string, conn *sctp.SCTPConn, message *ngapTy } func HandleNGSetupFailure(sctpAddr string, conn *sctp.SCTPConn, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle NG Setup Failure") + logger.NgapLog.Infoln("[N3IWF] Handle NG Setup Failure") var cause *ngapType.Cause var timeToWait *ngapType.TimeToWait @@ -147,47 +137,49 @@ func HandleNGSetupFailure(sctpAddr string, conn *sctp.SCTPConn, message *ngapTyp n3iwfSelf := context.N3IWFSelf() if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } unsuccessfulOutcome := message.UnsuccessfulOutcome if unsuccessfulOutcome == nil { - ngapLog.Error("Unsuccessful Message is nil") + logger.NgapLog.Error("Unsuccessful Message is nil") return } ngSetupFailure := unsuccessfulOutcome.Value.NGSetupFailure if ngSetupFailure == nil { - ngapLog.Error("NGSetupFailure is nil") + logger.NgapLog.Error("NGSetupFailure is nil") return } for _, ie := range ngSetupFailure.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDCause: - ngapLog.Traceln("[NGAP] Decode IE Cause") + logger.NgapLog.Traceln("[NGAP] Decode IE Cause") cause = ie.Value.Cause if cause == nil { - ngapLog.Error("Cause is nil") + logger.NgapLog.Error("Cause is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDTimeToWait: - ngapLog.Traceln("[NGAP] Decode IE TimeToWait") + logger.NgapLog.Traceln("[NGAP] Decode IE TimeToWait") timeToWait = ie.Value.TimeToWait case ngapType.ProtocolIEIDCriticalityDiagnostics: - ngapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") + logger.NgapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") criticalityDiagnostics = ie.Value.CriticalityDiagnostics } } if len(iesCriticalityDiagnostics.List) > 0 { // TODO: Send error indication - ngapLog.Traceln("[NGAP] Sending error indication to AMF, because some mandatory IEs were not included") + logger.NgapLog.Traceln("[NGAP] Sending error indication to AMF, because some mandatory IEs were not included") - cause = ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) + cause = ngap_message.BuildCause( + ngapType.CausePresentProtocol, + ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) procedureCode := ngapType.ProcedureCodeNGSetup triggeringMessage := ngapType.TriggeringMessagePresentUnsuccessfullOutcome @@ -229,7 +221,7 @@ func HandleNGSetupFailure(sctpAddr string, conn *sctp.SCTPConn, message *ngapTyp } if waitingTime != 0 { - ngapLog.Infof("Wait at lease %ds to reinitialize with same AMF[%s]", waitingTime, sctpAddr) + logger.NgapLog.Infof("Wait at lease %ds to reinitialize with same AMF[%s]", waitingTime, sctpAddr) n3iwfSelf.AMFReInitAvailableListStore(sctpAddr, false) time.AfterFunc(time.Duration(waitingTime)*time.Second, func() { n3iwfSelf.AMFReInitAvailableListStore(sctpAddr, true) @@ -240,7 +232,7 @@ func HandleNGSetupFailure(sctpAddr string, conn *sctp.SCTPConn, message *ngapTyp } func HandleNGReset(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle NG Reset") + logger.NgapLog.Infoln("[N3IWF] Handle NG Reset") var cause *ngapType.Cause var resetType *ngapType.ResetType @@ -250,37 +242,37 @@ func HandleNGReset(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { n3iwfSelf := context.N3IWFSelf() if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("InitiatingMessage is nil") + logger.NgapLog.Error("InitiatingMessage is nil") return } nGReset := initiatingMessage.Value.NGReset if nGReset == nil { - ngapLog.Error("nGReset is nil") + logger.NgapLog.Error("nGReset is nil") return } for _, ie := range nGReset.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDCause: - ngapLog.Traceln("[NGAP] Decode IE Cause") + logger.NgapLog.Traceln("[NGAP] Decode IE Cause") cause = ie.Value.Cause case ngapType.ProtocolIEIDResetType: - ngapLog.Traceln("[NGAP] Decode IE ResetType") + logger.NgapLog.Traceln("[NGAP] Decode IE ResetType") resetType = ie.Value.ResetType if resetType == nil { - ngapLog.Error("ResetType is nil") + logger.NgapLog.Error("ResetType is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) @@ -302,103 +294,103 @@ func HandleNGReset(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { switch resetType.Present { case ngapType.ResetTypePresentNGInterface: - ngapLog.Trace("ResetType Present: NG Interface") + logger.NgapLog.Trace("ResetType Present: NG Interface") // TODO: Release Uu Interface related to this amf(IPSec) // Remove all Ue if err := amf.RemoveAllRelatedUe(); err != nil { - ngapLog.Errorf("RemoveAllRelatedUe error : %+v", err) + logger.NgapLog.Errorf("RemoveAllRelatedUe error : %+v", err) } ngap_message.SendNGResetAcknowledge(amf, nil, nil) case ngapType.ResetTypePresentPartOfNGInterface: - ngapLog.Trace("ResetType Present: Part of NG Interface") + logger.NgapLog.Trace("ResetType Present: Part of NG Interface") partOfNGInterface := resetType.PartOfNGInterface if partOfNGInterface == nil { - ngapLog.Error("PartOfNGInterface is nil") + logger.NgapLog.Error("PartOfNGInterface is nil") return } - var ue *context.N3IWFUe + var ranUe *context.N3IWFRanUe for _, ueAssociatedLogicalNGConnectionItem := range partOfNGInterface.List { if ueAssociatedLogicalNGConnectionItem.RANUENGAPID != nil { - ngapLog.Tracef("RanUeNgapID[%d]", ueAssociatedLogicalNGConnectionItem.RANUENGAPID.Value) - ue, _ = n3iwfSelf.UePoolLoad(ueAssociatedLogicalNGConnectionItem.RANUENGAPID.Value) + logger.NgapLog.Tracef("RanUeNgapID[%d]", ueAssociatedLogicalNGConnectionItem.RANUENGAPID.Value) + ranUe, _ = n3iwfSelf.RanUePoolLoad(ueAssociatedLogicalNGConnectionItem.RANUENGAPID.Value) } else if ueAssociatedLogicalNGConnectionItem.AMFUENGAPID != nil { - ngapLog.Tracef("AmfUeNgapID[%d]", ueAssociatedLogicalNGConnectionItem.AMFUENGAPID.Value) - ue = amf.FindUeByAmfUeNgapID(ueAssociatedLogicalNGConnectionItem.AMFUENGAPID.Value) + logger.NgapLog.Tracef("AmfUeNgapID[%d]", ueAssociatedLogicalNGConnectionItem.AMFUENGAPID.Value) + ranUe = amf.FindUeByAmfUeNgapID(ueAssociatedLogicalNGConnectionItem.AMFUENGAPID.Value) } - if ue == nil { - ngapLog.Warn("Cannot not find UE Context") + if ranUe == nil { + logger.NgapLog.Warn("Cannot not find RanUE Context") if ueAssociatedLogicalNGConnectionItem.AMFUENGAPID != nil { - ngapLog.Warnf("AmfUeNgapID[%d]", ueAssociatedLogicalNGConnectionItem.AMFUENGAPID.Value) + logger.NgapLog.Warnf("AmfUeNgapID[%d]", ueAssociatedLogicalNGConnectionItem.AMFUENGAPID.Value) } if ueAssociatedLogicalNGConnectionItem.RANUENGAPID != nil { - ngapLog.Warnf("RanUeNgapID[%d]", ueAssociatedLogicalNGConnectionItem.RANUENGAPID.Value) + logger.NgapLog.Warnf("RanUeNgapID[%d]", ueAssociatedLogicalNGConnectionItem.RANUENGAPID.Value) } continue } // TODO: Release Uu Interface (IPSec) - if err := ue.Remove(); err != nil { - ngapLog.Errorf("Remove UE Context error : %+v", err) + if err := ranUe.Remove(); err != nil { + logger.NgapLog.Errorf("Remove RanUE Context error : %+v", err) } } ngap_message.SendNGResetAcknowledge(amf, partOfNGInterface, nil) default: - ngapLog.Warnf("Invalid ResetType[%d]", resetType.Present) + logger.NgapLog.Warnf("Invalid ResetType[%d]", resetType.Present) } } func HandleNGResetAcknowledge(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle NG Reset Acknowledge") + logger.NgapLog.Infoln("[N3IWF] Handle NG Reset Acknowledge") var uEAssociatedLogicalNGConnectionList *ngapType.UEAssociatedLogicalNGConnectionList var criticalityDiagnostics *ngapType.CriticalityDiagnostics if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } successfulOutcome := message.SuccessfulOutcome if successfulOutcome == nil { - ngapLog.Error("SuccessfulOutcome is nil") + logger.NgapLog.Error("SuccessfulOutcome is nil") return } nGResetAcknowledge := successfulOutcome.Value.NGResetAcknowledge if nGResetAcknowledge == nil { - ngapLog.Error("nGResetAcknowledge is nil") + logger.NgapLog.Error("nGResetAcknowledge is nil") return } for _, ie := range nGResetAcknowledge.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDUEAssociatedLogicalNGConnectionList: - ngapLog.Traceln("[NGAP] Decode IE UEAssociatedLogicalNGConnectionList") + logger.NgapLog.Traceln("[NGAP] Decode IE UEAssociatedLogicalNGConnectionList") uEAssociatedLogicalNGConnectionList = ie.Value.UEAssociatedLogicalNGConnectionList case ngapType.ProtocolIEIDCriticalityDiagnostics: - ngapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") + logger.NgapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") criticalityDiagnostics = ie.Value.CriticalityDiagnostics } } if uEAssociatedLogicalNGConnectionList != nil { - ngapLog.Tracef("%d UE association(s) has been reset", len(uEAssociatedLogicalNGConnectionList.List)) + logger.NgapLog.Tracef("%d RanUE association(s) has been reset", len(uEAssociatedLogicalNGConnectionList.List)) for i, item := range uEAssociatedLogicalNGConnectionList.List { if item.AMFUENGAPID != nil && item.RANUENGAPID != nil { - ngapLog.Tracef("%d: AmfUeNgapID[%d] RanUeNgapID[%d]", + logger.NgapLog.Tracef("%d: AmfUeNgapID[%d] RanUeNgapID[%d]", i+1, item.AMFUENGAPID.Value, item.RANUENGAPID.Value) } else if item.AMFUENGAPID != nil { - ngapLog.Tracef("%d: AmfUeNgapID[%d] RanUeNgapID[unknown]", i+1, item.AMFUENGAPID.Value) + logger.NgapLog.Tracef("%d: AmfUeNgapID[%d] RanUeNgapID[unknown]", i+1, item.AMFUENGAPID.Value) } else if item.RANUENGAPID != nil { - ngapLog.Tracef("%d: AmfUeNgapID[unknown] RanUeNgapID[%d]", i+1, item.RANUENGAPID.Value) + logger.NgapLog.Tracef("%d: AmfUeNgapID[unknown] RanUeNgapID[%d]", i+1, item.RANUENGAPID.Value) } } } @@ -409,7 +401,7 @@ func HandleNGResetAcknowledge(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) } func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle Initial Context Setup Request") + logger.NgapLog.Infoln("[N3IWF] Handle Initial Context Setup Request") var amfUeNgapID *ngapType.AMFUENGAPID var ranUeNgapID *ngapType.RANUENGAPID @@ -429,126 +421,127 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N var emergencyFallbackIndicator *ngapType.EmergencyFallbackIndicator var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList - var n3iwfUe *context.N3IWFUe + var ranUe *context.N3IWFRanUe n3iwfSelf := context.N3IWFSelf() if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("Initiating Message is nil") + logger.NgapLog.Error("Initiating Message is nil") return } initialContextSetupRequest := initiatingMessage.Value.InitialContextSetupRequest if initialContextSetupRequest == nil { - ngapLog.Error("InitialContextSetupRequest is nil") + logger.NgapLog.Error("InitialContextSetupRequest is nil") return } for _, ie := range initialContextSetupRequest.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") amfUeNgapID = ie.Value.AMFUENGAPID if amfUeNgapID == nil { - ngapLog.Errorf("AMFUENGAPID is nil") + logger.NgapLog.Errorf("AMFUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRANUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE RANUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE RANUENGAPID") ranUeNgapID = ie.Value.RANUENGAPID if ranUeNgapID == nil { - ngapLog.Errorf("RANUENGAPID is nil") + logger.NgapLog.Errorf("RANUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDOldAMF: - ngapLog.Traceln("[NGAP] Decode IE OldAMF") + logger.NgapLog.Traceln("[NGAP] Decode IE OldAMF") oldAMF = ie.Value.OldAMF case ngapType.ProtocolIEIDUEAggregateMaximumBitRate: - ngapLog.Traceln("[NGAP] Decode IE UEAggregateMaximumBitRate") + logger.NgapLog.Traceln("[NGAP] Decode IE UEAggregateMaximumBitRate") ueAggregateMaximumBitRate = ie.Value.UEAggregateMaximumBitRate case ngapType.ProtocolIEIDCoreNetworkAssistanceInformation: - ngapLog.Traceln("[NGAP] Decode IE CoreNetworkAssistanceInformation") + logger.NgapLog.Traceln("[NGAP] Decode IE CoreNetworkAssistanceInformation") coreNetworkAssistanceInformation = ie.Value.CoreNetworkAssistanceInformation if coreNetworkAssistanceInformation != nil { - ngapLog.Warnln("Not Supported IE [CoreNetworkAssistanceInformation]") + logger.NgapLog.Warnln("Not Supported IE [CoreNetworkAssistanceInformation]") } case ngapType.ProtocolIEIDGUAMI: - ngapLog.Traceln("[NGAP] Decode IE GUAMI") + logger.NgapLog.Traceln("[NGAP] Decode IE GUAMI") guami = ie.Value.GUAMI if guami == nil { - ngapLog.Errorf("GUAMI is nil") + logger.NgapLog.Errorf("GUAMI is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDPDUSessionResourceSetupListCxtReq: - ngapLog.Traceln("[NGAP] Decode IE PDUSessionResourceSetupListCxtReq") + logger.NgapLog.Traceln("[NGAP] Decode IE PDUSessionResourceSetupListCxtReq") pduSessionResourceSetupListCxtReq = ie.Value.PDUSessionResourceSetupListCxtReq case ngapType.ProtocolIEIDAllowedNSSAI: - ngapLog.Traceln("[NGAP] Decode IE AllowedNSSAI") + logger.NgapLog.Traceln("[NGAP] Decode IE AllowedNSSAI") allowedNSSAI = ie.Value.AllowedNSSAI if allowedNSSAI == nil { - ngapLog.Errorf("AllowedNSSAI is nil") + logger.NgapLog.Errorf("AllowedNSSAI is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDUESecurityCapabilities: - ngapLog.Traceln("[NGAP] Decode IE UESecurityCapabilities") + logger.NgapLog.Traceln("[NGAP] Decode IE UESecurityCapabilities") ueSecurityCapabilities = ie.Value.UESecurityCapabilities if ueSecurityCapabilities == nil { - ngapLog.Errorf("UESecurityCapabilities is nil") + logger.NgapLog.Errorf("UESecurityCapabilities is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDSecurityKey: - ngapLog.Traceln("[NGAP] Decode IE SecurityKey") + logger.NgapLog.Traceln("[NGAP] Decode IE SecurityKey") securityKey = ie.Value.SecurityKey if securityKey == nil { - ngapLog.Errorf("SecurityKey is nil") + logger.NgapLog.Errorf("SecurityKey is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDTraceActivation: - ngapLog.Traceln("[NGAP] Decode IE TraceActivation") + logger.NgapLog.Traceln("[NGAP] Decode IE TraceActivation") traceActivation = ie.Value.TraceActivation if traceActivation != nil { - ngapLog.Warnln("Not Supported IE [TraceActivation]") + logger.NgapLog.Warnln("Not Supported IE [TraceActivation]") } case ngapType.ProtocolIEIDUERadioCapability: - ngapLog.Traceln("[NGAP] Decode IE UERadioCapability") + logger.NgapLog.Traceln("[NGAP] Decode IE UERadioCapability") ueRadioCapability = ie.Value.UERadioCapability case ngapType.ProtocolIEIDIndexToRFSP: - ngapLog.Traceln("[NGAP] Decode IE IndexToRFSP") + logger.NgapLog.Traceln("[NGAP] Decode IE IndexToRFSP") indexToRFSP = ie.Value.IndexToRFSP case ngapType.ProtocolIEIDMaskedIMEISV: - ngapLog.Traceln("[NGAP] Decode IE MaskedIMEISV") + logger.NgapLog.Traceln("[NGAP] Decode IE MaskedIMEISV") maskedIMEISV = ie.Value.MaskedIMEISV case ngapType.ProtocolIEIDNASPDU: - ngapLog.Traceln("[NGAP] Decode IE NAS PDU") + logger.NgapLog.Traceln("[NGAP] Decode IE NAS PDU") // nasPDU = ie.Value.NASPDU case ngapType.ProtocolIEIDEmergencyFallbackIndicator: - ngapLog.Traceln("[NGAP] Decode IE EmergencyFallbackIndicator") + logger.NgapLog.Traceln("[NGAP] Decode IE EmergencyFallbackIndicator") emergencyFallbackIndicator = ie.Value.EmergencyFallbackIndicator if emergencyFallbackIndicator != nil { - ngapLog.Warnln("Not Supported IE [EmergencyFallbackIndicator]") + logger.NgapLog.Warnln("Not Supported IE [EmergencyFallbackIndicator]") } } } if len(iesCriticalityDiagnostics.List) > 0 { - ngapLog.Traceln("[NGAP] Sending unsuccessful outcome to AMF, because some mandatory IEs were not included") + logger.NgapLog.Traceln( + "[NGAP] Sending unsuccessful outcome to AMF, because some mandatory IEs were not included") cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorFalselyConstructedMessage) @@ -558,27 +551,27 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N for _, item := range pduSessionResourceSetupListCxtReq.List { transfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } ngap_message.AppendPDUSessionResourceFailedToSetupListCxtfail( failedListCxtFail, item.PDUSessionID.Value, transfer) } - ngap_message.SendInitialContextSetupFailure(amf, n3iwfUe, *cause, failedListCxtFail, &criticalityDiagnostics) + ngap_message.SendInitialContextSetupFailure(ranUe, *cause, failedListCxtFail, &criticalityDiagnostics) return } if (amfUeNgapID != nil) && (ranUeNgapID != nil) { // Find UE context var ok bool - n3iwfUe, ok = n3iwfSelf.UePoolLoad(ranUeNgapID.Value) + ranUe, ok = n3iwfSelf.RanUePoolLoad(ranUeNgapID.Value) if !ok { - ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", ranUeNgapID.Value) + logger.NgapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", ranUeNgapID.Value) // TODO: build cause and handle error // Cause: Unknown local UE NGAP ID return } else { - if n3iwfUe.AmfUeNgapId != amfUeNgapID.Value { + if ranUe.AmfUeNgapId != amfUeNgapID.Value { // TODO: build cause and handle error // Cause: Inconsistent remote UE NGAP ID return @@ -586,14 +579,19 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N } } - n3iwfUe.AmfUeNgapId = amfUeNgapID.Value - n3iwfUe.RanUeNgapId = ranUeNgapID.Value + if ranUe == nil { + logger.NgapLog.Errorf("RAN UE context is nil") + return + } + + ranUe.AmfUeNgapId = amfUeNgapID.Value + ranUe.RanUeNgapId = ranUeNgapID.Value if pduSessionResourceSetupListCxtReq != nil { if ueAggregateMaximumBitRate != nil { - n3iwfUe.Ambr = ueAggregateMaximumBitRate + ranUe.Ambr = ueAggregateMaximumBitRate } else { - ngapLog.Errorln("IE[UEAggregateMaximumBitRate] is nil") + logger.NgapLog.Errorln("IE[UEAggregateMaximumBitRate] is nil") cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorFalselyConstructedMessage) @@ -606,24 +604,25 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N for _, item := range pduSessionResourceSetupListCxtReq.List { transfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } ngap_message.AppendPDUSessionResourceFailedToSetupListCxtfail( failedListCxtFail, item.PDUSessionID.Value, transfer) } - ngap_message.SendInitialContextSetupFailure(amf, n3iwfUe, *cause, failedListCxtFail, &criticalityDiagnostics) + ngap_message.SendInitialContextSetupFailure(ranUe, *cause, failedListCxtFail, &criticalityDiagnostics) return } setupListCxtRes := new(ngapType.PDUSessionResourceSetupListCxtRes) failedListCxtRes := new(ngapType.PDUSessionResourceFailedToSetupListCxtRes) + // UE temporary data for PDU session setup response - n3iwfUe.TemporaryPDUSessionSetupData = &context.PDUSessionSetupTemporaryData{ - SetupListCxtRes: setupListCxtRes, - FailedListCxtRes: failedListCxtRes, - } - n3iwfUe.TemporaryPDUSessionSetupData.NGAPProcedureCode.Value = ngapType.ProcedureCodeInitialContextSetup + ranUe.TemporaryPDUSessionSetupData.SetupListCxtRes = setupListCxtRes + ranUe.TemporaryPDUSessionSetupData.FailedListCxtRes = failedListCxtRes + ranUe.TemporaryPDUSessionSetupData.Index = 0 + ranUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession = nil + ranUe.TemporaryPDUSessionSetupData.NGAPProcedureCode.Value = ngapType.ProcedureCodeInitialContextSetup for _, item := range pduSessionResourceSetupListCxtReq.List { pduSessionID := item.PDUSessionID.Value @@ -634,73 +633,77 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N transfer := ngapType.PDUSessionResourceSetupRequestTransfer{} err := aper.UnmarshalWithParams(item.PDUSessionResourceSetupRequestTransfer, &transfer, "valueExt") if err != nil { - ngapLog.Errorf("[PDUSessionID: %d] PDUSessionResourceSetupRequestTransfer Decode Error: %+v\n", + logger.NgapLog.Errorf("[PDUSessionID: %d] PDUSessionResourceSetupRequestTransfer Decode Error: %+v\n", pduSessionID, err) } - pduSession, err := n3iwfUe.CreatePDUSession(pduSessionID, snssai) + pduSession, err := ranUe.CreatePDUSession(pduSessionID, snssai) if err != nil { - ngapLog.Errorf("Create PDU Session Error: %+v\n", err) + logger.NgapLog.Errorf("Create PDU Session Error: %+v\n", err) cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentMultiplePDUSessionIDInstances) - unsuccessfulTransfer, buildErr := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) + unsuccessfulTransfer, buildErr := ngap_message. + BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if buildErr != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", buildErr) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", buildErr) } ngap_message.AppendPDUSessionResourceFailedToSetupListCxtRes( failedListCxtRes, pduSessionID, unsuccessfulTransfer) continue } - success, resTransfer := handlePDUSessionResourceSetupRequestTransfer(n3iwfUe, pduSession, transfer) + success, resTransfer := handlePDUSessionResourceSetupRequestTransfer(ranUe, pduSession, transfer) if success { // Append this PDU session to unactivated PDU session list - n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession = append( - n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession, - pduSessionID) + ranUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession = append( + ranUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession, + pduSession) } else { // Delete the pdusession store in UE conext - delete(n3iwfUe.PduSessionList, pduSessionID) - ngap_message.AppendPDUSessionResourceFailedToSetupListCxtRes(failedListCxtRes, pduSessionID, resTransfer) + delete(ranUe.PduSessionList, pduSessionID) + ngap_message. + AppendPDUSessionResourceFailedToSetupListCxtRes(failedListCxtRes, pduSessionID, resTransfer) } } } if oldAMF != nil { - ngapLog.Debugf("Old AMF: %s\n", oldAMF.Value) + logger.NgapLog.Debugf("Old AMF: %s\n", oldAMF.Value) } if guami != nil { - n3iwfUe.Guami = guami + ranUe.Guami = guami } if allowedNSSAI != nil { - n3iwfUe.AllowedNssai = allowedNSSAI + ranUe.AllowedNssai = allowedNSSAI } if maskedIMEISV != nil { - n3iwfUe.MaskedIMEISV = maskedIMEISV + ranUe.MaskedIMEISV = maskedIMEISV } if ueRadioCapability != nil { - n3iwfUe.RadioCapability = ueRadioCapability + ranUe.RadioCapability = ueRadioCapability } if coreNetworkAssistanceInformation != nil { - n3iwfUe.CoreNetworkAssistanceInformation = coreNetworkAssistanceInformation + ranUe.CoreNetworkAssistanceInformation = coreNetworkAssistanceInformation } if indexToRFSP != nil { - n3iwfUe.IndexToRfsp = indexToRFSP.Value + ranUe.IndexToRfsp = indexToRFSP.Value } if ueSecurityCapabilities != nil { - n3iwfUe.SecurityCapabilities = ueSecurityCapabilities + ranUe.SecurityCapabilities = ueSecurityCapabilities } - if securityKey != nil { - n3iwfUe.Kn3iwf = securityKey.Value.Bytes + spi, ok := n3iwfSelf.IkeSpiLoad(ranUe.RanUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get spi from ngapid : %+v", ranUe.RanUeNgapId) + return } // if nasPDU != nil { @@ -708,37 +711,8 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N // } // Send EAP Success to UE - ikeSecurityAssociation := n3iwfUe.N3IWFIKESecurityAssociation - responseIKEMessage := new(ike_message.IKEMessage) - var responseIKEPayload ike_message.IKEPayloadContainer - - // Build IKE message - responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, - ikeSecurityAssociation.LocalSPI, ike_message.IKE_AUTH, ike_message.ResponseBitCheck, - ikeSecurityAssociation.InitiatorMessageID) - responseIKEMessage.Payloads.Reset() - - // EAP Success - var identifier uint8 - for { - identifier = uint8(rand.Uint32()) - if identifier != ikeSecurityAssociation.LastEAPIdentifier { - ikeSecurityAssociation.LastEAPIdentifier = identifier - break - } - } - responseIKEPayload.BuildEAPSuccess(identifier) - - if err := handler.EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ngapLog.Errorf("Encrypting IKE message failed: %+v", err) - return - } - - n3iwfUe.N3IWFIKESecurityAssociation.State++ - - // Send IKE message to UE - handler.SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, - n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) + n3iwfSelf.IKEServer.RcvEventCh <- context.NewSendEAPSuccessMsgEvt(spi, securityKey.Value.Bytes, + len(ranUe.PduSessionList)) } // handlePDUSessionResourceSetupRequestTransfer parse and store needed information from NGAP @@ -749,7 +723,7 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N // 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, +func handlePDUSessionResourceSetupRequestTransfer(ranUe *context.N3IWFRanUe, pduSession *context.PDUSession, transfer ngapType.PDUSessionResourceSetupRequestTransfer, ) (bool, []byte) { var pduSessionAMBR *ngapType.PDUSessionAggregateMaximumBitRate @@ -799,7 +773,7 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer( *cause, &criticalityDiagnostics) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } return false, responseTransfer } @@ -818,11 +792,11 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio case ngapType.IntegrityProtectionIndicationPresentRequired: pduSession.SecurityIntegrity = true default: - ngapLog.Error("Unknown security integrity indication") + logger.NgapLog.Error("Unknown security integrity indication") cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentSemanticError) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } return false, responseTransfer } @@ -835,11 +809,11 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio case ngapType.ConfidentialityProtectionIndicationPresentRequired: pduSession.SecurityCipher = true default: - ngapLog.Error("Unknown security confidentiality indication") + logger.NgapLog.Error("Unknown security confidentiality indication") cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentSemanticError) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } return false, responseTransfer } @@ -874,24 +848,26 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio // UPF UDP address upfUDPAddr, err := net.ResolveUDPAddr("udp", upfIPv4+":2152") if err != nil { - ngapLog.Errorf("Resolve UDP address failed: %+v", err) + logger.NgapLog.Errorf("Resolve UDP address failed: %+v", err) cause := ngap_message.BuildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } return false, responseTransfer } // UE TEID - ueTEID := n3iwfSelf.NewTEID(ue) + ueTEID := n3iwfSelf.NewTEID(ranUe) if ueTEID == 0 { - ngapLog.Error("Invalid TEID (0).") - cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified) + logger.NgapLog.Error("Invalid TEID (0).") + cause := ngap_message.BuildCause( + ngapType.CausePresentProtocol, + ngapType.CauseProtocolPresentUnspecified) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } return false, responseTransfer } @@ -904,24 +880,26 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio // Setup GTP connection with UPF userPlaneConnection, upfUDPAddr, err := gtp_service.SetupGTPTunnelWithUPF(upfIPv4) if err != nil { - ngapLog.Errorf("Setup GTP connection with UPF failed: %+v", err) + logger.NgapLog.Errorf("Setup GTP connection with UPF failed: %+v", err) cause := ngap_message.BuildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } return false, responseTransfer } // UE TEID - ueTEID := n3iwfSelf.NewTEID(ue) + ueTEID := n3iwfSelf.NewTEID(ranUe) if ueTEID == 0 { - ngapLog.Error("Invalid TEID (0).") - cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified) + logger.NgapLog.Error("Invalid TEID (0).") + cause := ngap_message.BuildCause( + ngapType.CausePresentProtocol, + ngapType.CauseProtocolPresentUnspecified) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } return false, responseTransfer } @@ -937,12 +915,13 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio pduSession.GTPConnection = gtpConnection } else { - ngapLog.Error("Cannot parse \"PDU session resource setup request transfer\" message \"UL NG-U UP TNL Information\"") + logger.NgapLog.Error( + "Cannot parse \"PDU session resource setup request transfer\" message \"UL NG-U UP TNL Information\"") cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) } return false, responseTransfer } @@ -951,10 +930,10 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio } func HandleUEContextModificationRequest(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle UE Context Modification Request") + logger.NgapLog.Infoln("[N3IWF] Handle UE Context Modification Request") if amf == nil { - ngapLog.Error("Corresponding AMF context not found") + logger.NgapLog.Error("Corresponding AMF context not found") return } @@ -967,66 +946,66 @@ func HandleUEContextModificationRequest(amf *context.N3IWFAMF, message *ngapType var indexToRFSP *ngapType.IndexToRFSP var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList - var n3iwfUe *context.N3IWFUe + var ranUe *context.N3IWFRanUe n3iwfSelf := context.N3IWFSelf() if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("Initiating Message is nil") + logger.NgapLog.Error("Initiating Message is nil") return } ueContextModificationRequest := initiatingMessage.Value.UEContextModificationRequest if ueContextModificationRequest == nil { - ngapLog.Error("UEContextModificationRequest is nil") + logger.NgapLog.Error("UEContextModificationRequest is nil") return } for _, ie := range ueContextModificationRequest.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") amfUeNgapID = ie.Value.AMFUENGAPID if amfUeNgapID == nil { - ngapLog.Errorf("AMFUENGAPID is nil") + logger.NgapLog.Errorf("AMFUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRANUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE RANUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE RANUENGAPID") ranUeNgapID = ie.Value.RANUENGAPID if ranUeNgapID == nil { - ngapLog.Errorf("RANUENGAPID is nil") + logger.NgapLog.Errorf("RANUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDSecurityKey: - ngapLog.Traceln("[NGAP] Decode IE SecurityKey") + logger.NgapLog.Traceln("[NGAP] Decode IE SecurityKey") securityKey = ie.Value.SecurityKey case ngapType.ProtocolIEIDIndexToRFSP: - ngapLog.Traceln("[NGAP] Decode IE IndexToRFSP") + logger.NgapLog.Traceln("[NGAP] Decode IE IndexToRFSP") indexToRFSP = ie.Value.IndexToRFSP case ngapType.ProtocolIEIDUEAggregateMaximumBitRate: - ngapLog.Traceln("[NGAP] Decode IE UEAggregateMaximumBitRate") + logger.NgapLog.Traceln("[NGAP] Decode IE UEAggregateMaximumBitRate") ueAggregateMaximumBitRate = ie.Value.UEAggregateMaximumBitRate case ngapType.ProtocolIEIDUESecurityCapabilities: - ngapLog.Traceln("[NGAP] Decode IE UESecurityCapabilities") + logger.NgapLog.Traceln("[NGAP] Decode IE UESecurityCapabilities") ueSecurityCapabilities = ie.Value.UESecurityCapabilities case ngapType.ProtocolIEIDCoreNetworkAssistanceInformation: - ngapLog.Traceln("[NGAP] Decode IE CoreNetworkAssistanceInformation") - ngapLog.Warnln("Not Supported IE [CoreNetworkAssistanceInformation]") + logger.NgapLog.Traceln("[NGAP] Decode IE CoreNetworkAssistanceInformation") + logger.NgapLog.Warnln("Not Supported IE [CoreNetworkAssistanceInformation]") case ngapType.ProtocolIEIDEmergencyFallbackIndicator: - ngapLog.Traceln("[NGAP] Decode IE EmergencyFallbackIndicator") - ngapLog.Warnln("Not Supported IE [EmergencyFallbackIndicator]") + logger.NgapLog.Traceln("[NGAP] Decode IE EmergencyFallbackIndicator") + logger.NgapLog.Warnln("Not Supported IE [EmergencyFallbackIndicator]") case ngapType.ProtocolIEIDNewAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE NewAMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE NewAMFUENGAPID") newAmfUeNgapID = ie.Value.NewAMFUENGAPID } } @@ -1039,14 +1018,14 @@ func HandleUEContextModificationRequest(amf *context.N3IWFAMF, message *ngapType if (amfUeNgapID != nil) && (ranUeNgapID != nil) { // Find UE context var ok bool - n3iwfUe, ok = n3iwfSelf.UePoolLoad(ranUeNgapID.Value) + ranUe, ok = n3iwfSelf.RanUePoolLoad(ranUeNgapID.Value) if !ok { - ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", ranUeNgapID.Value) + logger.NgapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", ranUeNgapID.Value) // TODO: build cause and handle error // Cause: Unknown local UE NGAP ID return } else { - if n3iwfUe.AmfUeNgapId != amfUeNgapID.Value { + if ranUe.AmfUeNgapId != amfUeNgapID.Value { // TODO: build cause and handle error // Cause: Inconsistent remote UE NGAP ID return @@ -1055,37 +1034,42 @@ func HandleUEContextModificationRequest(amf *context.N3IWFAMF, message *ngapType } if newAmfUeNgapID != nil { - ngapLog.Debugf("New AmfUeNgapID[%d]\n", newAmfUeNgapID.Value) - n3iwfUe.AmfUeNgapId = newAmfUeNgapID.Value + logger.NgapLog.Debugf("New AmfUeNgapID[%d]\n", newAmfUeNgapID.Value) + ranUe.AmfUeNgapId = newAmfUeNgapID.Value } if ueAggregateMaximumBitRate != nil { - n3iwfUe.Ambr = ueAggregateMaximumBitRate + ranUe.Ambr = ueAggregateMaximumBitRate // TODO: use the received UE Aggregate Maximum Bit Rate for all non-GBR QoS flows } if ueSecurityCapabilities != nil { - n3iwfUe.SecurityCapabilities = ueSecurityCapabilities - } - - if securityKey != nil { - n3iwfUe.Kn3iwf = securityKey.Value.Bytes + ranUe.SecurityCapabilities = ueSecurityCapabilities } // TODO: use new security key to update security context if indexToRFSP != nil { - n3iwfUe.IndexToRfsp = indexToRFSP.Value + ranUe.IndexToRfsp = indexToRFSP.Value + } + + ngap_message.SendUEContextModificationResponse(ranUe, nil) + + spi, ok := n3iwfSelf.IkeSpiLoad(ranUe.RanUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get spi from ngapid : %+v", ranUe.RanUeNgapId) + return } - ngap_message.SendUEContextModificationResponse(amf, n3iwfUe, nil) + n3iwfSelf.IKEServer.RcvEventCh <- context.NewIKEContextUpdateEvt(spi, + securityKey.Value.Bytes) // Kn3iwf } func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle UE Context Release Command") + logger.NgapLog.Infoln("[N3IWF] Handle UE Context Release Command") if amf == nil { - ngapLog.Error("Corresponding AMF context not found") + logger.NgapLog.Error("Corresponding AMF context not found") return } @@ -1093,39 +1077,39 @@ func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAP var cause *ngapType.Cause var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList - var n3iwfUe *context.N3IWFUe + var ranUe *context.N3IWFRanUe n3iwfSelf := context.N3IWFSelf() if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("Initiating Message is nil") + logger.NgapLog.Error("Initiating Message is nil") return } ueContextReleaseCommand := initiatingMessage.Value.UEContextReleaseCommand if ueContextReleaseCommand == nil { - ngapLog.Error("UEContextReleaseCommand is nil") + logger.NgapLog.Error("UEContextReleaseCommand is nil") return } for _, ie := range ueContextReleaseCommand.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDUENGAPIDs: - ngapLog.Traceln("[NGAP] Decode IE UENGAPIDs") + logger.NgapLog.Traceln("[NGAP] Decode IE UENGAPIDs") ueNgapIDs = ie.Value.UENGAPIDs if ueNgapIDs == nil { - ngapLog.Errorf("UENGAPIDs is nil") + logger.NgapLog.Errorf("UENGAPIDs is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDCause: - ngapLog.Traceln("[NGAP] Decode IE Cause") + logger.NgapLog.Traceln("[NGAP] Decode IE Cause") cause = ie.Value.Cause } } @@ -1138,19 +1122,19 @@ func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAP switch ueNgapIDs.Present { case ngapType.UENGAPIDsPresentUENGAPIDPair: var ok bool - n3iwfUe, ok = n3iwfSelf.UePoolLoad(ueNgapIDs.UENGAPIDPair.RANUENGAPID.Value) + ranUe, ok = n3iwfSelf.RanUePoolLoad(ueNgapIDs.UENGAPIDPair.RANUENGAPID.Value) if !ok { - n3iwfUe = amf.FindUeByAmfUeNgapID(ueNgapIDs.UENGAPIDPair.AMFUENGAPID.Value) + ranUe = amf.FindUeByAmfUeNgapID(ueNgapIDs.UENGAPIDPair.AMFUENGAPID.Value) } case ngapType.UENGAPIDsPresentAMFUENGAPID: // TODO: find UE according to specific AMF // The implementation here may have error when N3IWF need to // connect multiple AMFs. // Use UEpool in AMF context can solve this problem - n3iwfUe = amf.FindUeByAmfUeNgapID(ueNgapIDs.AMFUENGAPID.Value) + ranUe = amf.FindUeByAmfUeNgapID(ueNgapIDs.AMFUENGAPID.Value) } - if n3iwfUe == nil { + if ranUe == nil { // TODO: send error indication(unknown local ngap ue id) return } @@ -1159,8 +1143,13 @@ func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAP printAndGetCause(cause) } - handler.SendIKEDeleteRequest(n3iwfUe) + localSPI, ok := n3iwfSelf.IkeSpiLoad(ranUe.RanUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get SPI from RanUeNgapID : %+v", ranUe.RanUeNgapId) + return + } + n3iwfSelf.IKEServer.RcvEventCh <- context.NewIKEDeleteRequestEvt(localSPI) // TODO: release pdu session and gtp info for ue } @@ -1177,10 +1166,10 @@ func encapNasMsgToEnvelope(nasPDU *ngapType.NASPDU) []byte { } func HandleDownlinkNASTransport(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle Downlink NAS Transport") + logger.NgapLog.Infoln("[N3IWF] Handle Downlink NAS Transport") if amf == nil { - ngapLog.Error("Corresponding AMF context not found") + logger.NgapLog.Error("Corresponding AMF context not found") return } @@ -1193,66 +1182,66 @@ func HandleDownlinkNASTransport(amf *context.N3IWFAMF, message *ngapType.NGAPPDU var allowedNSSAI *ngapType.AllowedNSSAI var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList - var n3iwfUe *context.N3IWFUe + var ranUe *context.N3IWFRanUe var n3iwfSelf *context.N3IWFContext = context.N3IWFSelf() if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("Initiating Message is nil") + logger.NgapLog.Error("Initiating Message is nil") return } downlinkNASTransport := initiatingMessage.Value.DownlinkNASTransport if downlinkNASTransport == nil { - ngapLog.Error("DownlinkNASTransport is nil") + logger.NgapLog.Error("DownlinkNASTransport is nil") return } for _, ie := range downlinkNASTransport.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") amfUeNgapID = ie.Value.AMFUENGAPID if amfUeNgapID == nil { - ngapLog.Errorf("AMFUENGAPID is nil") + logger.NgapLog.Errorf("AMFUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRANUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE RANUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE RANUENGAPID") ranUeNgapID = ie.Value.RANUENGAPID if ranUeNgapID == nil { - ngapLog.Errorf("RANUENGAPID is nil") + logger.NgapLog.Errorf("RANUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDOldAMF: - ngapLog.Traceln("[NGAP] Decode IE OldAMF") + logger.NgapLog.Traceln("[NGAP] Decode IE OldAMF") oldAMF = ie.Value.OldAMF case ngapType.ProtocolIEIDNASPDU: - ngapLog.Traceln("[NGAP] Decode IE NASPDU") + logger.NgapLog.Traceln("[NGAP] Decode IE NASPDU") nasPDU = ie.Value.NASPDU if nasPDU == nil { - ngapLog.Errorf("NASPDU is nil") + logger.NgapLog.Errorf("NASPDU is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDIndexToRFSP: - ngapLog.Traceln("[NGAP] Decode IE IndexToRFSP") + logger.NgapLog.Traceln("[NGAP] Decode IE IndexToRFSP") indexToRFSP = ie.Value.IndexToRFSP case ngapType.ProtocolIEIDUEAggregateMaximumBitRate: - ngapLog.Traceln("[NGAP] Decode IE UEAggregateMaximumBitRate") + logger.NgapLog.Traceln("[NGAP] Decode IE UEAggregateMaximumBitRate") ueAggregateMaximumBitRate = ie.Value.UEAggregateMaximumBitRate case ngapType.ProtocolIEIDAllowedNSSAI: - ngapLog.Traceln("[NGAP] Decode IE AllowedNSSAI") + logger.NgapLog.Traceln("[NGAP] Decode IE AllowedNSSAI") allowedNSSAI = ie.Value.AllowedNSSAI } } @@ -1263,115 +1252,79 @@ func HandleDownlinkNASTransport(amf *context.N3IWFAMF, message *ngapType.NGAPPDU if ranUeNgapID != nil { var ok bool - n3iwfUe, ok = n3iwfSelf.UePoolLoad(ranUeNgapID.Value) + ranUe, ok = n3iwfSelf.RanUePoolLoad(ranUeNgapID.Value) if !ok { - ngapLog.Warnf("No UE Context[RanUeNgapID:%d]\n", ranUeNgapID.Value) + logger.NgapLog.Warnf("No UE Context[RanUeNgapID:%d]\n", ranUeNgapID.Value) return } } if amfUeNgapID != nil { - if n3iwfUe.AmfUeNgapId == context.AmfUeNgapIdUnspecified { - ngapLog.Tracef("Create new logical UE-associated NG-connection") - n3iwfUe.AmfUeNgapId = amfUeNgapID.Value + if ranUe.AmfUeNgapId == context.AmfUeNgapIdUnspecified { + logger.NgapLog.Tracef("Create new logical UE-associated NG-connection") + ranUe.AmfUeNgapId = amfUeNgapID.Value } else { - if n3iwfUe.AmfUeNgapId != amfUeNgapID.Value { - ngapLog.Warn("AMFUENGAPID unmatched") + if ranUe.AmfUeNgapId != amfUeNgapID.Value { + logger.NgapLog.Warn("AMFUENGAPID unmatched") return } } } if oldAMF != nil { - ngapLog.Debugf("Old AMF: %s\n", oldAMF.Value) + logger.NgapLog.Debugf("Old AMF: %s\n", oldAMF.Value) } if indexToRFSP != nil { - n3iwfUe.IndexToRfsp = indexToRFSP.Value + ranUe.IndexToRfsp = indexToRFSP.Value } if ueAggregateMaximumBitRate != nil { - n3iwfUe.Ambr = ueAggregateMaximumBitRate + ranUe.Ambr = ueAggregateMaximumBitRate } if allowedNSSAI != nil { - n3iwfUe.AllowedNssai = allowedNSSAI + ranUe.AllowedNssai = allowedNSSAI } if nasPDU != nil { // TODO: Send NAS PDU to UE - if !n3iwfUe.SignallingIPsecSAEstablished { - var identifier uint8 - ikeSecurityAssociation := n3iwfUe.N3IWFIKESecurityAssociation - - for { - identifier = uint8(rand.Uint32()) - if identifier != n3iwfUe.N3IWFIKESecurityAssociation.LastEAPIdentifier { - n3iwfUe.N3IWFIKESecurityAssociation.LastEAPIdentifier = identifier - break - } - } - // Send NAS via IKE EAP - responseIKEMessage := new(ike_message.IKEMessage) - var responseIKEPayload ike_message.IKEPayloadContainer - - // Build IKE message - responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, - ikeSecurityAssociation.LocalSPI, ike_message.IKE_AUTH, ike_message.ResponseBitCheck, - ikeSecurityAssociation.InitiatorMessageID) - responseIKEMessage.Payloads.Reset() - // EAP-5G - responseIKEPayload.BuildEAP5GNAS(identifier, nasPDU.Value) - - if err := handler.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ngapLog.Errorf("[NGAP] Encrypting IKE message failed: %+v", err) - return - } + // Send EAP5G NAS to UE + spi, ok := n3iwfSelf.IkeSpiLoad(ranUe.RanUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get SPI from RanUeNGAPId : %+v", ranUe.RanUeNgapId) + return + } - // Send IKE message to UE - handler.SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, - n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) + if !ranUe.IsNASTCPConnEstablished { + n3iwfSelf.IKEServer.RcvEventCh <- context.NewSendEAPNASMsgEvt(spi, + []byte(nasPDU.Value)) } else { // Using a "NAS message envelope" to transport a NAS message // over the non-3GPP access between the UE and the N3IWF nasEnv := encapNasMsgToEnvelope(nasPDU) - // Check ue.TCPConnection. If failed, retry 2 times. - maxRetryTimes := 3 - for i := 0; i < maxRetryTimes; i++ { - if n3iwfUe.TCPConnection == nil { - if i == (maxRetryTimes - 1) { - ngapLog.Warn( - "No connection found for UE to send NAS message. This message will be cached in N3IWF") - n3iwfUe.TemporaryCachedNASMessage = nasEnv - return - } else { - ngapLog.Warn("No NAS signalling session found, retry...") - } - time.Sleep(500 * time.Millisecond) + if ranUe.IsNASTCPConnEstablishedComplete { + // Send to UE + if n, err := ranUe.TCPConnection.Write(nasEnv); err != nil { + logger.NgapLog.Errorf("Writing via IPSec signalling SA failed: %+v", err) } else { - break + logger.NgapLog.Trace("Forward NWu <- N2") + logger.NgapLog.Tracef("Wrote %d bytes", n) } - } - - // Send to UE - if n, err := n3iwfUe.TCPConnection.Write(nasEnv); err != nil { - ngapLog.Errorf("Writing via IPSec signalling SA failed: %+v", err) } else { - ngapLog.Trace("Forward NWu <- N2") - ngapLog.Tracef("Wrote %d bytes", n) + ranUe.TemporaryCachedNASMessage = nasEnv } } } } func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle PDU Session Resource Setup Request") + logger.NgapLog.Infoln("[N3IWF] Handle PDU Session Resource Setup Request") if amf == nil { - ngapLog.Error("Corresponding AMF context not found") + logger.NgapLog.Error("Corresponding AMF context not found") return } @@ -1382,54 +1335,54 @@ func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapTy var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList var pduSessionEstablishmentAccept *ngapType.NASPDU - var n3iwfUe *context.N3IWFUe + var ranUe *context.N3IWFRanUe n3iwfSelf := context.N3IWFSelf() if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("Initiating Message is nil") + logger.NgapLog.Error("Initiating Message is nil") return } pduSessionResourceSetupRequest := initiatingMessage.Value.PDUSessionResourceSetupRequest if pduSessionResourceSetupRequest == nil { - ngapLog.Error("PDUSessionResourceSetupRequest is nil") + logger.NgapLog.Error("PDUSessionResourceSetupRequest is nil") return } for _, ie := range pduSessionResourceSetupRequest.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") amfUeNgapID = ie.Value.AMFUENGAPID if amfUeNgapID == nil { - ngapLog.Errorf("AMFUENGAPID is nil") + logger.NgapLog.Errorf("AMFUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRANUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE RANUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE RANUENGAPID") ranUeNgapID = ie.Value.RANUENGAPID if ranUeNgapID == nil { - ngapLog.Errorf("RANUENGAPID is nil") + logger.NgapLog.Errorf("RANUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDNASPDU: - ngapLog.Traceln("[NGAP] Decode IE NASPDU") + logger.NgapLog.Traceln("[NGAP] Decode IE NASPDU") nasPDU = ie.Value.NASPDU case ngapType.ProtocolIEIDPDUSessionResourceSetupListSUReq: - ngapLog.Traceln("[NGAP] Decode IE PDUSessionResourceSetupRequestList") + logger.NgapLog.Traceln("[NGAP] Decode IE PDUSessionResourceSetupRequestList") pduSessionResourceSetupListSUReq = ie.Value.PDUSessionResourceSetupListSUReq if pduSessionResourceSetupListSUReq == nil { - ngapLog.Errorf("PDUSessionResourceSetupRequestList is nil") + logger.NgapLog.Errorf("PDUSessionResourceSetupRequestList is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) @@ -1439,21 +1392,21 @@ func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapTy if len(iesCriticalityDiagnostics.List) > 0 { // TODO: Send error indication to AMF - ngapLog.Errorln("Sending error indication to AMF") + logger.NgapLog.Errorln("Sending error indication to AMF") return } if (amfUeNgapID != nil) && (ranUeNgapID != nil) { // Find UE context var ok bool - n3iwfUe, ok = n3iwfSelf.UePoolLoad(ranUeNgapID.Value) + ranUe, ok = n3iwfSelf.RanUePoolLoad(ranUeNgapID.Value) if !ok { - ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", ranUeNgapID.Value) + logger.NgapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", ranUeNgapID.Value) // TODO: build cause and handle error // Cause: Unknown local UE NGAP ID return } else { - if n3iwfUe.AmfUeNgapId != amfUeNgapID.Value { + if ranUe.AmfUeNgapId != amfUeNgapID.Value { // TODO: build cause and handle error // Cause: Inconsistent remote UE NGAP ID return @@ -1463,32 +1416,35 @@ func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapTy if nasPDU != nil { // TODO: Send NAS to UE - if n3iwfUe.TCPConnection == nil { - ngapLog.Error("No IPSec NAS signalling SA for this UE") + if ranUe.TCPConnection == nil { + logger.NgapLog.Error("No IPSec NAS signalling SA for this UE") return } else { // Using a "NAS message envelope" to transport a NAS message // over the non-3GPP access between the UE and the N3IWF nasEnv := encapNasMsgToEnvelope(nasPDU) - if n, err := n3iwfUe.TCPConnection.Write(nasEnv); err != nil { - ngapLog.Errorf("Send NAS to UE failed: %+v", err) + if n, err := ranUe.TCPConnection.Write(nasEnv); err != nil { + logger.NgapLog.Errorf("Send NAS to UE failed: %+v", err) return } else { - ngapLog.Tracef("Wrote %d bytes", n) + logger.NgapLog.Tracef("Wrote %d bytes", n) } } } + tempPDUSessionSetupData := ranUe.TemporaryPDUSessionSetupData + tempPDUSessionSetupData.NGAPProcedureCode.Value = ngapType.ProcedureCodeInitialContextSetup + if pduSessionResourceSetupListSUReq != nil { setupListSURes := new(ngapType.PDUSessionResourceSetupListSURes) failedListSURes := new(ngapType.PDUSessionResourceFailedToSetupListSURes) - // UE temporary data for PDU session setup response - n3iwfUe.TemporaryPDUSessionSetupData = &context.PDUSessionSetupTemporaryData{ - SetupListSURes: setupListSURes, - FailedListSURes: failedListSURes, - } - n3iwfUe.TemporaryPDUSessionSetupData.NGAPProcedureCode.Value = ngapType.ProcedureCodePDUSessionResourceSetup + + tempPDUSessionSetupData.SetupListSURes = setupListSURes + tempPDUSessionSetupData.FailedListSURes = failedListSURes + tempPDUSessionSetupData.Index = 0 + tempPDUSessionSetupData.UnactivatedPDUSession = nil + tempPDUSessionSetupData.NGAPProcedureCode.Value = ngapType.ProcedureCodePDUSessionResourceSetup for _, item := range pduSessionResourceSetupListSUReq.List { pduSessionID := item.PDUSessionID.Value @@ -1498,154 +1454,50 @@ func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapTy transfer := ngapType.PDUSessionResourceSetupRequestTransfer{} err := aper.UnmarshalWithParams(item.PDUSessionResourceSetupRequestTransfer, &transfer, "valueExt") if err != nil { - ngapLog.Errorf("[PDUSessionID: %d] PDUSessionResourceSetupRequestTransfer Decode Error: %+v\n", + logger.NgapLog.Errorf("[PDUSessionID: %d] PDUSessionResourceSetupRequestTransfer Decode Error: %+v\n", pduSessionID, err) } - pduSession, err := n3iwfUe.CreatePDUSession(pduSessionID, snssai) + pduSession, err := ranUe.CreatePDUSession(pduSessionID, snssai) if err != nil { - ngapLog.Errorf("Create PDU Session Error: %+v\n", err) + logger.NgapLog.Errorf("Create PDU Session Error: %+v\n", err) cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentMultiplePDUSessionIDInstances) - unsuccessfulTransfer, buildErr := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) + unsuccessfulTransfer, buildErr := ngap_message. + BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if buildErr != nil { - ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", buildErr) + logger.NgapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", buildErr) } - ngap_message.AppendPDUSessionResourceFailedToSetupListSURes(failedListSURes, pduSessionID, unsuccessfulTransfer) + ngap_message.AppendPDUSessionResourceFailedToSetupListSURes( + failedListSURes, pduSessionID, unsuccessfulTransfer) continue } - success, resTransfer := handlePDUSessionResourceSetupRequestTransfer(n3iwfUe, pduSession, transfer) + success, resTransfer := handlePDUSessionResourceSetupRequestTransfer( + ranUe, pduSession, transfer) if success { // Append this PDU session to unactivated PDU session list - n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession = append( - n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession, - pduSessionID) + tempPDUSessionSetupData.UnactivatedPDUSession = append( + tempPDUSessionSetupData.UnactivatedPDUSession, + pduSession) } else { // Delete the pdusession store in UE conext - delete(n3iwfUe.PduSessionList, pduSessionID) - ngap_message.AppendPDUSessionResourceFailedToSetupListSURes(failedListSURes, pduSessionID, resTransfer) + delete(ranUe.PduSessionList, pduSessionID) + ngap_message.AppendPDUSessionResourceFailedToSetupListSURes( + failedListSURes, pduSessionID, resTransfer) } } } - if n3iwfUe.TemporaryPDUSessionSetupData != nil { - for { - if len(n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession) != 0 { - pduSessionID := n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession[0] - pduSession := n3iwfUe.PduSessionList[pduSessionID] - - ikeSecurityAssociation := n3iwfUe.N3IWFIKESecurityAssociation - - // Send CREATE_CHILD_SA to UE - ikeMessage := new(ike_message.IKEMessage) - var ikePayload ike_message.IKEPayloadContainer - - // Build IKE message - ikeMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, - ikeSecurityAssociation.LocalSPI, ike_message.CREATE_CHILD_SA, - 0, ikeSecurityAssociation.ResponderMessageID) - ikeMessage.Payloads.Reset() - // Add MessageID for IKE security association - ikeSecurityAssociation.ResponderMessageID++ - - // Build SA - requestSA := ikePayload.BuildSecurityAssociation() - - // Allocate SPI - var spi uint32 - spiByte := make([]byte, 4) - for { - randomUint64 := handler.GenerateRandomNumber().Uint64() - if _, ok := n3iwfSelf.ChildSA.Load(uint32(randomUint64)); !ok { - spi = uint32(randomUint64) - break - } - } - binary.BigEndian.PutUint32(spiByte, spi) - - // First Proposal - Proposal No.1 - proposal := requestSA.Proposals.BuildProposal(1, ike_message.TypeESP, spiByte) - - // Encryption transform - var attributeType uint16 = ike_message.AttributeTypeKeyLength - var attributeValue uint16 = 256 - proposal.EncryptionAlgorithm.BuildTransform( - ike_message.TypeEncryptionAlgorithm, ike_message.ENCR_AES_CBC, &attributeType, &attributeValue, nil) - // Integrity transform - if pduSession.SecurityIntegrity { - proposal.IntegrityAlgorithm.BuildTransform( - ike_message.TypeIntegrityAlgorithm, ike_message.AUTH_HMAC_SHA1_96, nil, nil, nil) - } - - // RFC 7296 - // Diffie-Hellman transform is optional in CREATE_CHILD_SA - // proposal.DiffieHellmanGroup.BuildTransform( - // ike_message.TypeDiffieHellmanGroup, ike_message.DH_1024_BIT_MODP, nil, nil, nil) - - // ESN transform - proposal.ExtendedSequenceNumbers.BuildTransform( - ike_message.TypeExtendedSequenceNumbers, ike_message.ESN_NO, nil, nil, nil) - - n3iwfUe.CreateHalfChildSA(ikeMessage.MessageID, spi, pduSessionID) - - // Build Nonce - nonceData := handler.GenerateRandomNumber().Bytes() - ikePayload.BuildNonce(nonceData) - - // Store nonce into context - ikeSecurityAssociation.ConcatenatedNonce = nonceData - - // TSi - n3iwfIPAddr := net.ParseIP(n3iwfSelf.IPSecGatewayAddress) - tsi := ikePayload.BuildTrafficSelectorInitiator() - tsi.TrafficSelectors.BuildIndividualTrafficSelector( - ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, - 0, 65535, n3iwfIPAddr.To4(), n3iwfIPAddr.To4()) - - // TSr - ueIPAddr := n3iwfUe.IPSecInnerIP - tsr := ikePayload.BuildTrafficSelectorResponder() - tsr.TrafficSelectors.BuildIndividualTrafficSelector( - ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, - 0, 65535, ueIPAddr.To4(), ueIPAddr.To4()) - - // Notify-Qos - ikePayload.BuildNotify5G_QOS_INFO(uint8(pduSessionID), pduSession.QFIList, true, false, 0) - - // Notify-UP_IP_ADDRESS - ikePayload.BuildNotifyUP_IP4_ADDRESS(n3iwfSelf.IPSecGatewayAddress) - - if err := handler.EncryptProcedure( - n3iwfUe.N3IWFIKESecurityAssociation, ikePayload, ikeMessage); err != nil { - ngapLog.Errorf("Encrypting IKE message failed: %+v", err) - n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession = n3iwfUe. - TemporaryPDUSessionSetupData.UnactivatedPDUSession[1:] - cause := ngap_message.BuildCause(ngapType.CausePresentTransport, - ngapType.CauseTransportPresentTransportResourceUnavailable) - transfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) - if err != nil { - ngapLog.Errorf("Build PDU Session Resource Setup Unsuccessful Transfer Failed: %+v", err) - continue - } - ngap_message.AppendPDUSessionResourceFailedToSetupListSURes( - n3iwfUe.TemporaryPDUSessionSetupData.FailedListSURes, - pduSessionID, transfer) - continue - } - - handler.SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, - n3iwfUe.IKEConnection.UEAddr, ikeMessage) - break - } else { - // Send PDU Session Resource Setup Response to AMF - ngap_message.SendPDUSessionResourceSetupResponse(amf, n3iwfUe, - n3iwfUe.TemporaryPDUSessionSetupData.SetupListSURes, - n3iwfUe.TemporaryPDUSessionSetupData.FailedListSURes, nil) - break - } + if tempPDUSessionSetupData != nil { + spi, ok := n3iwfSelf.IkeSpiLoad(ranUe.RanUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get SPI from ranNgapID : %+v", ranUeNgapID) + return } + n3iwfSelf.IKEServer.RcvEventCh <- context.NewCreatePDUSessionEvt(spi, + len(ranUe.PduSessionList), ranUe.TemporaryPDUSessionSetupData) // TS 23.501 4.12.5 Requested PDU Session Establishment via Untrusted non-3GPP Access // After all IPsec Child SAs are established, the N3IWF shall forward to UE via the signalling IPsec SA @@ -1653,15 +1505,15 @@ func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapTy nasEnv := encapNasMsgToEnvelope(pduSessionEstablishmentAccept) // Cache the pduSessionEstablishmentAccept and forward to the UE after all CREATE_CHILD_SAs finish - n3iwfUe.TemporaryCachedNASMessage = nasEnv + ranUe.TemporaryCachedNASMessage = nasEnv } } func HandlePDUSessionResourceModifyRequest(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle PDU Session Resource Modify Request") + logger.NgapLog.Infoln("[N3IWF] Handle PDU Session Resource Modify Request") if amf == nil { - ngapLog.Error("Corresponding AMF context not found") + logger.NgapLog.Error("Corresponding AMF context not found") return } @@ -1670,51 +1522,51 @@ func HandlePDUSessionResourceModifyRequest(amf *context.N3IWFAMF, message *ngapT var pduSessionResourceModifyListModReq *ngapType.PDUSessionResourceModifyListModReq var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList - var n3iwfUe *context.N3IWFUe + var ranUe *context.N3IWFRanUe n3iwfSelf := context.N3IWFSelf() if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("Initiating Message is nil") + logger.NgapLog.Error("Initiating Message is nil") return } pduSessionResourceModifyRequest := initiatingMessage.Value.PDUSessionResourceModifyRequest if pduSessionResourceModifyRequest == nil { - ngapLog.Error("PDUSessionResourceModifyRequest is nil") + logger.NgapLog.Error("PDUSessionResourceModifyRequest is nil") return } for _, ie := range pduSessionResourceModifyRequest.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") amfUeNgapID = ie.Value.AMFUENGAPID if amfUeNgapID == nil { - ngapLog.Error("AMFUENGAPID is nil") + logger.NgapLog.Error("AMFUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRANUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE RANUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE RANUENGAPID") ranUeNgapID = ie.Value.RANUENGAPID if ranUeNgapID == nil { - ngapLog.Error("RANUENGAPID is nil") + logger.NgapLog.Error("RANUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDPDUSessionResourceModifyListModReq: - ngapLog.Traceln("[NGAP] Decode IE PDUSessionResourceModifyListModReq") + logger.NgapLog.Traceln("[NGAP] Decode IE PDUSessionResourceModifyListModReq") pduSessionResourceModifyListModReq = ie.Value.PDUSessionResourceModifyListModReq if pduSessionResourceModifyListModReq == nil { - ngapLog.Error("PDUSessionResourceModifyListModReq is nil") + logger.NgapLog.Error("PDUSessionResourceModifyListModReq is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) @@ -1724,21 +1576,21 @@ func HandlePDUSessionResourceModifyRequest(amf *context.N3IWFAMF, message *ngapT if len(iesCriticalityDiagnostics.List) > 0 { criticalityDiagnostics := buildCriticalityDiagnostics(nil, nil, nil, &iesCriticalityDiagnostics) - ngap_message.SendPDUSessionResourceModifyResponse(amf, nil, nil, nil, &criticalityDiagnostics) + ngap_message.SendPDUSessionResourceModifyResponse(nil, nil, nil, &criticalityDiagnostics) return } if (amfUeNgapID != nil) && (ranUeNgapID != nil) { // Find UE context var ok bool - n3iwfUe, ok = n3iwfSelf.UePoolLoad(ranUeNgapID.Value) + ranUe, ok = n3iwfSelf.RanUePoolLoad(ranUeNgapID.Value) if !ok { - ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", ranUeNgapID.Value) + logger.NgapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", ranUeNgapID.Value) // TODO: build cause and send error indication // Cause: Unknown local UE NGAP ID return } else { - if n3iwfUe.AmfUeNgapId != amfUeNgapID.Value { + if ranUe.AmfUeNgapId != amfUeNgapID.Value { // TODO: build cause and send error indication // Cause: Inconsistent remote UE NGAP ID return @@ -1757,20 +1609,23 @@ func HandlePDUSessionResourceModifyRequest(amf *context.N3IWFAMF, message *ngapT transfer := ngapType.PDUSessionResourceModifyRequestTransfer{} err := aper.UnmarshalWithParams(item.PDUSessionResourceModifyRequestTransfer, transfer, "valueExt") if err != nil { - ngapLog.Errorf( - "[PDUSessionID: %d] PDUSessionResourceModifyRequestTransfer Decode Error: %+v\n", pduSessionID, err) + logger.NgapLog.Errorf( + "[PDUSessionID: %d] PDUSessionResourceModifyRequestTransfer Decode Error: %+v\n", + pduSessionID, err) } - if pduSession = n3iwfUe.FindPDUSession(pduSessionID); pduSession == nil { - ngapLog.Errorf("[PDUSessionID: %d] Unknown PDU session ID", pduSessionID) + if pduSession = ranUe.FindPDUSession(pduSessionID); pduSession == nil { + logger.NgapLog.Errorf("[PDUSessionID: %d] Unknown PDU session ID", pduSessionID) cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentUnknownPDUSessionID) - unsuccessfulTransfer, buildErr := ngap_message.BuildPDUSessionResourceModifyUnsuccessfulTransfer(*cause, nil) + unsuccessfulTransfer, buildErr := ngap_message. + BuildPDUSessionResourceModifyUnsuccessfulTransfer(*cause, nil) if buildErr != nil { - ngapLog.Errorf("Build PDUSessionResourceModifyUnsuccessfulTransfer Error: %+v\n", buildErr) + logger.NgapLog.Errorf("Build PDUSessionResourceModifyUnsuccessfulTransfer Error: %+v\n", buildErr) } - ngap_message.AppendPDUSessionResourceFailedToModifyListModRes(failedListModRes, pduSessionID, unsuccessfulTransfer) + ngap_message.AppendPDUSessionResourceFailedToModifyListModRes( + failedListModRes, pduSessionID, unsuccessfulTransfer) continue } @@ -1778,19 +1633,20 @@ func HandlePDUSessionResourceModifyRequest(amf *context.N3IWFAMF, message *ngapT if success { ngap_message.AppendPDUSessionResourceModifyListModRes(responseList, pduSessionID, resTransfer) } else { - ngap_message.AppendPDUSessionResourceFailedToModifyListModRes(failedListModRes, pduSessionID, resTransfer) + ngap_message.AppendPDUSessionResourceFailedToModifyListModRes( + failedListModRes, pduSessionID, resTransfer) } } } - ngap_message.SendPDUSessionResourceModifyResponse(amf, n3iwfUe, responseList, failedListModRes, nil) + ngap_message.SendPDUSessionResourceModifyResponse(ranUe, responseList, failedListModRes, nil) } func handlePDUSessionResourceModifyRequestTransfer( pduSession *context.PDUSession, transfer ngapType.PDUSessionResourceModifyRequestTransfer) ( success bool, responseTransfer []byte, ) { - ngapLog.Trace("[N3IWF] Handle PDU Session Resource Modify Request Transfer") + logger.NgapLog.Trace("[N3IWF] Handle PDU Session Resource Modify Request Transfer") var pduSessionAMBR *ngapType.PDUSessionAggregateMaximumBitRate var ulNGUUPTNLModifyList *ngapType.ULNGUUPTNLModifyList @@ -1810,40 +1666,40 @@ func handlePDUSessionResourceModifyRequestTransfer( for _, ie := range transfer.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDPDUSessionAggregateMaximumBitRate: - ngapLog.Traceln("[NGAP] Decode IE PDUSessionAggregateMaximumBitRate") + logger.NgapLog.Traceln("[NGAP] Decode IE PDUSessionAggregateMaximumBitRate") pduSessionAMBR = ie.Value.PDUSessionAggregateMaximumBitRate case ngapType.ProtocolIEIDULNGUUPTNLModifyList: - ngapLog.Traceln("[NGAP] Decode IE ULNGUUPTNLModifyList") + logger.NgapLog.Traceln("[NGAP] Decode IE ULNGUUPTNLModifyList") ulNGUUPTNLModifyList = ie.Value.ULNGUUPTNLModifyList if ulNGUUPTNLModifyList != nil && len(ulNGUUPTNLModifyList.List) == 0 { - ngapLog.Error("ULNGUUPTNLModifyList should have at least one element") + logger.NgapLog.Error("ULNGUUPTNLModifyList should have at least one element") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDNetworkInstance: - ngapLog.Traceln("[NGAP] Decode IE NetworkInstance") + logger.NgapLog.Traceln("[NGAP] Decode IE NetworkInstance") networkInstance = ie.Value.NetworkInstance case ngapType.ProtocolIEIDQosFlowAddOrModifyRequestList: - ngapLog.Traceln("[NGAP] Decode IE QosFLowAddOrModifyRequestList") + logger.NgapLog.Traceln("[NGAP] Decode IE QosFLowAddOrModifyRequestList") qosFlowAddOrModifyRequestList = ie.Value.QosFlowAddOrModifyRequestList if qosFlowAddOrModifyRequestList != nil && len(qosFlowAddOrModifyRequestList.List) == 0 { - ngapLog.Error("QosFlowAddOrModifyRequestList should have at least one element") + logger.NgapLog.Error("QosFlowAddOrModifyRequestList should have at least one element") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDQosFlowToReleaseList: - ngapLog.Traceln("[NGAP] Decode IE QosFlowToReleaseList") + logger.NgapLog.Traceln("[NGAP] Decode IE QosFlowToReleaseList") qosFlowToReleaseList = ie.Value.QosFlowToReleaseList if qosFlowToReleaseList != nil && len(qosFlowToReleaseList.List) == 0 { - ngapLog.Error("qosFlowToReleaseList should have at least one element") + logger.NgapLog.Error("qosFlowToReleaseList should have at least one element") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDAdditionalULNGUUPTNLInformation: - ngapLog.Traceln("[NGAP] Decode IE AdditionalULNGUUPTNLInformation") + logger.NgapLog.Traceln("[NGAP] Decode IE AdditionalULNGUUPTNLInformation") // additionalULNGUUPTNLInformation = ie.Value.AdditionalULNGUUPTNLInformation } } @@ -1856,7 +1712,7 @@ func handlePDUSessionResourceModifyRequestTransfer( unsuccessfulTransfer, err := ngap_message.BuildPDUSessionResourceModifyUnsuccessfulTransfer( *cause, &criticalityDiagnostics) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceModifyUnsuccessfulTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceModifyUnsuccessfulTransfer Error: %+v\n", err) } responseTransfer = unsuccessfulTransfer @@ -1868,7 +1724,7 @@ func handlePDUSessionResourceModifyRequestTransfer( // TODO: update GTP tunnel - ngapLog.Info("Update uplink NG-U user plane tunnel information") + logger.NgapLog.Info("Update uplink NG-U user plane tunnel information") resULNGUUPTNLInfo = &updateItem.ULNGUUPTNLInformation resDLNGUUPTNLInfo = &updateItem.DLNGUUPTNLInformation @@ -1878,7 +1734,7 @@ func handlePDUSessionResourceModifyRequestTransfer( for _, updateItem := range qosFlowAddOrModifyRequestList.List { target, ok := pduSession.QosFlows[updateItem.QosFlowIdentifier.Value] if ok { - ngapLog.Trace("Update qos flow level qos parameters") + logger.NgapLog.Trace("Update qos flow level qos parameters") target.Parameters = *updateItem.QosFlowLevelQosParameters @@ -1888,7 +1744,7 @@ func handlePDUSessionResourceModifyRequestTransfer( resQosFlowAddOrModifyRequestList.List = append(resQosFlowAddOrModifyRequestList.List, item) } else { - ngapLog.Errorf("Requested Qos flow not found, QosFlowID: %d", updateItem.QosFlowIdentifier) + logger.NgapLog.Errorf("Requested Qos flow not found, QosFlowID: %d", updateItem.QosFlowIdentifier) cause := ngap_message.BuildCause( ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentUnkownQosFlowID) @@ -1904,13 +1760,13 @@ func handlePDUSessionResourceModifyRequestTransfer( } if pduSessionAMBR != nil { - ngapLog.Trace("Store PDU session AMBR") + logger.NgapLog.Trace("Store PDU session AMBR") pduSession.Ambr = pduSessionAMBR } if networkInstance != nil { // Used to select transport layer resource - ngapLog.Trace("Store network instance") + logger.NgapLog.Trace("Store network instance") pduSession.NetworkInstance = networkInstance } @@ -1918,7 +1774,7 @@ func handlePDUSessionResourceModifyRequestTransfer( for _, releaseItem := range qosFlowToReleaseList.List { _, ok := pduSession.QosFlows[releaseItem.QosFlowIdentifier.Value] if ok { - ngapLog.Tracef("Delete QosFlow. ID: %d", releaseItem.QosFlowIdentifier.Value) + logger.NgapLog.Tracef("Delete QosFlow. ID: %d", releaseItem.QosFlowIdentifier.Value) printAndGetCause(&releaseItem.Cause) delete(pduSession.QosFlows, releaseItem.QosFlowIdentifier.Value) } @@ -1932,7 +1788,7 @@ func handlePDUSessionResourceModifyRequestTransfer( encodeData, err := ngap_message.BuildPDUSessionResourceModifyResponseTransfer( resULNGUUPTNLInfo, resDLNGUUPTNLInfo, &resQosFlowAddOrModifyRequestList, &resQosFlowFailedToAddOrModifyList) if err != nil { - ngapLog.Errorf("Build PDUSessionResourceModifyTransfer Error: %+v\n", err) + logger.NgapLog.Errorf("Build PDUSessionResourceModifyTransfer Error: %+v\n", err) } success = true @@ -1942,7 +1798,7 @@ func handlePDUSessionResourceModifyRequestTransfer( } func HandlePDUSessionResourceModifyConfirm(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle PDU Session Resource Modify Confirm") + logger.NgapLog.Infoln("[N3IWF] Handle PDU Session Resource Modify Confirm") var aMFUENGAPID *ngapType.AMFUENGAPID var rANUENGAPID *ngapType.RANUENGAPID @@ -1953,94 +1809,97 @@ func HandlePDUSessionResourceModifyConfirm(amf *context.N3IWFAMF, message *ngapT // var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } successfulOutcome := message.SuccessfulOutcome if successfulOutcome == nil { - ngapLog.Error("Successful Outcome is nil") + logger.NgapLog.Error("Successful Outcome is nil") return } pDUSessionResourceModifyConfirm := successfulOutcome.Value.PDUSessionResourceModifyConfirm if pDUSessionResourceModifyConfirm == nil { - ngapLog.Error("pDUSessionResourceModifyConfirm is nil") + logger.NgapLog.Error("pDUSessionResourceModifyConfirm is nil") return } for _, ie := range pDUSessionResourceModifyConfirm.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") aMFUENGAPID = ie.Value.AMFUENGAPID case ngapType.ProtocolIEIDRANUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE RANUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE RANUENGAPID") rANUENGAPID = ie.Value.RANUENGAPID case ngapType.ProtocolIEIDPDUSessionResourceModifyListModCfm: - ngapLog.Traceln("[NGAP] Decode IE PDUSessionResourceModifyListModCfm") + logger.NgapLog.Traceln("[NGAP] Decode IE PDUSessionResourceModifyListModCfm") pDUSessionResourceModifyListModCfm = ie.Value.PDUSessionResourceModifyListModCfm case ngapType.ProtocolIEIDPDUSessionResourceFailedToModifyListModCfm: - ngapLog.Traceln("[NGAP] Decode IE PDUSessionResourceFailedToModifyListModCfm") + logger.NgapLog.Traceln("[NGAP] Decode IE PDUSessionResourceFailedToModifyListModCfm") pDUSessionResourceFailedToModifyListModCfm = ie.Value.PDUSessionResourceFailedToModifyListModCfm case ngapType.ProtocolIEIDCriticalityDiagnostics: - ngapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") + logger.NgapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") criticalityDiagnostics = ie.Value.CriticalityDiagnostics } } - var ue *context.N3IWFUe + var ranUe *context.N3IWFRanUe n3iwfSelf := context.N3IWFSelf() if rANUENGAPID != nil { var ok bool - ue, ok = n3iwfSelf.UePoolLoad(rANUENGAPID.Value) + ranUe, ok = n3iwfSelf.RanUePoolLoad(rANUENGAPID.Value) if !ok { - ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) + logger.NgapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) return } } if aMFUENGAPID != nil { - if ue != nil { - if ue.AmfUeNgapId != aMFUENGAPID.Value { - ngapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, ue.AmfUeNgapId: %d", - aMFUENGAPID.Value, ue.AmfUeNgapId) + if ranUe != nil { + if ranUe.AmfUeNgapId != aMFUENGAPID.Value { + logger.NgapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, RanUe.AmfUeNgapId: %d", + aMFUENGAPID.Value, ranUe.AmfUeNgapId) return } } else { - ue = amf.FindUeByAmfUeNgapID(aMFUENGAPID.Value) - if ue == nil { - ngapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, ue.AmfUeNgapId: %d", - aMFUENGAPID.Value, ue.AmfUeNgapId) + ranUe = amf.FindUeByAmfUeNgapID(aMFUENGAPID.Value) + if ranUe == nil { + logger.NgapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, RanUe.AmfUeNgapId: %d", + aMFUENGAPID.Value, ranUe.AmfUeNgapId) return } } } - if ue == nil { - ngapLog.Warn("RANUENGAPID and AMFUENGAPID are both nil") + if ranUe == nil { + logger.NgapLog.Warn("RANUENGAPID and AMFUENGAPID are both nil") return } if pDUSessionResourceModifyListModCfm != nil { for _, item := range pDUSessionResourceModifyListModCfm.List { pduSessionId := item.PDUSessionID.Value - ngapLog.Tracef("PDU Session Id[%d] in Pdu Session Resource Modification Confrim List", pduSessionId) - sess, exist := ue.PduSessionList[pduSessionId] + logger.NgapLog.Tracef("PDU Session Id[%d] in Pdu Session Resource Modification Confrim List", pduSessionId) + sess, exist := ranUe.PduSessionList[pduSessionId] if !exist { - ngapLog.Warnf("PDU Session Id[%d] is not exist in Ue[ranUeNgapId:%d]", pduSessionId, ue.RanUeNgapId) + logger.NgapLog.Warnf( + "PDU Session Id[%d] is not exist in Ue[ranUeNgapId:%d]", pduSessionId, ranUe.RanUeNgapId) } else { transfer := ngapType.PDUSessionResourceModifyConfirmTransfer{} err := aper.UnmarshalWithParams(item.PDUSessionResourceModifyConfirmTransfer, &transfer, "valueExt") if err != nil { - ngapLog.Warnf("[PDUSessionID: %d] PDUSessionResourceSetupRequestTransfer Decode Error: %+v\n", + logger.NgapLog.Warnf( + "[PDUSessionID: %d] PDUSessionResourceSetupRequestTransfer Decode Error: %+v\n", pduSessionId, err) } else if transfer.QosFlowFailedToModifyList != nil { for _, flow := range transfer.QosFlowFailedToModifyList.List { - ngapLog.Warnf("Delete QFI[%d] due to Qos Flow Failure in Pdu Session Resource Modification Confrim List", + logger.NgapLog.Warnf( + "Delete QFI[%d] due to Qos Flow Failure in Pdu Session Resource Modification Confrim List", flow.QosFlowIdentifier.Value) delete(sess.QosFlows, flow.QosFlowIdentifier.Value) } @@ -2052,15 +1911,18 @@ func HandlePDUSessionResourceModifyConfirm(amf *context.N3IWFAMF, message *ngapT for _, item := range pDUSessionResourceFailedToModifyListModCfm.List { pduSessionId := item.PDUSessionID.Value transfer := ngapType.PDUSessionResourceModifyIndicationUnsuccessfulTransfer{} - err := aper.UnmarshalWithParams(item.PDUSessionResourceModifyIndicationUnsuccessfulTransfer, &transfer, "valueExt") + err := aper.UnmarshalWithParams( + item.PDUSessionResourceModifyIndicationUnsuccessfulTransfer, &transfer, "valueExt") if err != nil { - ngapLog.Warnf("[PDUSessionID: %d] PDUSessionResourceModifyIndicationUnsuccessfulTransfer Decode Error: %+v\n", + logger.NgapLog.Warnf( + "[PDUSessionID: %d] PDUSessionResourceModifyIndicationUnsuccessfulTransfer Decode Error: %+v\n", pduSessionId, err) } else { printAndGetCause(&transfer.Cause) } - ngapLog.Tracef("Release PDU Session Id[%d] due to PDU Session Resource Modify Indication Unsuccessful", pduSessionId) - delete(ue.PduSessionList, pduSessionId) + logger.NgapLog.Tracef( + "Release PDU Session Id[%d] due to PDU Session Resource Modify Indication Unsuccessful", pduSessionId) + delete(ranUe.PduSessionList, pduSessionId) } } @@ -2070,7 +1932,7 @@ func HandlePDUSessionResourceModifyConfirm(amf *context.N3IWFAMF, message *ngapT } func HandlePDUSessionResourceReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle PDU Session Resource Release Command") + logger.NgapLog.Infoln("[N3IWF] Handle PDU Session Resource Release Command") var aMFUENGAPID *ngapType.AMFUENGAPID var rANUENGAPID *ngapType.RANUENGAPID // var rANPagingPriority *ngapType.RANPagingPriority @@ -2080,58 +1942,58 @@ func HandlePDUSessionResourceReleaseCommand(amf *context.N3IWFAMF, message *ngap var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("Initiating Message is nil") + logger.NgapLog.Error("Initiating Message is nil") return } pDUSessionResourceReleaseCommand := initiatingMessage.Value.PDUSessionResourceReleaseCommand if pDUSessionResourceReleaseCommand == nil { - ngapLog.Error("pDUSessionResourceReleaseCommand is nil") + logger.NgapLog.Error("pDUSessionResourceReleaseCommand is nil") return } for _, ie := range pDUSessionResourceReleaseCommand.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") aMFUENGAPID = ie.Value.AMFUENGAPID if aMFUENGAPID == nil { - ngapLog.Error("AMFUENGAPID is nil") + logger.NgapLog.Error("AMFUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRANUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE RANUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE RANUENGAPID") rANUENGAPID = ie.Value.RANUENGAPID if rANUENGAPID == nil { - ngapLog.Error("RANUENGAPID is nil") + logger.NgapLog.Error("RANUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRANPagingPriority: - ngapLog.Traceln("[NGAP] Decode IE RANPagingPriority") + logger.NgapLog.Traceln("[NGAP] Decode IE RANPagingPriority") // rANPagingPriority = ie.Value.RANPagingPriority case ngapType.ProtocolIEIDNASPDU: - ngapLog.Traceln("[NGAP] Decode IE NASPDU") + logger.NgapLog.Traceln("[NGAP] Decode IE NASPDU") // nASPDU = ie.Value.NASPDU case ngapType.ProtocolIEIDPDUSessionResourceToReleaseListRelCmd: - ngapLog.Traceln("[NGAP] Decode IE PDUSessionResourceToReleaseListRelCmd") + logger.NgapLog.Traceln("[NGAP] Decode IE PDUSessionResourceToReleaseListRelCmd") pDUSessionResourceToReleaseListRelCmd = ie.Value.PDUSessionResourceToReleaseListRelCmd if pDUSessionResourceToReleaseListRelCmd == nil { - ngapLog.Error("PDUSessionResourceToReleaseListRelCmd is nil") + logger.NgapLog.Error("PDUSessionResourceToReleaseListRelCmd is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) @@ -2150,18 +2012,18 @@ func HandlePDUSessionResourceReleaseCommand(amf *context.N3IWFAMF, message *ngap } n3iwfSelf := context.N3IWFSelf() - ue, ok := n3iwfSelf.UePoolLoad(rANUENGAPID.Value) + ranUe, ok := n3iwfSelf.RanUePoolLoad(rANUENGAPID.Value) if !ok { - ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) + logger.NgapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentUnknownLocalUENGAPID) ngap_message.SendErrorIndication(amf, nil, nil, cause, nil) return } - if ue.AmfUeNgapId != aMFUENGAPID.Value { - ngapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, ue.AmfUeNgapId: %d", - aMFUENGAPID.Value, ue.AmfUeNgapId) + if ranUe.AmfUeNgapId != aMFUENGAPID.Value { + logger.NgapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, RanUe.AmfUeNgapId: %d", + aMFUENGAPID.Value, ranUe.AmfUeNgapId) cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentInconsistentRemoteUENGAPID) ngap_message.SendErrorIndication(amf, nil, &rANUENGAPID.Value, cause, nil) @@ -2173,17 +2035,20 @@ func HandlePDUSessionResourceReleaseCommand(amf *context.N3IWFAMF, message *ngap // } releaseList := ngapType.PDUSessionResourceReleasedListRelRes{} + var releaseIdList []int64 for _, item := range pDUSessionResourceToReleaseListRelCmd.List { pduSessionId := item.PDUSessionID.Value transfer := ngapType.PDUSessionResourceReleaseCommandTransfer{} err := aper.UnmarshalWithParams(item.PDUSessionResourceReleaseCommandTransfer, &transfer, "valueExt") if err != nil { - ngapLog.Warnf("[PDUSessionID: %d] PDUSessionResourceReleaseCommandTransfer Decode Error: %+v\n", pduSessionId, err) + logger.NgapLog.Warnf( + "[PDUSessionID: %d] PDUSessionResourceReleaseCommandTransfer Decode Error: %+v\n", + pduSessionId, err) } else { printAndGetCause(&transfer.Cause) } - ngapLog.Tracef("Release PDU Session Id[%d] due to PDU Session Resource Release Command", pduSessionId) - delete(ue.PduSessionList, pduSessionId) + logger.NgapLog.Tracef("Release PDU Session Id[%d] due to PDU Session Resource Release Command", pduSessionId) + delete(ranUe.PduSessionList, pduSessionId) // response list releaseItem := ngapType.PDUSessionResourceReleasedItemRelRes{ @@ -2191,17 +2056,27 @@ func HandlePDUSessionResourceReleaseCommand(amf *context.N3IWFAMF, message *ngap PDUSessionResourceReleaseResponseTransfer: getPDUSessionResourceReleaseResponseTransfer(), } releaseList.List = append(releaseList.List, releaseItem) + + releaseIdList = append(releaseIdList, pduSessionId) } - handler.SendChildSADeleteRequest(ue, releaseList.List) - ue.PduSessionReleaseList = releaseList + localSPI, ok := n3iwfSelf.IkeSpiLoad(rANUENGAPID.Value) + if !ok { + logger.NgapLog.Errorf("Cannot get SPI from RanUeNgapID : %+v", rANUENGAPID.Value) + return + } + + n3iwfSelf.IKEServer.RcvEventCh <- context.NewSendChildSADeleteRequestEvt(localSPI, + releaseIdList) + + ranUe.PduSessionReleaseList = releaseList // if nASPDU != nil { // TODO: Send NAS to UE // } } func HandleErrorIndication(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle Error Indication") + logger.NgapLog.Infoln("[N3IWF] Handle Error Indication") var aMFUENGAPID *ngapType.AMFUENGAPID var rANUENGAPID *ngapType.RANUENGAPID @@ -2209,21 +2084,21 @@ func HandleErrorIndication(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { var criticalityDiagnostics *ngapType.CriticalityDiagnostics if amf == nil { - ngapLog.Error("Corresponding AMF context not found") + logger.NgapLog.Error("Corresponding AMF context not found") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("InitiatingMessage is nil") + logger.NgapLog.Error("InitiatingMessage is nil") return } errorIndication := initiatingMessage.Value.ErrorIndication if errorIndication == nil { - ngapLog.Error("ErrorIndication is nil") + logger.NgapLog.Error("ErrorIndication is nil") return } @@ -2231,33 +2106,33 @@ func HandleErrorIndication(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: aMFUENGAPID = ie.Value.AMFUENGAPID - ngapLog.Trace("[NGAP] Decode IE AmfUeNgapID") + logger.NgapLog.Trace("[NGAP] Decode IE AmfUeNgapID") case ngapType.ProtocolIEIDRANUENGAPID: rANUENGAPID = ie.Value.RANUENGAPID - ngapLog.Trace("[NGAP] Decode IE RanUeNgapID") + logger.NgapLog.Trace("[NGAP] Decode IE RanUeNgapID") case ngapType.ProtocolIEIDCause: cause = ie.Value.Cause - ngapLog.Trace("[NGAP] Decode IE Cause") + logger.NgapLog.Trace("[NGAP] Decode IE Cause") case ngapType.ProtocolIEIDCriticalityDiagnostics: criticalityDiagnostics = ie.Value.CriticalityDiagnostics - ngapLog.Trace("[NGAP] Decode IE CriticalityDiagnostics") + logger.NgapLog.Trace("[NGAP] Decode IE CriticalityDiagnostics") } } if cause == nil && criticalityDiagnostics == nil { - ngapLog.Error("Both Cause IE and CriticalityDiagnostics IE are nil, should have at least one") + logger.NgapLog.Error("Both Cause IE and CriticalityDiagnostics IE are nil, should have at least one") return } if (aMFUENGAPID == nil) != (rANUENGAPID == nil) { - ngapLog.Error("One of UE NGAP ID is not included in this message") + logger.NgapLog.Error("One of UE NGAP ID is not included in this message") return } if (aMFUENGAPID != nil) && (rANUENGAPID != nil) { - ngapLog.Trace("UE-associated procedure error") - ngapLog.Warnf("AMF UE NGAP ID is defined, value = %d", aMFUENGAPID.Value) - ngapLog.Warnf("RAN UE NGAP ID is defined, value = %d", rANUENGAPID.Value) + logger.NgapLog.Trace("UE-associated procedure error") + logger.NgapLog.Warnf("AMF UE NGAP ID is defined, value = %d", aMFUENGAPID.Value) + logger.NgapLog.Warnf("RAN UE NGAP ID is defined, value = %d", rANUENGAPID.Value) } if cause != nil { @@ -2272,7 +2147,7 @@ func HandleErrorIndication(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { } func HandleUERadioCapabilityCheckRequest(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle UE Radio Capability Check Request") + logger.NgapLog.Infoln("[N3IWF] Handle UE Radio Capability Check Request") var aMFUENGAPID *ngapType.AMFUENGAPID var rANUENGAPID *ngapType.RANUENGAPID var uERadioCapability *ngapType.UERadioCapability @@ -2280,49 +2155,49 @@ func HandleUERadioCapabilityCheckRequest(amf *context.N3IWFAMF, message *ngapTyp var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("InitiatingMessage is nil") + logger.NgapLog.Error("InitiatingMessage is nil") return } uERadioCapabilityCheckRequest := initiatingMessage.Value.UERadioCapabilityCheckRequest if uERadioCapabilityCheckRequest == nil { - ngapLog.Error("uERadioCapabilityCheckRequest is nil") + logger.NgapLog.Error("uERadioCapabilityCheckRequest is nil") return } for _, ie := range uERadioCapabilityCheckRequest.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFUENGAPID") aMFUENGAPID = ie.Value.AMFUENGAPID if aMFUENGAPID == nil { - ngapLog.Error("AMFUENGAPID is nil") + logger.NgapLog.Error("AMFUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDRANUENGAPID: - ngapLog.Traceln("[NGAP] Decode IE RANUENGAPID") + logger.NgapLog.Traceln("[NGAP] Decode IE RANUENGAPID") rANUENGAPID = ie.Value.RANUENGAPID if rANUENGAPID == nil { - ngapLog.Error("RANUENGAPID is nil") + logger.NgapLog.Error("RANUENGAPID is nil") item := buildCriticalityDiagnosticsIEItem( ngapType.CriticalityPresentReject, ie.Id.Value, ngapType.TypeOfErrorPresentMissing) iesCriticalityDiagnostics.List = append(iesCriticalityDiagnostics.List, item) } case ngapType.ProtocolIEIDUERadioCapability: - ngapLog.Traceln("[NGAP] Decode IE UERadioCapability") + logger.NgapLog.Traceln("[NGAP] Decode IE UERadioCapability") uERadioCapability = ie.Value.UERadioCapability } } @@ -2338,20 +2213,20 @@ func HandleUERadioCapabilityCheckRequest(amf *context.N3IWFAMF, message *ngapTyp } n3iwfSelf := context.N3IWFSelf() - ue, ok := n3iwfSelf.UePoolLoad(rANUENGAPID.Value) + ranUe, ok := n3iwfSelf.RanUePoolLoad(rANUENGAPID.Value) if !ok { - ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) + logger.NgapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentUnknownLocalUENGAPID) ngap_message.SendErrorIndication(amf, nil, nil, cause, nil) return } - ue.RadioCapability = uERadioCapability + ranUe.RadioCapability = uERadioCapability } func HandleAMFConfigurationUpdate(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle AMF Configuration Updaet") + logger.NgapLog.Infoln("[N3IWF] Handle AMF Configuration Updaet") var aMFName *ngapType.AMFName var servedGUAMIList *ngapType.ServedGUAMIList @@ -2362,49 +2237,49 @@ func HandleAMFConfigurationUpdate(amf *context.N3IWFAMF, message *ngapType.NGAPP var aMFTNLAssociationToUpdateList *ngapType.AMFTNLAssociationToUpdateList if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("InitiatingMessage is nil") + logger.NgapLog.Error("InitiatingMessage is nil") return } aMFConfigurationUpdate := initiatingMessage.Value.AMFConfigurationUpdate if aMFConfigurationUpdate == nil { - ngapLog.Error("aMFConfigurationUpdate is nil") + logger.NgapLog.Error("aMFConfigurationUpdate is nil") return } for _, ie := range aMFConfigurationUpdate.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFName: - ngapLog.Traceln("[NGAP] Decode IE AMFName") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFName") aMFName = ie.Value.AMFName case ngapType.ProtocolIEIDServedGUAMIList: - ngapLog.Traceln("[NGAP] Decode IE ServedGUAMIList") + logger.NgapLog.Traceln("[NGAP] Decode IE ServedGUAMIList") servedGUAMIList = ie.Value.ServedGUAMIList case ngapType.ProtocolIEIDRelativeAMFCapacity: - ngapLog.Traceln("[NGAP] Decode IE RelativeAMFCapacity") + logger.NgapLog.Traceln("[NGAP] Decode IE RelativeAMFCapacity") relativeAMFCapacity = ie.Value.RelativeAMFCapacity case ngapType.ProtocolIEIDPLMNSupportList: - ngapLog.Traceln("[NGAP] Decode IE PLMNSupportList") + logger.NgapLog.Traceln("[NGAP] Decode IE PLMNSupportList") pLMNSupportList = ie.Value.PLMNSupportList case ngapType.ProtocolIEIDAMFTNLAssociationToAddList: - ngapLog.Traceln("[NGAP] Decode IE AMFTNLAssociationToAddList") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFTNLAssociationToAddList") aMFTNLAssociationToAddList = ie.Value.AMFTNLAssociationToAddList case ngapType.ProtocolIEIDAMFTNLAssociationToRemoveList: - ngapLog.Traceln("[NGAP] Decode IE AMFTNLAssociationToRemoveList") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFTNLAssociationToRemoveList") aMFTNLAssociationToRemoveList = ie.Value.AMFTNLAssociationToRemoveList case ngapType.ProtocolIEIDAMFTNLAssociationToUpdateList: - ngapLog.Traceln("[NGAP] Decode IE AMFTNLAssociationToUpdateList") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFTNLAssociationToUpdateList") aMFTNLAssociationToUpdateList = ie.Value.AMFTNLAssociationToUpdateList } } @@ -2471,36 +2346,36 @@ func HandleAMFConfigurationUpdate(amf *context.N3IWFAMF, message *ngapType.NGAPP } func HandleRANConfigurationUpdateAcknowledge(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle RAN Configuration Update Acknowledge") + logger.NgapLog.Infoln("[N3IWF] Handle RAN Configuration Update Acknowledge") var criticalityDiagnostics *ngapType.CriticalityDiagnostics if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } successfulOutcome := message.SuccessfulOutcome if successfulOutcome == nil { - ngapLog.Error("SuccessfulOutcome is nil") + logger.NgapLog.Error("SuccessfulOutcome is nil") return } rANConfigurationUpdateAcknowledge := successfulOutcome.Value.RANConfigurationUpdateAcknowledge if rANConfigurationUpdateAcknowledge == nil { - ngapLog.Error("rANConfigurationUpdateAcknowledge is nil") + logger.NgapLog.Error("rANConfigurationUpdateAcknowledge is nil") return } for _, ie := range rANConfigurationUpdateAcknowledge.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDCriticalityDiagnostics: - ngapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") + logger.NgapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") criticalityDiagnostics = ie.Value.CriticalityDiagnostics } } @@ -2511,7 +2386,7 @@ func HandleRANConfigurationUpdateAcknowledge(amf *context.N3IWFAMF, message *nga } func HandleRANConfigurationUpdateFailure(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle RAN Configuration Update Failure") + logger.NgapLog.Infoln("[N3IWF] Handle RAN Configuration Update Failure") var cause *ngapType.Cause var timeToWait *ngapType.TimeToWait @@ -2520,37 +2395,37 @@ func HandleRANConfigurationUpdateFailure(amf *context.N3IWFAMF, message *ngapTyp n3iwfSelf := context.N3IWFSelf() if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } unsuccessfulOutcome := message.UnsuccessfulOutcome if unsuccessfulOutcome == nil { - ngapLog.Error("UnsuccessfulOutcome is nil") + logger.NgapLog.Error("UnsuccessfulOutcome is nil") return } rANConfigurationUpdateFailure := unsuccessfulOutcome.Value.RANConfigurationUpdateFailure if rANConfigurationUpdateFailure == nil { - ngapLog.Error("rANConfigurationUpdateFailure is nil") + logger.NgapLog.Error("rANConfigurationUpdateFailure is nil") return } for _, ie := range rANConfigurationUpdateFailure.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDCause: - ngapLog.Traceln("[NGAP] Decode IE Cause") + logger.NgapLog.Traceln("[NGAP] Decode IE Cause") cause = ie.Value.Cause case ngapType.ProtocolIEIDTimeToWait: - ngapLog.Traceln("[NGAP] Decode IE TimeToWait") + logger.NgapLog.Traceln("[NGAP] Decode IE TimeToWait") timeToWait = ie.Value.TimeToWait case ngapType.ProtocolIEIDCriticalityDiagnostics: - ngapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") + logger.NgapLog.Traceln("[NGAP] Decode IE CriticalityDiagnostics") criticalityDiagnostics = ie.Value.CriticalityDiagnostics } } @@ -2581,11 +2456,11 @@ func HandleRANConfigurationUpdateFailure(amf *context.N3IWFAMF, message *ngapTyp } if waitingTime != 0 { - ngapLog.Infof("Wait at lease %ds to resend RAN Configuration Update to same AMF[%s]", + logger.NgapLog.Infof("Wait at lease %ds to resend RAN Configuration Update to same AMF[%s]", waitingTime, amf.SCTPAddr) n3iwfSelf.AMFReInitAvailableListStore(amf.SCTPAddr, false) time.AfterFunc(time.Duration(waitingTime)*time.Second, func() { - ngapLog.Infof("Re-send Ran Configuration Update Message when waiting time expired") + logger.NgapLog.Infof("Re-send Ran Configuration Update Message when waiting time expired") n3iwfSelf.AMFReInitAvailableListStore(amf.SCTPAddr, true) ngap_message.SendRANConfigurationUpdate(amf) }) @@ -2595,64 +2470,64 @@ func HandleRANConfigurationUpdateFailure(amf *context.N3IWFAMF, message *ngapTyp } func HandleDownlinkRANConfigurationTransfer(message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle Downlink RAN Configuration Transfer") + logger.NgapLog.Infoln("[N3IWF] Handle Downlink RAN Configuration Transfer") } func HandleDownlinkRANStatusTransfer(message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle Downlink RAN Status Transfer") + logger.NgapLog.Infoln("[N3IWF] Handle Downlink RAN Status Transfer") } func HandleAMFStatusIndication(message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle AMF Status Indication") + logger.NgapLog.Infoln("[N3IWF] Handle AMF Status Indication") } func HandleLocationReportingControl(message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle Location Reporting Control") + logger.NgapLog.Infoln("[N3IWF] Handle Location Reporting Control") } func HandleUETNLAReleaseRequest(message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle UE TNLA Release Request") + logger.NgapLog.Infoln("[N3IWF] Handle UE TNLA Release Request") } func HandleOverloadStart(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle Overload Start") + logger.NgapLog.Infoln("[N3IWF] Handle Overload Start") var aMFOverloadResponse *ngapType.OverloadResponse var aMFTrafficLoadReductionIndication *ngapType.TrafficLoadReductionIndication var overloadStartNSSAIList *ngapType.OverloadStartNSSAIList if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } if message == nil { - ngapLog.Error("NGAP Message is nil") + logger.NgapLog.Error("NGAP Message is nil") return } initiatingMessage := message.InitiatingMessage if initiatingMessage == nil { - ngapLog.Error("InitiatingMessage is nil") + logger.NgapLog.Error("InitiatingMessage is nil") return } overloadStart := initiatingMessage.Value.OverloadStart if overloadStart == nil { - ngapLog.Error("overloadStart is nil") + logger.NgapLog.Error("overloadStart is nil") return } for _, ie := range overloadStart.ProtocolIEs.List { switch ie.Id.Value { case ngapType.ProtocolIEIDAMFOverloadResponse: - ngapLog.Traceln("[NGAP] Decode IE AMFOverloadResponse") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFOverloadResponse") aMFOverloadResponse = ie.Value.AMFOverloadResponse case ngapType.ProtocolIEIDAMFTrafficLoadReductionIndication: - ngapLog.Traceln("[NGAP] Decode IE AMFTrafficLoadReductionIndication") + logger.NgapLog.Traceln("[NGAP] Decode IE AMFTrafficLoadReductionIndication") aMFTrafficLoadReductionIndication = ie.Value.AMFTrafficLoadReductionIndication case ngapType.ProtocolIEIDOverloadStartNSSAIList: - ngapLog.Traceln("[NGAP] Decode IE OverloadStartNSSAIList") + logger.NgapLog.Traceln("[NGAP] Decode IE OverloadStartNSSAIList") overloadStartNSSAIList = ie.Value.OverloadStartNSSAIList } } @@ -2661,10 +2536,10 @@ func HandleOverloadStart(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { } func HandleOverloadStop(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { - ngapLog.Infoln("[N3IWF] Handle Overload Stop") + logger.NgapLog.Infoln("[N3IWF] Handle Overload Stop") if amf == nil { - ngapLog.Error("AMF Context is nil") + logger.NgapLog.Error("AMF Context is nil") return } // TODO: remove restrict about overload action @@ -2722,22 +2597,22 @@ func printAndGetCause(cause *ngapType.Cause) (present int, value aper.Enumerated present = cause.Present switch cause.Present { case ngapType.CausePresentRadioNetwork: - ngapLog.Warnf("Cause RadioNetwork[%d]", cause.RadioNetwork.Value) + logger.NgapLog.Warnf("Cause RadioNetwork[%d]", cause.RadioNetwork.Value) value = cause.RadioNetwork.Value case ngapType.CausePresentTransport: - ngapLog.Warnf("Cause Transport[%d]", cause.Transport.Value) + logger.NgapLog.Warnf("Cause Transport[%d]", cause.Transport.Value) value = cause.Transport.Value case ngapType.CausePresentProtocol: - ngapLog.Warnf("Cause Protocol[%d]", cause.Protocol.Value) + logger.NgapLog.Warnf("Cause Protocol[%d]", cause.Protocol.Value) value = cause.Protocol.Value case ngapType.CausePresentNas: - ngapLog.Warnf("Cause Nas[%d]", cause.Nas.Value) + logger.NgapLog.Warnf("Cause Nas[%d]", cause.Nas.Value) value = cause.Nas.Value case ngapType.CausePresentMisc: - ngapLog.Warnf("Cause Misc[%d]", cause.Misc.Value) + logger.NgapLog.Warnf("Cause Misc[%d]", cause.Misc.Value) value = cause.Misc.Value default: - ngapLog.Errorf("Invalid Cause group[%d]", cause.Present) + logger.NgapLog.Errorf("Invalid Cause group[%d]", cause.Present) } return } @@ -2749,27 +2624,27 @@ func printCriticalityDiagnostics(criticalityDiagnostics *ngapType.CriticalityDia iesCriticalityDiagnostics := criticalityDiagnostics.IEsCriticalityDiagnostics if iesCriticalityDiagnostics != nil { for index, item := range iesCriticalityDiagnostics.List { - ngapLog.Warnf("Criticality IE item %d:", index+1) - ngapLog.Warnf("IE ID: %d", item.IEID.Value) + logger.NgapLog.Warnf("Criticality IE item %d:", index+1) + logger.NgapLog.Warnf("IE ID: %d", item.IEID.Value) switch item.IECriticality.Value { case ngapType.CriticalityPresentReject: - ngapLog.Warn("IE Criticality: Reject") + logger.NgapLog.Warn("IE Criticality: Reject") case ngapType.CriticalityPresentIgnore: - ngapLog.Warn("IE Criticality: Ignore") + logger.NgapLog.Warn("IE Criticality: Ignore") case ngapType.CriticalityPresentNotify: - ngapLog.Warn("IE Criticality: Notify") + logger.NgapLog.Warn("IE Criticality: Notify") } switch item.TypeOfError.Value { case ngapType.TypeOfErrorPresentNotUnderstood: - ngapLog.Warn("Type of error: Not Understood") + logger.NgapLog.Warn("Type of error: Not Understood") case ngapType.TypeOfErrorPresentMissing: - ngapLog.Warn("Type of error: Missing") + logger.NgapLog.Warn("Type of error: Missing") } } } else { - ngapLog.Error("IEsCriticalityDiagnostics is nil") + logger.NgapLog.Error("IEsCriticalityDiagnostics is nil") } return } @@ -2779,7 +2654,369 @@ func getPDUSessionResourceReleaseResponseTransfer() []byte { data := ngapType.PDUSessionResourceReleaseResponseTransfer{} encodeData, err := aper.MarshalWithParams(data, "valueExt") if err != nil { - ngapLog.Errorf("aper MarshalWithParams error in getPDUSessionResourceReleaseResponseTransfer: %d", err) + logger.NgapLog.Errorf("aper MarshalWithParams error in getPDUSessionResourceReleaseResponseTransfer: %d", err) } return encodeData } + +func HandleEvent(ngapEvent context.NgapEvt) { + logger.NgapLog.Infof("NGAP event handle") + + switch ngapEvent.Type() { + case context.UnmarshalEAP5GData: + HandleUnmarshalEAP5GData(ngapEvent) + case context.SendInitialUEMessage: + HandleSendInitialUEMessage(ngapEvent) + case context.SendPDUSessionResourceSetupResponse: + HandleSendPDUSessionResourceSetupResponse(ngapEvent) + case context.SendNASMsg: + HandleSendNASMsg(ngapEvent) + case context.StartTCPSignalNASMsg: + HandleStartTCPSignalNASMsg(ngapEvent) + case context.NASTCPConnEstablishedComplete: + HandleNASTCPConnEstablishedComplete(ngapEvent) + case context.SendUEContextReleaseRequest: + HandleSendUEContextReleaseRequest(ngapEvent) + case context.SendUEContextReleaseComplete: + HandleSendUEContextReleaseComplete(ngapEvent) + case context.SendPDUSessionResourceReleaseResponse: + HandleSendPDUSessionResourceReleaseRes(ngapEvent) + case context.GetNGAPContext: + HandleGetNGAPContext(ngapEvent) + default: + logger.NgapLog.Errorf("Undefine NGAP event type") + return + } +} + +func HandleGetNGAPContext(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle HandleGetNGAPContext Event") + + getNGAPContextEvt := ngapEvent.(*context.GetNGAPContextEvt) + ranUeNgapId := getNGAPContextEvt.RanUeNgapId + ngapCxtReqNumlist := getNGAPContextEvt.NgapCxtReqNumlist + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + var ngapCxt []interface{} + + for _, num := range ngapCxtReqNumlist { + switch num { + case context.CxtTempPDUSessionSetupData: + ngapCxt = append(ngapCxt, ranUe.TemporaryPDUSessionSetupData) + default: + logger.NgapLog.Errorf("Receive undefine NGAP Context Request number : %d", num) + } + } + + spi, ok := n3iwfSelf.IkeSpiLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get spi from ngapid : %+v", ranUeNgapId) + return + } + + n3iwfSelf.IKEServer.RcvEventCh <- context.NewGetNGAPContextRepEvt(spi, + ngapCxtReqNumlist, ngapCxt) +} + +func HandleUnmarshalEAP5GData(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle UnmarshalEAP5GData Event") + + unmarshalEAP5GDataEvt := ngapEvent.(*context.UnmarshalEAP5GDataEvt) + spi := unmarshalEAP5GDataEvt.LocalSPI + eapVendorData := unmarshalEAP5GDataEvt.EAPVendorData + isInitialUE := unmarshalEAP5GDataEvt.IsInitialUE + + n3iwfSelf := context.N3IWFSelf() + + anParameters, nasPDU, err := ngap_message.UnmarshalEAP5GData(eapVendorData) + if err != nil { + logger.NgapLog.Errorf("Unmarshalling EAP-5G packet failed: %+v", err) + return + } + + if !isInitialUE { // ikeSA.ikeUE == nil + logger.NgapLog.Debug("Select AMF with the following AN parameters:") + if anParameters.GUAMI == nil { + logger.NgapLog.Debug("\tGUAMI: nil") + } else { + logger.NgapLog.Debugf("\tGUAMI: PLMNIdentity[% x], "+ + "AMFRegionID[% x], AMFSetID[% x], AMFPointer[% x]", + anParameters.GUAMI.PLMNIdentity, anParameters.GUAMI.AMFRegionID, + anParameters.GUAMI.AMFSetID, anParameters.GUAMI.AMFPointer) + } + if anParameters.SelectedPLMNID == nil { + logger.NgapLog.Debug("\tSelectedPLMNID: nil") + } else { + logger.NgapLog.Debugf("\tSelectedPLMNID: % v", anParameters.SelectedPLMNID.Value) + } + if anParameters.RequestedNSSAI == nil { + logger.NgapLog.Debug("\tRequestedNSSAI: nil") + } else { + logger.NgapLog.Debugf("\tRequestedNSSAI:") + for i := 0; i < len(anParameters.RequestedNSSAI.List); i++ { + logger.NgapLog.Debugf("\tRequestedNSSAI:") + logger.NgapLog.Debugf("\t\tSNSSAI %d:", i+1) + logger.NgapLog.Debugf("\t\t\tSST: % x", anParameters.RequestedNSSAI.List[i].SNSSAI.SST.Value) + sd := anParameters.RequestedNSSAI.List[i].SNSSAI.SD + if sd == nil { + logger.NgapLog.Debugf("\t\t\tSD: nil") + } else { + logger.NgapLog.Debugf("\t\t\tSD: % x", sd.Value) + } + } + } + + selectedAMF := n3iwfSelf.AMFSelection(anParameters.GUAMI, anParameters.SelectedPLMNID) + if selectedAMF == nil { + n3iwfSelf.IKEServer.RcvEventCh <- context.NewSendEAP5GFailureMsgEvt(spi, context.ErrAMFSelection) + } else { + ranUe := n3iwfSelf.NewN3iwfRanUe() + ranUe.AMF = selectedAMF + if anParameters.EstablishmentCause != nil { + ranUe.RRCEstablishmentCause = int16(anParameters.EstablishmentCause.Value) + } + + n3iwfSelf.IKEServer.RcvEventCh <- context.NewUnmarshalEAP5GDataResponseEvt(spi, + ranUe.RanUeNgapId, nasPDU) + } + } else { + ranUeNgapId := unmarshalEAP5GDataEvt.RanUeNgapId + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + ngap_message.SendUplinkNASTransport(ranUe, nasPDU) + } +} + +func HandleSendInitialUEMessage(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle SendInitialUEMessage Event") + + sendInitialUEMessageEvt := ngapEvent.(*context.SendInitialUEMessageEvt) + ranUeNgapId := sendInitialUEMessageEvt.RanUeNgapId + ipv4Addr := sendInitialUEMessageEvt.IPv4Addr + ipv4Port := sendInitialUEMessageEvt.IPv4Port + nasPDU := sendInitialUEMessageEvt.NasPDU + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + ranUe.IPAddrv4 = ipv4Addr + ranUe.PortNumber = int32(ipv4Port) + ngap_message.SendInitialUEMessage(ranUe.AMF, ranUe, nasPDU) +} + +func HandleSendPDUSessionResourceSetupResponse(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle SendPDUSessionResourceSetupResponse Event") + + sendPDUSessionResourceSetupResEvt := ngapEvent.(*context.SendPDUSessionResourceSetupResEvt) + ranUeNgapId := sendPDUSessionResourceSetupResEvt.RanUeNgapId + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + temporaryPDUSessionSetupData := ranUe.TemporaryPDUSessionSetupData + + if len(temporaryPDUSessionSetupData.UnactivatedPDUSession) != 0 { + for index, pduSession := range temporaryPDUSessionSetupData.UnactivatedPDUSession { + errStr := temporaryPDUSessionSetupData.FailedErrStr[index] + if errStr != context.ErrNil { + var cause ngapType.Cause + switch errStr { + case context.ErrTransportResourceUnavailable: + cause = ngapType.Cause{ + Present: ngapType.CausePresentTransport, + Transport: &ngapType.CauseTransport{ + Value: ngapType.CauseTransportPresentTransportResourceUnavailable, + }, + } + default: + logger.NgapLog.Errorf("Undefine event error string : %+s", errStr.Error()) + return + } + + transfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(cause, nil) + if err != nil { + logger.NgapLog.Errorf("Build PDU Session Resource Setup Unsuccessful Transfer Failed: %+v", err) + continue + } + + if temporaryPDUSessionSetupData.NGAPProcedureCode.Value == ngapType.ProcedureCodeInitialContextSetup { + ngap_message.AppendPDUSessionResourceFailedToSetupListCxtRes( + temporaryPDUSessionSetupData.FailedListCxtRes, pduSession.Id, transfer) + } else { + ngap_message.AppendPDUSessionResourceFailedToSetupListSURes( + temporaryPDUSessionSetupData.FailedListSURes, pduSession.Id, transfer) + } + } else { + // Append NGAP PDU session resource setup response transfer + transfer, err := ngap_message.BuildPDUSessionResourceSetupResponseTransfer(pduSession) + if err != nil { + logger.NgapLog.Errorf("Build PDU session resource setup response transfer failed: %+v", err) + return + } + if temporaryPDUSessionSetupData.NGAPProcedureCode.Value == ngapType.ProcedureCodeInitialContextSetup { + ngap_message.AppendPDUSessionResourceSetupListCxtRes( + temporaryPDUSessionSetupData.SetupListCxtRes, pduSession.Id, transfer) + } else { + ngap_message.AppendPDUSessionResourceSetupListSURes( + temporaryPDUSessionSetupData.SetupListSURes, pduSession.Id, transfer) + } + } + } + + if temporaryPDUSessionSetupData.NGAPProcedureCode.Value == ngapType.ProcedureCodeInitialContextSetup { + ngap_message.SendInitialContextSetupResponse(ranUe, + temporaryPDUSessionSetupData.SetupListCxtRes, + temporaryPDUSessionSetupData.FailedListCxtRes, nil) + } else { + ngap_message.SendPDUSessionResourceSetupResponse(ranUe, + temporaryPDUSessionSetupData.SetupListSURes, + temporaryPDUSessionSetupData.FailedListSURes, nil) + } + } else { + ngap_message.SendInitialContextSetupResponse(ranUe, nil, nil, nil) + } +} + +func HandleSendNASMsg(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle SendNASMsg Event") + + sendNASMsgEvt := ngapEvent.(*context.SendNASMsgEvt) + ranUeNgapId := sendNASMsgEvt.RanUeNgapId + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + if n, ikeErr := ranUe.TCPConnection.Write(ranUe.TemporaryCachedNASMessage); ikeErr != nil { + logger.NgapLog.Errorf("Writing via IPSec signalling SA failed: %+v", ikeErr) + } else { + logger.NgapLog.Tracef("Forward PDU Seesion Establishment Accept to UE. Wrote %d bytes", n) + ranUe.TemporaryCachedNASMessage = nil + } +} + +func HandleStartTCPSignalNASMsg(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle StartTCPSignalNASMsg Event") + + startTCPSignalNASMsgEvt := ngapEvent.(*context.StartTCPSignalNASMsgEvt) + ranUeNgapId := startTCPSignalNASMsgEvt.RanUeNgapId + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + ranUe.IsNASTCPConnEstablished = true +} + +func HandleNASTCPConnEstablishedComplete(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle NASTCPConnEstablishedComplete Event") + + nasTCPConnEstablishedCompleteEvt := ngapEvent.(*context.NASTCPConnEstablishedCompleteEvt) + ranUeNgapId := nasTCPConnEstablishedCompleteEvt.RanUeNgapId + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + ranUe.IsNASTCPConnEstablishedComplete = true + + if ranUe.TemporaryCachedNASMessage != nil { + // Send to UE + if n, err := ranUe.TCPConnection.Write(ranUe.TemporaryCachedNASMessage); err != nil { + logger.NgapLog.Errorf("Writing via IPSec signalling SA failed: %+v", err) + } else { + logger.NgapLog.Trace("Forward NWu <- N2") + logger.NgapLog.Tracef("Wrote %d bytes", n) + } + ranUe.TemporaryCachedNASMessage = nil + } +} + +func HandleSendUEContextReleaseRequest(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle SendUEContextReleaseRequest Event") + + sendUEContextReleaseReqEvt := ngapEvent.(*context.SendUEContextReleaseRequestEvt) + + ranUeNgapId := sendUEContextReleaseReqEvt.RanUeNgapId + errMsg := sendUEContextReleaseReqEvt.ErrMsg + + var cause *ngapType.Cause + switch errMsg { + case context.ErrRadioConnWithUeLost: + cause = ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, + ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) + case context.ErrNil: + default: + logger.NgapLog.Errorf("Undefine event error string : %+s", errMsg.Error()) + return + } + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + ngap_message.SendUEContextReleaseRequest(ranUe, *cause) +} + +func HandleSendUEContextReleaseComplete(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle SendUEContextReleaseComplete Event") + + sendUEContextReleaseCompleteEvt := ngapEvent.(*context.SendUEContextReleaseCompleteEvt) + ranUeNgapId := sendUEContextReleaseCompleteEvt.RanUeNgapId + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + if err := ranUe.Remove(); err != nil { + logger.NgapLog.Errorf("Delete RanUe Context error : %+v", err) + } + ngap_message.SendUEContextReleaseComplete(ranUe, nil) +} + +func HandleSendPDUSessionResourceReleaseRes(ngapEvent context.NgapEvt) { + logger.NgapLog.Tracef("Handle SendPDUSessionResourceReleaseResponse Event") + + sendPDUSessionResourceReleaseResEvt := ngapEvent.(*context.SendPDUSessionResourceReleaseResEvt) + ranUeNgapId := sendPDUSessionResourceReleaseResEvt.RanUeNgapId + + n3iwfSelf := context.N3IWFSelf() + ranUe, ok := n3iwfSelf.RanUePoolLoad(ranUeNgapId) + if !ok { + logger.NgapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + ngap_message.SendPDUSessionResourceReleaseResponse(ranUe, ranUe.PduSessionReleaseList, nil) +} diff --git a/internal/ngap/message/3gpp_type.go b/internal/ngap/message/3gpp_type.go new file mode 100644 index 0000000..56f2651 --- /dev/null +++ b/internal/ngap/message/3gpp_type.go @@ -0,0 +1,282 @@ +package message + +import ( + "encoding/binary" + "errors" + + "github.com/free5gc/aper" + "github.com/free5gc/n3iwf/internal/logger" + "github.com/free5gc/ngap/ngapType" +) + +// 3GPP specified EAP-5G + +// Access Network Parameters +type ANParameters struct { + GUAMI *ngapType.GUAMI + SelectedPLMNID *ngapType.PLMNIdentity + RequestedNSSAI *ngapType.AllowedNSSAI + EstablishmentCause *ngapType.RRCEstablishmentCause +} + +func UnmarshalEAP5GData(codedData []byte) (anParameters *ANParameters, nasPDU []byte, err error) { + if len(codedData) >= 2 { + logger.NgapLog.Debug("===== Unmarshal EAP5G Data (Ref: TS24.502 Fig. 9.3.2.2.2-1) =====") + + codedData = codedData[2:] + + // [TS 24.502 f30] 9.3.2.2.2.3 + // AN-parameter value field in GUAMI, PLMN ID and NSSAI is coded as value part + // Therefore, IEI of AN-parameter is not needed to be included. + // anParameter = AN-parameter Type | AN-parameter Length | Value part of IE + + if len(codedData) >= 2 { + // Length of the AN-Parameter field + anParameterLength := binary.BigEndian.Uint16(codedData[:2]) + logger.NgapLog.Debugf("AN-parameters length: %d", anParameterLength) + + if anParameterLength != 0 { + anParameterField := codedData[2:] + + // Bound checking + if len(anParameterField) < int(anParameterLength) { + logger.NgapLog.Error("Packet contained error length of value") + return nil, nil, errors.New("Error formatting") + } else { + anParameterField = anParameterField[:anParameterLength] + } + + logger.NgapLog.Debugf("Parsing AN-parameters...: % v", anParameterField) + + anParameters = new(ANParameters) + + // Parse AN-Parameters + for len(anParameterField) >= 2 { + parameterType := anParameterField[0] + // The AN-parameter length field indicates the length of the AN-parameter value field. + parameterLength := anParameterField[1] + + switch parameterType { + case ANParametersTypeGUAMI: + logger.NgapLog.Debugf("-> Parameter type: GUAMI") + if parameterLength != 0 { + parameterValue := anParameterField[2:] + + if len(parameterValue) < int(parameterLength) { + return nil, nil, errors.New("Error formatting") + } else { + parameterValue = parameterValue[:parameterLength] + } + + if len(parameterValue) != ANParametersLenGUAMI { + return nil, nil, errors.New("Unmatched GUAMI length") + } + + guamiField := make([]byte, 1) + guamiField = append(guamiField, parameterValue...) + // Decode GUAMI using aper + ngapGUAMI := new(ngapType.GUAMI) + err := aper.UnmarshalWithParams(guamiField, ngapGUAMI, "valueExt") + if err != nil { + logger.NgapLog.Errorf("APER unmarshal with parameter failed: %+v", err) + return nil, nil, errors.New("Unmarshal failed when decoding GUAMI") + } + anParameters.GUAMI = ngapGUAMI + logger.NgapLog.Debugf("Unmarshal GUAMI: % x", guamiField) + logger.NgapLog.Debugf("\tGUAMI: PLMNIdentity[% x], "+ + "AMFRegionID[% x], AMFSetID[% x], AMFPointer[% x]", + anParameters.GUAMI.PLMNIdentity, anParameters.GUAMI.AMFRegionID, + anParameters.GUAMI.AMFSetID, anParameters.GUAMI.AMFPointer) + } else { + logger.NgapLog.Warn("AN-Parameter GUAMI field empty") + } + case ANParametersTypeSelectedPLMNID: + logger.NgapLog.Debugf("-> Parameter type: ANParametersTypeSelectedPLMNID") + if parameterLength != 0 { + parameterValue := anParameterField[2:] + + if len(parameterValue) < int(parameterLength) { + return nil, nil, errors.New("Error formatting") + } else { + parameterValue = parameterValue[:parameterLength] + } + + if len(parameterValue) != ANParametersLenPLMNID { + return nil, nil, errors.New("Unmatched PLMN ID length") + } + + plmnField := make([]byte, 1) + plmnField = append(plmnField, parameterValue...) + // Decode PLMN using aper + ngapPLMN := new(ngapType.PLMNIdentity) + err := aper.UnmarshalWithParams(plmnField, ngapPLMN, "valueExt") + if err != nil { + logger.NgapLog.Errorf("APER unmarshal with parameter failed: %v", err) + return nil, nil, errors.New("Unmarshal failed when decoding PLMN") + } + anParameters.SelectedPLMNID = ngapPLMN + logger.NgapLog.Debugf("Unmarshal SelectedPLMNID: % x", plmnField) + logger.NgapLog.Debugf("\tSelectedPLMNID: % x", anParameters.SelectedPLMNID.Value) + } else { + logger.NgapLog.Warn("AN-Parameter PLMN field empty") + } + case ANParametersTypeRequestedNSSAI: + logger.NgapLog.Debugf("-> Parameter type: ANParametersTypeRequestedNSSAI") + if parameterLength != 0 { + parameterValue := anParameterField[2:] + + if len(parameterValue) < int(parameterLength) { + return nil, nil, errors.New("Error formatting") + } else { + parameterValue = parameterValue[:parameterLength] + } + + ngapNSSAI := new(ngapType.AllowedNSSAI) + + // [TS 24501 f30] 9.11.2.8 S-NSSAI + // s-nssai(LV) consists of + // len(1 byte) | SST(1) | SD(3,opt) | Mapped HPLMN SST (1,opt) | Mapped HPLMN SD (3,opt) + // The length of minimum s-nssai comprised of a length and a SST is 2 bytes. + + for len(parameterValue) >= 2 { + snssaiLength := parameterValue[0] + snssaiValue := parameterValue[1:] + + if len(snssaiValue) < int(snssaiLength) { + logger.NgapLog.Error("SNSSAI length error") + return nil, nil, errors.New("Error formatting") + } else { + snssaiValue = snssaiValue[:snssaiLength] + } + + ngapSNSSAIItem := ngapType.AllowedNSSAIItem{} + + if len(snssaiValue) == 1 { + ngapSNSSAIItem.SNSSAI = ngapType.SNSSAI{ + SST: ngapType.SST{ + Value: []byte{snssaiValue[0]}, + }, + } + } else if len(snssaiValue) == 4 { + ngapSNSSAIItem.SNSSAI = ngapType.SNSSAI{ + SST: ngapType.SST{ + Value: []byte{snssaiValue[0]}, + }, + SD: &ngapType.SD{ + Value: []byte{snssaiValue[1], snssaiValue[2], snssaiValue[3]}, + }, + } + } else { + logger.NgapLog.Error("Empty SNSSAI value") + return nil, nil, errors.New("Error formatting") + } + + ngapNSSAI.List = append(ngapNSSAI.List, ngapSNSSAIItem) + + logger.NgapLog.Debugf("Unmarshal SNSSAI: % x", parameterValue[:1+snssaiLength]) + logger.NgapLog.Debugf("\t\t\tSST: % x", ngapSNSSAIItem.SNSSAI.SST.Value) + sd := ngapSNSSAIItem.SNSSAI.SD + if sd == nil { + logger.NgapLog.Debugf("\t\t\tSD: nil") + } else { + logger.NgapLog.Debugf("\t\t\tSD: % x", sd.Value) + } + + // shift parameterValue for parsing next s-nssai + parameterValue = parameterValue[1+snssaiLength:] + } + anParameters.RequestedNSSAI = ngapNSSAI + } else { + logger.NgapLog.Warn("AN-Parameter NSSAI is empty") + } + case ANParametersTypeEstablishmentCause: + logger.NgapLog.Debugf("-> Parameter type: ANParametersTypeEstablishmentCause") + if parameterLength != 0 { + parameterValue := anParameterField[2:] + + if len(parameterValue) < int(parameterLength) { + return nil, nil, errors.New("Error formatting") + } else { + parameterValue = parameterValue[:parameterLength] + } + + if len(parameterValue) != ANParametersLenEstCause { + return nil, nil, errors.New("Unmatched Establishment Cause length") + } + + logger.NgapLog.Debugf("Unmarshal ANParametersTypeEstablishmentCause: % x", parameterValue) + + establishmentCause := parameterValue[0] & 0x0f + switch establishmentCause { + case EstablishmentCauseEmergency: + logger.NgapLog.Trace("AN-Parameter establishment cause: Emergency") + case EstablishmentCauseHighPriorityAccess: + logger.NgapLog.Trace("AN-Parameter establishment cause: High Priority Access") + case EstablishmentCauseMO_Signalling: + logger.NgapLog.Trace("AN-Parameter establishment cause: MO Signalling") + case EstablishmentCauseMO_Data: + logger.NgapLog.Trace("AN-Parameter establishment cause: MO Data") + case EstablishmentCauseMPS_PriorityAccess: + logger.NgapLog.Trace("AN-Parameter establishment cause: MPS Priority Access") + case EstablishmentCauseMCS_PriorityAccess: + logger.NgapLog.Trace("AN-Parameter establishment cause: MCS Priority Access") + default: + logger.NgapLog.Trace("AN-Parameter establishment cause: Unknown. Treat as mo-Data") + establishmentCause = EstablishmentCauseMO_Data + } + + ngapEstablishmentCause := new(ngapType.RRCEstablishmentCause) + ngapEstablishmentCause.Value = aper.Enumerated(establishmentCause) + + anParameters.EstablishmentCause = ngapEstablishmentCause + } else { + logger.NgapLog.Warn("AN-Parameter establishment cause field empty") + } + default: + logger.NgapLog.Warn("Unsopprted AN-Parameter. Ignore.") + } + + // shift anParameterField + anParameterField = anParameterField[2+parameterLength:] + } + } + + // shift codedData + codedData = codedData[2+anParameterLength:] + } else { + logger.NgapLog.Error("No AN-Parameter type or length specified") + return nil, nil, errors.New("Error formatting") + } + + if len(codedData) >= 2 { + // Length of the NASPDU field + nasPDULength := binary.BigEndian.Uint16(codedData[:2]) + logger.NgapLog.Debugf("nasPDULength: %d", nasPDULength) + + if nasPDULength != 0 { + nasPDUField := codedData[2:] + + // Bound checking + if len(nasPDUField) < int(nasPDULength) { + return nil, nil, errors.New("Error formatting") + } else { + nasPDUField = nasPDUField[:nasPDULength] + } + + logger.NgapLog.Debugf("nasPDUField: % v", nasPDUField) + + nasPDU = append(nasPDU, nasPDUField...) + } else { + logger.NgapLog.Error("No NAS PDU included in EAP-5G packet") + return nil, nil, errors.New("No NAS PDU") + } + } else { + logger.NgapLog.Error("No NASPDU length specified") + return nil, nil, errors.New("Error formatting") + } + + return + } else { + return nil, nil, errors.New("No data to decode") + } +} diff --git a/internal/ngap/message/build.go b/internal/ngap/message/build.go index 716e7a1..4e049b3 100644 --- a/internal/ngap/message/build.go +++ b/internal/ngap/message/build.go @@ -234,7 +234,7 @@ func BuildNGResetAcknowledge( } func BuildInitialContextSetupResponse( - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, responseList *ngapType.PDUSessionResourceSetupListCxtRes, failedList *ngapType.PDUSessionResourceFailedToSetupListCxtRes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, @@ -261,7 +261,7 @@ func BuildInitialContextSetupResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId initialContextSetupResponseIEs.List = append(initialContextSetupResponseIEs.List, ie) @@ -273,7 +273,7 @@ func BuildInitialContextSetupResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId initialContextSetupResponseIEs.List = append(initialContextSetupResponseIEs.List, ie) @@ -310,7 +310,7 @@ func BuildInitialContextSetupResponse( } func BuildInitialContextSetupFailure( - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, cause ngapType.Cause, failedList *ngapType.PDUSessionResourceFailedToSetupListCxtFail, criticalityDiagnostics *ngapType.CriticalityDiagnostics, @@ -337,7 +337,7 @@ func BuildInitialContextSetupFailure( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId initialContextSetupFailureIEs.List = append(initialContextSetupFailureIEs.List, ie) @@ -349,7 +349,7 @@ func BuildInitialContextSetupFailure( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId initialContextSetupFailureIEs.List = append(initialContextSetupFailureIEs.List, ie) @@ -384,7 +384,7 @@ func BuildInitialContextSetupFailure( } func BuildUEContextModificationResponse( - ue *context.N3IWFUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, + ranUe *context.N3IWFRanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentSuccessfulOutcome @@ -408,7 +408,7 @@ func BuildUEContextModificationResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId uEContextModificationResponseIEs.List = append(uEContextModificationResponseIEs.List, ie) @@ -420,7 +420,7 @@ func BuildUEContextModificationResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId uEContextModificationResponseIEs.List = append(uEContextModificationResponseIEs.List, ie) @@ -434,7 +434,7 @@ func BuildUEContextModificationResponse( return ngap.Encoder(pdu) } -func BuildUEContextModificationFailure(ue *context.N3IWFUe, cause ngapType.Cause, +func BuildUEContextModificationFailure(ranUe *context.N3IWFRanUe, cause ngapType.Cause, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { var pdu ngapType.NGAPPDU @@ -459,7 +459,7 @@ func BuildUEContextModificationFailure(ue *context.N3IWFUe, cause ngapType.Cause ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId uEContextModificationFailureIEs.List = append(uEContextModificationFailureIEs.List, ie) @@ -471,7 +471,7 @@ func BuildUEContextModificationFailure(ue *context.N3IWFUe, cause ngapType.Cause ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId uEContextModificationFailureIEs.List = append(uEContextModificationFailureIEs.List, ie) @@ -493,7 +493,7 @@ func BuildUEContextModificationFailure(ue *context.N3IWFUe, cause ngapType.Cause return ngap.Encoder(pdu) } -func BuildUEContextReleaseComplete(ue *context.N3IWFUe, +func BuildUEContextReleaseComplete(ranUe *context.N3IWFRanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { var pdu ngapType.NGAPPDU @@ -518,7 +518,7 @@ func BuildUEContextReleaseComplete(ue *context.N3IWFUe, ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId uEContextReleaseCompleteIEs.List = append(uEContextReleaseCompleteIEs.List, ie) @@ -530,7 +530,7 @@ func BuildUEContextReleaseComplete(ue *context.N3IWFUe, ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId uEContextReleaseCompleteIEs.List = append(uEContextReleaseCompleteIEs.List, ie) @@ -546,13 +546,13 @@ func BuildUEContextReleaseComplete(ue *context.N3IWFUe, userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) userLocationInfoN3IWF := userLocationInformation.UserLocationInformationN3IWF - userLocationInfoN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ue.IPAddrv4, ue.IPAddrv6) - userLocationInfoN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ue.PortNumber) + userLocationInfoN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6) + userLocationInfoN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ranUe.PortNumber) uEContextReleaseCompleteIEs.List = append(uEContextReleaseCompleteIEs.List, ie) // PDU Session Resource List (optional) - if len(ue.PduSessionList) > 0 { + if len(ranUe.PduSessionList) > 0 { ie = ngapType.UEContextReleaseCompleteIEs{} ie.Id.Value = ngapType.ProtocolIEIDPDUSessionResourceListCxtRelCpl ie.Criticality.Value = ngapType.CriticalityPresentReject @@ -562,7 +562,7 @@ func BuildUEContextReleaseComplete(ue *context.N3IWFUe, pDUSessionResourceListCxtRelCpl := ie.Value.PDUSessionResourceListCxtRelCpl // PDU Session Resource Item (in PDU Session Resource List) - for _, pduSession := range ue.PduSessionList { + for _, pduSession := range ranUe.PduSessionList { pDUSessionResourceItemCxtRelCpl := ngapType.PDUSessionResourceItemCxtRelCpl{} pDUSessionResourceItemCxtRelCpl.PDUSessionID.Value = pduSession.Id pDUSessionResourceListCxtRelCpl.List = append(pDUSessionResourceListCxtRelCpl.List, @@ -584,7 +584,7 @@ func BuildUEContextReleaseComplete(ue *context.N3IWFUe, return ngap.Encoder(pdu) } -func BuildUEContextReleaseRequest(ue *context.N3IWFUe, cause ngapType.Cause) ([]byte, error) { +func BuildUEContextReleaseRequest(ranUe *context.N3IWFRanUe, cause ngapType.Cause) ([]byte, error) { var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -607,7 +607,7 @@ func BuildUEContextReleaseRequest(ue *context.N3IWFUe, cause ngapType.Cause) ([] ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId uEContextReleaseRequestIEs.List = append(uEContextReleaseRequestIEs.List, ie) @@ -619,7 +619,7 @@ func BuildUEContextReleaseRequest(ue *context.N3IWFUe, cause ngapType.Cause) ([] ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId uEContextReleaseRequestIEs.List = append(uEContextReleaseRequestIEs.List, ie) @@ -633,7 +633,7 @@ func BuildUEContextReleaseRequest(ue *context.N3IWFUe, cause ngapType.Cause) ([] pDUSessionResourceListCxtRelReq := ie.Value.PDUSessionResourceListCxtRelReq // PDU Session Resource Item in PDU session Resource List - for _, pduSession := range ue.PduSessionList { + for _, pduSession := range ranUe.PduSessionList { pDUSessionResourceItem := ngapType.PDUSessionResourceItemCxtRelReq{} pDUSessionResourceItem.PDUSessionID.Value = pduSession.Id pDUSessionResourceListCxtRelReq.List = append(pDUSessionResourceListCxtRelReq.List, @@ -652,7 +652,7 @@ func BuildUEContextReleaseRequest(ue *context.N3IWFUe, cause ngapType.Cause) ([] return ngap.Encoder(pdu) } -func BuildInitialUEMessage(ue *context.N3IWFUe, nasPdu []byte, +func BuildInitialUEMessage(ranUe *context.N3IWFRanUe, nasPdu []byte, allowedNSSAI *ngapType.AllowedNSSAI, ) ([]byte, error) { var pdu ngapType.NGAPPDU @@ -677,7 +677,7 @@ func BuildInitialUEMessage(ue *context.N3IWFUe, nasPdu []byte, ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } @@ -707,8 +707,8 @@ func BuildInitialUEMessage(ue *context.N3IWFUe, nasPdu []byte, userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) userLocationInfoN3IWF := userLocationInformation.UserLocationInformationN3IWF - userLocationInfoN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ue.IPAddrv4, ue.IPAddrv6) - userLocationInfoN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ue.PortNumber) + userLocationInfoN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6) + userLocationInfoN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ranUe.PortNumber) initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } @@ -721,11 +721,11 @@ func BuildInitialUEMessage(ue *context.N3IWFUe, nasPdu []byte, ie.Value.RRCEstablishmentCause = new(ngapType.RRCEstablishmentCause) rRCEstablishmentCause := ie.Value.RRCEstablishmentCause - rRCEstablishmentCause.Value = aper.Enumerated(ue.RRCEstablishmentCause) + rRCEstablishmentCause.Value = aper.Enumerated(ranUe.RRCEstablishmentCause) initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } // FiveGSTMSI - if len(ue.Guti) != 0 { + if len(ranUe.Guti) != 0 { ie := ngapType.InitialUEMessageIEs{} ie.Id.Value = ngapType.ProtocolIEIDFiveGSTMSI ie.Criticality.Value = ngapType.CriticalityPresentReject @@ -735,12 +735,12 @@ func BuildInitialUEMessage(ue *context.N3IWFUe, nasPdu []byte, fiveGSTMSI := ie.Value.FiveGSTMSI var amfID string var tmsi string - if len(ue.Guti) == 19 { - amfID = ue.Guti[5:11] - tmsi = ue.Guti[11:] + if len(ranUe.Guti) == 19 { + amfID = ranUe.Guti[5:11] + tmsi = ranUe.Guti[11:] } else { - amfID = ue.Guti[6:12] - tmsi = ue.Guti[12:] + amfID = ranUe.Guti[6:12] + tmsi = ranUe.Guti[12:] } _, amfSetID, amfPointer := ngapConvert.AmfIdToNgap(amfID) @@ -754,7 +754,7 @@ func BuildInitialUEMessage(ue *context.N3IWFUe, nasPdu []byte, initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } // AMFSetID - if len(ue.Guti) != 0 { + if len(ranUe.Guti) != 0 { ie := ngapType.InitialUEMessageIEs{} ie.Id.Value = ngapType.ProtocolIEIDAMFSetID ie.Criticality.Value = ngapType.CriticalityPresentIgnore @@ -766,10 +766,10 @@ func BuildInitialUEMessage(ue *context.N3IWFUe, nasPdu []byte, // is 3 bytes, is 3 bytes // 1 byte is 2 characters var amfID string - if len(ue.Guti) == 19 { // MNC is 2 char - amfID = ue.Guti[5:11] + if len(ranUe.Guti) == 19 { // MNC is 2 char + amfID = ranUe.Guti[5:11] } else { - amfID = ue.Guti[6:12] + amfID = ranUe.Guti[6:12] } _, aMFSetID.Value, _ = ngapConvert.AmfIdToNgap(amfID) @@ -802,7 +802,7 @@ func BuildInitialUEMessage(ue *context.N3IWFUe, nasPdu []byte, return ngap.Encoder(pdu) } -func BuildUplinkNASTransport(ue *context.N3IWFUe, nasPdu []byte) ([]byte, error) { +func BuildUplinkNASTransport(ranUe *context.N3IWFRanUe, nasPdu []byte) ([]byte, error) { var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -825,7 +825,7 @@ func BuildUplinkNASTransport(ue *context.N3IWFUe, nasPdu []byte) ([]byte, error) ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId uplinkNasTransportIEs.List = append(uplinkNasTransportIEs.List, ie) @@ -837,7 +837,7 @@ func BuildUplinkNASTransport(ue *context.N3IWFUe, nasPdu []byte) ([]byte, error) ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId uplinkNasTransportIEs.List = append(uplinkNasTransportIEs.List, ie) @@ -862,15 +862,15 @@ func BuildUplinkNASTransport(ue *context.N3IWFUe, nasPdu []byte) ([]byte, error) userLocationInformation.Present = ngapType.UserLocationInformationPresentUserLocationInformationN3IWF userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) userLocationInformationN3IWF := userLocationInformation.UserLocationInformationN3IWF - userLocationInformationN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ue.IPAddrv4, ue.IPAddrv6) - userLocationInformationN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ue.PortNumber) + userLocationInformationN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6) + userLocationInformationN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ranUe.PortNumber) uplinkNasTransportIEs.List = append(uplinkNasTransportIEs.List, ie) return ngap.Encoder(pdu) } -func BuildNASNonDeliveryIndication(ue *context.N3IWFUe, nasPdu []byte, cause ngapType.Cause) ([]byte, error) { +func BuildNASNonDeliveryIndication(ranUe *context.N3IWFRanUe, nasPdu []byte, cause ngapType.Cause) ([]byte, error) { var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -893,7 +893,7 @@ func BuildNASNonDeliveryIndication(ue *context.N3IWFUe, nasPdu []byte, cause nga ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId nASNonDeliveryIndicationIEs.List = append(nASNonDeliveryIndicationIEs.List, ie) } @@ -906,7 +906,7 @@ func BuildNASNonDeliveryIndication(ue *context.N3IWFUe, nasPdu []byte, cause nga ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId nASNonDeliveryIndicationIEs.List = append(nASNonDeliveryIndicationIEs.List, ie) } @@ -944,7 +944,7 @@ func BuildRerouteNASRequest() ([]byte, error) { } func BuildPDUSessionResourceSetupResponse( - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, responseList *ngapType.PDUSessionResourceSetupListSURes, failedList *ngapType.PDUSessionResourceFailedToSetupListSURes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, @@ -971,7 +971,7 @@ func BuildPDUSessionResourceSetupResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId pduSessionResourceSetupResponseIEs.List = append(pduSessionResourceSetupResponseIEs.List, ie) @@ -983,7 +983,7 @@ func BuildPDUSessionResourceSetupResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId pduSessionResourceSetupResponseIEs.List = append(pduSessionResourceSetupResponseIEs.List, ie) @@ -1020,7 +1020,7 @@ func BuildPDUSessionResourceSetupResponse( } func BuildPDUSessionResourceModifyResponse( - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, responseList *ngapType.PDUSessionResourceModifyListModRes, failedList *ngapType.PDUSessionResourceFailedToModifyListModRes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, @@ -1045,7 +1045,7 @@ func BuildPDUSessionResourceModifyResponse( ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.PDUSessionResourceModifyResponseIEsPresentAMFUENGAPID ie.Value.AMFUENGAPID = &ngapType.AMFUENGAPID{ - Value: ue.AmfUeNgapId, + Value: ranUe.AmfUeNgapId, } pduSessionResourceModifyResponseIEs.List = append(pduSessionResourceModifyResponseIEs.List, ie) @@ -1055,7 +1055,7 @@ func BuildPDUSessionResourceModifyResponse( ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.PDUSessionResourceModifyResponseIEsPresentRANUENGAPID ie.Value.RANUENGAPID = &ngapType.RANUENGAPID{ - Value: ue.RanUeNgapId, + Value: ranUe.RanUeNgapId, } pduSessionResourceModifyResponseIEs.List = append(pduSessionResourceModifyResponseIEs.List, ie) @@ -1091,8 +1091,8 @@ func BuildPDUSessionResourceModifyResponse( userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) userLocationInformationN3IWF := userLocationInformation.UserLocationInformationN3IWF - userLocationInformationN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ue.IPAddrv4, ue.IPAddrv6) - userLocationInformationN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ue.PortNumber) + userLocationInformationN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6) + userLocationInformationN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ranUe.PortNumber) pduSessionResourceModifyResponseIEs.List = append(pduSessionResourceModifyResponseIEs.List, ie) @@ -1109,7 +1109,7 @@ func BuildPDUSessionResourceModifyResponse( } func BuildPDUSessionResourceModifyIndication( - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, modifyList []ngapType.PDUSessionResourceModifyItemModInd, ) ([]byte, error) { var pdu ngapType.NGAPPDU @@ -1134,7 +1134,7 @@ func BuildPDUSessionResourceModifyIndication( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId pDUSessionResourceModifyIndicationIEs.List = append(pDUSessionResourceModifyIndicationIEs.List, ie) } @@ -1147,7 +1147,7 @@ func BuildPDUSessionResourceModifyIndication( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId pDUSessionResourceModifyIndicationIEs.List = append(pDUSessionResourceModifyIndicationIEs.List, ie) } @@ -1169,7 +1169,7 @@ func BuildPDUSessionResourceModifyIndication( } func BuildPDUSessionResourceNotify( - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, notiList *ngapType.PDUSessionResourceNotifyList, relList *ngapType.PDUSessionResourceReleasedListNot, ) ([]byte, error) { @@ -1195,7 +1195,7 @@ func BuildPDUSessionResourceNotify( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId pDUSessionResourceNotifyIEs.List = append(pDUSessionResourceNotifyIEs.List, ie) } @@ -1208,7 +1208,7 @@ func BuildPDUSessionResourceNotify( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId pDUSessionResourceNotifyIEs.List = append(pDUSessionResourceNotifyIEs.List, ie) } @@ -1239,7 +1239,7 @@ func BuildPDUSessionResourceNotify( pDUSessionResourceNotifyIEs.List = append(pDUSessionResourceNotifyIEs.List, ie) } // UserLocationInformation - if (ue.IPAddrv4 != "" || ue.IPAddrv6 != "") && ue.PortNumber != 0 { + if (ranUe.IPAddrv4 != "" || ranUe.IPAddrv6 != "") && ranUe.PortNumber != 0 { ie := ngapType.PDUSessionResourceNotifyIEs{} ie.Id.Value = ngapType.ProtocolIEIDUserLocationInformation ie.Criticality.Value = ngapType.CriticalityPresentIgnore @@ -1250,8 +1250,8 @@ func BuildPDUSessionResourceNotify( *userLocationInformation = ngapType.UserLocationInformation{ Present: ngapType.UserLocationInformationPresentUserLocationInformationN3IWF, UserLocationInformationN3IWF: &ngapType.UserLocationInformationN3IWF{ - IPAddress: ngapConvert.IPAddressToNgap(ue.IPAddrv4, ue.IPAddrv6), - PortNumber: ngapConvert.PortNumberToNgap(ue.PortNumber), + IPAddress: ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6), + PortNumber: ngapConvert.PortNumberToNgap(ranUe.PortNumber), }, } @@ -1262,7 +1262,7 @@ func BuildPDUSessionResourceNotify( } func BuildPDUSessionResourceReleaseResponse( - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, relList ngapType.PDUSessionResourceReleasedListRelRes, diagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { @@ -1288,7 +1288,7 @@ func BuildPDUSessionResourceReleaseResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId pDUSessionResourceReleaseResponseIEs.List = append(pDUSessionResourceReleaseResponseIEs.List, ie) } @@ -1301,7 +1301,7 @@ func BuildPDUSessionResourceReleaseResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId pDUSessionResourceReleaseResponseIEs.List = append(pDUSessionResourceReleaseResponseIEs.List, ie) } @@ -1319,7 +1319,7 @@ func BuildPDUSessionResourceReleaseResponse( pDUSessionResourceReleaseResponseIEs.List = append(pDUSessionResourceReleaseResponseIEs.List, ie) } // UserLocationInformation - if (ue.IPAddrv4 != "" || ue.IPAddrv6 != "") && ue.PortNumber != 0 { + if (ranUe.IPAddrv4 != "" || ranUe.IPAddrv6 != "") && ranUe.PortNumber != 0 { ie := ngapType.PDUSessionResourceReleaseResponseIEs{} ie.Id.Value = ngapType.ProtocolIEIDUserLocationInformation ie.Criticality.Value = ngapType.CriticalityPresentIgnore @@ -1330,8 +1330,8 @@ func BuildPDUSessionResourceReleaseResponse( *userLocationInformation = ngapType.UserLocationInformation{ Present: ngapType.UserLocationInformationPresentUserLocationInformationN3IWF, UserLocationInformationN3IWF: &ngapType.UserLocationInformationN3IWF{ - IPAddress: ngapConvert.IPAddressToNgap(ue.IPAddrv4, ue.IPAddrv6), - PortNumber: ngapConvert.PortNumberToNgap(ue.PortNumber), + IPAddress: ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6), + PortNumber: ngapConvert.PortNumberToNgap(ranUe.PortNumber), }, } @@ -1421,7 +1421,7 @@ func BuildUERadioCapabilityInfoIndication() ([]byte, error) { } func BuildUERadioCapabilityCheckResponse( - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, diagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { var pdu ngapType.NGAPPDU @@ -1446,7 +1446,7 @@ func BuildUERadioCapabilityCheckResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ue.AmfUeNgapId + aMFUENGAPID.Value = ranUe.AmfUeNgapId uERadioCapabilityCheckResponseIEs.List = append(uERadioCapabilityCheckResponseIEs.List, ie) } // RANUENGAPID @@ -1458,7 +1458,7 @@ func BuildUERadioCapabilityCheckResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ue.RanUeNgapId + rANUENGAPID.Value = ranUe.RanUeNgapId uERadioCapabilityCheckResponseIEs.List = append(uERadioCapabilityCheckResponseIEs.List, ie) } // IMSVoiceSupportIndicator @@ -1470,7 +1470,7 @@ func BuildUERadioCapabilityCheckResponse( ie.Value.IMSVoiceSupportIndicator = new(ngapType.IMSVoiceSupportIndicator) iMSVoiceSupportIndicator := ie.Value.IMSVoiceSupportIndicator - iMSVoiceSupportIndicator.Value = aper.Enumerated(ue.IMSVoiceSupported) + iMSVoiceSupportIndicator.Value = aper.Enumerated(ranUe.IMSVoiceSupported) uERadioCapabilityCheckResponseIEs.List = append(uERadioCapabilityCheckResponseIEs.List, ie) } // CriticalityDiagnostics diff --git a/internal/ngap/message/send.go b/internal/ngap/message/send.go index 1a3944b..fafaf26 100644 --- a/internal/ngap/message/send.go +++ b/internal/ngap/message/send.go @@ -4,27 +4,20 @@ import ( "runtime/debug" "git.cs.nctu.edu.tw/calee/sctp" - "github.com/sirupsen/logrus" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/ngap/ngapType" ) -var ngaplog *logrus.Entry - -func init() { - ngaplog = logger.NgapLog -} - func SendToAmf(amf *context.N3IWFAMF, pkt []byte) { if amf == nil { - ngaplog.Errorf("[N3IWF] AMF Context is nil ") + logger.NgapLog.Errorf("[N3IWF] AMF Context is nil ") } else { if n, err := amf.SCTPConn.Write(pkt); err != nil { - ngaplog.Errorf("Write to SCTP socket failed: %+v", err) + logger.NgapLog.Errorf("Write to SCTP socket failed: %+v", err) } else { - ngaplog.Tracef("Wrote %d bytes", n) + logger.NgapLog.Tracef("Wrote %d bytes", n) } } } @@ -37,24 +30,26 @@ func SendNGSetupRequest(conn *sctp.SCTPConn) { } }() - ngaplog.Infoln("[N3IWF] Send NG Setup Request") + logger.NgapLog.Infoln("[N3IWF] Send NG Setup Request") sctpAddr := conn.RemoteAddr().String() if available, _ := context.N3IWFSelf().AMFReInitAvailableListLoad(sctpAddr); !available { - ngaplog.Warnf("[N3IWF] Please Wait at least for the indicated time before reinitiating toward same AMF[%s]", sctpAddr) + logger.NgapLog.Warnf( + "[N3IWF] Please Wait at least for the indicated time before reinitiating toward same AMF[%s]", + sctpAddr) return } pkt, err := BuildNGSetupRequest() if err != nil { - ngaplog.Errorf("Build NGSetup Request failed: %+v\n", err) + logger.NgapLog.Errorf("Build NGSetup Request failed: %+v\n", err) return } if n, err := conn.Write(pkt); err != nil { - ngaplog.Errorf("Write to SCTP socket failed: %+v", err) + logger.NgapLog.Errorf("Write to SCTP socket failed: %+v", err) } else { - ngaplog.Tracef("Wrote %d bytes", n) + logger.NgapLog.Tracef("Wrote %d bytes", n) } } @@ -64,11 +59,11 @@ func SendNGReset( cause ngapType.Cause, partOfNGInterface *ngapType.UEAssociatedLogicalNGConnectionList, ) { - ngaplog.Infoln("[N3IWF] Send NG Reset") + logger.NgapLog.Infoln("[N3IWF] Send NG Reset") pkt, err := BuildNGReset(cause, partOfNGInterface) if err != nil { - ngaplog.Errorf("Build NGReset failed : %s", err.Error()) + logger.NgapLog.Errorf("Build NGReset failed : %s", err.Error()) return } @@ -80,16 +75,16 @@ func SendNGResetAcknowledge( partOfNGInterface *ngapType.UEAssociatedLogicalNGConnectionList, diagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send NG Reset Acknowledge") + logger.NgapLog.Infoln("[N3IWF] Send NG Reset Acknowledge") if partOfNGInterface != nil && len(partOfNGInterface.List) == 0 { - ngaplog.Error("length of partOfNGInterface is 0") + logger.NgapLog.Error("length of partOfNGInterface is 0") return } pkt, err := BuildNGResetAcknowledge(partOfNGInterface, diagnostics) if err != nil { - ngaplog.Errorf("Build NGReset Acknowledge failed : %s", err.Error()) + logger.NgapLog.Errorf("Build NGReset Acknowledge failed : %s", err.Error()) return } @@ -97,300 +92,289 @@ func SendNGResetAcknowledge( } func SendInitialContextSetupResponse( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, responseList *ngapType.PDUSessionResourceSetupListCxtRes, failedList *ngapType.PDUSessionResourceFailedToSetupListCxtRes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send Initial Context Setup Response") + logger.NgapLog.Infoln("[N3IWF] Send Initial Context Setup Response") if responseList != nil && len(responseList.List) > context.MaxNumOfPDUSessions { - ngaplog.Errorln("Pdu List out of range") + logger.NgapLog.Errorln("Pdu List out of range") return } if failedList != nil && len(failedList.List) > context.MaxNumOfPDUSessions { - ngaplog.Errorln("Pdu List out of range") + logger.NgapLog.Errorln("Pdu List out of range") return } - pkt, err := BuildInitialContextSetupResponse(ue, responseList, failedList, criticalityDiagnostics) + pkt, err := BuildInitialContextSetupResponse(ranUe, responseList, failedList, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build Initial Context Setup Response failed : %+v\n", err) + logger.NgapLog.Errorf("Build Initial Context Setup Response failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendInitialContextSetupFailure( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, cause ngapType.Cause, failedList *ngapType.PDUSessionResourceFailedToSetupListCxtFail, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send Initial Context Setup Failure") + logger.NgapLog.Infoln("[N3IWF] Send Initial Context Setup Failure") if failedList != nil && len(failedList.List) > context.MaxNumOfPDUSessions { - ngaplog.Errorln("Pdu List out of range") + logger.NgapLog.Errorln("Pdu List out of range") return } - pkt, err := BuildInitialContextSetupFailure(ue, cause, failedList, criticalityDiagnostics) + pkt, err := BuildInitialContextSetupFailure(ranUe, cause, failedList, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build Initial Context Setup Failure failed : %+v\n", err) + logger.NgapLog.Errorf("Build Initial Context Setup Failure failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendUEContextModificationResponse( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send UE Context Modification Response") + logger.NgapLog.Infoln("[N3IWF] Send UE Context Modification Response") - pkt, err := BuildUEContextModificationResponse(ue, criticalityDiagnostics) + pkt, err := BuildUEContextModificationResponse(ranUe, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build UE Context Modification Response failed : %+v\n", err) + logger.NgapLog.Errorf("Build UE Context Modification Response failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendUEContextModificationFailure( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, cause ngapType.Cause, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send UE Context Modification Failure") + logger.NgapLog.Infoln("[N3IWF] Send UE Context Modification Failure") - pkt, err := BuildUEContextModificationFailure(ue, cause, criticalityDiagnostics) + pkt, err := BuildUEContextModificationFailure(ranUe, cause, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build UE Context Modification Failure failed : %+v\n", err) + logger.NgapLog.Errorf("Build UE Context Modification Failure failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendUEContextReleaseComplete( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send UE Context Release Complete") + logger.NgapLog.Infoln("[N3IWF] Send UE Context Release Complete") - pkt, err := BuildUEContextReleaseComplete(ue, criticalityDiagnostics) + pkt, err := BuildUEContextReleaseComplete(ranUe, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build UE Context Release Complete failed : %+v\n", err) + logger.NgapLog.Errorf("Build UE Context Release Complete failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendUEContextReleaseRequest( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, cause ngapType.Cause, + ranUe *context.N3IWFRanUe, cause ngapType.Cause, ) { - ngaplog.Infoln("[N3IWF] Send UE Context Release Request") + logger.NgapLog.Infoln("[N3IWF] Send UE Context Release Request") - pkt, err := BuildUEContextReleaseRequest(ue, cause) + pkt, err := BuildUEContextReleaseRequest(ranUe, cause) if err != nil { - ngaplog.Errorf("Build UE Context Release Request failed : %+v\n", err) + logger.NgapLog.Errorf("Build UE Context Release Request failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendInitialUEMessage(amf *context.N3IWFAMF, - ue *context.N3IWFUe, nasPdu []byte, + ranUe *context.N3IWFRanUe, nasPdu []byte, ) { - ngaplog.Infoln("[N3IWF] Send Initial UE Message") + logger.NgapLog.Infoln("[N3IWF] Send Initial UE Message") // Attach To AMF - pkt, err := BuildInitialUEMessage(ue, nasPdu, nil) + pkt, err := BuildInitialUEMessage(ranUe, nasPdu, nil) if err != nil { - ngaplog.Errorf("Build Initial UE Message failed : %+v\n", err) + logger.NgapLog.Errorf("Build Initial UE Message failed : %+v\n", err) return } - SendToAmf(amf, pkt) - // ue.AttachAMF() + SendToAmf(ranUe.AMF, pkt) + // ranUe.AttachAMF() } func SendUplinkNASTransport( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, nasPdu []byte, ) { - ngaplog.Infoln("[N3IWF] Send Uplink NAS Transport") + logger.NgapLog.Infoln("[N3IWF] Send Uplink NAS Transport") if len(nasPdu) == 0 { - ngaplog.Errorln("NAS Pdu is nil") + logger.NgapLog.Errorln("NAS Pdu is nil") return } - pkt, err := BuildUplinkNASTransport(ue, nasPdu) + pkt, err := BuildUplinkNASTransport(ranUe, nasPdu) if err != nil { - ngaplog.Errorf("Build Uplink NAS Transport failed : %+v\n", err) + logger.NgapLog.Errorf("Build Uplink NAS Transport failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendNASNonDeliveryIndication( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, nasPdu []byte, cause ngapType.Cause, ) { - ngaplog.Infoln("[N3IWF] Send NAS NonDelivery Indication") + logger.NgapLog.Infoln("[N3IWF] Send NAS NonDelivery Indication") if len(nasPdu) == 0 { - ngaplog.Errorln("NAS Pdu is nil") + logger.NgapLog.Errorln("NAS Pdu is nil") return } - pkt, err := BuildNASNonDeliveryIndication(ue, nasPdu, cause) + pkt, err := BuildNASNonDeliveryIndication(ranUe, nasPdu, cause) if err != nil { - ngaplog.Errorf("Build Uplink NAS Transport failed : %+v\n", err) + logger.NgapLog.Errorf("Build Uplink NAS Transport failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendRerouteNASRequest() { - ngaplog.Infoln("[N3IWF] Send Reroute NAS Request") + logger.NgapLog.Infoln("[N3IWF] Send Reroute NAS Request") } func SendPDUSessionResourceSetupResponse( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, responseList *ngapType.PDUSessionResourceSetupListSURes, failedListSURes *ngapType.PDUSessionResourceFailedToSetupListSURes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send PDU Session Resource Setup Response") + logger.NgapLog.Infoln("[N3IWF] Send PDU Session Resource Setup Response") - if ue == nil { - ngaplog.Error("UE context is nil, this information is mandatory.") + if ranUe == nil { + logger.NgapLog.Error("UE context is nil, this information is mandatory.") return } - pkt, err := BuildPDUSessionResourceSetupResponse(ue, responseList, failedListSURes, criticalityDiagnostics) + pkt, err := BuildPDUSessionResourceSetupResponse(ranUe, responseList, failedListSURes, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build PDU Session Resource Setup Response failed : %+v", err) + logger.NgapLog.Errorf("Build PDU Session Resource Setup Response failed : %+v", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendPDUSessionResourceModifyResponse( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, responseList *ngapType.PDUSessionResourceModifyListModRes, failedList *ngapType.PDUSessionResourceFailedToModifyListModRes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send PDU Session Resource Modify Response") + logger.NgapLog.Infoln("[N3IWF] Send PDU Session Resource Modify Response") - if ue == nil && criticalityDiagnostics == nil { - ngaplog.Error("UE context is nil, this information is mandatory") + if ranUe == nil && criticalityDiagnostics == nil { + logger.NgapLog.Error("UE context is nil, this information is mandatory") return } - pkt, err := BuildPDUSessionResourceModifyResponse(ue, responseList, failedList, criticalityDiagnostics) + pkt, err := BuildPDUSessionResourceModifyResponse(ranUe, responseList, failedList, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build PDU Session Resource Modify Response failed : %+v", err) + logger.NgapLog.Errorf("Build PDU Session Resource Modify Response failed : %+v", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendPDUSessionResourceModifyIndication( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, modifyList []ngapType.PDUSessionResourceModifyItemModInd, ) { - ngaplog.Infoln("[N3IWF] Send PDU Session Resource Modify Indication") + logger.NgapLog.Infoln("[N3IWF] Send PDU Session Resource Modify Indication") - if ue == nil { - ngaplog.Error("UE context is nil, this information is mandatory") + if ranUe == nil { + logger.NgapLog.Error("UE context is nil, this information is mandatory") return } if modifyList == nil { - ngaplog.Errorln("PDU Session Resource Modify Indication List is nil. This message shall contain at least one Item") + logger.NgapLog.Errorln( + "PDU Session Resource Modify Indication List is nil. This message shall contain at least one Item") return } - pkt, err := BuildPDUSessionResourceModifyIndication(ue, modifyList) + pkt, err := BuildPDUSessionResourceModifyIndication(ranUe, modifyList) if err != nil { - ngaplog.Errorf("Build PDU Session Resource Modify Indication failed : %+v", err) + logger.NgapLog.Errorf("Build PDU Session Resource Modify Indication failed : %+v", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendPDUSessionResourceNotify( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, notiList *ngapType.PDUSessionResourceNotifyList, relList *ngapType.PDUSessionResourceReleasedListNot, ) { - ngaplog.Infoln("[N3IWF] Send PDU Session Resource Notify") + logger.NgapLog.Infoln("[N3IWF] Send PDU Session Resource Notify") - if ue == nil { - ngaplog.Error("UE context is nil, this information is mandatory") + if ranUe == nil { + logger.NgapLog.Error("UE context is nil, this information is mandatory") return } - pkt, err := BuildPDUSessionResourceNotify(ue, notiList, relList) + pkt, err := BuildPDUSessionResourceNotify(ranUe, notiList, relList) if err != nil { - ngaplog.Errorf("Build PDUSession Resource Notify failed : %+v", err) + logger.NgapLog.Errorf("Build PDUSession Resource Notify failed : %+v", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendPDUSessionResourceReleaseResponse( - amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, relList ngapType.PDUSessionResourceReleasedListRelRes, diagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send PDU Session Resource Release Response") + logger.NgapLog.Infoln("[N3IWF] Send PDU Session Resource Release Response") - if ue == nil { - ngaplog.Error("UE context is nil, this information is mandatory") + if ranUe == nil { + logger.NgapLog.Error("UE context is nil, this information is mandatory") return } if len(relList.List) < 1 { - ngaplog.Errorln("PDUSessionResourceReleasedListRelRes is nil. This message shall contain at least one Item") + logger.NgapLog.Errorln( + "PDUSessionResourceReleasedListRelRes is nil. This message shall contain at least one Item") return } - pkt, err := BuildPDUSessionResourceReleaseResponse(ue, relList, diagnostics) + pkt, err := BuildPDUSessionResourceReleaseResponse(ranUe, relList, diagnostics) if err != nil { - ngaplog.Errorf("Build PDU Session Resource Release Response failed : %+v", err) + logger.NgapLog.Errorf("Build PDU Session Resource Release Response failed : %+v", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendErrorIndication( @@ -400,16 +384,16 @@ func SendErrorIndication( cause *ngapType.Cause, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send Error Indication") + logger.NgapLog.Infoln("[N3IWF] Send Error Indication") if (cause == nil) && (criticalityDiagnostics == nil) { - ngaplog.Errorln("Both cause and criticality is nil. This message shall contain at least one of them.") + logger.NgapLog.Errorln("Both cause and criticality is nil. This message shall contain at least one of them.") return } pkt, err := BuildErrorIndication(amfUENGAPID, ranUENGAPID, cause, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build Error Indication failed : %+v\n", err) + logger.NgapLog.Errorf("Build Error Indication failed : %+v\n", err) return } @@ -423,43 +407,43 @@ func SendErrorIndicationWithSctpConn( cause *ngapType.Cause, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send Error Indication") + logger.NgapLog.Infoln("[N3IWF] Send Error Indication") if (cause == nil) && (criticalityDiagnostics == nil) { - ngaplog.Errorln("Both cause and criticality is nil. This message shall contain at least one of them.") + logger.NgapLog.Errorln("Both cause and criticality is nil. This message shall contain at least one of them.") return } pkt, err := BuildErrorIndication(amfUENGAPID, ranUENGAPID, cause, criticalityDiagnostics) if err != nil { - ngaplog.Errorf("Build Error Indication failed : %+v\n", err) + logger.NgapLog.Errorf("Build Error Indication failed : %+v\n", err) return } if n, err := sctpConn.Write(pkt); err != nil { - ngaplog.Errorf("Write to SCTP socket failed: %+v", err) + logger.NgapLog.Errorf("Write to SCTP socket failed: %+v", err) } else { - ngaplog.Tracef("Wrote %d bytes", n) + logger.NgapLog.Tracef("Wrote %d bytes", n) } } func SendUERadioCapabilityInfoIndication() { - ngaplog.Infoln("[N3IWF] Send UE Radio Capability Info Indication") + logger.NgapLog.Infoln("[N3IWF] Send UE Radio Capability Info Indication") } func SendUERadioCapabilityCheckResponse( amf *context.N3IWFAMF, - ue *context.N3IWFUe, + ranUe *context.N3IWFRanUe, diagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send UE Radio Capability Check Response") + logger.NgapLog.Infoln("[N3IWF] Send UE Radio Capability Check Response") - pkt, err := BuildUERadioCapabilityCheckResponse(ue, diagnostics) + pkt, err := BuildUERadioCapabilityCheckResponse(ranUe, diagnostics) if err != nil { - ngaplog.Errorf("Build UERadio Capability Check Response failed : %+v\n", err) + logger.NgapLog.Errorf("Build UERadio Capability Check Response failed : %+v\n", err) return } - SendToAmf(amf, pkt) + SendToAmf(ranUe.AMF, pkt) } func SendAMFConfigurationUpdateAcknowledge( @@ -468,11 +452,11 @@ func SendAMFConfigurationUpdateAcknowledge( failList *ngapType.TNLAssociationList, diagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send AMF Configuration Update Acknowledge") + logger.NgapLog.Infoln("[N3IWF] Send AMF Configuration Update Acknowledge") pkt, err := BuildAMFConfigurationUpdateAcknowledge(setupList, failList, diagnostics) if err != nil { - ngaplog.Errorf("Build AMF Configuration Update Acknowledge failed : %+v\n", err) + logger.NgapLog.Errorf("Build AMF Configuration Update Acknowledge failed : %+v\n", err) return } @@ -485,10 +469,10 @@ func SendAMFConfigurationUpdateFailure( time *ngapType.TimeToWait, diagnostics *ngapType.CriticalityDiagnostics, ) { - ngaplog.Infoln("[N3IWF] Send AMF Configuration Update Failure") + logger.NgapLog.Infoln("[N3IWF] Send AMF Configuration Update Failure") pkt, err := BuildAMFConfigurationUpdateFailure(ngCause, time, diagnostics) if err != nil { - ngaplog.Errorf("Build AMF Configuration Update Failure failed : %+v\n", err) + logger.NgapLog.Errorf("Build AMF Configuration Update Failure failed : %+v\n", err) return } @@ -496,17 +480,18 @@ func SendAMFConfigurationUpdateFailure( } func SendRANConfigurationUpdate(amf *context.N3IWFAMF) { - ngaplog.Infoln("[N3IWF] Send RAN Configuration Update") + logger.NgapLog.Infoln("[N3IWF] Send RAN Configuration Update") if available, _ := context.N3IWFSelf().AMFReInitAvailableListLoad(amf.SCTPAddr); !available { - ngaplog.Warnf( - "[N3IWF] Please Wait at least for the indicated time before reinitiating toward same AMF[%s]", amf.SCTPAddr) + logger.NgapLog.Warnf( + "[N3IWF] Please Wait at least for the indicated time before reinitiating toward same AMF[%s]", + amf.SCTPAddr) return } pkt, err := BuildRANConfigurationUpdate() if err != nil { - ngaplog.Errorf("Build AMF Configuration Update Failure failed : %+v\n", err) + logger.NgapLog.Errorf("Build AMF Configuration Update Failure failed : %+v\n", err) return } @@ -514,21 +499,21 @@ func SendRANConfigurationUpdate(amf *context.N3IWFAMF) { } func SendUplinkRANConfigurationTransfer() { - ngaplog.Infoln("[N3IWF] Send Uplink RAN Configuration Transfer") + logger.NgapLog.Infoln("[N3IWF] Send Uplink RAN Configuration Transfer") } func SendUplinkRANStatusTransfer() { - ngaplog.Infoln("[N3IWF] Send Uplink RAN Status Transfer") + logger.NgapLog.Infoln("[N3IWF] Send Uplink RAN Status Transfer") } func SendLocationReportingFailureIndication() { - ngaplog.Infoln("[N3IWF] Send Location Reporting Failure Indication") + logger.NgapLog.Infoln("[N3IWF] Send Location Reporting Failure Indication") } func SendLocationReport() { - ngaplog.Infoln("[N3IWF] Send Location Report") + logger.NgapLog.Infoln("[N3IWF] Send Location Report") } func SendRRCInactiveTransitionReport() { - ngaplog.Infoln("[N3IWF] Send RRC Inactive Transition Report") + logger.NgapLog.Infoln("[N3IWF] Send RRC Inactive Transition Report") } diff --git a/internal/ngap/message/types.go b/internal/ngap/message/types.go new file mode 100644 index 0000000..a7f7e0d --- /dev/null +++ b/internal/ngap/message/types.go @@ -0,0 +1,26 @@ +package message + +// Used in AN-Parameter field for IE types +const ( + ANParametersTypeGUAMI = 1 + ANParametersTypeSelectedPLMNID = 2 + ANParametersTypeRequestedNSSAI = 3 + ANParametersTypeEstablishmentCause = 4 +) + +// Used for checking if AN-Parameter length field is legal +const ( + ANParametersLenGUAMI = 6 + ANParametersLenPLMNID = 3 + ANParametersLenEstCause = 1 +) + +// Used in IE Establishment Cause field for cause types +const ( + EstablishmentCauseEmergency = 0 + EstablishmentCauseHighPriorityAccess = 1 + EstablishmentCauseMO_Signalling = 3 + EstablishmentCauseMO_Data = 4 + EstablishmentCauseMPS_PriorityAccess = 8 + EstablishmentCauseMCS_PriorityAccess = 9 +) diff --git a/internal/ngap/service/service.go b/internal/ngap/service/service.go index 81d8516..58e909e 100644 --- a/internal/ngap/service/service.go +++ b/internal/ngap/service/service.go @@ -4,26 +4,26 @@ import ( "errors" "io" "runtime/debug" + "sync" "time" "git.cs.nctu.edu.tw/calee/sctp" - "github.com/sirupsen/logrus" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/internal/ngap" + "github.com/free5gc/n3iwf/internal/ngap/handler" "github.com/free5gc/n3iwf/internal/ngap/message" "github.com/free5gc/n3iwf/pkg/context" lib_ngap "github.com/free5gc/ngap" ) -var ngapLog *logrus.Entry - -func init() { - ngapLog = logger.NgapLog -} +var ( + RECEIVE_NGAPPACKET_CHANNEL_LEN = 512 + RECEIVE_NGAPEVENT_CHANNEL_LEN = 512 +) // Run start the N3IWF SCTP process. -func Run() error { +func Run(wg *sync.WaitGroup) error { // n3iwf context n3iwfSelf := context.N3IWFSelf() // load amf SCTP address slice @@ -31,24 +31,65 @@ func Run() error { localAddr := new(sctp.SCTPAddr) + n3iwfSelf.NGAPServer = NewNGAPServer() for _, remoteAddr := range amfSCTPAddresses { errChan := make(chan error) - go listenAndServe(localAddr, remoteAddr, errChan) + wg.Add(1) + go Receiver(localAddr, remoteAddr, errChan, n3iwfSelf.NGAPServer, wg) if err, ok := <-errChan; ok { - ngapLog.Errorln(err) + logger.NgapLog.Errorln(err) return errors.New("NGAP service run failed") } } + wg.Add(1) + go server(n3iwfSelf.NGAPServer, wg) + return nil } -func listenAndServe(localAddr, remoteAddr *sctp.SCTPAddr, errChan chan<- error) { +func NewNGAPServer() *context.NGAPServer { + return &context.NGAPServer{ + RcvNgapPktCh: make(chan context.ReceiveNGAPPacket, RECEIVE_NGAPPACKET_CHANNEL_LEN), + RcvEventCh: make(chan context.NgapEvt, RECEIVE_NGAPEVENT_CHANNEL_LEN), + } +} + +func server(ngapServer *context.NGAPServer, wg *sync.WaitGroup) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. logger.NgapLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } + logger.NgapLog.Infof("NGAP server stopped") + close(ngapServer.RcvEventCh) + close(ngapServer.RcvNgapPktCh) + wg.Done() + }() + + for { + select { + case rcvPkt := <-ngapServer.RcvNgapPktCh: + if len(rcvPkt.Buf) == 0 { // receiver closed + return + } + ngap.NGAPDispatch(rcvPkt.Conn, rcvPkt.Buf) + case rcvEvt := <-ngapServer.RcvEventCh: + handler.HandleEvent(rcvEvt) + } + } +} + +func Receiver(localAddr, remoteAddr *sctp.SCTPAddr, errChan chan<- error, ngapServer *context.NGAPServer, + wg *sync.WaitGroup, +) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NgapLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + logger.NgapLog.Infof("NGAP receiver stopped") + wg.Done() }() var conn *sctp.SCTPConn @@ -57,16 +98,16 @@ func listenAndServe(localAddr, remoteAddr *sctp.SCTPAddr, errChan chan<- error) for i := 0; i < 3; i++ { conn, err = sctp.DialSCTP("sctp", localAddr, remoteAddr) if err != nil { - ngapLog.Errorf("[SCTP] DialSCTP(): %+v", err) + logger.NgapLog.Errorf("[SCTP] DialSCTP(): %+v", err) } else { break } if i != 2 { - ngapLog.Info("Retry to connect AMF after 1 second...") + logger.NgapLog.Info("Retry to connect AMF after 1 second...") time.Sleep(1 * time.Second) } else { - ngapLog.Debugf("[SCTP] AMF SCTP address: %+v", remoteAddr.String()) + logger.NgapLog.Debugf("[SCTP] AMF SCTP address: %s", remoteAddr) errChan <- errors.New("Failed to connect to AMF.") return } @@ -75,10 +116,10 @@ func listenAndServe(localAddr, remoteAddr *sctp.SCTPAddr, errChan chan<- error) // Set default sender SCTP information sinfo_ppid = NGAP_PPID = 60 info, err := conn.GetDefaultSentParam() if err != nil { - ngapLog.Errorf("[SCTP] GetDefaultSentParam(): %+v", err) + logger.NgapLog.Errorf("[SCTP] GetDefaultSentParam(): %+v", err) errConn := conn.Close() if errConn != nil { - ngapLog.Errorf("conn close error in GetDefaultSentParam(): %+v", errConn) + logger.NgapLog.Errorf("conn close error in GetDefaultSentParam(): %+v", errConn) } errChan <- errors.New("Get socket information failed.") return @@ -86,10 +127,10 @@ func listenAndServe(localAddr, remoteAddr *sctp.SCTPAddr, errChan chan<- error) info.PPID = lib_ngap.PPID err = conn.SetDefaultSentParam(info) if err != nil { - ngapLog.Errorf("[SCTP] SetDefaultSentParam(): %+v", err) + logger.NgapLog.Errorf("[SCTP] SetDefaultSentParam(): %+v", err) errConn := conn.Close() if errConn != nil { - ngapLog.Errorf("conn close error in SetDefaultSentParam(): %+v", errConn) + logger.NgapLog.Errorf("conn close error in SetDefaultSentParam(): %+v", errConn) } errChan <- errors.New("Set socket parameter failed.") return @@ -98,48 +139,63 @@ func listenAndServe(localAddr, remoteAddr *sctp.SCTPAddr, errChan chan<- error) // Subscribe receiver SCTP information err = conn.SubscribeEvents(sctp.SCTP_EVENT_DATA_IO) if err != nil { - ngapLog.Errorf("[SCTP] SubscribeEvents(): %+v", err) + logger.NgapLog.Errorf("[SCTP] SubscribeEvents(): %+v", err) errConn := conn.Close() if errConn != nil { - ngapLog.Errorf("conn close error in SubscribeEvents(): %+v", errConn) + logger.NgapLog.Errorf("conn close error in SubscribeEvents(): %+v", errConn) } errChan <- errors.New("Subscribe SCTP event failed.") return } // Send NG setup request - go message.SendNGSetupRequest(conn) + message.SendNGSetupRequest(conn) close(errChan) - data := make([]byte, 65535) + ngapServer.Conn = append(ngapServer.Conn, conn) + data := make([]byte, 65535) for { n, info, _, err := conn.SCTPRead(data) if err != nil { - ngapLog.Debugf("[SCTP] AMF SCTP address: %+v", conn.RemoteAddr().String()) + logger.NgapLog.Debugf("[SCTP] AMF SCTP address: %s", remoteAddr) if err == io.EOF || err == io.ErrUnexpectedEOF { - ngapLog.Warn("[SCTP] Close connection.") + logger.NgapLog.Warn("[SCTP] Close connection.") errConn := conn.Close() if errConn != nil { - ngapLog.Errorf("conn close error: %+v", errConn) + logger.NgapLog.Errorf("conn close error: %+v", errConn) } + ngapServer.RcvNgapPktCh <- context.ReceiveNGAPPacket{} return } - ngapLog.Errorf("[SCTP] Read from SCTP connection failed: %+v", err) + logger.NgapLog.Errorf("[SCTP] Read from SCTP connection failed: %+v", err) } else { - ngapLog.Tracef("[SCTP] Successfully read %d bytes.", n) + logger.NgapLog.Tracef("[SCTP] Successfully read %d bytes.", n) if info == nil || info.PPID != lib_ngap.PPID { - ngapLog.Warn("Received SCTP PPID != 60") + logger.NgapLog.Warn("Received SCTP PPID != 60") continue } forwardData := make([]byte, n) copy(forwardData, data[:n]) - go ngap.Dispatch(conn, forwardData) + ngapServer.RcvNgapPktCh <- context.ReceiveNGAPPacket{ + Conn: conn, + Buf: forwardData[:n], + } + } + } +} + +func Stop(n3iwfContext *context.N3IWFContext) { + logger.NgapLog.Infof("Close NGAP server....") + + for _, ngapServerConn := range n3iwfContext.NGAPServer.Conn { + if err := ngapServerConn.Close(); err != nil { + logger.NgapLog.Errorf("Stop ngap server error : %+v", err) } } } diff --git a/internal/nwucp/service/service.go b/internal/nwucp/service/service.go index 283d6ff..6fb8e3b 100644 --- a/internal/nwucp/service/service.go +++ b/internal/nwucp/service/service.go @@ -8,36 +8,34 @@ import ( "net" "runtime/debug" "strings" - - "github.com/sirupsen/logrus" + "sync" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/internal/ngap/message" "github.com/free5gc/n3iwf/pkg/context" ) -var nwucpLog *logrus.Entry - -func init() { - nwucpLog = logger.NWuCPLog -} +var tcpListener net.Listener // Run setup N3IWF NAS for UE to forward NAS message // to AMF -func Run() error { +func Run(wg *sync.WaitGroup) error { // N3IWF context n3iwfSelf := context.N3IWFSelf() tcpAddr := fmt.Sprintf("%s:%d", n3iwfSelf.IPSecGatewayAddress, n3iwfSelf.TCPPort) - tcpListener, err := net.Listen("tcp", tcpAddr) + listener, err := net.Listen("tcp", tcpAddr) if err != nil { - nwucpLog.Errorf("Listen TCP address failed: %+v", err) + logger.NWuCPLog.Errorf("Listen TCP address failed: %+v", err) return errors.New("Listen failed") } - nwucpLog.Tracef("Successfully listen %+v", tcpAddr) + tcpListener = listener - go listenAndServe(tcpListener) + logger.NWuCPLog.Tracef("Successfully listen %+v", tcpAddr) + + wg.Add(1) + go listenAndServe(tcpListener, wg) return nil } @@ -46,7 +44,7 @@ func Run() error { // requests. It also stores accepted connection into UE // context, and finally, call serveConn() to serve the messages // received from the connection. -func listenAndServe(tcpListener net.Listener) { +func listenAndServe(listener net.Listener, wg *sync.WaitGroup) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. @@ -55,46 +53,45 @@ func listenAndServe(tcpListener net.Listener) { err := tcpListener.Close() if err != nil { - nwucpLog.Errorf("Error closing tcpListener: %+v", err) + logger.NWuCPLog.Errorf("Error closing tcpListener: %+v", err) } + wg.Done() }() for { - connection, err := tcpListener.Accept() + connection, err := listener.Accept() if err != nil { - nwucpLog.Error("TCP server accept failed. Close the listener...") + logger.NWuCPLog.Errorf("TCP server accept failed : %+v. Close the listener...", err) return } - nwucpLog.Tracef("Accepted one UE from %+v", connection.RemoteAddr()) + logger.NWuCPLog.Tracef("Accepted one UE from %+v", connection.RemoteAddr()) // Find UE context and store this connection in to it, then check if // there is any cached NAS message for this UE. If yes, send to it. n3iwfSelf := context.N3IWFSelf() ueIP := strings.Split(connection.RemoteAddr().String(), ":")[0] - ue, ok := n3iwfSelf.AllocatedUEIPAddressLoad(ueIP) + ikeUe, ok := n3iwfSelf.AllocatedUEIPAddressLoad(ueIP) if !ok { - nwucpLog.Errorf("UE context not found for peer %+v", ueIP) + logger.NWuCPLog.Errorf("UE context not found for peer %+v", ueIP) continue } - // Store connection - ue.TCPConnection = connection - - if ue.TemporaryCachedNASMessage != nil { - // Send to UE - if n, err := connection.Write(ue.TemporaryCachedNASMessage); err != nil { - nwucpLog.Errorf("Writing via IPSec signalling SA failed: %+v", err) - } else { - nwucpLog.Trace("Forward NWu <- N2") - nwucpLog.Tracef("Wrote %d bytes", n) - } - // Clean the cached message - ue.TemporaryCachedNASMessage = nil + ranUe, err := n3iwfSelf.RanUeLoadFromIkeSPI(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + if err != nil { + logger.NWuCPLog.Errorf("RanUe context not found : %+v", err) + continue } + // Store connection + ranUe.TCPConnection = connection - go serveConn(ue, connection) + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewNASTCPConnEstablishedCompleteEvt( + ranUe.RanUeNgapId, + ) + + wg.Add(1) + go serveConn(ranUe, connection, wg) } } @@ -113,10 +110,29 @@ func decapNasMsgFromEnvelope(envelop []byte) []byte { return nasMsg } +func Stop(n3iwfContext *context.N3IWFContext) { + logger.NWuCPLog.Infof("Close Nwucp server...") + + if err := tcpListener.Close(); err != nil { + logger.NWuCPLog.Errorf("Stop nwuup server error : %+v", err) + } + + n3iwfContext.RANUePool.Range( + func(key, value interface{}) bool { + ranUe := value.(*context.N3IWFRanUe) + if ranUe.TCPConnection != nil { + if err := ranUe.TCPConnection.Close(); err != nil { + logger.InitLog.Errorf("Stop nwucp server error : %+v", err) + } + } + return true + }) +} + // serveConn handle accepted TCP connection. It reads NAS packets // from the connection and call forward() to forward NAS messages // to AMF -func serveConn(ue *context.N3IWFUe, connection net.Conn) { +func serveConn(ranUe *context.N3IWFRanUe, connection net.Conn, wg *sync.WaitGroup) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. @@ -125,41 +141,40 @@ func serveConn(ue *context.N3IWFUe, connection net.Conn) { err := connection.Close() if err != nil { - nwucpLog.Errorf("Error closing connection: %+v", err) + logger.NWuCPLog.Errorf("Error closing connection: %+v", err) } + wg.Done() }() data := make([]byte, 65535) for { n, err := connection.Read(data) if err != nil { - if err.Error() == "EOF" { - nwucpLog.Warn("Connection close by peer") - ue.TCPConnection = nil - return - } else { - nwucpLog.Errorf("Read TCP connection failed: %+v", err) - } + logger.NWuCPLog.Errorf("Read TCP connection failed: %+v", err) + ranUe.TCPConnection = nil + return } - nwucpLog.Tracef("Get NAS PDU from UE:\nNAS length: %d\nNAS content:\n%s", n, hex.Dump(data[:n])) + logger.NWuCPLog.Tracef("Get NAS PDU from UE:\nNAS length: %d\nNAS content:\n%s", n, hex.Dump(data[:n])) // Decap Nas envelope forwardData := decapNasMsgFromEnvelope(data) - go forward(ue, forwardData) + wg.Add(1) + go forward(ranUe, forwardData, wg) } } // forward forwards NAS messages sent from UE to the // associated AMF -func forward(ue *context.N3IWFUe, packet []byte) { +func forward(ranUe *context.N3IWFRanUe, packet []byte, wg *sync.WaitGroup) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. logger.NWuCPLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } + wg.Done() }() - nwucpLog.Trace("Forward NWu -> N2") - message.SendUplinkNASTransport(ue.AMF, ue, packet) + logger.NWuCPLog.Trace("Forward NWu -> N2") + message.SendUplinkNASTransport(ranUe, packet) } diff --git a/internal/nwuup/service/service.go b/internal/nwuup/service/service.go index e3e07fa..02f1727 100644 --- a/internal/nwuup/service/service.go +++ b/internal/nwuup/service/service.go @@ -4,8 +4,8 @@ import ( "errors" "net" "runtime/debug" + "sync" - "github.com/sirupsen/logrus" gtpv1 "github.com/wmnsk/go-gtp/gtpv1" gtpMsg "github.com/wmnsk/go-gtp/gtpv1/message" "golang.org/x/net/ipv4" @@ -16,16 +16,10 @@ import ( "github.com/free5gc/n3iwf/pkg/context" ) -var nwuupLog *logrus.Entry - -func init() { - nwuupLog = logger.NWuUPLog -} - // Run bind and listen IPv4 packet connection on N3IWF NWu interface // with UP_IP_ADDRESS, catching GRE encapsulated packets and forward // to N3 interface. -func Run() error { +func Run(wg *sync.WaitGroup) error { // Local IPSec address n3iwfSelf := context.N3IWFSelf() listenAddr := n3iwfSelf.IPSecGatewayAddress @@ -34,24 +28,26 @@ func Run() error { // This socket will only capture GRE encapsulated packet connection, err := net.ListenPacket("ip4:gre", listenAddr) if err != nil { - nwuupLog.Errorf("Error setting listen socket on %s: %+v", listenAddr, err) + logger.NWuUPLog.Errorf("Error setting listen socket on %s: %+v", listenAddr, err) return errors.New("ListenPacket failed") } ipv4PacketConn := ipv4.NewPacketConn(connection) if err != nil { - nwuupLog.Errorf("Error opening IPv4 packet connection socket on %s: %+v", listenAddr, err) + logger.NWuUPLog.Errorf("Error opening IPv4 packet connection socket on %s: %+v", listenAddr, err) return errors.New("NewPacketConn failed") } n3iwfSelf.NWuIPv4PacketConn = ipv4PacketConn - go listenAndServe(ipv4PacketConn) + + wg.Add(1) + go listenAndServe(ipv4PacketConn, wg) return nil } // listenAndServe read from socket and call forward() to // forward packet. -func listenAndServe(ipv4PacketConn *ipv4.PacketConn) { +func listenAndServe(ipv4PacketConn *ipv4.PacketConn, wg *sync.WaitGroup) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. @@ -60,62 +56,72 @@ func listenAndServe(ipv4PacketConn *ipv4.PacketConn) { err := ipv4PacketConn.Close() if err != nil { - nwuupLog.Errorf("Error closing raw socket: %+v", err) + logger.NWuUPLog.Errorf("Error closing raw socket: %+v", err) } + wg.Done() }() buffer := make([]byte, 65535) if err := ipv4PacketConn.SetControlMessage(ipv4.FlagInterface|ipv4.FlagTTL, true); err != nil { - nwuupLog.Errorf("Set control message visibility for IPv4 packet connection fail: %+v", err) + logger.NWuUPLog.Errorf("Set control message visibility for IPv4 packet connection fail: %+v", err) return } for { n, cm, src, err := ipv4PacketConn.ReadFrom(buffer) - nwuupLog.Tracef("Read %d bytes, %s", n, cm) + logger.NWuUPLog.Tracef("Read %d bytes, %s", n, cm) if err != nil { - nwuupLog.Errorf("Error read from IPv4 packet connection: %+v", err) + logger.NWuUPLog.Errorf("Error read from IPv4 packet connection: %+v", err) return } forwardData := make([]byte, n) copy(forwardData, buffer) - go forward(src.String(), cm.IfIndex, forwardData) + wg.Add(1) + go forward(src.String(), cm.IfIndex, forwardData, wg) } } // forward forwards user plane packets from NWu to UPF // with GTP header encapsulated -func forward(ueInnerIP string, ifIndex int, rawData []byte) { +func forward(ueInnerIP string, ifIndex int, rawData []byte, wg *sync.WaitGroup) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. logger.NWuUPLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } + wg.Done() }() // Find UE information self := context.N3IWFSelf() - ue, ok := self.AllocatedUEIPAddressLoad(ueInnerIP) + ikeUe, ok := self.AllocatedUEIPAddressLoad(ueInnerIP) if !ok { - nwuupLog.Error("UE context not found") + logger.NWuUPLog.Error("Ike UE context not found") + return + } + + ranUe, err := self.RanUeLoadFromIkeSPI(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + if err != nil { + logger.NWuUPLog.Error("ranUe not found") return } var pduSession *context.PDUSession - for _, childSA := range ue.N3IWFChildSecurityAssociation { + for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { // Check which child SA the packet come from with interface index, // and find the corresponding PDU session if childSA.XfrmIface != nil && childSA.XfrmIface.Attrs().Index == ifIndex { - pduSession = ue.PduSessionList[childSA.PDUSessionIds[0]] + pduSession = ranUe.PduSessionList[childSA.PDUSessionIds[0]] + break } } if pduSession == nil { - nwuupLog.Error("This UE doesn't have any available PDU session") + logger.NWuUPLog.Error("This UE doesn't have any available PDU session") return } @@ -126,7 +132,7 @@ func forward(ueInnerIP string, ifIndex int, rawData []byte) { // Decapsulate GRE header and extract QoS Parameters if exist grePacket := gre.GREPacket{} if err := grePacket.Unmarshal(rawData); err != nil { - nwuupLog.Errorf("gre Unmarshal err: %+v", err) + logger.NWuUPLog.Errorf("gre Unmarshal err: %+v", err) return } @@ -142,26 +148,26 @@ func forward(ueInnerIP string, ifIndex int, rawData []byte) { qfi := grePacket.GetQFI() gtpPacket, err := buildQoSGTPPacket(gtpConnection.OutgoingTEID, qfi, payload) if err != nil { - nwuupLog.Errorf("buildQoSGTPPacket err: %+v", err) + logger.NWuUPLog.Errorf("buildQoSGTPPacket err: %+v", err) return } n, writeErr = userPlaneConnection.WriteTo(gtpPacket, gtpConnection.UPFUDPAddr) } else { - nwuupLog.Warnf("Receive GRE header without key field specifying QFI and RQI.") + logger.NWuUPLog.Warnf("Receive GRE header without key field specifying QFI and RQI.") n, writeErr = userPlaneConnection.WriteToGTP(gtpConnection.OutgoingTEID, payload, gtpConnection.UPFUDPAddr) } if writeErr != nil { - nwuupLog.Errorf("Write to UPF failed: %+v", writeErr) + logger.NWuUPLog.Errorf("Write to UPF failed: %+v", writeErr) if writeErr == gtpv1.ErrConnNotOpened { - nwuupLog.Error("The connection has been closed") + logger.NWuUPLog.Error("The connection has been closed") // TODO: Release the GTP resource } return } else { - nwuupLog.Trace("Forward NWu -> N3") - nwuupLog.Tracef("Wrote %d bytes", n) + logger.NWuUPLog.Trace("Forward NWu -> N3") + logger.NWuUPLog.Tracef("Wrote %d bytes", n) return } } @@ -178,9 +184,17 @@ func buildQoSGTPPacket(teid uint32, qfi uint8, payload []byte) ([]byte, error) { b := make([]byte, header.MarshalLen()) if err := header.MarshalTo(b); err != nil { - nwuupLog.Errorf("go-gtp MarshalTo err: %+v", err) + logger.NWuUPLog.Errorf("go-gtp MarshalTo err: %+v", err) return nil, err } return b, nil } + +func Stop(n3iwfContext *context.N3IWFContext) { + logger.NWuUPLog.Infof("Close Nwuup server...") + + if err := n3iwfContext.NWuIPv4PacketConn.Close(); err != nil { + logger.NWuUPLog.Errorf("Stop nwuup server error : %+v", err) + } +} diff --git a/internal/util/initContext.go b/internal/util/initContext.go deleted file mode 100644 index 4f42b82..0000000 --- a/internal/util/initContext.go +++ /dev/null @@ -1,333 +0,0 @@ -package util - -import ( - "crypto/rsa" - "crypto/sha1" - "crypto/x509" - "encoding/pem" - "fmt" - "io/ioutil" - "net" - "strings" - - "git.cs.nctu.edu.tw/calee/sctp" - "github.com/sirupsen/logrus" - - "github.com/free5gc/n3iwf/internal/logger" - "github.com/free5gc/n3iwf/pkg/context" - "github.com/free5gc/n3iwf/pkg/factory" -) - -var contextLog *logrus.Entry - -func InitN3IWFContext() bool { - var ok bool - contextLog = logger.ContextLog - - if factory.N3iwfConfig.Configuration == nil { - contextLog.Error("No N3IWF configuration found") - return false - } - - n3iwfContext := context.N3IWFSelf() - - // N3IWF NF information - n3iwfContext.NFInfo = factory.N3iwfConfig.Configuration.N3IWFInfo - if ok = formatSupportedTAList(&n3iwfContext.NFInfo); !ok { - return false - } - - // AMF SCTP addresses - if len(factory.N3iwfConfig.Configuration.AMFSCTPAddresses) == 0 { - contextLog.Error("No AMF specified") - return false - } else { - for _, amfAddress := range factory.N3iwfConfig.Configuration.AMFSCTPAddresses { - amfSCTPAddr := new(sctp.SCTPAddr) - // IP addresses - for _, ipAddrStr := range amfAddress.IPAddresses { - if ipAddr, err := net.ResolveIPAddr("ip", ipAddrStr); err != nil { - contextLog.Errorf("Resolve AMF IP address failed: %+v", err) - return false - } else { - amfSCTPAddr.IPAddrs = append(amfSCTPAddr.IPAddrs, *ipAddr) - } - } - // Port - if amfAddress.Port == 0 { - amfSCTPAddr.Port = 38412 - } else { - amfSCTPAddr.Port = amfAddress.Port - } - // Append to context - n3iwfContext.AMFSCTPAddresses = append(n3iwfContext.AMFSCTPAddresses, amfSCTPAddr) - } - } - - // IKE bind address - if factory.N3iwfConfig.Configuration.IKEBindAddr == "" { - contextLog.Error("IKE bind address is empty") - return false - } else { - n3iwfContext.IKEBindAddress = factory.N3iwfConfig.Configuration.IKEBindAddr - } - - // IPSec gateway address - if factory.N3iwfConfig.Configuration.IPSecGatewayAddr == "" { - contextLog.Error("IPSec interface address is empty") - return false - } else { - n3iwfContext.IPSecGatewayAddress = factory.N3iwfConfig.Configuration.IPSecGatewayAddr - } - - // GTP bind address - if factory.N3iwfConfig.Configuration.GTPBindAddr == "" { - contextLog.Error("GTP bind address is empty") - return false - } else { - n3iwfContext.GTPBindAddress = factory.N3iwfConfig.Configuration.GTPBindAddr - } - - // TCP port - if factory.N3iwfConfig.Configuration.TCPPort == 0 { - contextLog.Error("TCP port is not defined") - return false - } else { - n3iwfContext.TCPPort = factory.N3iwfConfig.Configuration.TCPPort - } - - // FQDN - if factory.N3iwfConfig.Configuration.FQDN == "" { - contextLog.Error("FQDN is empty") - return false - } else { - n3iwfContext.FQDN = factory.N3iwfConfig.Configuration.FQDN - } - - // Private key - { - var keyPath string - - if factory.N3iwfConfig.Configuration.PrivateKey == "" { - contextLog.Warn("No private key file path specified, load default key file...") - keyPath = N3iwfDefaultKeyPath - } else { - keyPath = factory.N3iwfConfig.Configuration.PrivateKey - } - - content, err := ioutil.ReadFile(keyPath) - if err != nil { - contextLog.Errorf("Cannot read private key data from file: %+v", err) - return false - } - block, _ := pem.Decode(content) - if block == nil { - contextLog.Error("Parse pem failed") - return false - } - key, err := x509.ParsePKCS8PrivateKey(block.Bytes) - if err != nil { - contextLog.Warnf("Parse PKCS8 private key failed: %+v", err) - contextLog.Info("Parse using PKCS1...") - - key, err = x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - contextLog.Errorf("Parse PKCS1 pricate key failed: %+v", err) - return false - } - } - rsaKey, ok := key.(*rsa.PrivateKey) - if !ok { - contextLog.Error("Private key is not an rsa private key") - return false - } - - n3iwfContext.N3IWFPrivateKey = rsaKey - } - - // Certificate authority - { - var keyPath string - - if factory.N3iwfConfig.Configuration.CertificateAuthority == "" { - contextLog.Warn("No certificate authority file path specified, load default CA certificate...") - keyPath = N3iwfDefaultPemPath - } else { - keyPath = factory.N3iwfConfig.Configuration.CertificateAuthority - } - - // Read .pem - content, err := ioutil.ReadFile(keyPath) - if err != nil { - contextLog.Errorf("Cannot read certificate authority data from file: %+v", err) - return false - } - // Decode pem - block, _ := pem.Decode(content) - if block == nil { - contextLog.Error("Parse pem failed") - return false - } - // Parse DER-encoded x509 certificate - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - contextLog.Errorf("Parse certificate authority failed: %+v", err) - return false - } - // Get sha1 hash of subject public key info - sha1Hash := sha1.New() - if _, err := sha1Hash.Write(cert.RawSubjectPublicKeyInfo); err != nil { - contextLog.Errorf("Hash function writing failed: %+v", err) - return false - } - - n3iwfContext.CertificateAuthority = sha1Hash.Sum(nil) - } - - // Certificate - { - var keyPath string - - if factory.N3iwfConfig.Configuration.Certificate == "" { - contextLog.Warn("No certificate file path specified, load default certificate...") - keyPath = N3iwfDefaultPemPath - } else { - keyPath = factory.N3iwfConfig.Configuration.Certificate - } - - // Read .pem - content, err := ioutil.ReadFile(keyPath) - if err != nil { - contextLog.Errorf("Cannot read certificate data from file: %+v", err) - return false - } - // Decode pem - block, _ := pem.Decode(content) - if block == nil { - contextLog.Error("Parse pem failed") - return false - } - - n3iwfContext.N3IWFCertificate = block.Bytes - } - - // UE IP address range - if factory.N3iwfConfig.Configuration.UEIPAddressRange == "" { - contextLog.Error("UE IP address range is empty") - return false - } else { - _, ueIPRange, err := net.ParseCIDR(factory.N3iwfConfig.Configuration.UEIPAddressRange) - if err != nil { - contextLog.Errorf("Parse CIDR failed: %+v", err) - return false - } - n3iwfContext.Subnet = ueIPRange - } - - // XFRM related - ikeBindIfaceName, err := GetInterfaceName(factory.N3iwfConfig.Configuration.IKEBindAddr) - if err != nil { - contextLog.Error(err) - return false - } else { - n3iwfContext.XfrmParentIfaceName = ikeBindIfaceName - } - - if factory.N3iwfConfig.Configuration.XfrmIfaceName == "" { - contextLog.Error("XFRM interface Name is empty, set to default \"ipsec\"") - n3iwfContext.XfrmIfaceName = "ipsec" - } else { - n3iwfContext.XfrmIfaceName = factory.N3iwfConfig.Configuration.XfrmIfaceName - } - - if factory.N3iwfConfig.Configuration.XfrmIfaceId == 0 { - contextLog.Warn("XFRM interface id is not defined, set to default value 7") - n3iwfContext.XfrmIfaceId = 7 - } else { - n3iwfContext.XfrmIfaceId = factory.N3iwfConfig.Configuration.XfrmIfaceId - } - - return true -} - -func formatSupportedTAList(info *context.N3IWFNFInfo) bool { - for taListIndex := range info.SupportedTAList { - supportedTAItem := &info.SupportedTAList[taListIndex] - - // Checking TAC - if supportedTAItem.TAC == "" { - contextLog.Error("TAC is mandatory.") - return false - } - if len(supportedTAItem.TAC) < 6 { - contextLog.Trace("Detect configuration TAC length < 6") - supportedTAItem.TAC = strings.Repeat("0", 6-len(supportedTAItem.TAC)) + supportedTAItem.TAC - contextLog.Tracef("Changed to %s", supportedTAItem.TAC) - } else if len(supportedTAItem.TAC) > 6 { - contextLog.Error("Detect configuration TAC length > 6") - return false - } - - // Checking SST and SD - for plmnListIndex := range supportedTAItem.BroadcastPLMNList { - broadcastPLMNItem := &supportedTAItem.BroadcastPLMNList[plmnListIndex] - - for sliceListIndex := range broadcastPLMNItem.TAISliceSupportList { - sliceSupportItem := &broadcastPLMNItem.TAISliceSupportList[sliceListIndex] - - // SST - if sliceSupportItem.SNSSAI.SST == "" { - contextLog.Error("SST is mandatory.") - } - if len(sliceSupportItem.SNSSAI.SST) < 2 { - contextLog.Trace("Detect configuration SST length < 2") - sliceSupportItem.SNSSAI.SST = "0" + sliceSupportItem.SNSSAI.SST - contextLog.Tracef("Change to %s", sliceSupportItem.SNSSAI.SST) - } else if len(sliceSupportItem.SNSSAI.SST) > 2 { - contextLog.Error("Detect configuration SST length > 2") - return false - } - - // SD - if sliceSupportItem.SNSSAI.SD != "" { - if len(sliceSupportItem.SNSSAI.SD) < 6 { - contextLog.Trace("Detect configuration SD length < 6") - sliceSupportItem.SNSSAI.SD = strings.Repeat("0", 6-len(sliceSupportItem.SNSSAI.SD)) + sliceSupportItem.SNSSAI.SD - contextLog.Tracef("Change to %s", sliceSupportItem.SNSSAI.SD) - } else if len(sliceSupportItem.SNSSAI.SD) > 6 { - contextLog.Error("Detect configuration SD length > 6") - return false - } - } - } - } - } - - return true -} - -func GetInterfaceName(IPAddress string) (interfaceName string, err error) { - interfaces, err := net.Interfaces() - if err != nil { - return "nil", err - } - - res, err := net.ResolveIPAddr("ip4", IPAddress) - if err != nil { - return "", fmt.Errorf("Error resolving address '%s': %v", IPAddress, err) - } - IPAddress = res.String() - - for _, inter := range interfaces { - addrs, err := inter.Addrs() - if err != nil { - return "nil", err - } - for _, addr := range addrs { - if IPAddress == addr.String()[0:strings.Index(addr.String(), "/")] { - return inter.Name, nil - } - } - } - return "", fmt.Errorf("Cannot find interface name") -} diff --git a/internal/util/ngap_convert.go b/internal/util/ngap_convert.go index 3328479..4a492be 100644 --- a/internal/util/ngap_convert.go +++ b/internal/util/ngap_convert.go @@ -7,11 +7,11 @@ import ( "github.com/free5gc/aper" "github.com/free5gc/n3iwf/internal/logger" - "github.com/free5gc/n3iwf/pkg/context" + "github.com/free5gc/n3iwf/pkg/factory" "github.com/free5gc/ngap/ngapType" ) -func PlmnIdToNgap(plmnId context.PLMNID) (ngapPlmnId ngapType.PLMNIdentity) { +func PlmnIdToNgap(plmnId factory.PLMNID) (ngapPlmnId ngapType.PLMNIdentity) { var hexString string mcc := strings.Split(plmnId.Mcc, "") mnc := strings.Split(plmnId.Mnc, "") diff --git a/internal/util/path.go b/internal/util/path.go deleted file mode 100644 index 7bd6801..0000000 --- a/internal/util/path.go +++ /dev/null @@ -1,7 +0,0 @@ -package util - -const ( - N3iwfDefaultPemPath = "./config/TLS/n3iwf.pem" - N3iwfDefaultKeyPath = "./config/TLS/n3iwf.key" - N3iwfDefaultConfigPath = "./config/n3iwfcfg.yaml" -) diff --git a/pkg/context/amf.go b/pkg/context/amf.go index e352d90..948cfba 100644 --- a/pkg/context/amf.go +++ b/pkg/context/amf.go @@ -22,7 +22,7 @@ type N3IWFAMF struct { // Overload related AMFOverloadContent *AMFOverloadContent // Relative Context - N3iwfUeList map[int64]*N3IWFUe // ranUeNgapId as key + N3iwfRanUeList map[int64]*N3IWFRanUe // ranUeNgapId as key } type AMFTNLAssociationItem struct { @@ -48,21 +48,21 @@ func (amf *N3IWFAMF) init(sctpAddr string, conn *sctp.SCTPConn) { amf.SCTPAddr = sctpAddr amf.SCTPConn = conn amf.AMFTNLAssociationList = make(map[string]*AMFTNLAssociationItem) - amf.N3iwfUeList = make(map[int64]*N3IWFUe) + amf.N3iwfRanUeList = make(map[int64]*N3IWFRanUe) } -func (amf *N3IWFAMF) FindUeByAmfUeNgapID(id int64) *N3IWFUe { - for _, n3iwfUe := range amf.N3iwfUeList { - if n3iwfUe.AmfUeNgapId == id { - return n3iwfUe +func (amf *N3IWFAMF) FindUeByAmfUeNgapID(id int64) *N3IWFRanUe { + for _, ranUe := range amf.N3iwfRanUeList { + if ranUe.AmfUeNgapId == id { + return ranUe } } return nil } func (amf *N3IWFAMF) RemoveAllRelatedUe() error { - for _, ue := range amf.N3iwfUeList { - if err := ue.Remove(); err != nil { + for _, ranUe := range amf.N3iwfRanUeList { + if err := ranUe.Remove(); err != nil { return fmt.Errorf("RemoveAllRelatedUe error : %+v", err) } } diff --git a/pkg/context/context.go b/pkg/context/context.go index b5820a9..7d5a605 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -1,29 +1,34 @@ package context import ( + "context" "crypto/rand" "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "encoding/pem" + "fmt" + "io/ioutil" "math" "math/big" "net" + "strings" "sync" "git.cs.nctu.edu.tw/calee/sctp" - "github.com/sirupsen/logrus" gtpv1 "github.com/wmnsk/go-gtp/gtpv1" "golang.org/x/net/ipv4" "github.com/free5gc/n3iwf/internal/logger" + "github.com/free5gc/n3iwf/pkg/factory" "github.com/free5gc/ngap/ngapType" "github.com/free5gc/util/idgenerator" ) -var contextLog *logrus.Entry - -var n3iwfContext = N3IWFContext{} +var n3iwfContext N3IWFContext type N3IWFContext struct { - NFInfo N3IWFNFInfo + NFInfo factory.N3IWFNFInfo AMFSCTPAddresses []*sctp.SCTPAddr // ID generator @@ -31,14 +36,17 @@ type N3IWFContext struct { TEIDGenerator *idgenerator.IDGenerator // Pools - UePool sync.Map // map[int64]*N3IWFUe, RanUeNgapID as key AMFPool sync.Map // map[string]*N3IWFAMF, SCTPAddr as key AMFReInitAvailableList sync.Map // map[string]bool, SCTPAddr as key IKESA sync.Map // map[uint64]*IKESecurityAssociation, SPI as key ChildSA sync.Map // map[uint32]*ChildSecurityAssociation, inboundSPI as key GTPConnectionWithUPF sync.Map // map[string]*gtpv1.UPlaneConn, UPF address as key - AllocatedUEIPAddress sync.Map // map[string]*N3IWFUe, IPAddr as key - AllocatedUETEID sync.Map // map[uint32]*N3IWFUe, TEID as key + AllocatedUEIPAddress sync.Map // map[string]*N3IWFIkeUe, IPAddr as key + AllocatedUETEID sync.Map // map[uint32]*N3IWFRanUe, TEID as key + IKEUePool sync.Map // map[uint64]*N3IWFIkeUe, SPI as key + RANUePool sync.Map // map[int64]*N3IWFRanUe, RanUeNgapID as key + IKESPIToNGAPId sync.Map // map[uint64]RanUeNgapID, SPI as key + NGAPIdToIKESPI sync.Map // map[uint64]SPI, RanUeNgapID as key // N3IWF FQDN FQDN string @@ -68,12 +76,326 @@ type N3IWFContext struct { // N3IWF NWu interface IPv4 packet connection NWuIPv4PacketConn *ipv4.PacketConn + + Ctx context.Context + Wg sync.WaitGroup + + NGAPServer *NGAPServer + IKEServer *IkeServer } -func init() { - // init log - contextLog = logger.ContextLog +func InitN3IWFContext() bool { + var ok bool + + if factory.N3iwfConfig.Configuration == nil { + logger.CtxLog.Error("No N3IWF configuration found") + return false + } + + n3iwfContext := N3IWFSelf() + + // N3IWF NF information + n3iwfContext.NFInfo = factory.N3iwfConfig.Configuration.N3IWFInfo + if ok = formatSupportedTAList(&n3iwfContext.NFInfo); !ok { + return false + } + + // AMF SCTP addresses + if len(factory.N3iwfConfig.Configuration.AMFSCTPAddresses) == 0 { + logger.CtxLog.Error("No AMF specified") + return false + } else { + for _, amfAddress := range factory.N3iwfConfig.Configuration.AMFSCTPAddresses { + amfSCTPAddr := new(sctp.SCTPAddr) + // IP addresses + for _, ipAddrStr := range amfAddress.IPAddresses { + if ipAddr, err := net.ResolveIPAddr("ip", ipAddrStr); err != nil { + logger.CtxLog.Errorf("Resolve AMF IP address failed: %+v", err) + return false + } else { + amfSCTPAddr.IPAddrs = append(amfSCTPAddr.IPAddrs, *ipAddr) + } + } + // Port + if amfAddress.Port == 0 { + amfSCTPAddr.Port = 38412 + } else { + amfSCTPAddr.Port = amfAddress.Port + } + // Append to context + n3iwfContext.AMFSCTPAddresses = append(n3iwfContext.AMFSCTPAddresses, amfSCTPAddr) + } + } + + // IKE bind address + if factory.N3iwfConfig.Configuration.IKEBindAddr == "" { + logger.CtxLog.Error("IKE bind address is empty") + return false + } else { + n3iwfContext.IKEBindAddress = factory.N3iwfConfig.Configuration.IKEBindAddr + } + + // IPSec gateway address + if factory.N3iwfConfig.Configuration.IPSecGatewayAddr == "" { + logger.CtxLog.Error("IPSec interface address is empty") + return false + } else { + n3iwfContext.IPSecGatewayAddress = factory.N3iwfConfig.Configuration.IPSecGatewayAddr + } + + // GTP bind address + if factory.N3iwfConfig.Configuration.GTPBindAddr == "" { + logger.CtxLog.Error("GTP bind address is empty") + return false + } else { + n3iwfContext.GTPBindAddress = factory.N3iwfConfig.Configuration.GTPBindAddr + } + + // TCP port + if factory.N3iwfConfig.Configuration.TCPPort == 0 { + logger.CtxLog.Error("TCP port is not defined") + return false + } else { + n3iwfContext.TCPPort = factory.N3iwfConfig.Configuration.TCPPort + } + + // FQDN + if factory.N3iwfConfig.Configuration.FQDN == "" { + logger.CtxLog.Error("FQDN is empty") + return false + } else { + n3iwfContext.FQDN = factory.N3iwfConfig.Configuration.FQDN + } + + // Private key + { + var keyPath string + + if factory.N3iwfConfig.Configuration.PrivateKey == "" { + logger.CtxLog.Warn("No private key file path specified, load default key file...") + keyPath = factory.N3iwfDefaultPrivateKeyPath + } else { + keyPath = factory.N3iwfConfig.Configuration.PrivateKey + } + + content, err := ioutil.ReadFile(keyPath) + if err != nil { + logger.CtxLog.Errorf("Cannot read private key data from file: %+v", err) + return false + } + block, _ := pem.Decode(content) + if block == nil { + logger.CtxLog.Error("Parse pem failed") + return false + } + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + logger.CtxLog.Warnf("Parse PKCS8 private key failed: %+v", err) + logger.CtxLog.Info("Parse using PKCS1...") + + key, err = x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + logger.CtxLog.Errorf("Parse PKCS1 pricate key failed: %+v", err) + return false + } + } + rsaKey, ok := key.(*rsa.PrivateKey) + if !ok { + logger.CtxLog.Error("Private key is not an rsa private key") + return false + } + + n3iwfContext.N3IWFPrivateKey = rsaKey + } + + // Certificate authority + { + var keyPath string + + if factory.N3iwfConfig.Configuration.CertificateAuthority == "" { + logger.CtxLog.Warn("No certificate authority file path specified, load default CA certificate...") + keyPath = factory.N3iwfDefaultCertPemPath + } else { + keyPath = factory.N3iwfConfig.Configuration.CertificateAuthority + } + + // Read .pem + content, err := ioutil.ReadFile(keyPath) + if err != nil { + logger.CtxLog.Errorf("Cannot read certificate authority data from file: %+v", err) + return false + } + // Decode pem + block, _ := pem.Decode(content) + if block == nil { + logger.CtxLog.Error("Parse pem failed") + return false + } + // Parse DER-encoded x509 certificate + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + logger.CtxLog.Errorf("Parse certificate authority failed: %+v", err) + return false + } + // Get sha1 hash of subject public key info + sha1Hash := sha1.New() + if _, err := sha1Hash.Write(cert.RawSubjectPublicKeyInfo); err != nil { + logger.CtxLog.Errorf("Hash function writing failed: %+v", err) + return false + } + + n3iwfContext.CertificateAuthority = sha1Hash.Sum(nil) + } + + // Certificate + { + var keyPath string + + if factory.N3iwfConfig.Configuration.Certificate == "" { + logger.CtxLog.Warn("No certificate file path specified, load default certificate...") + keyPath = factory.N3iwfDefaultCertPemPath + } else { + keyPath = factory.N3iwfConfig.Configuration.Certificate + } + + // Read .pem + content, err := ioutil.ReadFile(keyPath) + if err != nil { + logger.CtxLog.Errorf("Cannot read certificate data from file: %+v", err) + return false + } + // Decode pem + block, _ := pem.Decode(content) + if block == nil { + logger.CtxLog.Error("Parse pem failed") + return false + } + + n3iwfContext.N3IWFCertificate = block.Bytes + } + + // UE IP address range + if factory.N3iwfConfig.Configuration.UEIPAddressRange == "" { + logger.CtxLog.Error("UE IP address range is empty") + return false + } else { + _, ueIPRange, err := net.ParseCIDR(factory.N3iwfConfig.Configuration.UEIPAddressRange) + if err != nil { + logger.CtxLog.Errorf("Parse CIDR failed: %+v", err) + return false + } + n3iwfContext.Subnet = ueIPRange + } + + // XFRM related + ikeBindIfaceName, err := GetInterfaceName(factory.N3iwfConfig.Configuration.IKEBindAddr) + if err != nil { + logger.CtxLog.Error(err) + return false + } else { + n3iwfContext.XfrmParentIfaceName = ikeBindIfaceName + } + + if factory.N3iwfConfig.Configuration.XfrmIfaceName == "" { + logger.CtxLog.Error("XFRM interface Name is empty, set to default \"ipsec\"") + n3iwfContext.XfrmIfaceName = "ipsec" + } else { + n3iwfContext.XfrmIfaceName = factory.N3iwfConfig.Configuration.XfrmIfaceName + } + + if factory.N3iwfConfig.Configuration.XfrmIfaceId == 0 { + logger.CtxLog.Warn("XFRM interface id is not defined, set to default value 7") + n3iwfContext.XfrmIfaceId = 7 + } else { + n3iwfContext.XfrmIfaceId = factory.N3iwfConfig.Configuration.XfrmIfaceId + } + + return true +} + +func formatSupportedTAList(info *factory.N3IWFNFInfo) bool { + for taListIndex := range info.SupportedTAList { + supportedTAItem := &info.SupportedTAList[taListIndex] + + // Checking TAC + if supportedTAItem.TAC == "" { + logger.CtxLog.Error("TAC is mandatory.") + return false + } + if len(supportedTAItem.TAC) < 6 { + logger.CtxLog.Trace("Detect configuration TAC length < 6") + supportedTAItem.TAC = strings.Repeat("0", 6-len(supportedTAItem.TAC)) + supportedTAItem.TAC + logger.CtxLog.Tracef("Changed to %s", supportedTAItem.TAC) + } else if len(supportedTAItem.TAC) > 6 { + logger.CtxLog.Error("Detect configuration TAC length > 6") + return false + } + + // Checking SST and SD + for plmnListIndex := range supportedTAItem.BroadcastPLMNList { + broadcastPLMNItem := &supportedTAItem.BroadcastPLMNList[plmnListIndex] + + for sliceListIndex := range broadcastPLMNItem.TAISliceSupportList { + sliceSupportItem := &broadcastPLMNItem.TAISliceSupportList[sliceListIndex] + + // SST + if sliceSupportItem.SNSSAI.SST == "" { + logger.CtxLog.Error("SST is mandatory.") + } + if len(sliceSupportItem.SNSSAI.SST) < 2 { + logger.CtxLog.Trace("Detect configuration SST length < 2") + sliceSupportItem.SNSSAI.SST = "0" + sliceSupportItem.SNSSAI.SST + logger.CtxLog.Tracef("Change to %s", sliceSupportItem.SNSSAI.SST) + } else if len(sliceSupportItem.SNSSAI.SST) > 2 { + logger.CtxLog.Error("Detect configuration SST length > 2") + return false + } + + // SD + if sliceSupportItem.SNSSAI.SD != "" { + if len(sliceSupportItem.SNSSAI.SD) < 6 { + logger.CtxLog.Trace("Detect configuration SD length < 6") + sliceSupportItem.SNSSAI.SD = strings.Repeat("0", 6-len(sliceSupportItem.SNSSAI.SD)) + sliceSupportItem.SNSSAI.SD + logger.CtxLog.Tracef("Change to %s", sliceSupportItem.SNSSAI.SD) + } else if len(sliceSupportItem.SNSSAI.SD) > 6 { + logger.CtxLog.Error("Detect configuration SD length > 6") + return false + } + } + } + } + } + + return true +} + +func GetInterfaceName(IPAddress string) (interfaceName string, err error) { + interfaces, err := net.Interfaces() + if err != nil { + return "nil", err + } + + res, err := net.ResolveIPAddr("ip4", IPAddress) + if err != nil { + return "", fmt.Errorf("Error resolving address '%s': %v", IPAddress, err) + } + IPAddress = res.String() + + for _, inter := range interfaces { + addrs, err := inter.Addrs() + if err != nil { + return "nil", err + } + for _, addr := range addrs { + if IPAddress == addr.String()[0:strings.Index(addr.String(), "/")] { + return inter.Name, nil + } + } + } + return "", fmt.Errorf("Cannot find interface name") +} +func init() { // init ID generator n3iwfContext.RANUENGAPIDGenerator = idgenerator.NewGenerator(0, math.MaxInt64) n3iwfContext.TEIDGenerator = idgenerator.NewGenerator(1, math.MaxUint32) @@ -84,36 +406,117 @@ func N3IWFSelf() *N3IWFContext { return &n3iwfContext } -func (context *N3IWFContext) NewN3iwfUe() *N3IWFUe { +func (context *N3IWFContext) NewN3iwfIkeUe(spi uint64) *N3IWFIkeUe { + n3iwfIkeUe := new(N3IWFIkeUe) + n3iwfIkeUe.init() + context.IKEUePool.Store(spi, n3iwfIkeUe) + return n3iwfIkeUe +} + +func (context *N3IWFContext) NewN3iwfRanUe() *N3IWFRanUe { ranUeNgapId, err := context.RANUENGAPIDGenerator.Allocate() if err != nil { - contextLog.Errorf("New N3IWF UE failed: %+v", err) + logger.CtxLog.Errorf("New N3IWF UE failed: %+v", err) return nil } - n3iwfUe := new(N3IWFUe) - n3iwfUe.init(ranUeNgapId) - context.UePool.Store(ranUeNgapId, n3iwfUe) - return n3iwfUe + n3iwfRanUe := new(N3IWFRanUe) + n3iwfRanUe.init(ranUeNgapId) + context.RANUePool.Store(ranUeNgapId, n3iwfRanUe) + n3iwfRanUe.TemporaryPDUSessionSetupData = new(PDUSessionSetupTemporaryData) + + return n3iwfRanUe +} + +func (context *N3IWFContext) DeleteRanUe(ranUeNgapId int64) { + context.RANUePool.Delete(ranUeNgapId) + context.DeleteIkeSPIFromNgapId(ranUeNgapId) +} + +func (context *N3IWFContext) DeleteIKEUe(spi uint64) { + context.IKEUePool.Delete(spi) + context.DeleteNgapIdFromIkeSPI(spi) } -func (context *N3IWFContext) DeleteN3iwfUe(ranUeNgapId int64) { - context.UePool.Delete(ranUeNgapId) +func (context *N3IWFContext) IkeUePoolLoad(spi uint64) (*N3IWFIkeUe, bool) { + ikeUe, ok := context.IKEUePool.Load(spi) + if ok { + return ikeUe.(*N3IWFIkeUe), ok + } else { + return nil, ok + } } -func (context *N3IWFContext) UePoolLoad(ranUeNgapId int64) (*N3IWFUe, bool) { - ue, ok := context.UePool.Load(ranUeNgapId) +func (context *N3IWFContext) RanUePoolLoad(ranUeNgapId int64) (*N3IWFRanUe, bool) { + ranUe, ok := context.RANUePool.Load(ranUeNgapId) if ok { - return ue.(*N3IWFUe), ok + return ranUe.(*N3IWFRanUe), ok } else { return nil, ok } } +func (context *N3IWFContext) IkeSpiNgapIdMapping(spi uint64, ranUeNgapId int64) { + context.IKESPIToNGAPId.Store(spi, ranUeNgapId) + context.NGAPIdToIKESPI.Store(ranUeNgapId, spi) +} + +func (context *N3IWFContext) IkeSpiLoad(ranUeNgapId int64) (uint64, bool) { + spi, ok := context.NGAPIdToIKESPI.Load(ranUeNgapId) + if ok { + return spi.(uint64), ok + } else { + return 0, ok + } +} + +func (context *N3IWFContext) NgapIdLoad(spi uint64) (int64, bool) { + ranNgapId, ok := context.IKESPIToNGAPId.Load(spi) + if ok { + return ranNgapId.(int64), ok + } else { + return 0, ok + } +} + +func (context *N3IWFContext) DeleteNgapIdFromIkeSPI(spi uint64) { + context.IKESPIToNGAPId.Delete(spi) +} + +func (context *N3IWFContext) DeleteIkeSPIFromNgapId(ranUeNgapId int64) { + context.NGAPIdToIKESPI.Delete(ranUeNgapId) +} + +func (context *N3IWFContext) RanUeLoadFromIkeSPI(spi uint64) (*N3IWFRanUe, error) { + ranNgapId, ok := context.IKESPIToNGAPId.Load(spi) + if ok { + ranUe, err := context.RanUePoolLoad(ranNgapId.(int64)) + if !err { + return nil, fmt.Errorf("Cannot find RanUE from RanNgapId : %+v", ranNgapId) + } + return ranUe, nil + } else { + return nil, fmt.Errorf("Cannot find RanNgapId from IkeUe SPI : %+v", spi) + } +} + +func (context *N3IWFContext) IkeUeLoadFromNgapId(ranUeNgapId int64) (*N3IWFIkeUe, error) { + spi, ok := context.NGAPIdToIKESPI.Load(ranUeNgapId) + if ok { + ikeUe, err := context.IkeUePoolLoad(spi.(uint64)) + if !err { + return nil, fmt.Errorf("Cannot find IkeUe from spi : %+v", spi) + } + return ikeUe, nil + } else { + return nil, fmt.Errorf("Cannot find SPI from NgapId : %+v", ranUeNgapId) + } +} + func (context *N3IWFContext) NewN3iwfAmf(sctpAddr string, conn *sctp.SCTPConn) *N3IWFAMF { amf := new(N3IWFAMF) amf.init(sctpAddr, conn) if item, loaded := context.AMFPool.LoadOrStore(sctpAddr, amf); loaded { - contextLog.Warn("[Context] NewN3iwfAmf(): AMF entry already exists.") + logger.CtxLog.Warn("[Context] NewN3iwfAmf(): AMF entry already exists.") return item.(*N3IWFAMF) } else { return amf @@ -159,7 +562,7 @@ func (context *N3IWFContext) NewIKESecurityAssociation() *IKESecurityAssociation for { localSPI, err := rand.Int(rand.Reader, maxSPI) if err != nil { - contextLog.Error("[Context] Error occurs when generate new IKE SPI") + logger.CtxLog.Error("[Context] Error occurs when generate new IKE SPI") return nil } localSPIuint64 = localSPI.Uint64() @@ -203,7 +606,7 @@ func (context *N3IWFContext) GTPConnectionWithUPFStore(upfAddr string, conn *gtp context.GTPConnectionWithUPF.Store(upfAddr, conn) } -func (context *N3IWFContext) NewInternalUEIPAddr(ue *N3IWFUe) net.IP { +func (context *N3IWFContext) NewInternalUEIPAddr(ikeUe *N3IWFIkeUe) net.IP { var ueIPAddr net.IP // TODO: Check number of allocated IP to detect running out of IPs @@ -213,7 +616,7 @@ func (context *N3IWFContext) NewInternalUEIPAddr(ue *N3IWFUe) net.IP { if ueIPAddr.String() == context.IPSecGatewayAddress { continue } - if _, ok := context.AllocatedUEIPAddress.LoadOrStore(ueIPAddr.String(), ue); !ok { + if _, ok := context.AllocatedUEIPAddress.LoadOrStore(ueIPAddr.String(), ikeUe); !ok { break } } @@ -226,36 +629,37 @@ func (context *N3IWFContext) DeleteInternalUEIPAddr(ipAddr string) { context.AllocatedUEIPAddress.Delete(ipAddr) } -func (context *N3IWFContext) AllocatedUEIPAddressLoad(ipAddr string) (*N3IWFUe, bool) { - ue, ok := context.AllocatedUEIPAddress.Load(ipAddr) +func (context *N3IWFContext) AllocatedUEIPAddressLoad(ipAddr string) (*N3IWFIkeUe, bool) { + ikeUe, ok := context.AllocatedUEIPAddress.Load(ipAddr) if ok { - return ue.(*N3IWFUe), ok + return ikeUe.(*N3IWFIkeUe), ok } else { return nil, ok } } -func (context *N3IWFContext) NewTEID(ue *N3IWFUe) uint32 { +func (context *N3IWFContext) NewTEID(ranUe *N3IWFRanUe) uint32 { teid64, err := context.TEIDGenerator.Allocate() if err != nil { - contextLog.Errorf("New TEID failed: %+v", err) + logger.CtxLog.Errorf("New TEID failed: %+v", err) return 0 } teid32 := uint32(teid64) - context.AllocatedUETEID.Store(teid32, ue) + context.AllocatedUETEID.Store(teid32, ranUe) return teid32 } func (context *N3IWFContext) DeleteTEID(teid uint32) { + context.TEIDGenerator.FreeID(int64(teid)) context.AllocatedUETEID.Delete(teid) } -func (context *N3IWFContext) AllocatedUETEIDLoad(teid uint32) (*N3IWFUe, bool) { - ue, ok := context.AllocatedUETEID.Load(teid) +func (context *N3IWFContext) AllocatedUETEIDLoad(teid uint32) (*N3IWFRanUe, bool) { + ranUe, ok := context.AllocatedUETEID.Load(teid) if ok { - return ue.(*N3IWFUe), ok + return ranUe.(*N3IWFRanUe), ok } else { return nil, ok } @@ -290,7 +694,7 @@ func generateRandomIPinRange(subnet *net.IPNet) net.IP { _, err := rand.Read(randomNumber) if err != nil { - contextLog.Errorf("Generate random number for IP address failed: %+v", err) + logger.CtxLog.Errorf("Generate random number for IP address failed: %+v", err) return nil } diff --git a/pkg/context/ike.go b/pkg/context/ike.go new file mode 100644 index 0000000..1899959 --- /dev/null +++ b/pkg/context/ike.go @@ -0,0 +1,199 @@ +package context + +import ( + "net" +) + +type IkeServer struct { + Listener map[int]*net.UDPConn + RcvIkePktCh chan IkeReceivePacket + RcvEventCh chan IkeEvt + StopServer chan struct{} +} + +type IkeReceivePacket struct { + Listener net.UDPConn + LocalAddr net.UDPAddr + RemoteAddr net.UDPAddr + Msg []byte +} + +type IkeEventType int64 + +// IKE Event type +const ( + UnmarshalEAP5GDataResponse IkeEventType = iota + SendEAP5GFailureMsg + SendEAPNASMsg + SendEAPSuccessMsg + CreatePDUSession + IKEDeleteRequest + SendChildSADeleteRequest + IKEContextUpdate + GetNGAPContextResponse +) + +type IkeEvt interface { + Type() IkeEventType +} + +type UnmarshalEAP5GDataResponseEvt struct { + LocalSPI uint64 + RanUeNgapId int64 + NasPDU []byte +} + +func (unmarshalEAP5GDataResponseEvt *UnmarshalEAP5GDataResponseEvt) Type() IkeEventType { + return UnmarshalEAP5GDataResponse +} + +func NewUnmarshalEAP5GDataResponseEvt(localSPI uint64, ranUeNgapId int64, nasPDU []byte, +) *UnmarshalEAP5GDataResponseEvt { + return &UnmarshalEAP5GDataResponseEvt{ + LocalSPI: localSPI, + RanUeNgapId: ranUeNgapId, + NasPDU: nasPDU, + } +} + +type SendEAP5GFailureMsgEvt struct { + LocalSPI uint64 + ErrMsg EvtError +} + +func (sendEAP5GFailureMsgEvt *SendEAP5GFailureMsgEvt) Type() IkeEventType { + return SendEAP5GFailureMsg +} + +func NewSendEAP5GFailureMsgEvt(localSPI uint64, errMsg EvtError, +) *SendEAP5GFailureMsgEvt { + return &SendEAP5GFailureMsgEvt{ + LocalSPI: localSPI, + ErrMsg: errMsg, + } +} + +type SendEAPNASMsgEvt struct { + LocalSPI uint64 + NasPDU []byte +} + +func (sendEAPNASMsgEvt *SendEAPNASMsgEvt) Type() IkeEventType { + return SendEAPNASMsg +} + +func NewSendEAPNASMsgEvt(localSPI uint64, nasPDU []byte, +) *SendEAPNASMsgEvt { + return &SendEAPNASMsgEvt{ + LocalSPI: localSPI, + NasPDU: nasPDU, + } +} + +type SendEAPSuccessMsgEvt struct { + LocalSPI uint64 + Kn3iwf []byte + PduSessionListLen int +} + +func (SendEAPSuccessMsgEvt *SendEAPSuccessMsgEvt) Type() IkeEventType { + return SendEAPSuccessMsg +} + +func NewSendEAPSuccessMsgEvt(localSPI uint64, kn3iwf []byte, pduSessionListLen int, +) *SendEAPSuccessMsgEvt { + return &SendEAPSuccessMsgEvt{ + LocalSPI: localSPI, + Kn3iwf: kn3iwf, + PduSessionListLen: pduSessionListLen, + } +} + +type CreatePDUSessionEvt struct { + LocalSPI uint64 + PduSessionListLen int + TempPDUSessionSetupData *PDUSessionSetupTemporaryData +} + +func (createPDUSessionEvt *CreatePDUSessionEvt) Type() IkeEventType { + return CreatePDUSession +} + +func NewCreatePDUSessionEvt(localSPI uint64, pduSessionListLen int, + tempPDUSessionSetupData *PDUSessionSetupTemporaryData, +) *CreatePDUSessionEvt { + return &CreatePDUSessionEvt{ + LocalSPI: localSPI, + PduSessionListLen: pduSessionListLen, + TempPDUSessionSetupData: tempPDUSessionSetupData, + } +} + +type IKEDeleteRequestEvt struct { + LocalSPI uint64 +} + +func (ikeDeleteRequestEvt *IKEDeleteRequestEvt) Type() IkeEventType { + return IKEDeleteRequest +} + +func NewIKEDeleteRequestEvt(localSPI uint64, +) *IKEDeleteRequestEvt { + return &IKEDeleteRequestEvt{ + LocalSPI: localSPI, + } +} + +type SendChildSADeleteRequestEvt struct { + LocalSPI uint64 + ReleaseIdList []int64 +} + +func (sendChildSADeleteRequestEvt *SendChildSADeleteRequestEvt) Type() IkeEventType { + return SendChildSADeleteRequest +} + +func NewSendChildSADeleteRequestEvt(localSPI uint64, releaseIdList []int64, +) *SendChildSADeleteRequestEvt { + return &SendChildSADeleteRequestEvt{ + LocalSPI: localSPI, + ReleaseIdList: releaseIdList, + } +} + +type IKEContextUpdateEvt struct { + LocalSPI uint64 + Kn3iwf []byte +} + +func (ikeContextUpdateEvt *IKEContextUpdateEvt) Type() IkeEventType { + return IKEContextUpdate +} + +func NewIKEContextUpdateEvt(localSPI uint64, kn3iwf []byte, +) *IKEContextUpdateEvt { + return &IKEContextUpdateEvt{ + LocalSPI: localSPI, + Kn3iwf: kn3iwf, + } +} + +type GetNGAPContextRepEvt struct { + LocalSPI uint64 + NgapCxtReqNumlist []int64 + NgapCxt []interface{} +} + +func (getNGAPContextRepEvt *GetNGAPContextRepEvt) Type() IkeEventType { + return GetNGAPContextResponse +} + +func NewGetNGAPContextRepEvt(localSPI uint64, ngapCxtReqNumlist []int64, + ngapCxt []interface{}, +) *GetNGAPContextRepEvt { + return &GetNGAPContextRepEvt{ + LocalSPI: localSPI, + NgapCxtReqNumlist: ngapCxtReqNumlist, + NgapCxt: ngapCxt, + } +} diff --git a/pkg/context/ngap.go b/pkg/context/ngap.go new file mode 100644 index 0000000..1b02e4f --- /dev/null +++ b/pkg/context/ngap.go @@ -0,0 +1,213 @@ +package context + +import ( + "git.cs.nctu.edu.tw/calee/sctp" +) + +type NGAPServer struct { + Conn []*sctp.SCTPConn + RcvNgapPktCh chan ReceiveNGAPPacket + RcvEventCh chan NgapEvt +} +type ReceiveNGAPPacket struct { + Conn *sctp.SCTPConn + Buf []byte +} + +type NgapEventType int64 + +// NGAP event type +const ( + UnmarshalEAP5GData NgapEventType = iota + SendInitialUEMessage + SendPDUSessionResourceSetupResponse + SendNASMsg + StartTCPSignalNASMsg + NASTCPConnEstablishedComplete + SendUEContextReleaseRequest + SendUEContextReleaseComplete + SendPDUSessionResourceReleaseResponse + GetNGAPContext +) + +type EvtError string + +func (e EvtError) Error() string { return string(e) } + +// NGAP IKE event error string +const ( + ErrNil = EvtError("Nil") + ErrRadioConnWithUeLost = EvtError("RadioConnectionWithUeLost") + ErrTransportResourceUnavailable = EvtError("TransportResourceUnavailable") + ErrAMFSelection = EvtError("No avalible AMF for this UE") +) + +type NgapEvt interface { + Type() NgapEventType +} + +type UnmarshalEAP5GDataEvt struct { + LocalSPI uint64 + EAPVendorData []byte + IsInitialUE bool + RanUeNgapId int64 +} + +func (unmarshalEAP5GDataEvt *UnmarshalEAP5GDataEvt) Type() NgapEventType { + return UnmarshalEAP5GData +} + +func NewUnmarshalEAP5GDataEvt(localSPI uint64, eapVendorData []byte, isInitialUE bool, + ranUeNgapId int64, +) *UnmarshalEAP5GDataEvt { + return &UnmarshalEAP5GDataEvt{ + LocalSPI: localSPI, + EAPVendorData: eapVendorData, + IsInitialUE: isInitialUE, + RanUeNgapId: ranUeNgapId, + } +} + +type SendInitialUEMessageEvt struct { + RanUeNgapId int64 + IPv4Addr string + IPv4Port int + NasPDU []byte +} + +func (sendInitialUEMessageEvt *SendInitialUEMessageEvt) Type() NgapEventType { + return SendInitialUEMessage +} + +func NewSendInitialUEMessageEvt(ranUeNgapId int64, ipv4Addr string, ipv4Port int, + nasPDU []byte, +) *SendInitialUEMessageEvt { + return &SendInitialUEMessageEvt{ + RanUeNgapId: ranUeNgapId, + IPv4Addr: ipv4Addr, + IPv4Port: ipv4Port, + NasPDU: nasPDU, + } +} + +type SendPDUSessionResourceSetupResEvt struct { + RanUeNgapId int64 +} + +func (sendPDUSessionResourceSetupResEvt *SendPDUSessionResourceSetupResEvt) Type() NgapEventType { + return SendPDUSessionResourceSetupResponse +} + +func NewSendPDUSessionResourceSetupResEvt(ranUeNgapId int64) *SendPDUSessionResourceSetupResEvt { + return &SendPDUSessionResourceSetupResEvt{ + RanUeNgapId: ranUeNgapId, + } +} + +type SendNASMsgEvt struct { + RanUeNgapId int64 +} + +func (sendNASMsgEvt *SendNASMsgEvt) Type() NgapEventType { + return SendNASMsg +} + +func NewSendNASMsgEvt(ranUeNgapId int64) *SendNASMsgEvt { + return &SendNASMsgEvt{ + RanUeNgapId: ranUeNgapId, + } +} + +type StartTCPSignalNASMsgEvt struct { + RanUeNgapId int64 +} + +func (startTCPSignalNASMsgEvt *StartTCPSignalNASMsgEvt) Type() NgapEventType { + return StartTCPSignalNASMsg +} + +func NewStartTCPSignalNASMsgEvt(ranUeNgapId int64) *StartTCPSignalNASMsgEvt { + return &StartTCPSignalNASMsgEvt{ + RanUeNgapId: ranUeNgapId, + } +} + +type NASTCPConnEstablishedCompleteEvt struct { + RanUeNgapId int64 +} + +func (nasTCPConnEstablishedCompleteEvt *NASTCPConnEstablishedCompleteEvt) Type() NgapEventType { + return NASTCPConnEstablishedComplete +} + +func NewNASTCPConnEstablishedCompleteEvt(ranUeNgapId int64) *NASTCPConnEstablishedCompleteEvt { + return &NASTCPConnEstablishedCompleteEvt{ + RanUeNgapId: ranUeNgapId, + } +} + +type SendUEContextReleaseRequestEvt struct { + RanUeNgapId int64 + ErrMsg EvtError +} + +func (sendUEContextReleaseRequestEvt *SendUEContextReleaseRequestEvt) Type() NgapEventType { + return SendUEContextReleaseRequest +} + +func NewSendUEContextReleaseRequestEvt(ranUeNgapId int64, errMsg EvtError, +) *SendUEContextReleaseRequestEvt { + return &SendUEContextReleaseRequestEvt{ + RanUeNgapId: ranUeNgapId, + ErrMsg: errMsg, + } +} + +type SendUEContextReleaseCompleteEvt struct { + RanUeNgapId int64 +} + +func (sendUEContextReleaseCompleteEvt *SendUEContextReleaseCompleteEvt) Type() NgapEventType { + return SendUEContextReleaseComplete +} + +func NewSendUEContextReleaseCompleteEvt(ranUeNgapId int64) *SendUEContextReleaseCompleteEvt { + return &SendUEContextReleaseCompleteEvt{ + RanUeNgapId: ranUeNgapId, + } +} + +type SendPDUSessionResourceReleaseResEvt struct { + RanUeNgapId int64 +} + +func (sendPDUSessionResourceReleaseResEvt *SendPDUSessionResourceReleaseResEvt) Type() NgapEventType { + return SendPDUSessionResourceReleaseResponse +} + +func NewSendPDUSessionResourceReleaseResEvt(ranUeNgapId int64) *SendPDUSessionResourceReleaseResEvt { + return &SendPDUSessionResourceReleaseResEvt{ + RanUeNgapId: ranUeNgapId, + } +} + +// Ngap context +const ( + CxtTempPDUSessionSetupData int64 = iota +) + +type GetNGAPContextEvt struct { + RanUeNgapId int64 + NgapCxtReqNumlist []int64 +} + +func (getNGAPContextEvt *GetNGAPContextEvt) Type() NgapEventType { + return GetNGAPContext +} + +func NewGetNGAPContextEvt(ranUeNgapId int64, ngapCxtReqNumlist []int64) *GetNGAPContextEvt { + return &GetNGAPContextEvt{ + RanUeNgapId: ranUeNgapId, + NgapCxtReqNumlist: ngapCxtReqNumlist, + } +} diff --git a/pkg/context/types.go b/pkg/context/types.go deleted file mode 100644 index 2836343..0000000 --- a/pkg/context/types.go +++ /dev/null @@ -1,64 +0,0 @@ -package context - -import ( - "errors" - - "github.com/asaskevich/govalidator" -) - -type N3IWFNFInfo struct { - GlobalN3IWFID GlobalN3IWFID `yaml:"GlobalN3IWFID" valid:"required"` - RanNodeName string `yaml:"Name,omitempty" valid:"optional"` - SupportedTAList []SupportedTAItem `yaml:"SupportedTAList" valid:"required"` -} - -type GlobalN3IWFID struct { - PLMNID PLMNID `yaml:"PLMNID" valid:"required"` - N3IWFID uint16 `yaml:"N3IWFID" valid:"range(0|65535),required"` // with length 2 bytes -} - -type SupportedTAItem struct { - TAC string `yaml:"TAC" valid:"hexadecimal,stringlength(6|6),required"` - BroadcastPLMNList []BroadcastPLMNItem `yaml:"BroadcastPLMNList" valid:"required"` -} - -type BroadcastPLMNItem struct { - PLMNID PLMNID `yaml:"PLMNID" valid:"required"` - TAISliceSupportList []SliceSupportItem `yaml:"TAISliceSupportList" valid:"required"` -} - -type PLMNID struct { - Mcc string `yaml:"MCC" valid:"numeric,stringlength(3|3),required"` - Mnc string `yaml:"MNC" valid:"numeric,stringlength(2|3),required"` -} - -type SliceSupportItem struct { - SNSSAI SNSSAIItem `yaml:"SNSSAI" valid:"required"` -} - -type SNSSAIItem struct { - SST string `yaml:"SST" valid:"hexadecimal,stringlength(1|1),required"` - SD string `yaml:"SD,omitempty" valid:"hexadecimal,stringlength(6|6),required"` -} - -type AMFSCTPAddresses struct { - IPAddresses []string `yaml:"IP" valid:"required"` - Port int `yaml:"Port,omitempty" valid:"port,optional"` // Default port is 38412 if not defined. -} - -func (a *AMFSCTPAddresses) Validate() (bool, error) { - var errs govalidator.Errors - - for _, IPAddress := range a.IPAddresses { - if !govalidator.IsHost(IPAddress) { - err := errors.New("Invalid AMFSCTPAddresses.IP: " + IPAddress + ", does not validate as IP") - errs = append(errs, err) - } - } - - if len(errs) > 0 { - return false, errs - } - - return true, nil -} diff --git a/pkg/context/ue.go b/pkg/context/ue.go index 183d8aa..ba41734 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -16,21 +16,46 @@ const ( AmfUeNgapIdUnspecified int64 = 0xffffffffff ) -type N3IWFUe struct { +type N3IWFIkeUe struct { /* UE identity */ - RanUeNgapId int64 - AmfUeNgapId int64 - IPAddrv4 string - IPAddrv6 string - PortNumber int32 - MaskedIMEISV *ngapType.MaskedIMEISV // TS 38.413 9.3.1.54 - Guti string IPSecInnerIP net.IP IPSecInnerIPAddr *net.IPAddr // Used to send UP packets to UE + /* IKE Security Association */ + N3IWFIKESecurityAssociation *IKESecurityAssociation + N3IWFChildSecurityAssociation map[uint32]*ChildSecurityAssociation // inbound SPI as key + + /* Temporary Mapping of two SPIs */ + // Exchange Message ID(including a SPI) and ChildSA(including a SPI) + // Mapping of Message ID of exchange in IKE and Child SA when creating new child SA + TemporaryExchangeMsgIDChildSAMapping map[uint32]*ChildSecurityAssociation // Message ID as a key + + /* Security */ + Kn3iwf []uint8 // 32 bytes (256 bits), value is from NGAP IE "Security Key" + + /* NAS IKE Connection */ + IKEConnection *UDPSocketInfo + + // Length of PDU Session List + PduSessionListLen int +} + +type N3IWFRanUe struct { + /* UE identity */ + RanUeNgapId int64 + AmfUeNgapId int64 + IPAddrv4 string + IPAddrv6 string + PortNumber int32 + MaskedIMEISV *ngapType.MaskedIMEISV // TS 38.413 9.3.1.54 + Guti string + /* Relative Context */ AMF *N3IWFAMF + /* Security */ + SecurityCapabilities *ngapType.UESecurityCapabilities // TS 38.413 9.3.1.86 + /* PDU Session */ PduSessionList map[int64]*PDUSession // pduSessionId as key @@ -44,22 +69,10 @@ type N3IWFUe struct { // UE send CREATE_CHILD_SA response TemporaryCachedNASMessage []byte - /* Security */ - Kn3iwf []uint8 // 32 bytes (256 bits), value is from NGAP IE "Security Key" - SecurityCapabilities *ngapType.UESecurityCapabilities // TS 38.413 9.3.1.86 - - /* IKE Security Association */ - N3IWFIKESecurityAssociation *IKESecurityAssociation - N3IWFChildSecurityAssociation map[uint32]*ChildSecurityAssociation // inbound SPI as key - SignallingIPsecSAEstablished bool - - /* Temporary Mapping of two SPIs */ - // Exchange Message ID(including a SPI) and ChildSA(including a SPI) - // Mapping of Message ID of exchange in IKE and Child SA when creating new child SA - TemporaryExchangeMsgIDChildSAMapping map[uint32]*ChildSecurityAssociation // Message ID as a key + /* NAS TCP Connection Established */ + IsNASTCPConnEstablished bool + IsNASTCPConnEstablishedComplete bool - /* NAS IKE Connection */ - IKEConnection *UDPSocketInfo /* NAS TCP Connection */ TCPConnection net.Conn @@ -92,7 +105,7 @@ type PDUSession struct { type PDUSessionSetupTemporaryData struct { // Slice of unactivated PDU session - UnactivatedPDUSession []int64 // PDUSessionID as content + UnactivatedPDUSession []*PDUSession // PDUSession as content // NGAPProcedureCode is used to identify which type of // response shall be used NGAPProcedureCode ngapType.ProcedureCode @@ -101,6 +114,16 @@ type PDUSessionSetupTemporaryData struct { FailedListCxtRes *ngapType.PDUSessionResourceFailedToSetupListCxtRes SetupListSURes *ngapType.PDUSessionResourceSetupListSURes FailedListSURes *ngapType.PDUSessionResourceFailedToSetupListSURes + // List of Error for failed setup PDUSessionID + FailedErrStr []EvtError // Error string as content + // Current Index of UnactivatedPDUSession + Index int +} + +type IkeMsgTemporaryData struct { + SecurityAssociation *ike_message.SecurityAssociation + TrafficSelectorInitiator *ike_message.TrafficSelectorInitiator + TrafficSelectorResponder *ike_message.TrafficSelectorResponder } type QosFlow struct { @@ -156,6 +179,9 @@ type IKESecurityAssociation struct { TrafficSelectorResponder *ike_message.TrafficSelectorResponder LastEAPIdentifier uint8 + // UDP Connection + IKEConnection *UDPSocketInfo + // Authentication data ResponderSignedOctets []byte InitiatorSignedOctets []byte @@ -167,14 +193,23 @@ type IKESecurityAssociation struct { // If N3IWFIsBehindNAT == true, N3IWF should send UDP keepalive periodically N3IWFIsBehindNAT bool - // UE context - ThisUE *N3IWFUe + // IKE UE context + IkeUE *N3IWFIkeUe + + // Temporary store the receive ike message + TemporaryIkeMsg *IkeMsgTemporaryData DPDReqRetransTimer *Timer // The time from sending the DPD request to receiving the response CurrentRetryTimes int32 // Accumulate the number of times the DPD response wasn't received IKESAClosedCh chan struct{} + IsUseDPD bool } +// Temporary State Data Args +const ( + ArgsUEUDPConn string = "UE UDP Socket Info" +) + type ChildSecurityAssociation struct { // SPI InboundSPI uint32 // N3IWF Specify @@ -212,8 +247,8 @@ type ChildSecurityAssociation struct { // PDU Session IDs associated with this child SA PDUSessionIds []int64 - // UE context - ThisUE *N3IWFUe + // IKE UE context + IkeUE *N3IWFIkeUe } type UDPSocketInfo struct { @@ -222,38 +257,59 @@ type UDPSocketInfo struct { UEAddr *net.UDPAddr } -func (ue *N3IWFUe) init(ranUeNgapId int64) { - ue.RanUeNgapId = ranUeNgapId - ue.AmfUeNgapId = AmfUeNgapIdUnspecified - ue.PduSessionList = make(map[int64]*PDUSession) - ue.N3IWFChildSecurityAssociation = make(map[uint32]*ChildSecurityAssociation) - ue.TemporaryExchangeMsgIDChildSAMapping = make(map[uint32]*ChildSecurityAssociation) +func (ikeUe *N3IWFIkeUe) init() { + ikeUe.N3IWFChildSecurityAssociation = make(map[uint32]*ChildSecurityAssociation) + ikeUe.TemporaryExchangeMsgIDChildSAMapping = make(map[uint32]*ChildSecurityAssociation) } -func (ue *N3IWFUe) Remove() error { - // remove from AMF context - ue.DetachAMF() - ue.N3IWFIKESecurityAssociation.IKESAClosedCh <- struct{}{} - // remove from N3IWF context +func (ranUe *N3IWFRanUe) init(ranUeNgapId int64) { + ranUe.RanUeNgapId = ranUeNgapId + ranUe.AmfUeNgapId = AmfUeNgapIdUnspecified + ranUe.PduSessionList = make(map[int64]*PDUSession) + ranUe.IsNASTCPConnEstablished = false + ranUe.IsNASTCPConnEstablishedComplete = false +} + +func (ikeUe *N3IWFIkeUe) Remove() error { + if ikeUe.N3IWFIKESecurityAssociation.IsUseDPD { + ikeUe.N3IWFIKESecurityAssociation.IKESAClosedCh <- struct{}{} + } + + // remove from IKE UE context n3iwfSelf := N3IWFSelf() - n3iwfSelf.DeleteN3iwfUe(ue.RanUeNgapId) - n3iwfSelf.DeleteIKESecurityAssociation(ue.N3IWFIKESecurityAssociation.LocalSPI) - n3iwfSelf.DeleteInternalUEIPAddr(ue.IPSecInnerIP.String()) + n3iwfSelf.DeleteIKESecurityAssociation(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + n3iwfSelf.DeleteInternalUEIPAddr(ikeUe.IPSecInnerIP.String()) - for _, childSA := range ue.N3IWFChildSecurityAssociation { - if err := ue.DeleteChildSA(childSA); err != nil { + for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { + if err := ikeUe.DeleteChildSA(childSA); err != nil { return err } } + n3iwfSelf.DeleteIKEUe(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + + return nil +} + +func (ranUe *N3IWFRanUe) Remove() error { + // remove from AMF context + ranUe.DetachAMF() - for _, pduSession := range ue.PduSessionList { + // remove from RAN UE context + n3iwfSelf := N3IWFSelf() + n3iwfSelf.DeleteRanUe(ranUe.RanUeNgapId) + + for _, pduSession := range ranUe.PduSessionList { n3iwfSelf.DeleteTEID(pduSession.GTPConnection.IncomingTEID) } + if err := ranUe.TCPConnection.Close(); err != nil { + return fmt.Errorf("Stop nwucp server error : %+v", err) + } + return nil } -func (ue *N3IWFUe) DeleteChildSA(childSA *ChildSecurityAssociation) error { +func (ikeUe *N3IWFIkeUe) DeleteChildSA(childSA *ChildSecurityAssociation) error { n3iwfSelf := N3IWFSelf() iface := childSA.XfrmIface @@ -277,21 +333,21 @@ func (ue *N3IWFUe) DeleteChildSA(childSA *ChildSecurityAssociation) error { n3iwfSelf.XfrmIfaces.Delete(uint32(childSA.XfrmStateList[0].Ifid)) } - delete(ue.N3IWFChildSecurityAssociation, childSA.InboundSPI) + delete(ikeUe.N3IWFChildSecurityAssociation, childSA.InboundSPI) return nil } -func (ue *N3IWFUe) FindPDUSession(pduSessionID int64) *PDUSession { - if pduSession, ok := ue.PduSessionList[pduSessionID]; ok { +func (ranUe *N3IWFRanUe) FindPDUSession(pduSessionID int64) *PDUSession { + if pduSession, ok := ranUe.PduSessionList[pduSessionID]; ok { return pduSession } else { return nil } } -func (ue *N3IWFUe) CreatePDUSession(pduSessionID int64, snssai ngapType.SNSSAI) (*PDUSession, error) { - if _, exists := ue.PduSessionList[pduSessionID]; exists { +func (ranUe *N3IWFRanUe) CreatePDUSession(pduSessionID int64, snssai ngapType.SNSSAI) (*PDUSession, error) { + if _, exists := ranUe.PduSessionList[pduSessionID]; exists { return nil, fmt.Errorf("PDU Session[ID:%d] is already exists", pduSessionID) } pduSession := &PDUSession{ @@ -299,33 +355,33 @@ func (ue *N3IWFUe) CreatePDUSession(pduSessionID int64, snssai ngapType.SNSSAI) Snssai: snssai, QosFlows: make(map[int64]*QosFlow), } - ue.PduSessionList[pduSessionID] = pduSession + ranUe.PduSessionList[pduSessionID] = pduSession return pduSession, nil } // When N3IWF send CREATE_CHILD_SA request to N3UE, the inbound SPI of childSA will be only stored first until // receive response and call CompleteChildSAWithProposal to fill the all data of childSA -func (ue *N3IWFUe) CreateHalfChildSA(msgID, inboundSPI uint32, pduSessionID int64) { +func (ikeUe *N3IWFIkeUe) CreateHalfChildSA(msgID, inboundSPI uint32, pduSessionID int64) { childSA := new(ChildSecurityAssociation) childSA.InboundSPI = inboundSPI childSA.PDUSessionIds = append(childSA.PDUSessionIds, pduSessionID) // Link UE context - childSA.ThisUE = ue + childSA.IkeUE = ikeUe // Map Exchange Message ID and Child SA data until get paired response - ue.TemporaryExchangeMsgIDChildSAMapping[msgID] = childSA + ikeUe.TemporaryExchangeMsgIDChildSAMapping[msgID] = childSA } -func (ue *N3IWFUe) CompleteChildSA(msgID uint32, outboundSPI uint32, +func (ikeUe *N3IWFIkeUe) CompleteChildSA(msgID uint32, outboundSPI uint32, chosenSecurityAssociation *ike_message.SecurityAssociation, ) (*ChildSecurityAssociation, error) { - childSA, ok := ue.TemporaryExchangeMsgIDChildSAMapping[msgID] + childSA, ok := ikeUe.TemporaryExchangeMsgIDChildSAMapping[msgID] if !ok { return nil, fmt.Errorf("There's not a half child SA created by the exchange with message ID %d.", msgID) } // Remove mapping of exchange msg ID and child SA - delete(ue.TemporaryExchangeMsgIDChildSAMapping, msgID) + delete(ikeUe.TemporaryExchangeMsgIDChildSAMapping, msgID) if chosenSecurityAssociation == nil { return nil, errors.New("chosenSecurityAssociation is nil") @@ -352,26 +408,26 @@ func (ue *N3IWFUe) CompleteChildSA(msgID uint32, outboundSPI uint32, } // Record to UE context with inbound SPI as key - ue.N3IWFChildSecurityAssociation[childSA.InboundSPI] = childSA + ikeUe.N3IWFChildSecurityAssociation[childSA.InboundSPI] = childSA // Record to N3IWF context with inbound SPI as key n3iwfContext.ChildSA.Store(childSA.InboundSPI, childSA) return childSA, nil } -func (ue *N3IWFUe) AttachAMF(sctpAddr string) bool { +func (ranUe *N3IWFRanUe) AttachAMF(sctpAddr string) bool { if amf, ok := n3iwfContext.AMFPoolLoad(sctpAddr); ok { - amf.N3iwfUeList[ue.RanUeNgapId] = ue - ue.AMF = amf + amf.N3iwfRanUeList[ranUe.RanUeNgapId] = ranUe + ranUe.AMF = amf return true } else { return false } } -func (ue *N3IWFUe) DetachAMF() { - if ue.AMF == nil { +func (ranUe *N3IWFRanUe) DetachAMF() { + if ranUe.AMF == nil { return } - delete(ue.AMF.N3iwfUeList, ue.RanUeNgapId) + delete(ranUe.AMF.N3iwfRanUeList, ranUe.RanUeNgapId) } diff --git a/pkg/factory/config.go b/pkg/factory/config.go index a4c2d1e..ed952b5 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -5,40 +5,90 @@ package factory import ( + "errors" "fmt" + "sync" "time" "github.com/asaskevich/govalidator" - "github.com/free5gc/n3iwf/pkg/context" - logger_util "github.com/free5gc/util/logger" + "github.com/free5gc/n3iwf/internal/logger" ) const ( - N3iwfExpectedConfigVersion = "1.0.4" + N3iwfDefaultTLSKeyLogPath = "./log/n3iwfsslkey.log" + N3iwfDefaultCertPemPath = "./cert/n3iwf.pem" + N3iwfDefaultPrivateKeyPath = "./cert/n3iwf.key" + N3iwfDefaultConfigPath = "./config/n3iwfcfg.yaml" ) -type Config struct { - Info *Info `yaml:"info" valid:"required"` - Configuration *Configuration `yaml:"configuration" valid:"required"` - Logger *logger_util.Logger `yaml:"logger" valid:"optional"` +type N3IWFNFInfo struct { + GlobalN3IWFID GlobalN3IWFID `yaml:"GlobalN3IWFID" valid:"required"` + RanNodeName string `yaml:"Name,omitempty" valid:"optional"` + SupportedTAList []SupportedTAItem `yaml:"SupportedTAList" valid:"required"` } -func (c *Config) Validate() (bool, error) { - if info := c.Info; info != nil { - if result, err := info.validate(); err != nil { - return result, err +type GlobalN3IWFID struct { + PLMNID PLMNID `yaml:"PLMNID" valid:"required"` + N3IWFID uint16 `yaml:"N3IWFID" valid:"range(0|65535),required"` // with length 2 bytes +} + +type SupportedTAItem struct { + TAC string `yaml:"TAC" valid:"hexadecimal,stringlength(6|6),required"` + BroadcastPLMNList []BroadcastPLMNItem `yaml:"BroadcastPLMNList" valid:"required"` +} + +type BroadcastPLMNItem struct { + PLMNID PLMNID `yaml:"PLMNID" valid:"required"` + TAISliceSupportList []SliceSupportItem `yaml:"TAISliceSupportList" valid:"required"` +} + +type PLMNID struct { + Mcc string `yaml:"MCC" valid:"numeric,stringlength(3|3),required"` + Mnc string `yaml:"MNC" valid:"numeric,stringlength(2|3),required"` +} + +type SliceSupportItem struct { + SNSSAI SNSSAIItem `yaml:"SNSSAI" valid:"required"` +} + +type SNSSAIItem struct { + SST string `yaml:"SST" valid:"hexadecimal,stringlength(1|1),required"` + SD string `yaml:"SD,omitempty" valid:"hexadecimal,stringlength(6|6),required"` +} + +type AMFSCTPAddresses struct { + IPAddresses []string `yaml:"IP" valid:"required"` + Port int `yaml:"Port,omitempty" valid:"port,optional"` // Default port is 38412 if not defined. +} + +func (a *AMFSCTPAddresses) Validate() (bool, error) { + var errs govalidator.Errors + + for _, IPAddress := range a.IPAddresses { + if !govalidator.IsHost(IPAddress) { + err := errors.New("Invalid AMFSCTPAddresses.IP: " + IPAddress + ", does not validate as IP") + errs = append(errs, err) } } - if configuration := c.Configuration; configuration != nil { - if result, err := configuration.validate(); err != nil { - return result, err - } + if len(errs) > 0 { + return false, errs } - if logger := c.Logger; logger != nil { - if result, err := logger.Validate(); err != nil { + return true, nil +} + +type Config struct { + Info *Info `yaml:"info" valid:"required"` + Configuration *Configuration `yaml:"configuration" valid:"required"` + Logger *Logger `yaml:"logger" valid:"required"` + sync.RWMutex +} + +func (c *Config) Validate() (bool, error) { + if configuration := c.Configuration; configuration != nil { + if result, err := configuration.validate(); err != nil { return result, err } } @@ -48,18 +98,13 @@ func (c *Config) Validate() (bool, error) { } type Info struct { - Version string `yaml:"version,omitempty" valid:"type(string),required"` - Description string `yaml:"description,omitempty" valid:"type(string),optional"` -} - -func (i *Info) validate() (bool, error) { - result, err := govalidator.ValidateStruct(i) - return result, appendInvalid(err) + Version string `yaml:"version,omitempty" valid:"required,in(1.0.5)"` + Description string `yaml:"description,omitempty" valid:"type(string)"` } type Configuration struct { - N3IWFInfo context.N3IWFNFInfo `yaml:"N3IWFInformation" valid:"required"` - AMFSCTPAddresses []context.AMFSCTPAddresses `yaml:"AMFSCTPAddresses" valid:"required"` + N3IWFInfo N3IWFNFInfo `yaml:"N3IWFInformation" valid:"required"` + AMFSCTPAddresses []AMFSCTPAddresses `yaml:"AMFSCTPAddresses" valid:"required"` TCPPort uint16 `yaml:"NASTCPPort" valid:"port,required"` IKEBindAddr string `yaml:"IKEBindAddress" valid:"host,required"` @@ -75,6 +120,12 @@ type Configuration struct { LivenessCheck TimerValue `yaml:"LivenessCheck" valid:"required"` } +type Logger struct { + Enable bool `yaml:"enable" valid:"type(bool)"` + Level string `yaml:"level" valid:"required,in(trace|debug|info|warn|error|fatal|panic)"` + ReportCaller bool `yaml:"reportCaller" valid:"type(bool)"` +} + func (c *Configuration) validate() (bool, error) { for _, amfSCTPAddress := range c.AMFSCTPAddresses { if result, err := amfSCTPAddress.Validate(); err != nil { @@ -94,6 +145,20 @@ func (c *Configuration) validate() (bool, error) { return result, appendInvalid(err) } +type TimerValue struct { + Enable bool `yaml:"enable" valid:"type(bool)"` + TransFreq time.Duration `yaml:"transFreq" valid:"type(time.Duration)"` + MaxRetryTimes int32 `yaml:"maxRetryTimes,omitempty" valid:"type(int32)"` +} + +func (t *TimerValue) validate() (bool, error) { + if _, err := govalidator.ValidateStruct(t); err != nil { + return false, appendInvalid(err) + } + + return true, nil +} + func appendInvalid(err error) error { var errs govalidator.Errors @@ -110,22 +175,85 @@ func appendInvalid(err error) error { } func (c *Config) GetVersion() string { - if c.Info != nil && c.Info.Version != "" { + c.RLock() + defer c.RUnlock() + + if c.Info.Version != "" { return c.Info.Version } return "" } -type TimerValue struct { - Enable bool `yaml:"enable" valid:"type(bool)"` - TransFreq time.Duration `yaml:"transFreq" valid:"type(time.Duration)"` - MaxRetryTimes int32 `yaml:"maxRetryTimes,omitempty" valid:"type(int32)"` +func (c *Config) SetLogEnable(enable bool) { + c.Lock() + defer c.Unlock() + + if c.Logger == nil { + logger.CfgLog.Warnf("Logger should not be nil") + c.Logger = &Logger{ + Enable: enable, + Level: "info", + } + } else { + c.Logger.Enable = enable + } } -func (t *TimerValue) validate() (bool, error) { - if _, err := govalidator.ValidateStruct(t); err != nil { - return false, appendInvalid(err) +func (c *Config) SetLogLevel(level string) { + c.Lock() + defer c.Unlock() + + if c.Logger == nil { + logger.CfgLog.Warnf("Logger should not be nil") + c.Logger = &Logger{ + Level: level, + } + } else { + c.Logger.Level = level } +} - return true, nil +func (c *Config) SetLogReportCaller(reportCaller bool) { + c.Lock() + defer c.Unlock() + + if c.Logger == nil { + logger.CfgLog.Warnf("Logger should not be nil") + c.Logger = &Logger{ + Level: "info", + ReportCaller: reportCaller, + } + } else { + c.Logger.ReportCaller = reportCaller + } +} + +func (c *Config) GetLogEnable() bool { + c.RLock() + defer c.RUnlock() + if c.Logger == nil { + logger.CfgLog.Warnf("Logger should not be nil") + return false + } + return c.Logger.Enable +} + +func (c *Config) GetLogLevel() string { + c.RLock() + defer c.RUnlock() + if c.Logger == nil { + logger.CfgLog.Warnf("Logger should not be nil") + return "info" + } + return c.Logger.Level +} + +func (c *Config) GetLogReportCaller() bool { + c.RLock() + defer c.RUnlock() + if c.Logger == nil { + logger.CfgLog.Warnf("Logger should not be nil") + return false + } + return c.Logger.ReportCaller } diff --git a/pkg/factory/factory.go b/pkg/factory/factory.go index 61f1c89..5f35a85 100644 --- a/pkg/factory/factory.go +++ b/pkg/factory/factory.go @@ -8,37 +8,46 @@ import ( "fmt" "io/ioutil" + "github.com/asaskevich/govalidator" yaml "gopkg.in/yaml.v2" "github.com/free5gc/n3iwf/internal/logger" ) -var N3iwfConfig Config +var N3iwfConfig *Config // TODO: Support configuration update from REST api -func InitConfigFactory(f string) error { +func InitConfigFactory(f string, cfg *Config) error { + if f == "" { + // Use default config path + f = N3iwfDefaultConfigPath + } + if content, err := ioutil.ReadFile(f); err != nil { - return err + return fmt.Errorf("[Factory] %+v", err) } else { - N3iwfConfig = Config{} - - if yamlErr := yaml.Unmarshal(content, &N3iwfConfig); yamlErr != nil { - return yamlErr + logger.CfgLog.Infof("Read config from [%s]", f) + if yamlErr := yaml.Unmarshal(content, cfg); yamlErr != nil { + return fmt.Errorf("[Factory] %+v", yamlErr) } } return nil } -func CheckConfigVersion() error { - currentVersion := N3iwfConfig.GetVersion() - - if currentVersion != N3iwfExpectedConfigVersion { - return fmt.Errorf("config version is [%s], but expected is [%s].", - currentVersion, N3iwfExpectedConfigVersion) +func ReadConfig(cfgPath string) (*Config, error) { + cfg := &Config{} + if err := InitConfigFactory(cfgPath, cfg); err != nil { + return nil, fmt.Errorf("ReadConfig [%s] Error: %+v", cfgPath, err) + } + if _, err := cfg.Validate(); err != nil { + validErrs := err.(govalidator.Errors).Errors() + for _, validErr := range validErrs { + logger.CfgLog.Errorf("%+v", validErr) + } + logger.CfgLog.Errorf("[-- PLEASE REFER TO SAMPLE CONFIG FILE COMMENTS --]") + return nil, fmt.Errorf("Config validate Error") } - logger.CfgLog.Infof("config version [%s]", currentVersion) - - return nil + return cfg, nil } diff --git a/pkg/ike/dispatcher.go b/pkg/ike/dispatcher.go index 55e5b33..a75bdfc 100644 --- a/pkg/ike/dispatcher.go +++ b/pkg/ike/dispatcher.go @@ -4,20 +4,12 @@ import ( "net" "runtime/debug" - "github.com/sirupsen/logrus" - "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/ike/handler" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" ) -var ikeLog *logrus.Entry - -func init() { - ikeLog = logger.IKELog -} - -func Dispatch(udpConn *net.UDPConn, localAddr, remoteAddr *net.UDPAddr, msg []byte) { +func IkeDispatch(udpConn *net.UDPConn, localAddr, remoteAddr *net.UDPAddr, msg []byte) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. @@ -30,7 +22,7 @@ func Dispatch(udpConn *net.UDPConn, localAddr, remoteAddr *net.UDPAddr, msg []by if localAddr.Port == 4500 { for i := 0; i < 4; i++ { if msg[i] != 0 { - ikeLog.Warn( + logger.IKELog.Warn( "Received an IKE packet that does not prepend 4 bytes zero from UDP port 4500," + " this packet may be the UDP encapsulated ESP. The packet will not be handled.") return @@ -43,7 +35,7 @@ func Dispatch(udpConn *net.UDPConn, localAddr, remoteAddr *net.UDPAddr, msg []by err := ikeMessage.Decode(msg) if err != nil { - ikeLog.Error(err) + logger.IKELog.Error(err) return } @@ -57,6 +49,6 @@ func Dispatch(udpConn *net.UDPConn, localAddr, remoteAddr *net.UDPAddr, msg []by case ike_message.INFORMATIONAL: handler.HandleInformational(udpConn, localAddr, remoteAddr, ikeMessage) default: - ikeLog.Warnf("Unimplemented IKE message type, exchange type: %d", ikeMessage.ExchangeType) + logger.IKELog.Warnf("Unimplemented IKE message type, exchange type: %d", ikeMessage.ExchangeType) } } diff --git a/pkg/ike/handler/3gpp_types.go b/pkg/ike/handler/3gpp_types.go index 350a756..464462e 100644 --- a/pkg/ike/handler/3gpp_types.go +++ b/pkg/ike/handler/3gpp_types.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/free5gc/aper" + "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/ike/message" "github.com/free5gc/ngap/ngapType" ) @@ -21,10 +22,10 @@ type ANParameters struct { func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *ANParameters, nasPDU []byte, err error) { if len(codedData) >= 2 { - ikeLog.Debug("===== Unmarshal EAP5G Data (Ref: TS24.502 Fig. 9.3.2.2.2-1) =====") + logger.IKELog.Debug("===== Unmarshal EAP5G Data (Ref: TS24.502 Fig. 9.3.2.2.2-1) =====") eap5GMessageID = codedData[0] - ikeLog.Debugf("Message-Id: %d", eap5GMessageID) + logger.IKELog.Debugf("Message-Id: %d", eap5GMessageID) if eap5GMessageID == message.EAP5GType5GStop { return } @@ -39,20 +40,20 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A if len(codedData) >= 2 { // Length of the AN-Parameter field anParameterLength := binary.BigEndian.Uint16(codedData[:2]) - ikeLog.Debugf("AN-parameters length: %d", anParameterLength) + logger.IKELog.Debugf("AN-parameters length: %d", anParameterLength) if anParameterLength != 0 { anParameterField := codedData[2:] // Bound checking if len(anParameterField) < int(anParameterLength) { - ikeLog.Error("Packet contained error length of value") + logger.IKELog.Error("Packet contained error length of value") return 0, nil, nil, errors.New("Error formatting") } else { anParameterField = anParameterField[:anParameterLength] } - ikeLog.Debugf("Parsing AN-parameters...: % v", anParameterField) + logger.IKELog.Debugf("Parsing AN-parameters...: % v", anParameterField) anParameters = new(ANParameters) @@ -64,7 +65,7 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A switch parameterType { case message.ANParametersTypeGUAMI: - ikeLog.Debugf("-> Parameter type: GUAMI") + logger.IKELog.Debugf("-> Parameter type: GUAMI") if parameterLength != 0 { parameterValue := anParameterField[2:] @@ -84,20 +85,20 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A ngapGUAMI := new(ngapType.GUAMI) err := aper.UnmarshalWithParams(guamiField, ngapGUAMI, "valueExt") if err != nil { - ikeLog.Errorf("APER unmarshal with parameter failed: %+v", err) + logger.IKELog.Errorf("APER unmarshal with parameter failed: %+v", err) return 0, nil, nil, errors.New("Unmarshal failed when decoding GUAMI") } anParameters.GUAMI = ngapGUAMI - ikeLog.Debugf("Unmarshal GUAMI: % x", guamiField) - ikeLog.Debugf("\tGUAMI: PLMNIdentity[% x], "+ + logger.IKELog.Debugf("Unmarshal GUAMI: % x", guamiField) + logger.IKELog.Debugf("\tGUAMI: PLMNIdentity[% x], "+ "AMFRegionID[% x], AMFSetID[% x], AMFPointer[% x]", anParameters.GUAMI.PLMNIdentity, anParameters.GUAMI.AMFRegionID, anParameters.GUAMI.AMFSetID, anParameters.GUAMI.AMFPointer) } else { - ikeLog.Warn("AN-Parameter GUAMI field empty") + logger.IKELog.Warn("AN-Parameter GUAMI field empty") } case message.ANParametersTypeSelectedPLMNID: - ikeLog.Debugf("-> Parameter type: ANParametersTypeSelectedPLMNID") + logger.IKELog.Debugf("-> Parameter type: ANParametersTypeSelectedPLMNID") if parameterLength != 0 { parameterValue := anParameterField[2:] @@ -117,17 +118,17 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A ngapPLMN := new(ngapType.PLMNIdentity) err := aper.UnmarshalWithParams(plmnField, ngapPLMN, "valueExt") if err != nil { - ikeLog.Errorf("APER unmarshal with parameter failed: %v", err) + logger.IKELog.Errorf("APER unmarshal with parameter failed: %v", err) return 0, nil, nil, errors.New("Unmarshal failed when decoding PLMN") } anParameters.SelectedPLMNID = ngapPLMN - ikeLog.Debugf("Unmarshal SelectedPLMNID: % x", plmnField) - ikeLog.Debugf("\tSelectedPLMNID: % x", anParameters.SelectedPLMNID.Value) + logger.IKELog.Debugf("Unmarshal SelectedPLMNID: % x", plmnField) + logger.IKELog.Debugf("\tSelectedPLMNID: % x", anParameters.SelectedPLMNID.Value) } else { - ikeLog.Warn("AN-Parameter PLMN field empty") + logger.IKELog.Warn("AN-Parameter PLMN field empty") } case message.ANParametersTypeRequestedNSSAI: - ikeLog.Debugf("-> Parameter type: ANParametersTypeRequestedNSSAI") + logger.IKELog.Debugf("-> Parameter type: ANParametersTypeRequestedNSSAI") if parameterLength != 0 { parameterValue := anParameterField[2:] @@ -149,7 +150,7 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A snssaiValue := parameterValue[1:] if len(snssaiValue) < int(snssaiLength) { - ikeLog.Error("SNSSAI length error") + logger.IKELog.Error("SNSSAI length error") return 0, nil, nil, errors.New("Error formatting") } else { snssaiValue = snssaiValue[:snssaiLength] @@ -173,19 +174,19 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A }, } } else { - ikeLog.Error("Empty SNSSAI value") + logger.IKELog.Error("Empty SNSSAI value") return 0, nil, nil, errors.New("Error formatting") } ngapNSSAI.List = append(ngapNSSAI.List, ngapSNSSAIItem) - ikeLog.Debugf("Unmarshal SNSSAI: % x", parameterValue[:1+snssaiLength]) - ikeLog.Debugf("\t\t\tSST: % x", ngapSNSSAIItem.SNSSAI.SST.Value) + logger.IKELog.Debugf("Unmarshal SNSSAI: % x", parameterValue[:1+snssaiLength]) + logger.IKELog.Debugf("\t\t\tSST: % x", ngapSNSSAIItem.SNSSAI.SST.Value) sd := ngapSNSSAIItem.SNSSAI.SD if sd == nil { - ikeLog.Debugf("\t\t\tSD: nil") + logger.IKELog.Debugf("\t\t\tSD: nil") } else { - ikeLog.Debugf("\t\t\tSD: % x", sd.Value) + logger.IKELog.Debugf("\t\t\tSD: % x", sd.Value) } // shift parameterValue for parsing next s-nssai @@ -193,10 +194,10 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A } anParameters.RequestedNSSAI = ngapNSSAI } else { - ikeLog.Warn("AN-Parameter NSSAI is empty") + logger.IKELog.Warn("AN-Parameter NSSAI is empty") } case message.ANParametersTypeEstablishmentCause: - ikeLog.Debugf("-> Parameter type: ANParametersTypeEstablishmentCause") + logger.IKELog.Debugf("-> Parameter type: ANParametersTypeEstablishmentCause") if parameterLength != 0 { parameterValue := anParameterField[2:] @@ -210,24 +211,24 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A return 0, nil, nil, errors.New("Unmatched Establishment Cause length") } - ikeLog.Debugf("Unmarshal ANParametersTypeEstablishmentCause: % x", parameterValue) + logger.IKELog.Debugf("Unmarshal ANParametersTypeEstablishmentCause: % x", parameterValue) establishmentCause := parameterValue[0] & 0x0f switch establishmentCause { case message.EstablishmentCauseEmergency: - ikeLog.Trace("AN-Parameter establishment cause: Emergency") + logger.IKELog.Trace("AN-Parameter establishment cause: Emergency") case message.EstablishmentCauseHighPriorityAccess: - ikeLog.Trace("AN-Parameter establishment cause: High Priority Access") + logger.IKELog.Trace("AN-Parameter establishment cause: High Priority Access") case message.EstablishmentCauseMO_Signalling: - ikeLog.Trace("AN-Parameter establishment cause: MO Signalling") + logger.IKELog.Trace("AN-Parameter establishment cause: MO Signalling") case message.EstablishmentCauseMO_Data: - ikeLog.Trace("AN-Parameter establishment cause: MO Data") + logger.IKELog.Trace("AN-Parameter establishment cause: MO Data") case message.EstablishmentCauseMPS_PriorityAccess: - ikeLog.Trace("AN-Parameter establishment cause: MPS Priority Access") + logger.IKELog.Trace("AN-Parameter establishment cause: MPS Priority Access") case message.EstablishmentCauseMCS_PriorityAccess: - ikeLog.Trace("AN-Parameter establishment cause: MCS Priority Access") + logger.IKELog.Trace("AN-Parameter establishment cause: MCS Priority Access") default: - ikeLog.Trace("AN-Parameter establishment cause: Unknown. Treat as mo-Data") + logger.IKELog.Trace("AN-Parameter establishment cause: Unknown. Treat as mo-Data") establishmentCause = message.EstablishmentCauseMO_Data } @@ -236,10 +237,10 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A anParameters.EstablishmentCause = ngapEstablishmentCause } else { - ikeLog.Warn("AN-Parameter establishment cause field empty") + logger.IKELog.Warn("AN-Parameter establishment cause field empty") } default: - ikeLog.Warn("Unsopprted AN-Parameter. Ignore.") + logger.IKELog.Warn("Unsopprted AN-Parameter. Ignore.") } // shift anParameterField @@ -250,14 +251,14 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A // shift codedData codedData = codedData[2+anParameterLength:] } else { - ikeLog.Error("No AN-Parameter type or length specified") + logger.IKELog.Error("No AN-Parameter type or length specified") return 0, nil, nil, errors.New("Error formatting") } if len(codedData) >= 2 { // Length of the NASPDU field nasPDULength := binary.BigEndian.Uint16(codedData[:2]) - ikeLog.Debugf("nasPDULength: %d", nasPDULength) + logger.IKELog.Debugf("nasPDULength: %d", nasPDULength) if nasPDULength != 0 { nasPDUField := codedData[2:] @@ -269,15 +270,15 @@ func UnmarshalEAP5GData(codedData []byte) (eap5GMessageID uint8, anParameters *A nasPDUField = nasPDUField[:nasPDULength] } - ikeLog.Debugf("nasPDUField: % v", nasPDUField) + logger.IKELog.Debugf("nasPDUField: % v", nasPDUField) nasPDU = append(nasPDU, nasPDUField...) } else { - ikeLog.Error("No NAS PDU included in EAP-5G packet") + logger.IKELog.Error("No NAS PDU included in EAP-5G packet") return 0, nil, nil, errors.New("No NAS PDU") } } else { - ikeLog.Error("No NASPDU length specified") + logger.IKELog.Error("No NASPDU length specified") return 0, nil, nil, errors.New("Error formatting") } diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index c28dae7..fc62719 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -10,32 +10,23 @@ import ( "encoding/hex" "errors" "fmt" + math_rand "math/rand" "net" "sync/atomic" - "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" "golang.org/x/sys/unix" "github.com/free5gc/n3iwf/internal/logger" - ngap_message "github.com/free5gc/n3iwf/internal/ngap/message" "github.com/free5gc/n3iwf/pkg/context" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" "github.com/free5gc/n3iwf/pkg/ike/xfrm" - "github.com/free5gc/ngap/ngapType" ) -// Log -var ikeLog *logrus.Entry - -func init() { - ikeLog = logger.IKELog -} - func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage, realMessage1 []byte, ) { - ikeLog.Infoln("Handle IKE_SA_INIT") + logger.IKELog.Infoln("Handle IKE_SA_INIT") // Used to receive value from peer var securityAssociation *ike_message.SecurityAssociation @@ -55,7 +46,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa var ueIsBehindNAT, n3iwfIsBehindNAT bool if message == nil { - ikeLog.Error("IKE Message is nil") + logger.IKELog.Error("IKE Message is nil") return } @@ -63,7 +54,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa // check major version majorVersion := ((message.Version & 0xf0) >> 4) if majorVersion > 2 { - ikeLog.Warn("Received an IKE message with higher major version") + logger.IKELog.Warn("Received an IKE message with higher major version") // send INFORMATIONAL type message with INVALID_MAJOR_VERSION Notify payload responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, message.MessageID) @@ -87,7 +78,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa case ike_message.TypeN: notifications = append(notifications, ikePayload.(*ike_message.Notification)) default: - ikeLog.Warnf( + logger.IKELog.Warnf( "Get IKE payload (type %d) in IKE_SA_INIT message, this payload will not be handled by IKE handler", ikePayload.Type()) } @@ -176,7 +167,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa } if len(responseSecurityAssociation.Proposals) == 0 { - ikeLog.Warn("No proposal chosen") + logger.IKELog.Warn("No proposal chosen") // Respond NO_PROPOSAL_CHOSEN to UE responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, message.MessageID) @@ -188,7 +179,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa return } } else { - ikeLog.Error("The security association field is nil") + logger.IKELog.Error("The security association field is nil") // TODO: send error message to UE return } @@ -196,7 +187,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa if keyExcahge != nil { chosenDiffieHellmanGroup := diffieHellmanGroupTransform.TransformID if chosenDiffieHellmanGroup != keyExcahge.DiffieHellmanGroup { - ikeLog.Warn("The Diffie-Hellman group defined in key exchange payload not matches the one in chosen proposal") + logger.IKELog.Warn("The Diffie-Hellman group defined in key exchange payload not matches the one in chosen proposal") // send INVALID_KE_PAYLOAD to UE responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, message.MessageID) @@ -218,7 +209,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa keyExcahge.KeyExchangeData, chosenDiffieHellmanGroup) responseIKEMessage.Payloads.BUildKeyExchange(chosenDiffieHellmanGroup, localPublicValue) } else { - ikeLog.Error("The key exchange field is nil") + logger.IKELog.Error("The key exchange field is nil") // TODO: send error message to UE return } @@ -229,7 +220,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa responseIKEMessage.Payloads.BuildNonce(localNonce) } else { - ikeLog.Error("The nonce field is nil") + logger.IKELog.Error("The nonce field is nil") // TODO: send error message to UE return } @@ -238,7 +229,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa for _, notification := range notifications { switch notification.NotifyMessageType { case ike_message.NAT_DETECTION_SOURCE_IP: - ikeLog.Trace("Received IKE Notify: NAT_DETECTION_SOURCE_IP") + logger.IKELog.Trace("Received IKE Notify: NAT_DETECTION_SOURCE_IP") // Calculate local NAT_DETECTION_SOURCE_IP hash // : sha1(ispi | rspi | ueip | ueport) localDetectionData := make([]byte, 22) @@ -249,7 +240,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa sha1HashFunction := sha1.New() if _, err := sha1HashFunction.Write(localDetectionData); err != nil { - ikeLog.Errorf("Hash function write error: %+v", err) + logger.IKELog.Errorf("Hash function write error: %+v", err) return } @@ -257,7 +248,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa ueIsBehindNAT = true } case ike_message.NAT_DETECTION_DESTINATION_IP: - ikeLog.Trace("Received IKE Notify: NAT_DETECTION_DESTINATION_IP") + logger.IKELog.Trace("Received IKE Notify: NAT_DETECTION_DESTINATION_IP") // Calculate local NAT_DETECTION_SOURCE_IP hash // : sha1(ispi | rspi | n3iwfip | n3iwfport) localDetectionData := make([]byte, 22) @@ -268,7 +259,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa sha1HashFunction := sha1.New() if _, err := sha1HashFunction.Write(localDetectionData); err != nil { - ikeLog.Errorf("Hash function write error: %+v", err) + logger.IKELog.Errorf("Hash function write error: %+v", err) return } @@ -299,7 +290,7 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa ikeSecurityAssociation.DiffieHellmanSharedKey = append(ikeSecurityAssociation.DiffieHellmanSharedKey, sharedKeyData...) if err := GenerateKeyForIKESA(ikeSecurityAssociation); err != nil { - ikeLog.Errorf("Generate key for IKE SA failed: %+v", err) + logger.IKELog.Errorf("Generate key for IKE SA failed: %+v", err) return } @@ -338,8 +329,8 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa // ResponderSignedOctet = RealMessage2 | NonceIData | MACedIDForR responseIKEMessageData, err := responseIKEMessage.Encode() if err != nil { - ikeLog.Errorln(err) - ikeLog.Error("Encoding IKE message failed") + logger.IKELog.Errorln(err) + logger.IKELog.Error("Encoding IKE message failed") return } ikeSecurityAssociation.ResponderSignedOctets = append(responseIKEMessageData, nonce.NonceData...) @@ -348,38 +339,42 @@ func HandleIKESAINIT(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, messa idPayload.BuildIdentificationResponder(ike_message.ID_FQDN, []byte(n3iwfSelf.FQDN)) idPayloadData, err := idPayload.Encode() if err != nil { - ikeLog.Errorln(err) - ikeLog.Error("Encode IKE payload failed.") + logger.IKELog.Errorln(err) + logger.IKELog.Error("Encode IKE payload failed.") return } pseudorandomFunction, ok := NewPseudorandomFunction(ikeSecurityAssociation.SK_pr, ikeSecurityAssociation.PseudorandomFunction.TransformID) if !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") return } if _, err := pseudorandomFunction.Write(idPayloadData[4:]); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) + logger.IKELog.Errorf("Pseudorandom function write error: %+v", err) return } ikeSecurityAssociation.ResponderSignedOctets = append(ikeSecurityAssociation.ResponderSignedOctets, pseudorandomFunction.Sum(nil)...) - ikeLog.Tracef("Local unsigned authentication data:\n%s", hex.Dump(ikeSecurityAssociation.ResponderSignedOctets)) + logger.IKELog.Tracef("Local unsigned authentication data:\n%s", hex.Dump(ikeSecurityAssociation.ResponderSignedOctets)) // Send response to UE SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) } -// IKE_AUTH state const ( + // IKE_AUTH state PreSignalling = iota EAPSignalling PostSignalling + EndSignalling + + // CREATE_CHILDSA + HandleCreateChildSA ) func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage) { - ikeLog.Infoln("Handle IKE_AUTH") + logger.IKELog.Infoln("Handle IKE_AUTH") var encryptedPayload *ike_message.Encrypted @@ -390,7 +385,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message var responseIKEPayload ike_message.IKEPayloadContainer if message == nil { - ikeLog.Error("IKE Message is nil") + logger.IKELog.Error("IKE Message is nil") return } @@ -398,7 +393,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message // check major version majorVersion := ((message.Version & 0xf0) >> 4) if majorVersion > 2 { - ikeLog.Warn("Received an IKE message with higher major version") + logger.IKELog.Warn("Received an IKE message with higher major version") // send INFORMATIONAL type message with INVALID_MAJOR_VERSION Notify payload ( OUTSIDE IKE SA ) responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, message.MessageID) @@ -414,7 +409,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message localSPI := message.ResponderSPI ikeSecurityAssociation, ok := n3iwfSelf.IKESALoad(localSPI) if !ok { - ikeLog.Warn("Unrecognized SPI") + logger.IKELog.Warn("Unrecognized SPI") // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, 0, ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, message.MessageID) @@ -431,7 +426,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message case ike_message.TypeSK: encryptedPayload = ikePayload.(*ike_message.Encrypted) default: - ikeLog.Warnf( + logger.IKELog.Warnf( "Get IKE payload (type %d) in IKE_AUTH message, this payload will not be handled by IKE handler", ikePayload.Type()) } @@ -439,7 +434,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message decryptedIKEPayload, err := DecryptProcedure(ikeSecurityAssociation, message, encryptedPayload) if err != nil { - ikeLog.Errorf("Decrypt IKE message failed: %+v", err) + logger.IKELog.Errorf("Decrypt IKE message failed: %+v", err) return } @@ -475,7 +470,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message case ike_message.TypeCP: configuration = ikePayload.(*ike_message.Configuration) default: - ikeLog.Warnf( + logger.IKELog.Warnf( "Get IKE payload (type %d) in IKE_AUTH message, this payload will not be handled by IKE handler", ikePayload.Type()) } @@ -488,7 +483,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message switch ikeSecurityAssociation.State { case PreSignalling: if initiatorID != nil { - ikeLog.Info("Ecoding initiator for later IKE authentication") + logger.IKELog.Info("Ecoding initiator for later IKE authentication") ikeSecurityAssociation.InitiatorID = initiatorID // Record maced identification for authentication @@ -497,25 +492,26 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message } idPayloadData, err := idPayload.Encode() if err != nil { - ikeLog.Errorln(err) - ikeLog.Error("Encoding ID payload message failed.") + logger.IKELog.Errorln(err) + logger.IKELog.Error("Encoding ID payload message failed.") return } - pseudorandomFunction, ok := NewPseudorandomFunction(ikeSecurityAssociation.SK_pi, + pseudorandomFunction, ok1 := NewPseudorandomFunction( + ikeSecurityAssociation.SK_pi, transformPseudorandomFunction.TransformID) - if !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") + if !ok1 { + logger.IKELog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") return } if _, err := pseudorandomFunction.Write(idPayloadData[4:]); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) + logger.IKELog.Errorf("Pseudorandom function write error: %+v", err) return } ikeSecurityAssociation.InitiatorSignedOctets = append( ikeSecurityAssociation.InitiatorSignedOctets, pseudorandomFunction.Sum(nil)...) } else { - ikeLog.Error("The initiator identification field is nil") + logger.IKELog.Error("The initiator identification field is nil") // TODO: send error message to UE return } @@ -529,20 +525,20 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message // can be validated up to one of the specified certification // authorities. This can be a chain of certificates. if certificateRequest != nil { - ikeLog.Info("UE request N3IWF certificate") + logger.IKELog.Info("UE request N3IWF certificate") if CompareRootCertificate(certificateRequest.CertificateEncoding, certificateRequest.CertificationAuthority) { // TODO: Complete N3IWF Certificate/Certificate Authority related procedure - ikeLog.Info("Certificate Request sent from UE matches N3IWF CA") + logger.IKELog.Info("Certificate Request sent from UE matches N3IWF CA") } } if certificate != nil { - ikeLog.Info("UE send its certficate") + logger.IKELog.Info("UE send its certficate") ikeSecurityAssociation.InitiatorCertificate = certificate } if securityAssociation != nil { - ikeLog.Info("Parsing security association") + logger.IKELog.Info("Parsing security association") responseSecurityAssociation := new(ike_message.SecurityAssociation) for _, proposal := range securityAssociation.Proposals { @@ -627,7 +623,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message } if len(responseSecurityAssociation.Proposals) == 0 { - ikeLog.Warn("No proposal chosen") + logger.IKELog.Warn("No proposal chosen") // Respond NO_PROPOSAL_CHOSEN to UE // Build IKE message responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, @@ -641,7 +637,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message responseIKEPayload.BuildNotification(ike_message.TypeNone, ike_message.NO_PROPOSAL_CHOSEN, nil, nil) if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) return } @@ -653,25 +649,25 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message ikeSecurityAssociation.IKEAuthResponseSA = responseSecurityAssociation } else { - ikeLog.Error("The security association field is nil") + logger.IKELog.Error("The security association field is nil") // TODO: send error message to UE return } if trafficSelectorInitiator != nil { - ikeLog.Info("Received traffic selector initiator from UE") + logger.IKELog.Info("Received traffic selector initiator from UE") ikeSecurityAssociation.TrafficSelectorInitiator = trafficSelectorInitiator } else { - ikeLog.Error("The initiator traffic selector field is nil") + logger.IKELog.Error("The initiator traffic selector field is nil") // TODO: send error message to UE return } if trafficSelectorResponder != nil { - ikeLog.Info("Received traffic selector initiator from UE") + logger.IKELog.Info("Received traffic selector initiator from UE") ikeSecurityAssociation.TrafficSelectorResponder = trafficSelectorResponder } else { - ikeLog.Error("The initiator traffic selector field is nil") + logger.IKELog.Error("The initiator traffic selector field is nil") // TODO: send error message to UE return } @@ -688,16 +684,16 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message responseIKEPayload.BuildCertificate(ike_message.X509CertificateSignature, n3iwfSelf.N3IWFCertificate) // Authentication Data - ikeLog.Tracef("Local authentication data:\n%s", hex.Dump(ikeSecurityAssociation.ResponderSignedOctets)) + logger.IKELog.Tracef("Local authentication data:\n%s", hex.Dump(ikeSecurityAssociation.ResponderSignedOctets)) sha1HashFunction := sha1.New() if _, err := sha1HashFunction.Write(ikeSecurityAssociation.ResponderSignedOctets); err != nil { - ikeLog.Errorf("Hash function write error: %+v", err) + logger.IKELog.Errorf("Hash function write error: %+v", err) return } signedAuth, err := rsa.SignPKCS1v15(rand.Reader, n3iwfSelf.N3IWFPrivateKey, crypto.SHA1, sha1HashFunction.Sum(nil)) if err != nil { - ikeLog.Errorf("Sign authentication data failed: %+v", err) + logger.IKELog.Errorf("Sign authentication data failed: %+v", err) } responseIKEPayload.BuildAuthentication(ike_message.RSADigitalSignature, signedAuth) @@ -707,7 +703,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message for { identifier, err = GenerateRandomUint8() if err != nil { - ikeLog.Errorf("Random number failed: %+v", err) + logger.IKELog.Errorf("Random number failed: %+v", err) return } if identifier != ikeSecurityAssociation.LastEAPIdentifier { @@ -718,7 +714,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message responseIKEPayload.BuildEAP5GStart(identifier) if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) return } @@ -732,11 +728,11 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message // If success, N3IWF will send an UPLinkNASTransport to AMF if eap != nil { if eap.Code != ike_message.EAPCodeResponse { - ikeLog.Error("[EAP] Received an EAP payload with code other than response. Drop the payload.") + logger.IKELog.Error("[EAP] Received an EAP payload with code other than response. Drop the payload.") return } if eap.Identifier != ikeSecurityAssociation.LastEAPIdentifier { - ikeLog.Error("[EAP] Received an EAP payload with unmatched identifier. Drop the payload.") + logger.IKELog.Error("[EAP] Received an EAP payload with unmatched identifier. Drop the payload.") return } @@ -751,24 +747,21 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message case ike_message.EAPTypeExpanded: eapExpanded = eapTypeData.(*ike_message.EAPExpanded) default: - ikeLog.Errorf("[EAP] Received EAP packet with type other than EAP expanded type: %d", eapTypeData.Type()) + logger.IKELog.Errorf("[EAP] Received EAP packet with type other than EAP expanded type: %d", eapTypeData.Type()) return } if eapExpanded.VendorID != ike_message.VendorID3GPP { - ikeLog.Error("The peer sent EAP expended packet with wrong vendor ID. Drop the packet.") + logger.IKELog.Error("The peer sent EAP expended packet with wrong vendor ID. Drop the packet.") return } if eapExpanded.VendorType != ike_message.VendorTypeEAP5G { - ikeLog.Error("The peer sent EAP expanded packet with wrong vendor type. Drop the packet.") + logger.IKELog.Error("The peer sent EAP expanded packet with wrong vendor type. Drop the packet.") return } - eap5GMessageID, anParameters, nasPDU, err := UnmarshalEAP5GData(eapExpanded.VendorData) - if err != nil { - ikeLog.Errorf("Unmarshalling EAP-5G packet failed: %+v", err) - return - } + eap5GMessageID := eapExpanded.VendorData[0] + logger.IKELog.Infof("EAP5G MessageID : %+v", eap5GMessageID) if eap5GMessageID == ike_message.EAP5GType5GStop { // Send EAP failure @@ -780,13 +773,13 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message // EAP identifier, err := GenerateRandomUint8() if err != nil { - ikeLog.Errorf("Generate random uint8 failed: %+v", err) + logger.IKELog.Errorf("Generate random uint8 failed: %+v", err) return } responseIKEPayload.BuildEAPfailure(identifier) if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) return } @@ -795,132 +788,48 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message return } - // Send Initial UE Message or Uplink NAS Transport - if ikeSecurityAssociation.ThisUE == nil { // if anParameters != nil { - // print AN parameters - ikeLog.Debug("Select AMF with the following AN parameters:") - if anParameters.GUAMI == nil { - ikeLog.Debug("\tGUAMI: nil") - } else { - ikeLog.Debugf("\tGUAMI: PLMNIdentity[% x], "+ - "AMFRegionID[% x], AMFSetID[% x], AMFPointer[% x]", - anParameters.GUAMI.PLMNIdentity, anParameters.GUAMI.AMFRegionID, - anParameters.GUAMI.AMFSetID, anParameters.GUAMI.AMFPointer) - } - if anParameters.SelectedPLMNID == nil { - ikeLog.Debug("\tSelectedPLMNID: nil") - } else { - ikeLog.Debugf("\tSelectedPLMNID: % v", anParameters.SelectedPLMNID.Value) - } - if anParameters.RequestedNSSAI == nil { - ikeLog.Debug("\tRequestedNSSAI: nil") - } else { - ikeLog.Debugf("\tRequestedNSSAI:") - for i := 0; i < len(anParameters.RequestedNSSAI.List); i++ { - ikeLog.Debugf("\tRequestedNSSAI:") - ikeLog.Debugf("\t\tSNSSAI %d:", i+1) - ikeLog.Debugf("\t\t\tSST: % x", anParameters.RequestedNSSAI.List[i].SNSSAI.SST.Value) - sd := anParameters.RequestedNSSAI.List[i].SNSSAI.SD - if sd == nil { - ikeLog.Debugf("\t\t\tSD: nil") - } else { - ikeLog.Debugf("\t\t\tSD: % x", sd.Value) - } - } - } - - // AMF selection - selectedAMF := n3iwfSelf.AMFSelection(anParameters.GUAMI, anParameters.SelectedPLMNID) - if selectedAMF == nil { - ikeLog.Warn("No avalible AMF for this UE") - - // Send EAP failure - // Build IKE message - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_AUTH, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - - // EAP - identifier, err := GenerateRandomUint8() - if err != nil { - ikeLog.Errorf("Generate random uint8 failed: %+v", err) - return - } - responseIKEPayload.BuildEAPfailure(identifier) - - if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) - return - } - - // Send IKE message to UE - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - return - } - ikeLog.Infof("Selected AMF Name: %s", selectedAMF.AMFName.Value) - - // Create UE context - ue := n3iwfSelf.NewN3iwfUe() - - // Relative context - ikeSecurityAssociation.ThisUE = ue - ue.N3IWFIKESecurityAssociation = ikeSecurityAssociation - ue.AMF = selectedAMF - - // Store some information in conext - ikeSecurityAssociation.InitiatorMessageID = message.MessageID - - ue.IKEConnection = &context.UDPSocketInfo{ - Conn: udpConn, - N3IWFAddr: n3iwfAddr, - UEAddr: ueAddr, - } - ue.IPAddrv4 = ueAddr.IP.To4().String() - ue.PortNumber = int32(ueAddr.Port) - if anParameters.EstablishmentCause != nil { - ue.RRCEstablishmentCause = int16(anParameters.EstablishmentCause.Value) - } - - // Send Initial UE Message - ngap_message.SendInitialUEMessage(selectedAMF, ue, nasPDU) - } else { - ue := ikeSecurityAssociation.ThisUE - amf := ue.AMF - - // Store some information in context - ikeSecurityAssociation.InitiatorMessageID = message.MessageID - - ue.IKEConnection = &context.UDPSocketInfo{ - Conn: udpConn, - N3IWFAddr: n3iwfAddr, - UEAddr: ueAddr, - } + var ranNgapId int64 + ranNgapId, ok = n3iwfSelf.NgapIdLoad(ikeSecurityAssociation.LocalSPI) + if !ok { + ranNgapId = 0 + } - // Send Uplink NAS Transport - ngap_message.SendUplinkNASTransport(amf, ue, nasPDU) + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewUnmarshalEAP5GDataEvt( + ikeSecurityAssociation.LocalSPI, + eapExpanded.VendorData, + ikeSecurityAssociation.IkeUE != nil, + ranNgapId, + ) + + ikeSecurityAssociation.IKEConnection = &context.UDPSocketInfo{ + Conn: udpConn, + N3IWFAddr: n3iwfAddr, + UEAddr: ueAddr, } + + ikeSecurityAssociation.InitiatorMessageID = message.MessageID } else { - ikeLog.Error("EAP is nil") + logger.IKELog.Error("EAP is nil") } case PostSignalling: // Load needed information - thisUE := ikeSecurityAssociation.ThisUE + ikeUE := ikeSecurityAssociation.IkeUE // Prepare pseudorandom function for calculating/verifying authentication data - pseudorandomFunction, ok := NewPseudorandomFunction(thisUE.Kn3iwf, transformPseudorandomFunction.TransformID) + pseudorandomFunction, ok := NewPseudorandomFunction(ikeUE.Kn3iwf, transformPseudorandomFunction.TransformID) if !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") return } if _, err := pseudorandomFunction.Write([]byte("Key Pad for IKEv2")); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) + logger.IKELog.Errorf("Pseudorandom function write error: %+v", err) return } secret := pseudorandomFunction.Sum(nil) pseudorandomFunction, ok = NewPseudorandomFunction(secret, transformPseudorandomFunction.TransformID) if !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") return } @@ -928,14 +837,14 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message // Verifying remote AUTH pseudorandomFunction.Reset() if _, err := pseudorandomFunction.Write(ikeSecurityAssociation.InitiatorSignedOctets); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) + logger.IKELog.Errorf("Pseudorandom function write error: %+v", err) return } expectedAuthenticationData := pseudorandomFunction.Sum(nil) - ikeLog.Tracef("Expected Authentication Data:\n%s", hex.Dump(expectedAuthenticationData)) + logger.IKELog.Tracef("Expected Authentication Data:\n%s", hex.Dump(expectedAuthenticationData)) if !bytes.Equal(authentication.AuthenticationData, expectedAuthenticationData) { - ikeLog.Warn("Peer authentication failed.") + logger.IKELog.Warn("Peer authentication failed.") // Inform UE the authentication has failed // Build IKE message responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, @@ -946,7 +855,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message responseIKEPayload.BuildNotification(ike_message.TypeNone, ike_message.AUTHENTICATION_FAILED, nil, nil) if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) return } @@ -954,10 +863,10 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) return } else { - ikeLog.Tracef("Peer authentication success") + logger.IKELog.Tracef("Peer authentication success") } } else { - ikeLog.Warn("Peer authentication failed.") + logger.IKELog.Warn("Peer authentication failed.") // Inform UE the authentication has failed // Build IKE message responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, @@ -968,7 +877,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message responseIKEPayload.BuildNotification(ike_message.TypeNone, ike_message.AUTHENTICATION_FAILED, nil, nil) if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) return } @@ -982,7 +891,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message var addrRequest bool = false if configuration != nil { - ikeLog.Tracef("Received configuration payload with type: %d", configuration.ConfigurationType) + logger.IKELog.Tracef("Received configuration payload with type: %d", configuration.ConfigurationType) var attribute *ike_message.IndividualConfigurationAttribute for _, attribute = range configuration.ConfigurationAttribute { @@ -990,15 +899,15 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message case ike_message.INTERNAL_IP4_ADDRESS: addrRequest = true if len(attribute.Value) != 0 { - ikeLog.Tracef("Got client requested address: %d.%d.%d.%d", + logger.IKELog.Tracef("Got client requested address: %d.%d.%d.%d", attribute.Value[0], attribute.Value[1], attribute.Value[2], attribute.Value[3]) } default: - ikeLog.Warnf("Receive other type of configuration request: %d", attribute.Type) + logger.IKELog.Warnf("Receive other type of configuration request: %d", attribute.Type) } } } else { - ikeLog.Warn("Configuration is nil. UE did not sent any configuration request.") + logger.IKELog.Warn("Configuration is nil. UE did not sent any configuration request.") } // Build response IKE message @@ -1009,7 +918,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message // Calculate local AUTH pseudorandomFunction.Reset() if _, err := pseudorandomFunction.Write(ikeSecurityAssociation.ResponderSignedOctets); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) + logger.IKELog.Errorf("Pseudorandom function write error: %+v", err) return } @@ -1021,7 +930,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message var ueIPAddr, n3iwfIPAddr net.IP if addrRequest { // IP addresses (IPSec) - ueIPAddr = n3iwfSelf.NewInternalUEIPAddr(thisUE).To4() + ueIPAddr = n3iwfSelf.NewInternalUEIPAddr(ikeUE).To4() n3iwfIPAddr = net.ParseIP(n3iwfSelf.IPSecGatewayAddress).To4() responseConfiguration := responseIKEPayload.BuildConfiguration(ike_message.CFG_REPLY) @@ -1029,16 +938,16 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message responseConfiguration.ConfigurationAttribute.BuildConfigurationAttribute( ike_message.INTERNAL_IP4_NETMASK, n3iwfSelf.Subnet.Mask) - thisUE.IPSecInnerIP = ueIPAddr + ikeUE.IPSecInnerIP = ueIPAddr if ipsecInnerIPAddr, err := net.ResolveIPAddr("ip", ueIPAddr.String()); err != nil { - ikeLog.Errorf("Resolve UE inner IP address failed: %+v", err) + logger.IKELog.Errorf("Resolve UE inner IP address failed: %+v", err) return } else { - thisUE.IPSecInnerIPAddr = ipsecInnerIPAddr + ikeUE.IPSecInnerIPAddr = ipsecInnerIPAddr } - ikeLog.Tracef("ueIPAddr: %+v", ueIPAddr) + logger.IKELog.Tracef("ueIPAddr: %+v", ueIPAddr) } else { - ikeLog.Error("UE did not send any configuration request for its IP address.") + logger.IKELog.Error("UE did not send any configuration request for its IP address.") return } @@ -1065,7 +974,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message for { randomUint64 := GenerateRandomNumber().Uint64() // check if the inbound SPI havn't been allocated by N3IWF - if _, ok := n3iwfSelf.ChildSA.Load(uint32(randomUint64)); !ok { + if _, ok1 := n3iwfSelf.ChildSA.Load(uint32(randomUint64)); !ok1 { inboundSPI = uint32(randomUint64) break } @@ -1073,32 +982,32 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message binary.BigEndian.PutUint32(inboundSPIByte, inboundSPI) outboundSPI := binary.BigEndian.Uint32(ikeSecurityAssociation.IKEAuthResponseSA.Proposals[0].SPI) - ikeLog.Infof("Inbound SPI: %+v, Outbound SPI: %+v", inboundSPI, outboundSPI) + logger.IKELog.Infof("Inbound SPI: %+v, Outbound SPI: %+v", inboundSPI, outboundSPI) // SPI field of IKEAuthResponseSA is used to save outbound SPI temporarily. // After N3IWF produced its inbound SPI, the field will be overwritten with the SPI. ikeSecurityAssociation.IKEAuthResponseSA.Proposals[0].SPI = inboundSPIByte // Consider 0x01 as the speicified index for IKE_AUTH exchange - thisUE.CreateHalfChildSA(0x01, inboundSPI, -1) - childSecurityAssociationContext, err := thisUE.CompleteChildSA( + ikeUE.CreateHalfChildSA(0x01, inboundSPI, -1) + childSecurityAssociationContext, err := ikeUE.CompleteChildSA( 0x01, outboundSPI, ikeSecurityAssociation.IKEAuthResponseSA) if err != nil { - ikeLog.Errorf("Create child security association context failed: %+v", err) + logger.IKELog.Errorf("Create child security association context failed: %+v", err) return } err = parseIPAddressInformationToChildSecurityAssociation(childSecurityAssociationContext, ueAddr.IP, ikeSecurityAssociation.TrafficSelectorResponder.TrafficSelectors[0], ikeSecurityAssociation.TrafficSelectorInitiator.TrafficSelectors[0]) if err != nil { - ikeLog.Errorf("Parse IP address to child security association failed: %+v", err) + logger.IKELog.Errorf("Parse IP address to child security association failed: %+v", err) return } // Select TCP traffic childSecurityAssociationContext.SelectedIPProtocol = unix.IPPROTO_TCP if errGen := GenerateKeyForChildSA(ikeSecurityAssociation, childSecurityAssociationContext); errGen != nil { - ikeLog.Errorf("Generate key for child SA failed: %+v", errGen) + logger.IKELog.Errorf("Generate key for child SA failed: %+v", errGen) return } // NAT-T concern @@ -1115,140 +1024,42 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message responseIKEPayload.BuildNotifyNAS_TCP_PORT(n3iwfSelf.TCPPort) if errEncrypt := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); errEncrypt != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", errEncrypt) + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", errEncrypt) return } // Aplly XFRM rules // IPsec for CP always use default XFRM interface if err = xfrm.ApplyXFRMRule(false, n3iwfSelf.XfrmIfaceId, childSecurityAssociationContext); err != nil { - ikeLog.Errorf("Applying XFRM rules failed: %+v", err) + logger.IKELog.Errorf("Applying XFRM rules failed: %+v", err) return } // Send IKE message to UE SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - // After this, N3IWF will forward NAS with Child SA (IPSec SA) - thisUE.SignallingIPsecSAEstablished = true + ranNgapId, ok := n3iwfSelf.NgapIdLoad(ikeUE.N3IWFIKESecurityAssociation.LocalSPI) + if !ok { + logger.IKELog.Errorf("Cannot get RanNgapId from SPI : %+v", ikeUE.N3IWFIKESecurityAssociation.LocalSPI) + return + } - // If needed, setup PDU session - if thisUE.TemporaryPDUSessionSetupData != nil { - for { - if len(thisUE.TemporaryPDUSessionSetupData.UnactivatedPDUSession) != 0 { - pduSessionID := thisUE.TemporaryPDUSessionSetupData.UnactivatedPDUSession[0] - pduSession := thisUE.PduSessionList[pduSessionID] - - // Add MessageID for IKE security association - ikeSecurityAssociation.InitiatorMessageID++ - - // Send CREATE_CHILD_SA to UE - ikeMessage := new(ike_message.IKEMessage) - var ikePayload ike_message.IKEPayloadContainer - - // Build IKE message - ikeMessage.BuildIKEHeader(ikeSecurityAssociation.LocalSPI, - ikeSecurityAssociation.RemoteSPI, ike_message.CREATE_CHILD_SA, - ike_message.InitiatorBitCheck, ikeSecurityAssociation.InitiatorMessageID) - ikeMessage.Payloads.Reset() - - // Build SA - requestSA := ikePayload.BuildSecurityAssociation() - - // Allocate SPI - var spi uint32 - spiByte := make([]byte, 4) - for { - randomUint64 := GenerateRandomNumber().Uint64() - if _, ok := n3iwfSelf.ChildSA.Load(uint32(randomUint64)); !ok { - spi = uint32(randomUint64) - break - } - } - binary.BigEndian.PutUint32(spiByte, spi) - - // First Proposal - Proposal No.1 - proposal := requestSA.Proposals.BuildProposal(1, ike_message.TypeESP, spiByte) - - // Encryption transform - var attributeType uint16 = ike_message.AttributeTypeKeyLength - var attributeValue uint16 = 256 - proposal.EncryptionAlgorithm.BuildTransform(ike_message.TypeEncryptionAlgorithm, - ike_message.ENCR_AES_CBC, &attributeType, &attributeValue, nil) - // Integrity transform - if pduSession.SecurityIntegrity { - proposal.IntegrityAlgorithm.BuildTransform( - ike_message.TypeIntegrityAlgorithm, ike_message.AUTH_HMAC_SHA1_96, nil, nil, nil) - } - // ESN transform - proposal.ExtendedSequenceNumbers.BuildTransform( - ike_message.TypeExtendedSequenceNumbers, ike_message.ESN_NO, nil, nil, nil) - - // Build Nonce - nonceData := GenerateRandomNumber().Bytes() - ikePayload.BuildNonce(nonceData) - - // Store nonce into context - ikeSecurityAssociation.ConcatenatedNonce = nonceData - - // TSi - ueIPAddr := thisUE.IPSecInnerIP - tsi := ikePayload.BuildTrafficSelectorInitiator() - tsi.TrafficSelectors.BuildIndividualTrafficSelector(ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, - 0, 65535, ueIPAddr, ueIPAddr) - // TSr - n3iwfIPAddr := net.ParseIP(n3iwfSelf.IPSecGatewayAddress) - tsr := ikePayload.BuildTrafficSelectorResponder() - tsr.TrafficSelectors.BuildIndividualTrafficSelector(ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, - 0, 65535, n3iwfIPAddr, n3iwfIPAddr) - - // Notify-Qos - ikePayload.BuildNotify5G_QOS_INFO(uint8(pduSessionID), pduSession.QFIList, true, false, 0) - - // Notify-UP_IP_ADDRESS - ikePayload.BuildNotifyUP_IP4_ADDRESS(n3iwfSelf.IPSecGatewayAddress) - - if err := EncryptProcedure( - thisUE.N3IWFIKESecurityAssociation, ikePayload, ikeMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) - thisUE.TemporaryPDUSessionSetupData.UnactivatedPDUSession = thisUE. - TemporaryPDUSessionSetupData.UnactivatedPDUSession[1:] - cause := ngapType.Cause{ - Present: ngapType.CausePresentTransport, - Transport: &ngapType.CauseTransport{ - Value: ngapType.CauseTransportPresentTransportResourceUnavailable, - }, - } - transfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(cause, nil) - if err != nil { - ikeLog.Errorf("Build PDU Session Resource Setup Unsuccessful Transfer Failed: %+v", err) - continue - } - ngap_message.AppendPDUSessionResourceFailedToSetupListCxtRes( - thisUE.TemporaryPDUSessionSetupData.FailedListCxtRes, pduSessionID, transfer) - continue - } + ikeSecurityAssociation.State++ - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - break - } else { - // Send Initial Context Setup Response to AMF - ngap_message.SendInitialContextSetupResponse(thisUE.AMF, thisUE, - thisUE.TemporaryPDUSessionSetupData.SetupListCxtRes, - thisUE.TemporaryPDUSessionSetupData.FailedListCxtRes, nil) - break - } - } - } else { - // Send Initial Context Setup Response to AMF - ngap_message.SendInitialContextSetupResponse(thisUE.AMF, thisUE, nil, nil, nil) - } - go StartDPD(thisUE) + // After this, N3IWF will forward NAS with Child SA (IPSec SA) + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewStartTCPSignalNASMsgEvt( + ranNgapId, + ) + + // Get TempPDUSessionSetupData from NGAP to setup PDU session if needed + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewGetNGAPContextEvt( + ranNgapId, []int64{context.CxtTempPDUSessionSetupData}, + ) } } func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage) { - ikeLog.Infoln("Handle CREATE_CHILD_SA") + logger.IKELog.Infoln("Handle CREATE_CHILD_SA") var encryptedPayload *ike_message.Encrypted @@ -1257,7 +1068,7 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m responseIKEMessage := new(ike_message.IKEMessage) if message == nil { - ikeLog.Error("IKE Message is nil") + logger.IKELog.Error("IKE Message is nil") return } @@ -1265,7 +1076,7 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m // check major version majorVersion := ((message.Version & 0xf0) >> 4) if majorVersion > 2 { - ikeLog.Warn("Received an IKE message with higher major version") + logger.IKELog.Warn("Received an IKE message with higher major version") // send INFORMATIONAL type message with INVALID_MAJOR_VERSION Notify payload ( OUTSIDE IKE SA ) responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, message.MessageID) @@ -1280,10 +1091,10 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m // Find corresponding IKE security association responderSPI := message.ResponderSPI - ikeLog.Warnf("CREATE_CHILD_SA responderSPI: %+v", responderSPI) + logger.IKELog.Warnf("CREATE_CHILD_SA responderSPI: %+v", responderSPI) ikeSecurityAssociation, ok := n3iwfSelf.IKESALoad(responderSPI) if !ok { - ikeLog.Warn("Unrecognized SPI") + logger.IKELog.Warn("Unrecognized SPI") // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) responseIKEMessage.BuildIKEHeader(0, message.ResponderSPI, ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, message.MessageID) @@ -1300,7 +1111,7 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m case ike_message.TypeSK: encryptedPayload = ikePayload.(*ike_message.Encrypted) default: - ikeLog.Warnf( + logger.IKELog.Warnf( "Get IKE payload (type %d) in CREATE_CHILD_SA message, this payload will not be handled by IKE handler", ikePayload.Type()) } @@ -1308,7 +1119,7 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m decryptedIKEPayload, err := DecryptProcedure(ikeSecurityAssociation, message, encryptedPayload) if err != nil { - ikeLog.Errorf("Decrypt IKE message failed: %+v", err) + logger.IKELog.Errorf("Decrypt IKE message failed: %+v", err) return } @@ -1329,51 +1140,25 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m case ike_message.TypeTSr: trafficSelectorResponder = ikePayload.(*ike_message.TrafficSelectorResponder) default: - ikeLog.Warnf( + logger.IKELog.Warnf( "Get IKE payload (type %d) in CREATE_CHILD_SA message, this payload will not be handled by IKE handler", ikePayload.Type()) } } - // Record message ID - ikeSecurityAssociation.ResponderMessageID = message.MessageID - - // UE context - thisUE := ikeSecurityAssociation.ThisUE - if thisUE == nil { - ikeLog.Error("UE context is nil") - return - } - // PDU session information - if thisUE.TemporaryPDUSessionSetupData == nil { - ikeLog.Error("No PDU session information") - return - } - temporaryPDUSessionSetupData := thisUE.TemporaryPDUSessionSetupData - if len(temporaryPDUSessionSetupData.UnactivatedPDUSession) == 0 { - ikeLog.Error("No unactivated PDU session information") - return - } - pduSessionID := temporaryPDUSessionSetupData.UnactivatedPDUSession[0] - pduSession, ok := thisUE.PduSessionList[pduSessionID] - if !ok { - ikeLog.Errorf("No such PDU session [PDU session ID: %d]", pduSessionID) - return - } - // Check received message if securityAssociation == nil { - ikeLog.Error("The security association field is nil") + logger.IKELog.Error("The security association field is nil") return } if trafficSelectorInitiator == nil { - ikeLog.Error("The traffic selector initiator field is nil") + logger.IKELog.Error("The traffic selector initiator field is nil") return } if trafficSelectorResponder == nil { - ikeLog.Error("The traffic selector responder field is nil") + logger.IKELog.Error("The traffic selector responder field is nil") return } @@ -1381,65 +1166,113 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m if nonce != nil { ikeSecurityAssociation.ConcatenatedNonce = append(ikeSecurityAssociation.ConcatenatedNonce, nonce.NonceData...) } else { - ikeLog.Error("The nonce field is nil") + logger.IKELog.Error("The nonce field is nil") // TODO: send error message to UE return } + ikeSecurityAssociation.TemporaryIkeMsg = &context.IkeMsgTemporaryData{ + SecurityAssociation: securityAssociation, + TrafficSelectorInitiator: trafficSelectorInitiator, + TrafficSelectorResponder: trafficSelectorResponder, + } + + ranNgapId, ok := n3iwfSelf.NgapIdLoad(ikeSecurityAssociation.LocalSPI) + if !ok { + logger.IKELog.Errorf("Cannot get RanNgapID from SPI : %+v", ikeSecurityAssociation.LocalSPI) + return + } + + ngapCxtReqNumlist := []int64{context.CxtTempPDUSessionSetupData} + + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewGetNGAPContextEvt(ranNgapId, + ngapCxtReqNumlist) +} + +func continueCreateChildSA(ikeSecurityAssociation *context.IKESecurityAssociation, + temporaryPDUSessionSetupData *context.PDUSessionSetupTemporaryData, +) { + n3iwfSelf := context.N3IWFSelf() + + // UE context + ikeUe := ikeSecurityAssociation.IkeUE + if ikeUe == nil { + logger.IKELog.Error("UE context is nil") + return + } + + // PDU session information + if temporaryPDUSessionSetupData == nil { + logger.IKELog.Error("No PDU session information") + return + } + + if len(temporaryPDUSessionSetupData.UnactivatedPDUSession) == 0 { + logger.IKELog.Error("No unactivated PDU session information") + return + } + + temporaryIkeMsg := ikeSecurityAssociation.TemporaryIkeMsg + ikeConnection := ikeSecurityAssociation.IKEConnection + // Get xfrm needed data // As specified in RFC 7296, ESP negotiate two child security association (pair) in one exchange // Message ID is used to be a index to pair two SPI in serveral IKE messages. - outboundSPI := binary.BigEndian.Uint32(securityAssociation.Proposals[0].SPI) - childSecurityAssociationContext, err := thisUE.CompleteChildSA( - ikeSecurityAssociation.ResponderMessageID, outboundSPI, securityAssociation) + outboundSPI := binary.BigEndian.Uint32(temporaryIkeMsg.SecurityAssociation.Proposals[0].SPI) + childSecurityAssociationContext, err := ikeUe.CompleteChildSA( + ikeSecurityAssociation.ResponderMessageID, outboundSPI, temporaryIkeMsg.SecurityAssociation) if err != nil { - ikeLog.Errorf("Create child security association context failed: %+v", err) + logger.IKELog.Errorf("Create child security association context failed: %+v", err) return } // Build TSi if there is no one in the response - if len(trafficSelectorInitiator.TrafficSelectors) == 0 { - ikeLog.Warnf("There is no TSi in CREATE_CHILD_SA response.") + if len(temporaryIkeMsg.TrafficSelectorInitiator.TrafficSelectors) == 0 { + logger.IKELog.Warnf("There is no TSi in CREATE_CHILD_SA response.") n3iwfIPAddr := net.ParseIP(n3iwfSelf.IPSecGatewayAddress) - trafficSelectorInitiator.TrafficSelectors.BuildIndividualTrafficSelector( + temporaryIkeMsg.TrafficSelectorInitiator.TrafficSelectors.BuildIndividualTrafficSelector( ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, 0, 65535, n3iwfIPAddr, n3iwfIPAddr) } // Build TSr if there is no one in the response - if len(trafficSelectorResponder.TrafficSelectors) == 0 { - ikeLog.Warnf("There is no TSr in CREATE_CHILD_SA response.") - ueIPAddr := thisUE.IPSecInnerIP - trafficSelectorResponder.TrafficSelectors.BuildIndividualTrafficSelector( + if len(temporaryIkeMsg.TrafficSelectorResponder.TrafficSelectors) == 0 { + logger.IKELog.Warnf("There is no TSr in CREATE_CHILD_SA response.") + ueIPAddr := ikeUe.IPSecInnerIP + temporaryIkeMsg.TrafficSelectorResponder.TrafficSelectors.BuildIndividualTrafficSelector( ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, 0, 65535, ueIPAddr, ueIPAddr) } - err = parseIPAddressInformationToChildSecurityAssociation(childSecurityAssociationContext, ueAddr.IP, - trafficSelectorInitiator.TrafficSelectors[0], trafficSelectorResponder.TrafficSelectors[0]) + err = parseIPAddressInformationToChildSecurityAssociation(childSecurityAssociationContext, + ikeConnection.UEAddr.IP, + temporaryIkeMsg.TrafficSelectorInitiator.TrafficSelectors[0], + temporaryIkeMsg.TrafficSelectorResponder.TrafficSelectors[0]) if err != nil { - ikeLog.Errorf("Parse IP address to child security association failed: %+v", err) + logger.IKELog.Errorf("Parse IP address to child security association failed: %+v", err) return } // Select GRE traffic childSecurityAssociationContext.SelectedIPProtocol = unix.IPPROTO_GRE if errGen := GenerateKeyForChildSA(ikeSecurityAssociation, childSecurityAssociationContext); errGen != nil { - ikeLog.Errorf("Generate key for child SA failed: %+v", errGen) + logger.IKELog.Errorf("Generate key for child SA failed: %+v", errGen) return } // NAT-T concern if ikeSecurityAssociation.UEIsBehindNAT || ikeSecurityAssociation.N3IWFIsBehindNAT { childSecurityAssociationContext.EnableEncapsulate = true - childSecurityAssociationContext.N3IWFPort = n3iwfAddr.Port - childSecurityAssociationContext.NATPort = ueAddr.Port + childSecurityAssociationContext.N3IWFPort = ikeConnection.N3IWFAddr.Port + childSecurityAssociationContext.NATPort = ikeConnection.UEAddr.Port } newXfrmiId := n3iwfSelf.XfrmIfaceId + pduSessionListLen := ikeUe.PduSessionListLen + // The additional PDU session will be separated from default xfrm interface // to avoid SPD entry collision - if len(thisUE.PduSessionList) > 1 { + if pduSessionListLen > 1 { // Setup XFRM interface for ipsec var linkIPSec netlink.Link n3iwfIPAddr := net.ParseIP(n3iwfSelf.IPSecGatewayAddress).To4() @@ -1449,7 +1282,7 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m if linkIPSec, err = xfrm.SetupIPsecXfrmi(newXfrmiName, n3iwfSelf.XfrmParentIfaceName, newXfrmiId, n3iwfIPAddrAndSubnet); err != nil { - ikeLog.Errorf("Setup XFRM interface %s fail: %+v", newXfrmiName, err) + logger.IKELog.Errorf("Setup XFRM interface %s fail: %+v", newXfrmiName, err) return } @@ -1460,52 +1293,425 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m if linkIPSec, ok := n3iwfSelf.XfrmIfaces.Load(newXfrmiId); ok { childSecurityAssociationContext.XfrmIface = linkIPSec.(netlink.Link) } else { - ikeLog.Warnf("Cannot find the XFRM interface with if_id: %d", newXfrmiId) + logger.IKELog.Warnf("Cannot find the XFRM interface with if_id: %d", newXfrmiId) + return } } // Aplly XFRM rules if err = xfrm.ApplyXFRMRule(true, newXfrmiId, childSecurityAssociationContext); err != nil { - ikeLog.Errorf("Applying XFRM rules failed: %+v", err) + logger.IKELog.Errorf("Applying XFRM rules failed: %+v", err) return } else { + ranNgapId, ok := n3iwfSelf.NgapIdLoad(ikeSecurityAssociation.LocalSPI) + if !ok { + logger.IKELog.Errorf("Cannot get RanNgapId from SPI : %+v", ikeSecurityAssociation.LocalSPI) + return + } // Forward PDU Seesion Establishment Accept to UE - if n, ikeErr := thisUE.TCPConnection.Write(thisUE.TemporaryCachedNASMessage); ikeErr != nil { - ikeLog.Errorf("Writing via IPSec signalling SA failed: %+v", err) - } else { - ikeLog.Tracef("Forward PDU Seesion Establishment Accept to UE. Wrote %d bytes", n) + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewSendNASMsgEvt( + ranNgapId, + ) + } + + temporaryPDUSessionSetupData.FailedErrStr = append(temporaryPDUSessionSetupData.FailedErrStr, context.ErrNil) + + ikeSecurityAssociation.ResponderMessageID++ + + // If needed, setup another PDU session + CreatePDUSessionChildSA(ikeUe, temporaryPDUSessionSetupData) +} + +func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage) { + logger.IKELog.Infoln("Handle Informational") + + if message == nil { + logger.IKELog.Error("IKE Message is nil") + return + } + + n3iwfSelf := context.N3IWFSelf() + responseIKEMessage := new(ike_message.IKEMessage) + responderSPI := message.ResponderSPI + ikeSecurityAssociation, ok := n3iwfSelf.IKESALoad(responderSPI) + var encryptedPayload *ike_message.Encrypted + + if !ok { + logger.IKELog.Warn("Unrecognized SPI") + // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) + responseIKEMessage.BuildIKEHeader(0, message.ResponderSPI, ike_message.INFORMATIONAL, + ike_message.ResponseBitCheck, message.MessageID) + responseIKEMessage.Payloads.Reset() + responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) + + SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + + return + } + + for _, ikePayload := range message.Payloads { + switch ikePayload.Type() { + case ike_message.TypeSK: + encryptedPayload = ikePayload.(*ike_message.Encrypted) + default: + logger.IKELog.Warnf( + "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", + ikePayload.Type()) } } - // Append NGAP PDU session resource setup response transfer - transfer, err := ngap_message.BuildPDUSessionResourceSetupResponseTransfer(pduSession) + decryptedIKEPayload, err := DecryptProcedure(ikeSecurityAssociation, message, encryptedPayload) if err != nil { - ikeLog.Errorf("Build PDU session resource setup response transfer failed: %+v", err) + logger.IKELog.Errorf("Decrypt IKE message failed: %+v", err) + return + } + + n3iwfIke := ikeSecurityAssociation.IkeUE + + if n3iwfIke.N3IWFIKESecurityAssociation.DPDReqRetransTimer != nil { + n3iwfIke.N3IWFIKESecurityAssociation.DPDReqRetransTimer.Stop() + n3iwfIke.N3IWFIKESecurityAssociation.DPDReqRetransTimer = nil + atomic.StoreInt32(&n3iwfIke.N3IWFIKESecurityAssociation.CurrentRetryTimes, 0) + } + + if len(decryptedIKEPayload) == 0 { // Receive DPD message + return + } + + for _, ikePayload := range decryptedIKEPayload { + switch ikePayload.Type() { + case ike_message.TypeD: + deletePayload := ikePayload.(*ike_message.Delete) + + ranNgapId, ok := n3iwfSelf.NgapIdLoad(n3iwfIke.N3IWFIKESecurityAssociation.LocalSPI) + if !ok { + logger.IKELog.Errorf("Cannot get RanNgapId from SPI : %+v", n3iwfIke.N3IWFIKESecurityAssociation.LocalSPI) + return + } + + if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA + if err := n3iwfIke.Remove(); err != nil { + logger.IKELog.Errorf("Delete IkeUe Context error : %+v", err) + } + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewSendUEContextReleaseCompleteEvt( + ranNgapId, + ) + } else if deletePayload.ProtocolID == ike_message.TypeESP { + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewSendPDUSessionResourceReleaseResEvt( + ranNgapId, + ) + } + default: + logger.IKELog.Warnf( + "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", + ikePayload.Type()) + } + } + ikeSecurityAssociation.ResponderMessageID++ +} + +func HandleEvent(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle IKE event") + + switch ikeEvt.Type() { + case context.UnmarshalEAP5GDataResponse: + HandleUnmarshalEAP5GDataResponse(ikeEvt) + case context.SendEAP5GFailureMsg: + HandleSendEAP5GFailureMsg(ikeEvt) + case context.SendEAPSuccessMsg: + HandleSendEAPSuccessMsg(ikeEvt) + case context.SendEAPNASMsg: + HandleSendEAPNASMsg(ikeEvt) + case context.CreatePDUSession: + HandleCreatePDUSession(ikeEvt) + case context.IKEDeleteRequest: + HandleIKEDeleteRequest(ikeEvt) + case context.SendChildSADeleteRequest: + HandleSendChildSADeleteRequest(ikeEvt) + case context.IKEContextUpdate: + HandleIKEContextUpdate(ikeEvt) + case context.GetNGAPContextResponse: + HandleGetNGAPContextResponse(ikeEvt) + default: + logger.IKELog.Errorf("Undefine IKE event type : %d", ikeEvt.Type()) return } - ngap_message.AppendPDUSessionResourceSetupListSURes( - temporaryPDUSessionSetupData.SetupListSURes, pduSessionID, transfer) +} + +func HandleUnmarshalEAP5GDataResponse(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle UnmarshalEAP5GDataResponse event") + + unmarshalEAP5GDataResponseEvt := ikeEvt.(*context.UnmarshalEAP5GDataResponseEvt) + localSPI := unmarshalEAP5GDataResponseEvt.LocalSPI + ranUeNgapId := unmarshalEAP5GDataResponseEvt.RanUeNgapId + nasPDU := unmarshalEAP5GDataResponseEvt.NasPDU + + n3iwfSelf := context.N3IWFSelf() + ikeSecurityAssociation, _ := n3iwfSelf.IKESALoad(localSPI) + + // Create UE context + ikeUe := n3iwfSelf.NewN3iwfIkeUe(localSPI) + + // Relative context + ikeSecurityAssociation.IkeUE = ikeUe + ikeUe.N3IWFIKESecurityAssociation = ikeSecurityAssociation + ikeUe.IKEConnection = ikeSecurityAssociation.IKEConnection + + n3iwfSelf.IkeSpiNgapIdMapping(ikeUe.N3IWFIKESecurityAssociation.LocalSPI, ranUeNgapId) + + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewSendInitialUEMessageEvt( + ranUeNgapId, + ikeSecurityAssociation.IKEConnection.UEAddr.IP.To4().String(), + ikeSecurityAssociation.IKEConnection.UEAddr.Port, + nasPDU, + ) +} - // Remove handled PDU session setup request from queue - temporaryPDUSessionSetupData.UnactivatedPDUSession = temporaryPDUSessionSetupData.UnactivatedPDUSession[1:] +func HandleSendEAP5GFailureMsg(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle SendEAP5GFailureMsg event") + sendEAP5GFailureMsgEvt := ikeEvt.(*context.SendEAP5GFailureMsgEvt) + errMsg := sendEAP5GFailureMsgEvt.ErrMsg + localSPI := sendEAP5GFailureMsgEvt.LocalSPI + + n3iwfSelf := context.N3IWFSelf() + ikeSecurityAssociation, _ := n3iwfSelf.IKESALoad(localSPI) + logger.IKELog.Warnf("EAP Failure : %s", errMsg.Error()) + + responseIKEMessage := new(ike_message.IKEMessage) + var responseIKEPayload ike_message.IKEPayloadContainer + // Send EAP failure + // Build IKE message + responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, + ike_message.IKE_AUTH, ike_message.ResponseBitCheck, ikeSecurityAssociation.InitiatorMessageID) + responseIKEMessage.Payloads.Reset() + + // EAP + identifier, err := GenerateRandomUint8() + if err != nil { + logger.IKELog.Errorf("Generate random uint8 failed: %+v", err) + return + } + responseIKEPayload.BuildEAPfailure(identifier) + + if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) + return + } + + // Send IKE message to UE + SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, + ikeSecurityAssociation.IKEConnection.N3IWFAddr, ikeSecurityAssociation.IKEConnection.UEAddr, + responseIKEMessage) +} + +func HandleSendEAPSuccessMsg(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle SendEAPSuccessMsg event") + + sendEAPSuccessMsgEvt := ikeEvt.(*context.SendEAPSuccessMsgEvt) + localSPI := sendEAPSuccessMsgEvt.LocalSPI + kn3iwf := sendEAPSuccessMsgEvt.Kn3iwf + pduSessionListLen := sendEAPSuccessMsgEvt.PduSessionListLen + + n3iwfSelf := context.N3IWFSelf() + ikeSecurityAssociation, _ := n3iwfSelf.IKESALoad(localSPI) + + if kn3iwf != nil { + ikeSecurityAssociation.IkeUE.Kn3iwf = kn3iwf + } + + ikeSecurityAssociation.IkeUE.PduSessionListLen = pduSessionListLen + + responseIKEMessage := new(ike_message.IKEMessage) + var responseIKEPayload ike_message.IKEPayloadContainer + + // Build IKE message + responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, + ikeSecurityAssociation.LocalSPI, ike_message.IKE_AUTH, ike_message.ResponseBitCheck, + ikeSecurityAssociation.InitiatorMessageID) + responseIKEMessage.Payloads.Reset() + + var identifier uint8 + for { + identifier = uint8(math_rand.Uint32()) + if identifier != ikeSecurityAssociation.LastEAPIdentifier { + ikeSecurityAssociation.LastEAPIdentifier = identifier + break + } + } + + responseIKEPayload.BuildEAPSuccess(identifier) + + if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) + return + } + + // Send IKE message to UE + SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, + ikeSecurityAssociation.IKEConnection.N3IWFAddr, + ikeSecurityAssociation.IKEConnection.UEAddr, responseIKEMessage) + + ikeSecurityAssociation.State++ +} + +func HandleSendEAPNASMsg(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle SendEAPNASMsg event") + + sendEAPNASMsgEvt := ikeEvt.(*context.SendEAPNASMsgEvt) + localSPI := sendEAPNASMsgEvt.LocalSPI + nasPDU := sendEAPNASMsgEvt.NasPDU + + n3iwfSelf := context.N3IWFSelf() + ikeSecurityAssociation, _ := n3iwfSelf.IKESALoad(localSPI) + + responseIKEMessage := new(ike_message.IKEMessage) + var responseIKEPayload ike_message.IKEPayloadContainer + + // Build IKE message + responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, + ikeSecurityAssociation.LocalSPI, ike_message.IKE_AUTH, ike_message.ResponseBitCheck, + ikeSecurityAssociation.InitiatorMessageID) + responseIKEMessage.Payloads.Reset() + + var identifier uint8 for { - if len(temporaryPDUSessionSetupData.UnactivatedPDUSession) != 0 { - ngapProcedure := temporaryPDUSessionSetupData.NGAPProcedureCode.Value - pduSessionID := temporaryPDUSessionSetupData.UnactivatedPDUSession[0] - pduSession := thisUE.PduSessionList[pduSessionID] + identifier = uint8(math_rand.Uint32()) + if identifier != ikeSecurityAssociation.LastEAPIdentifier { + ikeSecurityAssociation.LastEAPIdentifier = identifier + break + } + } + + responseIKEPayload.BuildEAP5GNAS(identifier, nasPDU) + + if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) + return + } + + // Send IKE message to UE + SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, + ikeSecurityAssociation.IKEConnection.N3IWFAddr, + ikeSecurityAssociation.IKEConnection.UEAddr, responseIKEMessage) +} + +func HandleCreatePDUSession(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle CreatePDUSession event") + + createPDUSessionEvt := ikeEvt.(*context.CreatePDUSessionEvt) + localSPI := createPDUSessionEvt.LocalSPI + pduSessionListLen := createPDUSessionEvt.PduSessionListLen + temporaryPDUSessionSetupData := createPDUSessionEvt.TempPDUSessionSetupData + + n3iwfSelf := context.N3IWFSelf() + ikeSecurityAssociation, _ := n3iwfSelf.IKESALoad(localSPI) + + ikeSecurityAssociation.IkeUE.PduSessionListLen = pduSessionListLen + + CreatePDUSessionChildSA(ikeSecurityAssociation.IkeUE, temporaryPDUSessionSetupData) +} + +func HandleIKEDeleteRequest(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle IKEDeleteRequest event") + + ikeDeleteRequest := ikeEvt.(*context.IKEDeleteRequestEvt) + localSPI := ikeDeleteRequest.LocalSPI + + SendIKEDeleteRequest(localSPI) +} + +func HandleSendChildSADeleteRequest(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle SendChildSADeleteRequest event") + + sendChildSADeleteRequestEvt := ikeEvt.(*context.SendChildSADeleteRequestEvt) + localSPI := sendChildSADeleteRequestEvt.LocalSPI + releaseIdList := sendChildSADeleteRequestEvt.ReleaseIdList + + ikeUe, ok := context.N3IWFSelf().IkeUePoolLoad(localSPI) + if !ok { + logger.IKELog.Errorf("Cannot get IkeUE from SPI : %+v", localSPI) + return + } + SendChildSADeleteRequest(ikeUe, releaseIdList) +} + +func HandleIKEContextUpdate(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle IKEContextUpdate event") + + ikeContextUpdateEvt := ikeEvt.(*context.IKEContextUpdateEvt) + localSPI := ikeContextUpdateEvt.LocalSPI + kn3iwf := ikeContextUpdateEvt.Kn3iwf + + ikeUe, ok := context.N3IWFSelf().IkeUePoolLoad(localSPI) + if !ok { + logger.IKELog.Errorf("Cannot get IkeUE from SPI : %+v", localSPI) + return + } + + if kn3iwf != nil { + ikeUe.Kn3iwf = kn3iwf + } +} + +func HandleGetNGAPContextResponse(ikeEvt context.IkeEvt) { + logger.IKELog.Infof("Handle GetNGAPContextResponse event") + + getNGAPContextRepEvt := ikeEvt.(*context.GetNGAPContextRepEvt) + localSPI := getNGAPContextRepEvt.LocalSPI + ngapCxtReqNumlist := getNGAPContextRepEvt.NgapCxtReqNumlist + ngapCxt := getNGAPContextRepEvt.NgapCxt + + n3iwfSelf := context.N3IWFSelf() + ikeSecurityAssociation, _ := n3iwfSelf.IKESALoad(localSPI) + + var tempPDUSessionSetupData *context.PDUSessionSetupTemporaryData + + for i, num := range ngapCxtReqNumlist { + switch num { + case context.CxtTempPDUSessionSetupData: + tempPDUSessionSetupData = ngapCxt[i].(*context.PDUSessionSetupTemporaryData) + default: + logger.IKELog.Errorf("Receive undefine NGAP Context Request number : %d", num) + } + } - // Add MessageID for IKE security association - ikeSecurityAssociation.ResponderMessageID++ + switch ikeSecurityAssociation.State { + case EndSignalling: + CreatePDUSessionChildSA(ikeSecurityAssociation.IkeUE, tempPDUSessionSetupData) + ikeSecurityAssociation.State++ + go StartDPD(ikeSecurityAssociation.IkeUE) + case HandleCreateChildSA: + continueCreateChildSA(ikeSecurityAssociation, tempPDUSessionSetupData) + } +} + +func CreatePDUSessionChildSA(ikeUe *context.N3IWFIkeUe, + temporaryPDUSessionSetupData *context.PDUSessionSetupTemporaryData, +) { + n3iwfSelf := context.N3IWFSelf() + ikeSecurityAssociation := ikeUe.N3IWFIKESecurityAssociation + + ranNgapId, ok := n3iwfSelf.NgapIdLoad(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + if !ok { + logger.IKELog.Errorf("Cannot get RanNgapId from SPI : %+v", ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + return + } + + for { + if len(temporaryPDUSessionSetupData.UnactivatedPDUSession) > temporaryPDUSessionSetupData.Index { + pduSession := temporaryPDUSessionSetupData.UnactivatedPDUSession[temporaryPDUSessionSetupData.Index] + pduSessionID := pduSession.Id // Send CREATE_CHILD_SA to UE ikeMessage := new(ike_message.IKEMessage) var ikePayload ike_message.IKEPayloadContainer + errStr := context.ErrNil // Build IKE message ikeMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, ike_message.CREATE_CHILD_SA, - ike_message.InitiatorBitCheck, ikeSecurityAssociation.ResponderMessageID) + 0, ikeSecurityAssociation.ResponderMessageID) ikeMessage.Payloads.Reset() // Build SA @@ -1534,11 +1740,19 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m // Integrity transform if pduSession.SecurityIntegrity { proposal.IntegrityAlgorithm.BuildTransform(ike_message.TypeIntegrityAlgorithm, - ike_message.AUTH_HMAC_MD5_96, nil, nil, nil) + ike_message.AUTH_HMAC_SHA1_96, nil, nil, nil) } + + // RFC 7296 + // Diffie-Hellman transform is optional in CREATE_CHILD_SA + // proposal.DiffieHellmanGroup.BuildTransform( + // ike_message.TypeDiffieHellmanGroup, ike_message.DH_1024_BIT_MODP, nil, nil, nil) + // ESN transform - proposal.ExtendedSequenceNumbers.BuildTransform(ike_message.TypeExtendedSequenceNumbers, - ike_message.ESN_NO, nil, nil, nil) + proposal.ExtendedSequenceNumbers.BuildTransform( + ike_message.TypeExtendedSequenceNumbers, ike_message.ESN_NO, nil, nil, nil) + + ikeUe.CreateHalfChildSA(ikeMessage.MessageID, spi, pduSessionID) // Build Nonce nonceData := GenerateRandomNumber().Bytes() @@ -1548,15 +1762,18 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m ikeSecurityAssociation.ConcatenatedNonce = nonceData // TSi - ueIPAddr := thisUE.IPSecInnerIP + n3iwfIPAddr := net.ParseIP(n3iwfSelf.IPSecGatewayAddress) tsi := ikePayload.BuildTrafficSelectorInitiator() - tsi.TrafficSelectors.BuildIndividualTrafficSelector(ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, - 0, 65535, ueIPAddr, ueIPAddr) + tsi.TrafficSelectors.BuildIndividualTrafficSelector( + ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, + 0, 65535, n3iwfIPAddr.To4(), n3iwfIPAddr.To4()) + // TSr - n3iwfIPAddr := net.ParseIP(n3iwfSelf.IPSecGatewayAddress) + ueIPAddr := ikeUe.IPSecInnerIP tsr := ikePayload.BuildTrafficSelectorResponder() - tsr.TrafficSelectors.BuildIndividualTrafficSelector(ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, - 0, 65535, n3iwfIPAddr, n3iwfIPAddr) + tsr.TrafficSelectors.BuildIndividualTrafficSelector( + ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, + 0, 65535, ueIPAddr.To4(), ueIPAddr.To4()) // Notify-Qos ikePayload.BuildNotify5G_QOS_INFO(uint8(pduSessionID), pduSession.QFIList, true, false, 0) @@ -1564,127 +1781,31 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m // Notify-UP_IP_ADDRESS ikePayload.BuildNotifyUP_IP4_ADDRESS(n3iwfSelf.IPSecGatewayAddress) - if err := EncryptProcedure(thisUE.N3IWFIKESecurityAssociation, ikePayload, ikeMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) - temporaryPDUSessionSetupData.UnactivatedPDUSession = temporaryPDUSessionSetupData.UnactivatedPDUSession[1:] - cause := ngapType.Cause{ - Present: ngapType.CausePresentTransport, - Transport: &ngapType.CauseTransport{ - Value: ngapType.CauseTransportPresentTransportResourceUnavailable, - }, - } - transfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(cause, nil) - if err != nil { - ikeLog.Errorf("Build PDU Session Resource Setup Unsuccessful Transfer Failed: %+v", err) - continue - } - if ngapProcedure == ngapType.ProcedureCodeInitialContextSetup { - ngap_message.AppendPDUSessionResourceFailedToSetupListCxtRes( - temporaryPDUSessionSetupData.FailedListCxtRes, pduSessionID, transfer) - } else { - ngap_message.AppendPDUSessionResourceFailedToSetupListSURes( - temporaryPDUSessionSetupData.FailedListSURes, pduSessionID, transfer) - } + temporaryPDUSessionSetupData.Index++ + + if err := EncryptProcedure(ikeUe.N3IWFIKESecurityAssociation, ikePayload, ikeMessage); err != nil { + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) + errStr = context.ErrTransportResourceUnavailable + temporaryPDUSessionSetupData.FailedErrStr = append(temporaryPDUSessionSetupData.FailedErrStr, + errStr) continue } - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + temporaryPDUSessionSetupData.FailedErrStr = append(temporaryPDUSessionSetupData.FailedErrStr, + errStr) + + SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, ikeSecurityAssociation.IKEConnection.N3IWFAddr, + ikeSecurityAssociation.IKEConnection.UEAddr, ikeMessage) break } else { - // Send Response to AMF - ngapProcedure := temporaryPDUSessionSetupData.NGAPProcedureCode.Value - if ngapProcedure == ngapType.ProcedureCodeInitialContextSetup { - ngap_message.SendInitialContextSetupResponse(thisUE.AMF, thisUE, - temporaryPDUSessionSetupData.SetupListCxtRes, - temporaryPDUSessionSetupData.FailedListCxtRes, nil) - } else { - ngap_message.SendPDUSessionResourceSetupResponse(thisUE.AMF, thisUE, - temporaryPDUSessionSetupData.SetupListSURes, - temporaryPDUSessionSetupData.FailedListSURes, nil) - } + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewSendPDUSessionResourceSetupResEvt( + ranNgapId, + ) break } } } -func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage) { - ikeLog.Infoln("Handle Informational") - - if message == nil { - ikeLog.Error("IKE Message is nil") - return - } - - n3iwfSelf := context.N3IWFSelf() - responseIKEMessage := new(ike_message.IKEMessage) - responderSPI := message.ResponderSPI - ikeSecurityAssociation, ok := n3iwfSelf.IKESALoad(responderSPI) - var encryptedPayload *ike_message.Encrypted - - if !ok { - ikeLog.Warn("Unrecognized SPI") - // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) - responseIKEMessage.BuildIKEHeader(0, message.ResponderSPI, ike_message.INFORMATIONAL, - ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) - - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - - return - } - - for _, ikePayload := range message.Payloads { - switch ikePayload.Type() { - case ike_message.TypeSK: - encryptedPayload = ikePayload.(*ike_message.Encrypted) - default: - ikeLog.Warnf( - "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", - ikePayload.Type()) - } - } - - decryptedIKEPayload, err := DecryptProcedure(ikeSecurityAssociation, message, encryptedPayload) - if err != nil { - ikeLog.Errorf("Decrypt IKE message failed: %+v", err) - return - } - - n3iwfUe := ikeSecurityAssociation.ThisUE - amf := n3iwfUe.AMF - - if n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer != nil { - n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer.Stop() - n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = nil - atomic.StoreInt32(&n3iwfUe.N3IWFIKESecurityAssociation.CurrentRetryTimes, 0) - } - - if len(decryptedIKEPayload) == 0 { // Receive DPD message - return - } - - for _, ikePayload := range decryptedIKEPayload { - switch ikePayload.Type() { - case ike_message.TypeD: - deletePayload := ikePayload.(*ike_message.Delete) - if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA - if err := n3iwfUe.Remove(); err != nil { - ikeLog.Errorf("Delete Ue Context error : %+v", err) - } - ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) - } else if deletePayload.ProtocolID == ike_message.TypeESP { - ngap_message.SendPDUSessionResourceReleaseResponse(amf, n3iwfUe, n3iwfUe.PduSessionReleaseList, nil) - } - default: - ikeLog.Warnf( - "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", - ikePayload.Type()) - } - } - ikeSecurityAssociation.ResponderMessageID++ -} - func is_supported(transformType uint8, transformID uint16, attributePresent bool, attributeValue uint16) bool { switch transformType { case ike_message.TypeEncryptionAlgorithm: @@ -1922,8 +2043,8 @@ func parseIPAddressInformationToChildSecurityAssociation( childSecurityAssociation.PeerPublicIPAddr = uePublicIPAddr childSecurityAssociation.LocalPublicIPAddr = net.ParseIP(context.N3IWFSelf().IKEBindAddress) - ikeLog.Tracef("Local TS: %+v", trafficSelectorLocal.StartAddress) - ikeLog.Tracef("Remote TS: %+v", trafficSelectorRemote.StartAddress) + logger.IKELog.Tracef("Local TS: %+v", trafficSelectorLocal.StartAddress) + logger.IKELog.Tracef("Remote TS: %+v", trafficSelectorRemote.StartAddress) childSecurityAssociation.TrafficSelectorLocal = net.IPNet{ IP: trafficSelectorLocal.StartAddress, diff --git a/pkg/ike/handler/security.go b/pkg/ike/handler/security.go index 96b50d5..810e724 100644 --- a/pkg/ike/handler/security.go +++ b/pkg/ike/handler/security.go @@ -16,6 +16,7 @@ import ( "math/big" "strings" + "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/ike/message" ) @@ -37,7 +38,7 @@ func GenerateRandomNumber() *big.Int { for { number, err = rand.Int(rand.Reader, &randomNumberMaximum) if err != nil { - ikeLog.Errorf("Error occurs when generate random number: %+v", err) + logger.IKELog.Errorf("Error occurs when generate random number: %+v", err) return nil } else { if number.Cmp(&randomNumberMinimum) == 1 { @@ -52,7 +53,7 @@ func GenerateRandomUint8() (uint8, error) { number := make([]byte, 1) _, err := io.ReadFull(rand.Reader, number) if err != nil { - ikeLog.Errorf("Read random failed: %+v", err) + logger.IKELog.Errorf("Read random failed: %+v", err) return 0, errors.New("Read failed") } return number[0], nil @@ -101,7 +102,7 @@ func CalculateDiffieHellmanMaterials(secret *big.Int, peerPublicValue []byte, generator = new(big.Int).SetUint64(Group2Generator) factor, ok = new(big.Int).SetString(Group2PrimeString, 16) if !ok { - ikeLog.Errorf( + logger.IKELog.Errorf( "Error occurs when setting big number \"factor\" in %d group", diffieHellmanGroupNumber) } @@ -109,12 +110,12 @@ func CalculateDiffieHellmanMaterials(secret *big.Int, peerPublicValue []byte, generator = new(big.Int).SetUint64(Group14Generator) factor, ok = new(big.Int).SetString(Group14PrimeString, 16) if !ok { - ikeLog.Errorf( + logger.IKELog.Errorf( "Error occurs when setting big number \"factor\" in %d group", diffieHellmanGroupNumber) } default: - ikeLog.Errorf("Unsupported Diffie-Hellman group: %d", diffieHellmanGroupNumber) + logger.IKELog.Errorf("Unsupported Diffie-Hellman group: %d", diffieHellmanGroupNumber) return } @@ -137,7 +138,7 @@ func NewPseudorandomFunction(key []byte, algorithmType uint16) (hash.Hash, bool) case message.PRF_HMAC_SHA1: return hmac.New(sha1.New, key), true default: - ikeLog.Errorf("Unsupported pseudo random function: %d", algorithmType) + logger.IKELog.Errorf("Unsupported pseudo random function: %d", algorithmType) return nil, false } } @@ -151,7 +152,7 @@ func CalculateChecksum(key []byte, originData []byte, algorithmType uint16) ([]b } integrityFunction := hmac.New(md5.New, key) if _, err := integrityFunction.Write(originData); err != nil { - ikeLog.Errorf("Hash function write error when calculating checksum: %+v", err) + logger.IKELog.Errorf("Hash function write error when calculating checksum: %+v", err) return nil, errors.New("Hash function write error") } return integrityFunction.Sum(nil), nil @@ -161,12 +162,12 @@ func CalculateChecksum(key []byte, originData []byte, algorithmType uint16) ([]b } integrityFunction := hmac.New(sha1.New, key) if _, err := integrityFunction.Write(originData); err != nil { - ikeLog.Errorf("Hash function write error when calculating checksum: %+v", err) + logger.IKELog.Errorf("Hash function write error when calculating checksum: %+v", err) return nil, errors.New("Hash function write error") } return integrityFunction.Sum(nil)[:12], nil default: - ikeLog.Errorf("Unsupported integrity function: %d", algorithmType) + logger.IKELog.Errorf("Unsupported integrity function: %d", algorithmType) return nil, errors.New("Unsupported algorithm") } } @@ -179,12 +180,12 @@ func VerifyIKEChecksum(key []byte, originData []byte, checksum []byte, algorithm } integrityFunction := hmac.New(md5.New, key) if _, err := integrityFunction.Write(originData); err != nil { - ikeLog.Errorf("Hash function write error when verifying IKE checksum: %+v", err) + logger.IKELog.Errorf("Hash function write error when verifying IKE checksum: %+v", err) return false, errors.New("Hash function write error") } checksumOfMessage := integrityFunction.Sum(nil) - ikeLog.Tracef("Calculated checksum:\n%s\nReceived checksum:\n%s", + logger.IKELog.Tracef("Calculated checksum:\n%s\nReceived checksum:\n%s", hex.Dump(checksumOfMessage), hex.Dump(checksum)) return hmac.Equal(checksumOfMessage, checksum), nil @@ -194,17 +195,17 @@ func VerifyIKEChecksum(key []byte, originData []byte, checksum []byte, algorithm } integrityFunction := hmac.New(sha1.New, key) if _, err := integrityFunction.Write(originData); err != nil { - ikeLog.Errorf("Hash function write error when verifying IKE checksum: %+v", err) + logger.IKELog.Errorf("Hash function write error when verifying IKE checksum: %+v", err) return false, errors.New("Hash function write error") } checksumOfMessage := integrityFunction.Sum(nil)[:12] - ikeLog.Tracef("Calculated checksum:\n%s\nReceived checksum:\n%s", + logger.IKELog.Tracef("Calculated checksum:\n%s\nReceived checksum:\n%s", hex.Dump(checksumOfMessage), hex.Dump(checksum)) return hmac.Equal(checksumOfMessage, checksum), nil default: - ikeLog.Errorf("Unsupported integrity function: %d", algorithmType) + logger.IKELog.Errorf("Unsupported integrity function: %d", algorithmType) return false, errors.New("Unsupported algorithm") } } @@ -219,7 +220,7 @@ func EncryptMessage(key []byte, originData []byte, algorithmType uint16) ([]byte block, err := aes.NewCipher(key) if err != nil { - ikeLog.Errorf("Error occur when create new cipher: %+v", err) + logger.IKELog.Errorf("Error occur when create new cipher: %+v", err) return nil, errors.New("Create cipher failed") } @@ -228,7 +229,7 @@ func EncryptMessage(key []byte, originData []byte, algorithmType uint16) ([]byte _, err = io.ReadFull(rand.Reader, initializationVector) if err != nil { - ikeLog.Errorf("Read random failed: %+v", err) + logger.IKELog.Errorf("Read random failed: %+v", err) return nil, errors.New("Read random initialization vector failed") } @@ -237,7 +238,7 @@ func EncryptMessage(key []byte, originData []byte, algorithmType uint16) ([]byte return cipherText, nil default: - ikeLog.Errorf("Unsupported encryption algorithm: %d", algorithmType) + logger.IKELog.Errorf("Unsupported encryption algorithm: %d", algorithmType) return nil, errors.New("Unsupported algorithm") } } @@ -246,7 +247,7 @@ func DecryptMessage(key []byte, cipherText []byte, algorithmType uint16) ([]byte switch algorithmType { case message.ENCR_AES_CBC: if len(cipherText) < aes.BlockSize { - ikeLog.Error("Length of cipher text is too short to decrypt") + logger.IKELog.Error("Length of cipher text is too short to decrypt") return nil, errors.New("Cipher text is too short") } @@ -254,7 +255,7 @@ func DecryptMessage(key []byte, cipherText []byte, algorithmType uint16) ([]byte encryptedMessage := cipherText[aes.BlockSize:] if len(encryptedMessage)%aes.BlockSize != 0 { - ikeLog.Error("Cipher text is not a multiple of block size") + logger.IKELog.Error("Cipher text is not a multiple of block size") return nil, errors.New("Cipher text length error") } @@ -262,22 +263,22 @@ func DecryptMessage(key []byte, cipherText []byte, algorithmType uint16) ([]byte block, err := aes.NewCipher(key) if err != nil { - ikeLog.Errorf("Error occur when create new cipher: %+v", err) + logger.IKELog.Errorf("Error occur when create new cipher: %+v", err) return nil, errors.New("Create cipher failed") } cbcBlockMode := cipher.NewCBCDecrypter(block, initializationVector) cbcBlockMode.CryptBlocks(plainText, encryptedMessage) - ikeLog.Tracef("Decrypted content:\n%s", hex.Dump(plainText)) + logger.IKELog.Tracef("Decrypted content:\n%s", hex.Dump(plainText)) padding := int(plainText[len(plainText)-1]) + 1 plainText = plainText[:len(plainText)-padding] - ikeLog.Tracef("Decrypted content with out padding:\n%s", hex.Dump(plainText)) + logger.IKELog.Tracef("Decrypted content with out padding:\n%s", hex.Dump(plainText)) return plainText, nil default: - ikeLog.Errorf("Unsupported encryption algorithm: %d", algorithmType) + logger.IKELog.Errorf("Unsupported encryption algorithm: %d", algorithmType) return nil, errors.New("Unsupported algorithm") } } @@ -294,14 +295,14 @@ func PKCS7Padding(plainText []byte, blockSize int) []byte { // Certificate func CompareRootCertificate(certificateEncoding uint8, requestedCertificateAuthorityHash []byte) bool { if certificateEncoding != message.X509CertificateSignature { - ikeLog.Debugf("Not support certificate type: %d. Reject.", certificateEncoding) + logger.IKELog.Debugf("Not support certificate type: %d. Reject.", certificateEncoding) return false } n3iwfSelf := context.N3IWFSelf() if len(n3iwfSelf.CertificateAuthority) == 0 { - ikeLog.Error("Certificate authority in context is empty") + logger.IKELog.Error("Certificate authority in context is empty") return false } @@ -348,20 +349,20 @@ func GenerateKeyForIKESA(ikeSecurityAssociation *context.IKESecurityAssociation) if length_SK_d, ok = getKeyLength(transformPseudorandomFunction.TransformType, transformPseudorandomFunction.TransformID, transformPseudorandomFunction.AttributePresent, transformPseudorandomFunction.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") return errors.New("Get key length failed") } if length_SK_ai, ok = getKeyLength(transformIntegrityAlgorithm.TransformType, transformIntegrityAlgorithm.TransformID, transformIntegrityAlgorithm.AttributePresent, transformIntegrityAlgorithm.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") return errors.New("Get key length failed") } length_SK_ar = length_SK_ai if length_SK_ei, ok = getKeyLength(transformEncryptionAlgorithm.TransformType, transformEncryptionAlgorithm.TransformID, transformEncryptionAlgorithm.AttributePresent, transformEncryptionAlgorithm.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") return errors.New("Get key length failed") } length_SK_er = length_SK_ei @@ -373,21 +374,21 @@ func GenerateKeyForIKESA(ikeSecurityAssociation *context.IKESecurityAssociation) if pseudorandomFunction, ok = NewPseudorandomFunction(ikeSecurityAssociation.ConcatenatedNonce, transformPseudorandomFunction.TransformID); !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") return errors.New("New pseudorandom function failed") } - ikeLog.Tracef("DH shared key:\n%s", hex.Dump(ikeSecurityAssociation.DiffieHellmanSharedKey)) - ikeLog.Tracef("Concatenated nonce:\n%s", hex.Dump(ikeSecurityAssociation.ConcatenatedNonce)) + logger.IKELog.Tracef("DH shared key:\n%s", hex.Dump(ikeSecurityAssociation.DiffieHellmanSharedKey)) + logger.IKELog.Tracef("Concatenated nonce:\n%s", hex.Dump(ikeSecurityAssociation.ConcatenatedNonce)) if _, err := pseudorandomFunction.Write(ikeSecurityAssociation.DiffieHellmanSharedKey); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) + logger.IKELog.Errorf("Pseudorandom function write error: %+v", err) return errors.New("Pseudorandom function write failed") } SKEYSEED := pseudorandomFunction.Sum(nil) - ikeLog.Tracef("SKEYSEED:\n%s", hex.Dump(SKEYSEED)) + logger.IKELog.Tracef("SKEYSEED:\n%s", hex.Dump(SKEYSEED)) seed := concatenateNonceAndSPI(ikeSecurityAssociation.ConcatenatedNonce, ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI) @@ -396,11 +397,11 @@ func GenerateKeyForIKESA(ikeSecurityAssociation *context.IKESecurityAssociation) var index byte for index = 1; len(keyStream) < totalKeyLength; index++ { if pseudorandomFunction, ok = NewPseudorandomFunction(SKEYSEED, transformPseudorandomFunction.TransformID); !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") return errors.New("New pseudorandom function failed") } if _, err := pseudorandomFunction.Write(append(append(generatedKeyBlock, seed...), index)); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) + logger.IKELog.Errorf("Pseudorandom function write error: %+v", err) return errors.New("Pseudorandom function write failed") } generatedKeyBlock = pseudorandomFunction.Sum(nil) @@ -423,17 +424,17 @@ func GenerateKeyForIKESA(ikeSecurityAssociation *context.IKESecurityAssociation) ikeSecurityAssociation.SK_pr = keyStream[:length_SK_pr] // keyStream = keyStream[length_SK_pr:] - ikeLog.Debugln("====== IKE Security Association Info =====") - ikeLog.Debugf("Initiator's SPI: %016x", ikeSecurityAssociation.RemoteSPI) - ikeLog.Debugf("Responder's SPI: %016x", ikeSecurityAssociation.LocalSPI) - ikeLog.Debugf("Encryption Algorithm: %d", ikeSecurityAssociation.EncryptionAlgorithm.TransformID) - ikeLog.Debugf("SK_ei: %x", ikeSecurityAssociation.SK_ei) - ikeLog.Debugf("SK_er: %x", ikeSecurityAssociation.SK_er) - ikeLog.Debugf("Integrity Algorithm: %d", ikeSecurityAssociation.IntegrityAlgorithm.TransformID) - ikeLog.Debugf("SK_ai: %x", ikeSecurityAssociation.SK_ai) - ikeLog.Debugf("SK_ar: %x", ikeSecurityAssociation.SK_ar) - ikeLog.Debugf("SK_pi: %x", ikeSecurityAssociation.SK_pi) - ikeLog.Debugf("SK_pr: %x", ikeSecurityAssociation.SK_pr) + logger.IKELog.Debugln("====== IKE Security Association Info =====") + logger.IKELog.Debugf("Initiator's SPI: %016x", ikeSecurityAssociation.RemoteSPI) + logger.IKELog.Debugf("Responder's SPI: %016x", ikeSecurityAssociation.LocalSPI) + logger.IKELog.Debugf("Encryption Algorithm: %d", ikeSecurityAssociation.EncryptionAlgorithm.TransformID) + logger.IKELog.Debugf("SK_ei: %x", ikeSecurityAssociation.SK_ei) + logger.IKELog.Debugf("SK_er: %x", ikeSecurityAssociation.SK_er) + logger.IKELog.Debugf("Integrity Algorithm: %d", ikeSecurityAssociation.IntegrityAlgorithm.TransformID) + logger.IKELog.Debugf("SK_ai: %x", ikeSecurityAssociation.SK_ai) + logger.IKELog.Debugf("SK_ar: %x", ikeSecurityAssociation.SK_ar) + logger.IKELog.Debugf("SK_pi: %x", ikeSecurityAssociation.SK_pi) + logger.IKELog.Debugf("SK_pr: %x", ikeSecurityAssociation.SK_pr) return nil } @@ -484,7 +485,7 @@ func GenerateKeyForChildSA(ikeSecurityAssociation *context.IKESecurityAssociatio transformEncryptionAlgorithmForIPSec.TransformID, transformEncryptionAlgorithmForIPSec.AttributePresent, transformEncryptionAlgorithmForIPSec.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") return errors.New("Get key length failed") } if transformIntegrityAlgorithmForIPSec != nil { @@ -492,7 +493,7 @@ func GenerateKeyForChildSA(ikeSecurityAssociation *context.IKESecurityAssociatio transformIntegrityAlgorithmForIPSec.TransformID, transformIntegrityAlgorithmForIPSec.AttributePresent, transformIntegrityAlgorithmForIPSec.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") return errors.New("Get key length failed") } } @@ -508,11 +509,11 @@ func GenerateKeyForChildSA(ikeSecurityAssociation *context.IKESecurityAssociatio for index = 1; len(keyStream) < totalKeyLength; index++ { if pseudorandomFunction, ok = NewPseudorandomFunction(ikeSecurityAssociation.SK_d, transformPseudorandomFunction.TransformID); !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") return errors.New("New pseudorandom function failed") } if _, err := pseudorandomFunction.Write(append(append(generatedKeyBlock, seed...), index)); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) + logger.IKELog.Errorf("Pseudorandom function write error: %+v", err) return errors.New("Pseudorandom function write failed") } generatedKeyBlock = pseudorandomFunction.Sum(nil) @@ -575,7 +576,7 @@ func DecryptProcedure(ikeSecurityAssociation *context.IKESecurityAssociation, ik transformIntegrityAlgorithm.TransformID, transformIntegrityAlgorithm.AttributePresent, transformIntegrityAlgorithm.AttributeValue) if !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") return nil, errors.New("Get key length failed") } @@ -584,8 +585,8 @@ func DecryptProcedure(ikeSecurityAssociation *context.IKESecurityAssociation, ik ikeMessageData, err := ikeMessage.Encode() if err != nil { - ikeLog.Errorln(err) - ikeLog.Error("Error occur when encoding for checksum") + logger.IKELog.Errorln(err) + logger.IKELog.Error("Error occur when encoding for checksum") return nil, errors.New("Encoding IKE message failed") } @@ -593,11 +594,11 @@ func DecryptProcedure(ikeSecurityAssociation *context.IKESecurityAssociation, ik ikeMessageData[:len(ikeMessageData)-checksumLength], checksum, transformIntegrityAlgorithm.TransformID) if err != nil { - ikeLog.Errorf("Error occur when verifying checksum: %+v", err) + logger.IKELog.Errorf("Error occur when verifying checksum: %+v", err) return nil, errors.New("Error verify checksum") } if !ok { - ikeLog.Warn("Message checksum failed. Drop the message.") + logger.IKELog.Warn("Message checksum failed. Drop the message.") return nil, errors.New("Checksum failed, drop.") } @@ -606,14 +607,14 @@ func DecryptProcedure(ikeSecurityAssociation *context.IKESecurityAssociation, ik plainText, err := DecryptMessage(ikeSecurityAssociation.SK_ei, encryptedData, transformEncryptionAlgorithm.TransformID) if err != nil { - ikeLog.Errorf("Error occur when decrypting message: %+v", err) + logger.IKELog.Errorf("Error occur when decrypting message: %+v", err) return nil, errors.New("Error decrypting message") } var decryptedIKEPayload message.IKEPayloadContainer err = decryptedIKEPayload.Decode(encryptedPayload.NextPayload, plainText) if err != nil { - ikeLog.Errorln(err) + logger.IKELog.Errorln(err) return nil, errors.New("Decoding decrypted payload failed") } @@ -657,21 +658,21 @@ func EncryptProcedure(ikeSecurityAssociation *context.IKESecurityAssociation, transformIntegrityAlgorithm.TransformID, transformIntegrityAlgorithm.AttributePresent, transformIntegrityAlgorithm.AttributeValue) if !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") + logger.IKELog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") return errors.New("Get key length failed") } // Encrypting ikePayloadData, err := ikePayload.Encode() if err != nil { - ikeLog.Error(err) + logger.IKELog.Error(err) return errors.New("Encoding IKE payload failed.") } encryptedData, err := EncryptMessage(ikeSecurityAssociation.SK_er, ikePayloadData, transformEncryptionAlgorithm.TransformID) if err != nil { - ikeLog.Errorf("Encrypting data error: %+v", err) + logger.IKELog.Errorf("Encrypting data error: %+v", err) return errors.New("Error encrypting message") } @@ -681,14 +682,14 @@ func EncryptProcedure(ikeSecurityAssociation *context.IKESecurityAssociation, // Calculate checksum responseIKEMessageData, err := responseIKEMessage.Encode() if err != nil { - ikeLog.Error(err) + logger.IKELog.Error(err) return errors.New("Encoding IKE message error") } checksumOfMessage, err := CalculateChecksum(ikeSecurityAssociation.SK_ar, responseIKEMessageData[:len(responseIKEMessageData)-checksumLength], transformIntegrityAlgorithm.TransformID) if err != nil { - ikeLog.Errorf("Calculating checksum failed: %+v", err) + logger.IKELog.Errorf("Calculating checksum failed: %+v", err) return errors.New("Error calculating checksum") } checksumField := sk.EncryptedData[len(sk.EncryptedData)-checksumLength:] diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 0a760c1..330bb26 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -6,19 +6,18 @@ import ( "runtime/debug" "time" - ngap_message "github.com/free5gc/n3iwf/internal/ngap/message" + "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" - "github.com/free5gc/ngap/ngapType" ) func SendIKEMessageToUE(udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, message *ike_message.IKEMessage) { - ikeLog.Trace("Send IKE message to UE") - ikeLog.Trace("Encoding...") + logger.IKELog.Trace("Send IKE message to UE") + logger.IKELog.Trace("Encoding...") pkt, err := message.Encode() if err != nil { - ikeLog.Errorln(err) + logger.IKELog.Errorln(err) return } // As specified in RFC 7296 section 3.1, the IKE message send from/to UDP port 4500 @@ -28,22 +27,22 @@ func SendIKEMessageToUE(udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, mes pkt = append(prependZero, pkt...) } - ikeLog.Trace("Sending...") + logger.IKELog.Trace("Sending...") n, err := udpConn.WriteToUDP(pkt, dstAddr) if err != nil { - ikeLog.Error(err) + logger.IKELog.Error(err) return } if n != len(pkt) { - ikeLog.Errorf("Not all of the data is sent. Total length: %d. Sent: %d.", len(pkt), n) + logger.IKELog.Errorf("Not all of the data is sent. Total length: %d. Sent: %d.", len(pkt), n) return } } func SendUEInformationExchange( - n3iwfUe *context.N3IWFUe, payload ike_message.IKEPayloadContainer, + ikeUe *context.N3IWFIkeUe, payload ike_message.IKEPayloadContainer, ) { - ikeSecurityAssociation := n3iwfUe.N3IWFIKESecurityAssociation + ikeSecurityAssociation := ikeUe.N3IWFIKESecurityAssociation responseIKEMessage := new(ike_message.IKEMessage) // Build IKE message @@ -52,32 +51,38 @@ func SendUEInformationExchange( ikeSecurityAssociation.ResponderMessageID) if payload != nil { // This message isn't a DPD message if err := EncryptProcedure(ikeSecurityAssociation, payload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) + logger.IKELog.Errorf("Encrypting IKE message failed: %+v", err) return } } - SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, - n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) + SendIKEMessageToUE(ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.N3IWFAddr, + ikeUe.IKEConnection.UEAddr, responseIKEMessage) } -func SendIKEDeleteRequest(n3iwfUe *context.N3IWFUe) { +func SendIKEDeleteRequest(localSPI uint64) { + ikeUe, ok := context.N3IWFSelf().IkeUePoolLoad(localSPI) + if !ok { + logger.IKELog.Errorf("Cannot get IkeUE from SPI : %+v", localSPI) + return + } + var deletePayload ike_message.IKEPayloadContainer deletePayload.BuildDeletePayload(ike_message.TypeIKE, 0, 0, nil) - SendUEInformationExchange(n3iwfUe, deletePayload) + SendUEInformationExchange(ikeUe, deletePayload) } -func SendChildSADeleteRequest(n3iwfUe *context.N3IWFUe, relaseList []ngapType.PDUSessionResourceReleasedItemRelRes) { +func SendChildSADeleteRequest(ikeUe *context.N3IWFIkeUe, relaseList []int64) { var deleteSPIs []byte spiLen := uint16(0) for _, releaseItem := range relaseList { - for _, childSA := range n3iwfUe.N3IWFChildSecurityAssociation { - if childSA.PDUSessionIds[0] == releaseItem.PDUSessionID.Value { + for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { + if childSA.PDUSessionIds[0] == releaseItem { spiByte := make([]byte, 4) binary.BigEndian.PutUint32(spiByte, uint32(childSA.XfrmStateList[0].Spi)) deleteSPIs = append(deleteSPIs, spiByte...) spiLen += 1 - if err := n3iwfUe.DeleteChildSA(childSA); err != nil { - ikeLog.Errorf("Delete Child SA error : %+v", err) + if err := ikeUe.DeleteChildSA(childSA); err != nil { + logger.IKELog.Errorf("Delete Child SA error : %+v", err) } } } @@ -85,38 +90,48 @@ func SendChildSADeleteRequest(n3iwfUe *context.N3IWFUe, relaseList []ngapType.PD var deletePayload ike_message.IKEPayloadContainer deletePayload.BuildDeletePayload(ike_message.TypeESP, 4, spiLen, deleteSPIs) - SendUEInformationExchange(n3iwfUe, deletePayload) + SendUEInformationExchange(ikeUe, deletePayload) } -func StartDPD(n3iwfUe *context.N3IWFUe) { +func StartDPD(ikeUe *context.N3IWFIkeUe) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. - ikeLog.Errorf("panic: %v\n%s", p, string(debug.Stack())) + logger.IKELog.Errorf("panic: %v\n%s", p, string(debug.Stack())) } }() - n3iwfUe.N3IWFIKESecurityAssociation.IKESAClosedCh = make(chan struct{}) + ikeUe.N3IWFIKESecurityAssociation.IKESAClosedCh = make(chan struct{}) + + n3iwfSelf := context.N3IWFSelf() liveness := factory.N3iwfConfig.Configuration.LivenessCheck if liveness.Enable { + ikeUe.N3IWFIKESecurityAssociation.IsUseDPD = true timer := time.NewTicker(liveness.TransFreq) for { select { - case <-n3iwfUe.N3IWFIKESecurityAssociation.IKESAClosedCh: - close(n3iwfUe.N3IWFIKESecurityAssociation.IKESAClosedCh) + case <-ikeUe.N3IWFIKESecurityAssociation.IKESAClosedCh: + close(ikeUe.N3IWFIKESecurityAssociation.IKESAClosedCh) timer.Stop() return case <-timer.C: - SendUEInformationExchange(n3iwfUe, nil) + SendUEInformationExchange(ikeUe, nil) var DPDReqRetransTime time.Duration = 2 * time.Second - n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = context.NewDPDPeriodicTimer(DPDReqRetransTime, - liveness.MaxRetryTimes, n3iwfUe.N3IWFIKESecurityAssociation, func() { - ikeLog.Errorf("UE is down") - cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, - ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) - ngap_message.SendUEContextReleaseRequest(n3iwfUe.AMF, n3iwfUe, *cause) - n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = nil + ikeUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = context.NewDPDPeriodicTimer(DPDReqRetransTime, + liveness.MaxRetryTimes, ikeUe.N3IWFIKESecurityAssociation, func() { + logger.IKELog.Errorf("UE is down") + ranNgapId, ok := n3iwfSelf.NgapIdLoad(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + if !ok { + logger.IKELog.Infof("Cannot find ranNgapId form SPI : %+v", ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + return + } + + n3iwfSelf.NGAPServer.RcvEventCh <- context.NewSendUEContextReleaseRequestEvt( + ranNgapId, context.ErrRadioConnWithUeLost, + ) + + ikeUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = nil timer.Stop() }) } diff --git a/pkg/ike/message/build.go b/pkg/ike/message/build.go index 77289bc..f6440bb 100644 --- a/pkg/ike/message/build.go +++ b/pkg/ike/message/build.go @@ -3,6 +3,8 @@ package message import ( "encoding/binary" "net" + + "github.com/free5gc/n3iwf/internal/logger" ) func (ikeMessage *IKEMessage) BuildIKEHeader( @@ -242,7 +244,7 @@ func (container *IKEPayloadContainer) BuildEAP5GStart(identifier uint8) { func (container *IKEPayloadContainer) BuildEAP5GNAS(identifier uint8, nasPDU []byte) { if len(nasPDU) == 0 { - ikeLog.Error("BuildEAP5GNAS(): NASPDU is nil") + logger.IKELog.Error("BuildEAP5GNAS(): NASPDU is nil") return } diff --git a/pkg/ike/message/message.go b/pkg/ike/message/message.go index f1647ef..a541e95 100644 --- a/pkg/ike/message/message.go +++ b/pkg/ike/message/message.go @@ -6,18 +6,9 @@ import ( "errors" "fmt" - "github.com/sirupsen/logrus" - "github.com/free5gc/n3iwf/internal/logger" ) -// Log -var ikeLog *logrus.Entry - -func init() { - ikeLog = logger.IKELog -} - type IKEMessage struct { InitiatorSPI uint64 ResponderSPI uint64 @@ -29,7 +20,7 @@ type IKEMessage struct { } func (ikeMessage *IKEMessage) Encode() ([]byte, error) { - ikeLog.Info("Encoding IKE message") + logger.IKELog.Info("Encoding IKE message") ikeMessageData := make([]byte, 28) @@ -54,8 +45,8 @@ func (ikeMessage *IKEMessage) Encode() ([]byte, error) { ikeMessageData = append(ikeMessageData, ikeMessagePayloadData...) binary.BigEndian.PutUint32(ikeMessageData[24:28], uint32(len(ikeMessageData))) - ikeLog.Tracef("Encoded %d bytes", len(ikeMessageData)) - ikeLog.Tracef("IKE message data:\n%s", hex.Dump(ikeMessageData)) + logger.IKELog.Tracef("Encoded %d bytes", len(ikeMessageData)) + logger.IKELog.Tracef("IKE message data:\n%s", hex.Dump(ikeMessageData)) return ikeMessageData, nil } @@ -63,8 +54,8 @@ func (ikeMessage *IKEMessage) Encode() ([]byte, error) { func (ikeMessage *IKEMessage) Decode(rawData []byte) error { // IKE message packet format this implementation referenced is // defined in RFC 7296, Section 3.1 - ikeLog.Info("Decoding IKE message") - ikeLog.Tracef("Received IKE message:\n%s", hex.Dump(rawData)) + logger.IKELog.Info("Decoding IKE message") + logger.IKELog.Tracef("Received IKE message:\n%s", hex.Dump(rawData)) // bounds checking if len(rawData) < 28 { @@ -101,7 +92,7 @@ func (ikeMessage *IKEMessage) Decode(rawData []byte) error { type IKEPayloadContainer []IKEPayload func (container *IKEPayloadContainer) Encode() ([]byte, error) { - ikeLog.Info("Encoding IKE payloads") + logger.IKELog.Info("Encoding IKE payloads") ikeMessagePayloadData := make([]byte, 0) @@ -132,11 +123,11 @@ func (container *IKEPayloadContainer) Encode() ([]byte, error) { } func (container *IKEPayloadContainer) Decode(nextPayload uint8, rawData []byte) error { - ikeLog.Info("Decoding IKE payloads") + logger.IKELog.Info("Decoding IKE payloads") for len(rawData) > 0 { // bounds checking - ikeLog.Trace("DecodePayload(): Decode 1 payload") + logger.IKELog.Trace("DecodePayload(): Decode 1 payload") if len(rawData) < 4 { return errors.New("DecodePayload(): No sufficient bytes to decode next payload") } @@ -257,7 +248,7 @@ type Transform struct { func (securityAssociation *SecurityAssociation) Type() IKEPayloadType { return TypeSA } func (securityAssociation *SecurityAssociation) marshal() ([]byte, error) { - ikeLog.Info("[SecurityAssociation] marshal(): Start marshalling") + logger.IKELog.Info("[SecurityAssociation] marshal(): Start marshalling") securityAssociationData := make([]byte, 0) @@ -342,11 +333,11 @@ func (securityAssociation *SecurityAssociation) marshal() ([]byte, error) { } func (securityAssociation *SecurityAssociation) unmarshal(rawData []byte) error { - ikeLog.Info("[SecurityAssociation] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[SecurityAssociation] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[SecurityAssociation] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[SecurityAssociation] unmarshal(): Payload length %d bytes", len(rawData)) for len(rawData) > 0 { - ikeLog.Trace("[SecurityAssociation] unmarshal(): Unmarshal 1 proposal") + logger.IKELog.Trace("[SecurityAssociation] unmarshal(): Unmarshal 1 proposal") // bounds checking if len(rawData) < 8 { return errors.New("Proposal: No sufficient bytes to decode next proposal") @@ -361,10 +352,10 @@ func (securityAssociation *SecurityAssociation) unmarshal(rawData []byte) error // Log whether this proposal is the last if rawData[0] == 0 { - ikeLog.Trace("[SecurityAssociation] This proposal is the last") + logger.IKELog.Trace("[SecurityAssociation] This proposal is the last") } // Log the number of transform in the proposal - ikeLog.Tracef("[SecurityAssociation] This proposal contained %d transform", rawData[7]) + logger.IKELog.Tracef("[SecurityAssociation] This proposal contained %d transform", rawData[7]) proposal := new(Proposal) var transformData []byte @@ -385,7 +376,7 @@ func (securityAssociation *SecurityAssociation) unmarshal(rawData []byte) error for len(transformData) > 0 { // bounds checking - ikeLog.Trace("[SecurityAssociation] unmarshal(): Unmarshal 1 transform") + logger.IKELog.Trace("[SecurityAssociation] unmarshal(): Unmarshal 1 transform") if len(transformData) < 8 { return errors.New("Transform: No sufficient bytes to decode next transform") } @@ -399,7 +390,7 @@ func (securityAssociation *SecurityAssociation) unmarshal(rawData []byte) error // Log whether this transform is the last if transformData[0] == 0 { - ikeLog.Trace("[SecurityAssociation] This transform is the last") + logger.IKELog.Trace("[SecurityAssociation] This transform is the last") } transform := new(Transform) @@ -460,7 +451,7 @@ type KeyExchange struct { func (keyExchange *KeyExchange) Type() IKEPayloadType { return TypeKE } func (keyExchange *KeyExchange) marshal() ([]byte, error) { - ikeLog.Info("[KeyExchange] marshal(): Start marshalling") + logger.IKELog.Info("[KeyExchange] marshal(): Start marshalling") keyExchangeData := make([]byte, 4) @@ -471,11 +462,11 @@ func (keyExchange *KeyExchange) marshal() ([]byte, error) { } func (keyExchange *KeyExchange) unmarshal(rawData []byte) error { - ikeLog.Info("[KeyExchange] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[KeyExchange] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[KeyExchange] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[KeyExchange] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[KeyExchange] unmarshal(): Unmarshal 1 key exchange data") + logger.IKELog.Trace("[KeyExchange] unmarshal(): Unmarshal 1 key exchange data") // bounds checking if len(rawData) <= 4 { return errors.New("KeyExchange: No sufficient bytes to decode next key exchange data") @@ -500,7 +491,7 @@ type IdentificationInitiator struct { func (identification *IdentificationInitiator) Type() IKEPayloadType { return TypeIDi } func (identification *IdentificationInitiator) marshal() ([]byte, error) { - ikeLog.Info("[Identification] marshal(): Start marshalling") + logger.IKELog.Info("[Identification] marshal(): Start marshalling") identificationData := make([]byte, 4) @@ -511,11 +502,11 @@ func (identification *IdentificationInitiator) marshal() ([]byte, error) { } func (identification *IdentificationInitiator) unmarshal(rawData []byte) error { - ikeLog.Info("[Identification] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Identification] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Identification] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Identification] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[Identification] unmarshal(): Unmarshal 1 identification") + logger.IKELog.Trace("[Identification] unmarshal(): Unmarshal 1 identification") // bounds checking if len(rawData) <= 4 { return errors.New("Identification: No sufficient bytes to decode next identification") @@ -540,7 +531,7 @@ type IdentificationResponder struct { func (identification *IdentificationResponder) Type() IKEPayloadType { return TypeIDr } func (identification *IdentificationResponder) marshal() ([]byte, error) { - ikeLog.Info("[Identification] marshal(): Start marshalling") + logger.IKELog.Info("[Identification] marshal(): Start marshalling") identificationData := make([]byte, 4) @@ -551,11 +542,11 @@ func (identification *IdentificationResponder) marshal() ([]byte, error) { } func (identification *IdentificationResponder) unmarshal(rawData []byte) error { - ikeLog.Info("[Identification] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Identification] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Identification] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Identification] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[Identification] unmarshal(): Unmarshal 1 identification") + logger.IKELog.Trace("[Identification] unmarshal(): Unmarshal 1 identification") // bounds checking if len(rawData) <= 4 { return errors.New("Identification: No sufficient bytes to decode next identification") @@ -580,7 +571,7 @@ type Certificate struct { func (certificate *Certificate) Type() IKEPayloadType { return TypeCERT } func (certificate *Certificate) marshal() ([]byte, error) { - ikeLog.Info("[Certificate] marshal(): Start marshalling") + logger.IKELog.Info("[Certificate] marshal(): Start marshalling") certificateData := make([]byte, 1) @@ -591,11 +582,11 @@ func (certificate *Certificate) marshal() ([]byte, error) { } func (certificate *Certificate) unmarshal(rawData []byte) error { - ikeLog.Info("[Certificate] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Certificate] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Certificate] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Certificate] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[Certificate] unmarshal(): Unmarshal 1 certificate") + logger.IKELog.Trace("[Certificate] unmarshal(): Unmarshal 1 certificate") // bounds checking if len(rawData) <= 1 { return errors.New("Certificate: No sufficient bytes to decode next certificate") @@ -620,7 +611,7 @@ type CertificateRequest struct { func (certificateRequest *CertificateRequest) Type() IKEPayloadType { return TypeCERTreq } func (certificateRequest *CertificateRequest) marshal() ([]byte, error) { - ikeLog.Info("[CertificateRequest] marshal(): Start marshalling") + logger.IKELog.Info("[CertificateRequest] marshal(): Start marshalling") certificateRequestData := make([]byte, 1) @@ -631,11 +622,11 @@ func (certificateRequest *CertificateRequest) marshal() ([]byte, error) { } func (certificateRequest *CertificateRequest) unmarshal(rawData []byte) error { - ikeLog.Info("[CertificateRequest] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[CertificateRequest] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[CertificateRequest] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[CertificateRequest] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[CertificateRequest] unmarshal(): Unmarshal 1 certificate request") + logger.IKELog.Trace("[CertificateRequest] unmarshal(): Unmarshal 1 certificate request") // bounds checking if len(rawData) <= 1 { return errors.New("CertificateRequest: No sufficient bytes to decode next certificate request") @@ -660,7 +651,7 @@ type Authentication struct { func (authentication *Authentication) Type() IKEPayloadType { return TypeAUTH } func (authentication *Authentication) marshal() ([]byte, error) { - ikeLog.Info("[Authentication] marshal(): Start marshalling") + logger.IKELog.Info("[Authentication] marshal(): Start marshalling") authenticationData := make([]byte, 4) @@ -671,11 +662,11 @@ func (authentication *Authentication) marshal() ([]byte, error) { } func (authentication *Authentication) unmarshal(rawData []byte) error { - ikeLog.Info("[Authentication] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Authentication] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Authentication] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Authentication] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[Authentication] unmarshal(): Unmarshal 1 authentication") + logger.IKELog.Trace("[Authentication] unmarshal(): Unmarshal 1 authentication") // bounds checking if len(rawData) <= 4 { return errors.New("Authentication: No sufficient bytes to decode next authentication") @@ -699,7 +690,7 @@ type Nonce struct { func (nonce *Nonce) Type() IKEPayloadType { return TypeNiNr } func (nonce *Nonce) marshal() ([]byte, error) { - ikeLog.Info("[Nonce] marshal(): Start marshalling") + logger.IKELog.Info("[Nonce] marshal(): Start marshalling") nonceData := make([]byte, 0) nonceData = append(nonceData, nonce.NonceData...) @@ -708,11 +699,11 @@ func (nonce *Nonce) marshal() ([]byte, error) { } func (nonce *Nonce) unmarshal(rawData []byte) error { - ikeLog.Info("[Nonce] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Nonce] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Nonce] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Nonce] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[Nonce] unmarshal(): Unmarshal 1 nonce") + logger.IKELog.Trace("[Nonce] unmarshal(): Unmarshal 1 nonce") nonce.NonceData = append(nonce.NonceData, rawData...) } @@ -733,7 +724,7 @@ type Notification struct { func (notification *Notification) Type() IKEPayloadType { return TypeN } func (notification *Notification) marshal() ([]byte, error) { - ikeLog.Info("[Notification] marshal(): Start marshalling") + logger.IKELog.Info("[Notification] marshal(): Start marshalling") notificationData := make([]byte, 4) @@ -748,11 +739,11 @@ func (notification *Notification) marshal() ([]byte, error) { } func (notification *Notification) unmarshal(rawData []byte) error { - ikeLog.Info("[Notification] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Notification] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Notification] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Notification] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[Notification] unmarshal(): Unmarshal 1 notification") + logger.IKELog.Trace("[Notification] unmarshal(): Unmarshal 1 notification") // bounds checking if len(rawData) < 4 { return errors.New("Notification: No sufficient bytes to decode next notification") @@ -786,7 +777,7 @@ type Delete struct { func (del *Delete) Type() IKEPayloadType { return TypeD } func (del *Delete) marshal() ([]byte, error) { - ikeLog.Info("[Delete] marshal(): Start marshalling") + logger.IKELog.Info("[Delete] marshal(): Start marshalling") if len(del.SPIs) != (int(del.SPISize) * int(del.NumberOfSPI)) { return nil, fmt.Errorf("Total bytes of all SPIs not correct") @@ -806,11 +797,11 @@ func (del *Delete) marshal() ([]byte, error) { } func (del *Delete) unmarshal(rawData []byte) error { - ikeLog.Info("[Delete] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Delete] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Delete] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Delete] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[Delete] unmarshal(): Unmarshal 1 delete") + logger.IKELog.Trace("[Delete] unmarshal(): Unmarshal 1 delete") // bounds checking if len(rawData) <= 3 { return errors.New("Delete: No sufficient bytes to decode next delete") @@ -842,16 +833,16 @@ type VendorID struct { func (vendorID *VendorID) Type() IKEPayloadType { return TypeV } func (vendorID *VendorID) marshal() ([]byte, error) { - ikeLog.Info("[VendorID] marshal(): Start marshalling") + logger.IKELog.Info("[VendorID] marshal(): Start marshalling") return vendorID.VendorIDData, nil } func (vendorID *VendorID) unmarshal(rawData []byte) error { - ikeLog.Info("[VendorID] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[VendorID] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[VendorID] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[VendorID] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[VendorID] unmarshal(): Unmarshal 1 vendor ID") + logger.IKELog.Trace("[VendorID] unmarshal(): Unmarshal 1 vendor ID") vendorID.VendorIDData = append(vendorID.VendorIDData, rawData...) } @@ -880,7 +871,7 @@ type IndividualTrafficSelector struct { func (trafficSelector *TrafficSelectorInitiator) Type() IKEPayloadType { return TypeTSi } func (trafficSelector *TrafficSelectorInitiator) marshal() ([]byte, error) { - ikeLog.Info("[TrafficSelector] marshal(): Start marshalling") + logger.IKELog.Info("[TrafficSelector] marshal(): Start marshalling") if len(trafficSelector.TrafficSelectors) > 0 { trafficSelectorData := make([]byte, 4) @@ -890,7 +881,7 @@ func (trafficSelector *TrafficSelectorInitiator) marshal() ([]byte, error) { if individualTrafficSelector.TSType == TS_IPV4_ADDR_RANGE { // Address length checking if len(individualTrafficSelector.StartAddress) != 4 { - ikeLog.Errorf("Address length %d", len(individualTrafficSelector.StartAddress)) + logger.IKELog.Errorf("Address length %d", len(individualTrafficSelector.StartAddress)) return nil, errors.New("TrafficSelector: Start IPv4 address length is not correct") } if len(individualTrafficSelector.EndAddress) != 4 { @@ -944,11 +935,11 @@ func (trafficSelector *TrafficSelectorInitiator) marshal() ([]byte, error) { } func (trafficSelector *TrafficSelectorInitiator) unmarshal(rawData []byte) error { - ikeLog.Info("[TrafficSelector] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[TrafficSelector] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[TrafficSelector] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[TrafficSelector] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[TrafficSelector] unmarshal(): Unmarshal 1 traffic selector") + logger.IKELog.Trace("[TrafficSelector] unmarshal(): Unmarshal 1 traffic selector") // bounds checking if len(rawData) < 4 { return errors.New("TrafficSelector: No sufficient bytes to get number of traffic selector in header") @@ -1029,7 +1020,7 @@ type TrafficSelectorResponder struct { func (trafficSelector *TrafficSelectorResponder) Type() IKEPayloadType { return TypeTSr } func (trafficSelector *TrafficSelectorResponder) marshal() ([]byte, error) { - ikeLog.Info("[TrafficSelector] marshal(): Start marshalling") + logger.IKELog.Info("[TrafficSelector] marshal(): Start marshalling") if len(trafficSelector.TrafficSelectors) > 0 { trafficSelectorData := make([]byte, 4) @@ -1092,11 +1083,11 @@ func (trafficSelector *TrafficSelectorResponder) marshal() ([]byte, error) { } func (trafficSelector *TrafficSelectorResponder) unmarshal(rawData []byte) error { - ikeLog.Info("[TrafficSelector] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[TrafficSelector] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[TrafficSelector] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[TrafficSelector] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[TrafficSelector] unmarshal(): Unmarshal 1 traffic selector") + logger.IKELog.Trace("[TrafficSelector] unmarshal(): Unmarshal 1 traffic selector") // bounds checking if len(rawData) < 4 { return errors.New("TrafficSelector: No sufficient bytes to get number of traffic selector in header") @@ -1178,18 +1169,18 @@ type Encrypted struct { func (encrypted *Encrypted) Type() IKEPayloadType { return TypeSK } func (encrypted *Encrypted) marshal() ([]byte, error) { - ikeLog.Info("[Encrypted] marshal(): Start marshalling") + logger.IKELog.Info("[Encrypted] marshal(): Start marshalling") if len(encrypted.EncryptedData) == 0 { - ikeLog.Warn("[Encrypted] The encrypted data is empty") + logger.IKELog.Warn("[Encrypted] The encrypted data is empty") } return encrypted.EncryptedData, nil } func (encrypted *Encrypted) unmarshal(rawData []byte) error { - ikeLog.Info("[Encrypted] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Encrypted] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Encrypted] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Encrypted] unmarshal(): Payload length %d bytes", len(rawData)) encrypted.EncryptedData = append(encrypted.EncryptedData, rawData...) return nil } @@ -1213,7 +1204,7 @@ type IndividualConfigurationAttribute struct { func (configuration *Configuration) Type() IKEPayloadType { return TypeCP } func (configuration *Configuration) marshal() ([]byte, error) { - ikeLog.Info("[Configuration] marshal(): Start marshalling") + logger.IKELog.Info("[Configuration] marshal(): Start marshalling") configurationData := make([]byte, 4) @@ -1234,11 +1225,11 @@ func (configuration *Configuration) marshal() ([]byte, error) { } func (configuration *Configuration) unmarshal(rawData []byte) error { - ikeLog.Info("[Configuration] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Configuration] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[Configuration] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[Configuration] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[Configuration] unmarshal(): Unmarshal 1 configuration") + logger.IKELog.Trace("[Configuration] unmarshal(): Unmarshal 1 configuration") // bounds checking if len(rawData) <= 4 { return errors.New("Configuration: No sufficient bytes to decode next configuration") @@ -1248,7 +1239,7 @@ func (configuration *Configuration) unmarshal(rawData []byte) error { configurationAttributeData := rawData[4:] for len(configurationAttributeData) > 0 { - ikeLog.Trace("[Configuration] unmarshal(): Unmarshal 1 configuration attribute") + logger.IKELog.Trace("[Configuration] unmarshal(): Unmarshal 1 configuration attribute") // bounds checking if len(configurationAttributeData) < 4 { return errors.New("ConfigurationAttribute: No sufficient bytes to decode next configuration attribute") @@ -1286,7 +1277,7 @@ type EAP struct { func (eap *EAP) Type() IKEPayloadType { return TypeEAP } func (eap *EAP) marshal() ([]byte, error) { - ikeLog.Info("[EAP] marshal(): Start marshalling") + logger.IKELog.Info("[EAP] marshal(): Start marshalling") eapData := make([]byte, 4) @@ -1308,11 +1299,11 @@ func (eap *EAP) marshal() ([]byte, error) { } func (eap *EAP) unmarshal(rawData []byte) error { - ikeLog.Info("[EAP] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[EAP] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[EAP] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { - ikeLog.Trace("[EAP] unmarshal(): Unmarshal 1 EAP") + logger.IKELog.Trace("[EAP] unmarshal(): Unmarshal 1 EAP") // bounds checking if len(rawData) < 4 { return errors.New("EAP: No sufficient bytes to decode next EAP payload") @@ -1382,7 +1373,7 @@ type EAPIdentity struct { func (eapIdentity *EAPIdentity) Type() EAPType { return EAPTypeIdentity } func (eapIdentity *EAPIdentity) marshal() ([]byte, error) { - ikeLog.Info("[EAP][Identity] marshal(): Start marshalling") + logger.IKELog.Info("[EAP][Identity] marshal(): Start marshalling") if len(eapIdentity.IdentityData) == 0 { return nil, errors.New("EAPIdentity: EAP identity is empty") @@ -1395,8 +1386,8 @@ func (eapIdentity *EAPIdentity) marshal() ([]byte, error) { } func (eapIdentity *EAPIdentity) unmarshal(rawData []byte) error { - ikeLog.Info("[EAP][Identity] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP][Identity] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[EAP][Identity] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[EAP][Identity] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 1 { eapIdentity.IdentityData = append(eapIdentity.IdentityData, rawData[1:]...) @@ -1416,7 +1407,7 @@ type EAPNotification struct { func (eapNotification *EAPNotification) Type() EAPType { return EAPTypeNotification } func (eapNotification *EAPNotification) marshal() ([]byte, error) { - ikeLog.Info("[EAP][Notification] marshal(): Start marshalling") + logger.IKELog.Info("[EAP][Notification] marshal(): Start marshalling") if len(eapNotification.NotificationData) == 0 { return nil, errors.New("EAPNotification: EAP notification is empty") @@ -1429,8 +1420,8 @@ func (eapNotification *EAPNotification) marshal() ([]byte, error) { } func (eapNotification *EAPNotification) unmarshal(rawData []byte) error { - ikeLog.Info("[EAP][Notification] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP][Notification] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[EAP][Notification] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[EAP][Notification] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 1 { eapNotification.NotificationData = append(eapNotification.NotificationData, rawData[1:]...) @@ -1450,7 +1441,7 @@ type EAPNak struct { func (eapNak *EAPNak) Type() EAPType { return EAPTypeNak } func (eapNak *EAPNak) marshal() ([]byte, error) { - ikeLog.Info("[EAP][Nak] marshal(): Start marshalling") + logger.IKELog.Info("[EAP][Nak] marshal(): Start marshalling") if len(eapNak.NakData) == 0 { return nil, errors.New("EAPNak: EAP nak is empty") @@ -1463,8 +1454,8 @@ func (eapNak *EAPNak) marshal() ([]byte, error) { } func (eapNak *EAPNak) unmarshal(rawData []byte) error { - ikeLog.Info("[EAP][Nak] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP][Nak] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[EAP][Nak] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[EAP][Nak] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 1 { eapNak.NakData = append(eapNak.NakData, rawData[1:]...) @@ -1486,7 +1477,7 @@ type EAPExpanded struct { func (eapExpanded *EAPExpanded) Type() EAPType { return EAPTypeExpanded } func (eapExpanded *EAPExpanded) marshal() ([]byte, error) { - ikeLog.Info("[EAP][Expanded] marshal(): Start marshalling") + logger.IKELog.Info("[EAP][Expanded] marshal(): Start marshalling") eapExpandedData := make([]byte, 8) @@ -1497,7 +1488,7 @@ func (eapExpanded *EAPExpanded) marshal() ([]byte, error) { binary.BigEndian.PutUint32(eapExpandedData[4:8], eapExpanded.VendorType) if len(eapExpanded.VendorData) == 0 { - ikeLog.Warn("[EAP][Expanded] marshal(): EAP vendor data field is empty") + logger.IKELog.Warn("[EAP][Expanded] marshal(): EAP vendor data field is empty") return eapExpandedData, nil } @@ -1507,8 +1498,8 @@ func (eapExpanded *EAPExpanded) marshal() ([]byte, error) { } func (eapExpanded *EAPExpanded) unmarshal(rawData []byte) error { - ikeLog.Info("[EAP][Expanded] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP][Expanded] unmarshal(): Payload length %d bytes", len(rawData)) + logger.IKELog.Info("[EAP][Expanded] unmarshal(): Start unmarshalling received bytes") + logger.IKELog.Tracef("[EAP][Expanded] unmarshal(): Payload length %d bytes", len(rawData)) if len(rawData) > 0 { if len(rawData) < 8 { diff --git a/pkg/ike/message/message_test.go b/pkg/ike/message/message_test.go index b0a8d8b..ad0526f 100644 --- a/pkg/ike/message/message_test.go +++ b/pkg/ike/message/message_test.go @@ -13,16 +13,6 @@ import ( "testing" ) -var conn net.Conn - -func init() { - if connTmp, err := net.Dial("udp", "127.0.0.1:500"); err != nil { - panic(err) - } else { - conn = connTmp - } -} - // TestEncodeDecode tests the Encode() and Decode() function using the data // build manually. // First, build each payload with correct value, then the IKE message for @@ -32,6 +22,10 @@ func init() { // Third, send the encoded data to the UDP connection for verification with Wireshark. // Compare the dataFirstEncode and dataSecondEncode and return the result. func TestEncodeDecode(t *testing.T) { + conn, err := net.Dial("udp", "127.0.0.1:500") + if err != nil { + t.Fatalf("udp Dial failed: %+v", err) + } testPacket := &IKEMessage{} // random an SPI @@ -329,7 +323,8 @@ func TestEncodeDecode(t *testing.T) { // ciphertext cipherText := make([]byte, aes.BlockSize+len(ikePayloadDataForSK)) iv := cipherText[:aes.BlockSize] - if _, err := io.ReadFull(Crand.Reader, iv); err != nil { + _, err = io.ReadFull(Crand.Reader, iv) + if err != nil { t.Fatalf("IO ReadFull failed: %+v", err) } @@ -342,7 +337,6 @@ func TestEncodeDecode(t *testing.T) { testPacket.Payloads = append(testPacket.Payloads, testSK) var dataFirstEncode, dataSecondEncode []byte - var err error decodedPacket := new(IKEMessage) if dataFirstEncode, err = testPacket.Encode(); err != nil { diff --git a/pkg/ike/service/service.go b/pkg/ike/service/service.go index 7105f6c..dc7eeaa 100644 --- a/pkg/ike/service/service.go +++ b/pkg/ike/service/service.go @@ -4,86 +4,147 @@ import ( "errors" "net" "runtime/debug" - - "github.com/sirupsen/logrus" + "sync" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/ike" + "github.com/free5gc/n3iwf/pkg/ike/handler" ) -var ikeLog *logrus.Entry +var ( + RECEIVE_IKEPACKET_CHANNEL_LEN = 512 + RECEIVE_IKEEVENT_CHANNEL_LEN = 512 +) -func init() { - // init logger - ikeLog = logger.IKELog -} +func Run(wg *sync.WaitGroup) error { + n3iwfSelf := context.N3IWFSelf() -func Run() error { // Resolve UDP addresses - ip := context.N3IWFSelf().IKEBindAddress + ip := n3iwfSelf.IKEBindAddress udpAddrPort500, err := net.ResolveUDPAddr("udp", ip+":500") if err != nil { - ikeLog.Errorf("Resolve UDP address failed: %+v", err) + logger.IKELog.Errorf("Resolve UDP address failed: %+v", err) return errors.New("IKE service run failed") } udpAddrPort4500, err := net.ResolveUDPAddr("udp", ip+":4500") if err != nil { - ikeLog.Errorf("Resolve UDP address failed: %+v", err) + logger.IKELog.Errorf("Resolve UDP address failed: %+v", err) return errors.New("IKE service run failed") } + n3iwfSelf.IKEServer = NewIKEServer() + // Listen and serve var errChan chan error // Port 500 + wg.Add(1) errChan = make(chan error) - go listenAndServe(udpAddrPort500, errChan) + go Receiver(udpAddrPort500, n3iwfSelf.IKEServer, errChan, wg) if err, ok := <-errChan; ok { - ikeLog.Errorln(err) + logger.IKELog.Errorln(err) return errors.New("IKE service run failed") } // Port 4500 + wg.Add(1) errChan = make(chan error) - go listenAndServe(udpAddrPort4500, errChan) + go Receiver(udpAddrPort4500, n3iwfSelf.IKEServer, errChan, wg) if err, ok := <-errChan; ok { - ikeLog.Errorln(err) + logger.IKELog.Errorln(err) return errors.New("IKE service run failed") } + wg.Add(1) + go server(n3iwfSelf.IKEServer, wg) + return nil } -func listenAndServe(localAddr *net.UDPAddr, errChan chan<- error) { +func NewIKEServer() *context.IkeServer { + return &context.IkeServer{ + Listener: make(map[int]*net.UDPConn), + RcvIkePktCh: make(chan context.IkeReceivePacket, RECEIVE_IKEPACKET_CHANNEL_LEN), + RcvEventCh: make(chan context.IkeEvt, RECEIVE_IKEEVENT_CHANNEL_LEN), + StopServer: make(chan struct{}), + } +} + +func server(ikeServer *context.IkeServer, wg *sync.WaitGroup) { defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. logger.IKELog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } + logger.IKELog.Infof("Ike server stopped") + close(ikeServer.RcvIkePktCh) + close(ikeServer.StopServer) + wg.Done() + }() + + for { + select { + case rcvPkt := <-ikeServer.RcvIkePktCh: + logger.IKELog.Tracef("Receive IKE packet") + ike.IkeDispatch(&rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr, rcvPkt.Msg) + case rcvIkeEvent := <-ikeServer.RcvEventCh: + handler.HandleEvent(rcvIkeEvent) + case <-ikeServer.StopServer: + return + } + } +} + +func Receiver(localAddr *net.UDPAddr, ikeServer *context.IkeServer, errChan chan<- error, wg *sync.WaitGroup) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.IKELog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + logger.IKELog.Infof("Ike receiver stopped") + wg.Done() }() listener, err := net.ListenUDP("udp", localAddr) if err != nil { - ikeLog.Errorf("Listen UDP failed: %+v", err) + logger.IKELog.Errorf("Listen UDP failed: %+v", err) errChan <- errors.New("listenAndServe failed") return } close(errChan) + ikeServer.Listener[localAddr.Port] = listener + data := make([]byte, 65535) for { n, remoteAddr, err := listener.ReadFromUDP(data) if err != nil { - ikeLog.Errorf("ReadFromUDP failed: %+v", err) - continue + logger.IKELog.Errorf("ReadFromUDP failed: %+v", err) + return } forwardData := make([]byte, n) copy(forwardData, data[:n]) + ikeServer.RcvIkePktCh <- context.IkeReceivePacket{ + RemoteAddr: *remoteAddr, + Listener: *listener, + LocalAddr: *localAddr, + Msg: forwardData, + } + } +} - go ike.Dispatch(listener, localAddr, remoteAddr, forwardData) +func Stop(n3iwfContext *context.N3IWFContext) { + logger.IKELog.Infof("Close Ike server...") + + for _, ikeServerListener := range n3iwfContext.IKEServer.Listener { + if err := ikeServerListener.Close(); err != nil { + logger.IKELog.Errorf("Stop ike server : %s error : %+v", err, ikeServerListener.LocalAddr().String()) + } } + + n3iwfContext.IKEServer.StopServer <- struct{}{} } diff --git a/pkg/ike/xfrm/xfrm.go b/pkg/ike/xfrm/xfrm.go index 5800ec8..a596d21 100644 --- a/pkg/ike/xfrm/xfrm.go +++ b/pkg/ike/xfrm/xfrm.go @@ -5,7 +5,6 @@ import ( "fmt" "net" - "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" "github.com/free5gc/n3iwf/internal/logger" @@ -13,13 +12,6 @@ import ( "github.com/free5gc/n3iwf/pkg/ike/message" ) -// Log -var ikeLog *logrus.Entry - -func init() { - ikeLog = logger.IKELog -} - type XFRMEncryptionAlgorithmType uint16 func (xfrmEncryptionAlgorithmType XFRMEncryptionAlgorithmType) String() string { @@ -113,7 +105,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, // Commit xfrm state to netlink var err error if err = netlink.XfrmStateAdd(xfrmState); err != nil { - ikeLog.Errorf("Set XFRM rules failed: %+v", err) + logger.IKELog.Errorf("Set XFRM rules failed: %+v", err) return errors.New("Set XFRM state rule failed") } @@ -141,7 +133,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, // Commit xfrm policy to netlink if err = netlink.XfrmPolicyAdd(xfrmPolicy); err != nil { - ikeLog.Errorf("Set XFRM rules failed: %+v", err) + logger.IKELog.Errorf("Set XFRM rules failed: %+v", err) return errors.New("Set XFRM policy rule failed") } @@ -169,7 +161,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, // Commit xfrm state to netlink if err = netlink.XfrmStateAdd(xfrmState); err != nil { - ikeLog.Errorf("Set XFRM rules failed: %+v", err) + logger.IKELog.Errorf("Set XFRM rules failed: %+v", err) return errors.New("Set XFRM state rule failed") } @@ -187,7 +179,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, // Commit xfrm policy to netlink if err = netlink.XfrmPolicyAdd(xfrmPolicy); err != nil { - ikeLog.Errorf("Set XFRM rules failed: %+v", err) + logger.IKELog.Errorf("Set XFRM rules failed: %+v", err) return errors.New("Set XFRM policy rule failed") } @@ -212,26 +204,26 @@ func printSAInfo(n3iwf_is_initiator bool, xfrmiId uint32, childSecurityAssociati OutboundEncryptionKey = childSecurityAssociation.ResponderToInitiatorEncryptionKey OutboundIntegrityKey = childSecurityAssociation.ResponderToInitiatorIntegrityKey } - ikeLog.Debug("====== IPSec/Child SA Info ======") + logger.IKELog.Debug("====== IPSec/Child SA Info ======") // ====== Inbound ====== - ikeLog.Debugf("XFRM interface if_id: %d", xfrmiId) - ikeLog.Debugf("IPSec Inbound SPI: 0x%016x", childSecurityAssociation.InboundSPI) - ikeLog.Debugf("[UE:%+v] -> [N3IWF:%+v]", + logger.IKELog.Debugf("XFRM interface if_id: %d", xfrmiId) + logger.IKELog.Debugf("IPSec Inbound SPI: 0x%016x", childSecurityAssociation.InboundSPI) + logger.IKELog.Debugf("[UE:%+v] -> [N3IWF:%+v]", childSecurityAssociation.PeerPublicIPAddr, childSecurityAssociation.LocalPublicIPAddr) - ikeLog.Debugf("IPSec Encryption Algorithm: %d", childSecurityAssociation.EncryptionAlgorithm) - ikeLog.Debugf("IPSec Encryption Key: 0x%x", InboundEncryptionKey) - ikeLog.Debugf("IPSec Integrity Algorithm: %d", childSecurityAssociation.IntegrityAlgorithm) - ikeLog.Debugf("IPSec Integrity Key: 0x%x", InboundIntegrityKey) - ikeLog.Debug("====== IPSec/Child SA Info ======") + logger.IKELog.Debugf("IPSec Encryption Algorithm: %d", childSecurityAssociation.EncryptionAlgorithm) + logger.IKELog.Debugf("IPSec Encryption Key: 0x%x", InboundEncryptionKey) + logger.IKELog.Debugf("IPSec Integrity Algorithm: %d", childSecurityAssociation.IntegrityAlgorithm) + logger.IKELog.Debugf("IPSec Integrity Key: 0x%x", InboundIntegrityKey) + logger.IKELog.Debug("====== IPSec/Child SA Info ======") // ====== Outbound ====== - ikeLog.Debugf("XFRM interface if_id: %d", xfrmiId) - ikeLog.Debugf("IPSec Outbound SPI: 0x%016x", childSecurityAssociation.OutboundSPI) - ikeLog.Debugf("[N3IWF:%+v] -> [UE:%+v]", + logger.IKELog.Debugf("XFRM interface if_id: %d", xfrmiId) + logger.IKELog.Debugf("IPSec Outbound SPI: 0x%016x", childSecurityAssociation.OutboundSPI) + logger.IKELog.Debugf("[N3IWF:%+v] -> [UE:%+v]", childSecurityAssociation.LocalPublicIPAddr, childSecurityAssociation.PeerPublicIPAddr) - ikeLog.Debugf("IPSec Encryption Algorithm: %d", childSecurityAssociation.EncryptionAlgorithm) - ikeLog.Debugf("IPSec Encryption Key: 0x%x", OutboundEncryptionKey) - ikeLog.Debugf("IPSec Integrity Algorithm: %d", childSecurityAssociation.IntegrityAlgorithm) - ikeLog.Debugf("IPSec Integrity Key: 0x%x", OutboundIntegrityKey) + logger.IKELog.Debugf("IPSec Encryption Algorithm: %d", childSecurityAssociation.EncryptionAlgorithm) + logger.IKELog.Debugf("IPSec Encryption Key: 0x%x", OutboundEncryptionKey) + logger.IKELog.Debugf("IPSec Integrity Algorithm: %d", childSecurityAssociation.IntegrityAlgorithm) + logger.IKELog.Debugf("IPSec Integrity Key: 0x%x", OutboundIntegrityKey) } func SetupIPsecXfrmi(xfrmIfaceName, parentIfaceName string, xfrmIfaceId uint32, @@ -263,7 +255,7 @@ func SetupIPsecXfrmi(xfrmIfaceName, parentIfaceName string, xfrmIfaceId uint32, return nil, err } - ikeLog.Debugf("XFRM interface %s index is %d", xfrmIfaceName, xfrmi.Attrs().Index) + logger.IKELog.Debugf("XFRM interface %s index is %d", xfrmIfaceName, xfrmi.Attrs().Index) // ip addr add xfrmIfaceAddr dev linkIPSecAddr := &netlink.Addr{ diff --git a/pkg/service/init.go b/pkg/service/init.go index 1d89f6d..8106c13 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -1,235 +1,170 @@ package service import ( - "bufio" + "context" "fmt" + "io/ioutil" "net" "os" - "os/exec" "os/signal" "runtime/debug" - "sync" "syscall" "time" "github.com/sirupsen/logrus" - "github.com/urfave/cli" "github.com/vishvananda/netlink" - aperLogger "github.com/free5gc/aper/logger" "github.com/free5gc/n3iwf/internal/logger" ngap_service "github.com/free5gc/n3iwf/internal/ngap/service" nwucp_service "github.com/free5gc/n3iwf/internal/nwucp/service" nwuup_service "github.com/free5gc/n3iwf/internal/nwuup/service" - "github.com/free5gc/n3iwf/internal/util" - "github.com/free5gc/n3iwf/pkg/context" + n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" ike_service "github.com/free5gc/n3iwf/pkg/ike/service" "github.com/free5gc/n3iwf/pkg/ike/xfrm" - ngapLogger "github.com/free5gc/ngap/logger" ) -type N3IWF struct{} - -type ( - // Commands information. - Commands struct { - config string - } -) - -var commands Commands - -var cliCmd = []cli.Flag{ - cli.StringFlag{ - Name: "config, c", - Usage: "Load configuration from `FILE`", - }, - cli.StringFlag{ - Name: "log, l", - Usage: "Output NF log to `FILE`", - }, - cli.StringFlag{ - Name: "log5gc, lc", - Usage: "Output free5gc log to `FILE`", - }, +type N3iwfApp struct { + cfg *factory.Config + n3iwfCtx *n3iwf_context.N3IWFContext } -func (*N3IWF) GetCliCmd() (flags []cli.Flag) { - return cliCmd +func NewApp(cfg *factory.Config) (*N3iwfApp, error) { + n3iwf := &N3iwfApp{cfg: cfg} + n3iwf.SetLogEnable(cfg.GetLogEnable()) + n3iwf.SetLogLevel(cfg.GetLogLevel()) + n3iwf.SetReportCaller(cfg.GetLogReportCaller()) + + // n3iwf_context.Init() + n3iwf.n3iwfCtx = n3iwf_context.N3IWFSelf() + return n3iwf, nil } -func (n3iwf *N3IWF) Initialize(c *cli.Context) error { - commands = Commands{ - config: c.String("config"), +func (a *N3iwfApp) SetLogEnable(enable bool) { + logger.MainLog.Infof("Log enable is set to [%v]", enable) + if enable && logger.Log.Out == os.Stderr { + return + } else if !enable && logger.Log.Out == ioutil.Discard { + return } - if commands.config != "" { - if err := factory.InitConfigFactory(commands.config); err != nil { - return err - } + a.cfg.SetLogEnable(enable) + if enable { + logger.Log.SetOutput(os.Stderr) } else { - if err := factory.InitConfigFactory(util.N3iwfDefaultConfigPath); err != nil { - return err - } + logger.Log.SetOutput(ioutil.Discard) } - - n3iwf.SetLogLevel() - - if err := factory.CheckConfigVersion(); err != nil { - return err - } - - if _, err := factory.N3iwfConfig.Validate(); err != nil { - return err - } - - return nil } -func (n3iwf *N3IWF) SetLogLevel() { - if factory.N3iwfConfig.Logger == nil { - logger.InitLog.Warnln("N3IWF config without log level setting!!!") +func (a *N3iwfApp) SetLogLevel(level string) { + lvl, err := logrus.ParseLevel(level) + if err != nil { + logger.MainLog.Warnf("Log level [%s] is invalid", level) return } - if factory.N3iwfConfig.Logger.N3IWF != nil { - if factory.N3iwfConfig.Logger.N3IWF.DebugLevel != "" { - if level, err := logrus.ParseLevel(factory.N3iwfConfig.Logger.N3IWF.DebugLevel); err != nil { - logger.InitLog.Warnf("N3IWF Log level [%s] is invalid, set to [info] level", - factory.N3iwfConfig.Logger.N3IWF.DebugLevel) - logger.SetLogLevel(logrus.InfoLevel) - } else { - logger.InitLog.Infof("N3IWF Log level is set to [%s] level", level) - logger.SetLogLevel(level) - } - } else { - logger.InitLog.Infoln("N3IWF Log level is default set to [info] level") - logger.SetLogLevel(logrus.InfoLevel) - } - logger.SetReportCaller(factory.N3iwfConfig.Logger.N3IWF.ReportCaller) - } - - if factory.N3iwfConfig.Logger.NGAP != nil { - if factory.N3iwfConfig.Logger.NGAP.DebugLevel != "" { - if level, err := logrus.ParseLevel(factory.N3iwfConfig.Logger.NGAP.DebugLevel); err != nil { - ngapLogger.NgapLog.Warnf("NGAP Log level [%s] is invalid, set to [info] level", - factory.N3iwfConfig.Logger.NGAP.DebugLevel) - ngapLogger.SetLogLevel(logrus.InfoLevel) - } else { - ngapLogger.SetLogLevel(level) - } - } else { - ngapLogger.NgapLog.Warnln("NGAP Log level not set. Default set to [info] level") - ngapLogger.SetLogLevel(logrus.InfoLevel) - } - ngapLogger.SetReportCaller(factory.N3iwfConfig.Logger.NGAP.ReportCaller) + logger.MainLog.Infof("Log level is set to [%s]", level) + if lvl == logger.Log.GetLevel() { + return } - if factory.N3iwfConfig.Logger.Aper != nil { - if factory.N3iwfConfig.Logger.Aper.DebugLevel != "" { - if level, err := logrus.ParseLevel(factory.N3iwfConfig.Logger.Aper.DebugLevel); err != nil { - aperLogger.AperLog.Warnf("Aper Log level [%s] is invalid, set to [info] level", - factory.N3iwfConfig.Logger.Aper.DebugLevel) - aperLogger.SetLogLevel(logrus.InfoLevel) - } else { - aperLogger.SetLogLevel(level) - } - } else { - aperLogger.AperLog.Warnln("Aper Log level not set. Default set to [info] level") - aperLogger.SetLogLevel(logrus.InfoLevel) - } - aperLogger.SetReportCaller(factory.N3iwfConfig.Logger.Aper.ReportCaller) - } + a.cfg.SetLogLevel(level) + logger.Log.SetLevel(lvl) } -func (n3iwf *N3IWF) FilterCli(c *cli.Context) (args []string) { - for _, flag := range n3iwf.GetCliCmd() { - name := flag.GetName() - value := fmt.Sprint(c.Generic(name)) - if value == "" { - continue - } - - args = append(args, "--"+name, value) +func (a *N3iwfApp) SetReportCaller(reportCaller bool) { + logger.MainLog.Infof("Report Caller is set to [%v]", reportCaller) + if reportCaller == logger.Log.ReportCaller { + return } - return args + + a.cfg.SetLogReportCaller(reportCaller) + logger.Log.SetReportCaller(reportCaller) } -func (n3iwf *N3IWF) Start() { +func (a *N3iwfApp) Start(tlsKeyLogPath string) { logger.InitLog.Infoln("Server started") - if !util.InitN3IWFContext() { + var cancel context.CancelFunc + n3iwfContext := n3iwf_context.N3IWFSelf() + n3iwfContext.Ctx, cancel = context.WithCancel(context.Background()) + defer cancel() + + if !n3iwf_context.InitN3IWFContext() { logger.InitLog.Error("Initicating context failed") return } - if err := n3iwf.InitDefaultXfrmInterface(); err != nil { + if err := a.InitDefaultXfrmInterface(n3iwfContext); err != nil { logger.InitLog.Errorf("Initicating XFRM interface for control plane failed: %+v", err) return } + n3iwfContext.Wg.Add(1) // Graceful Shutdown - signalChannel := make(chan os.Signal, 1) - signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) - go func() { - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) - } - }() - - <-signalChannel - n3iwf.Terminate() - // Waiting for negotiatioon with netlink for deleting interfaces - time.Sleep(2 * time.Second) - os.Exit(0) - }() - - wg := sync.WaitGroup{} + go a.ListenShutdownEvent(n3iwfContext) // NGAP - if err := ngap_service.Run(); err != nil { + if err := ngap_service.Run(&n3iwfContext.Wg); err != nil { logger.InitLog.Errorf("Start NGAP service failed: %+v", err) return } logger.InitLog.Info("NGAP service running.") - wg.Add(1) // Relay listeners // Control plane - if err := nwucp_service.Run(); err != nil { + if err := nwucp_service.Run(&n3iwfContext.Wg); err != nil { logger.InitLog.Errorf("Listen NWu control plane traffic failed: %+v", err) return } logger.InitLog.Info("NAS TCP server successfully started.") - wg.Add(1) // User plane - if err := nwuup_service.Run(); err != nil { + if err := nwuup_service.Run(&n3iwfContext.Wg); err != nil { logger.InitLog.Errorf("Listen NWu user plane traffic failed: %+v", err) return } logger.InitLog.Info("Listening NWu user plane traffic") - wg.Add(1) // IKE - if err := ike_service.Run(); err != nil { + if err := ike_service.Run(&n3iwfContext.Wg); err != nil { logger.InitLog.Errorf("Start IKE service failed: %+v", err) return } logger.InitLog.Info("IKE service running.") - wg.Add(1) logger.InitLog.Info("N3IWF running...") - wg.Wait() + signalChannel := make(chan os.Signal, 1) + signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) + <-signalChannel + + cancel() + a.WaitRoutineStopped(n3iwfContext) } -func (n3iwf *N3IWF) InitDefaultXfrmInterface() error { - n3iwfContext := context.N3IWFSelf() +func (a *N3iwfApp) ListenShutdownEvent(n3iwfContext *n3iwf_context.N3IWFContext) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + n3iwfContext.Wg.Done() + }() + + <-n3iwfContext.Ctx.Done() + StopServiceConn(n3iwfContext) +} +func (a *N3iwfApp) WaitRoutineStopped(n3iwfContext *n3iwf_context.N3IWFContext) { + n3iwfContext.Wg.Wait() + // Waiting for negotiatioon with netlink for deleting interfaces + a.Terminate(n3iwfContext) + time.Sleep(2 * time.Second) + os.Exit(0) +} + +func (a *N3iwfApp) InitDefaultXfrmInterface(n3iwfContext *n3iwf_context.N3IWFContext) error { // Setup default IPsec interface for Control Plane var linkIPSec netlink.Link var err error @@ -260,9 +195,8 @@ func (n3iwf *N3IWF) InitDefaultXfrmInterface() error { return nil } -func (n3iwf *N3IWF) RemoveIPsecInterfaces() { - n3iwfSelf := context.N3IWFSelf() - n3iwfSelf.XfrmIfaces.Range( +func (a *N3iwfApp) RemoveIPsecInterfaces(n3iwfContext *n3iwf_context.N3IWFContext) { + n3iwfContext.XfrmIfaces.Range( func(key, value interface{}) bool { iface := value.(netlink.Link) if err := netlink.LinkDel(iface); err != nil { @@ -274,77 +208,21 @@ func (n3iwf *N3IWF) RemoveIPsecInterfaces() { }) } -func (n3iwf *N3IWF) Terminate() { +func (a *N3iwfApp) Terminate(n3iwfContext *n3iwf_context.N3IWFContext) { logger.InitLog.Info("Terminating N3IWF...") logger.InitLog.Info("Deleting interfaces created by N3IWF") - n3iwf.RemoveIPsecInterfaces() + a.RemoveIPsecInterfaces(n3iwfContext) logger.InitLog.Info("N3IWF terminated") } -func (n3iwf *N3IWF) Exec(c *cli.Context) error { - // N3IWF.Initialize(cfgPath, c) +func StopServiceConn(n3iwfContext *n3iwf_context.N3IWFContext) { + logger.InitLog.Info("Stopping service created by N3IWF") - logger.InitLog.Traceln("args:", c.String("n3iwfcfg")) - args := n3iwf.FilterCli(c) - logger.InitLog.Traceln("filter: ", args) - command := exec.Command("./n3iwf", args...) + ngap_service.Stop(n3iwfContext) - wg := sync.WaitGroup{} - wg.Add(3) - - stdout, err := command.StdoutPipe() - if err != nil { - logger.InitLog.Fatalln(err) - } - go func() { - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) - } - }() - - in := bufio.NewScanner(stdout) - for in.Scan() { - fmt.Println(in.Text()) - } - wg.Done() - }() - - stderr, err := command.StderrPipe() - if err != nil { - logger.InitLog.Fatalln(err) - } - go func() { - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) - } - }() - - in := bufio.NewScanner(stderr) - for in.Scan() { - fmt.Println(in.Text()) - } - wg.Done() - }() - - go func() { - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) - } - }() - - if errCom := command.Start(); errCom != nil { - logger.InitLog.Errorf("N3IWF start error: %v", errCom) - } - wg.Done() - }() + nwucp_service.Stop(n3iwfContext) - wg.Wait() + nwuup_service.Stop(n3iwfContext) - return err + ike_service.Stop(n3iwfContext) }