diff --git a/.golangci.yml b/.golangci.yml index 95b8615e..02663f30 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,35 +1,24 @@ -# This file contains all available configuration options -# with their default values. + # options for analysis running run: - # default concurrency is a available CPU number + # Number of operating system threads (`GOMAXPROCS`) that can execute golangci-lint simultaneously. + # If it is explicitly set to 0 (i.e. not the default) then golangci-lint will automatically set the value to match Linux container CPU quota. + # Default: the number of logical CPUs in the machine concurrency: 4 + # timeout for analysis, e.g. 30s, 5m, default is 1m timeout: 3m + # exit code when at least one issue was found, default is 1 issues-exit-code: 1 + # include test files or not, default is true tests: true + # list of build tags, all linters use it. Default is empty list. - build-tags: - # which dirs to skip: issues from them won't be reported; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but default dirs are skipped independently - # from this option's value (see skip-dirs-use-default). - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-dirs: - # default is true. Enables skipping of directories: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs-use-default: true - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-files: - # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + build-tags: [] + + # If set, we pass it to "go list -mod={option}". From "go help modules": # If invoked with -mod=readonly, the go command is disallowed from the implicit # automatic updating of go.mod described above. Instead, it fails when any changes # to go.mod are needed. This setting is most useful to check that go.mod does @@ -37,20 +26,46 @@ run: # If invoked with -mod=vendor, the go command assumes that the vendor # directory holds the correct copies of dependencies and ignores # the dependency descriptions in go.mod. - #modules-download-mode: readonly|release|vendor + # + # Allowed values: readonly|vendor|mod + # Default: "" + # modules-download-mode: readonly + # Allow multiple parallel golangci-lint instances running. - # If false (default) - golangci-lint acquires file lock on start. + # If false, golangci-lint acquires file lock on start. + # Default: false allow-parallel-runners: true + + # Allow multiple golangci-lint instances running, but serialize them around a lock. + # If false, golangci-lint exits with an error if it fails to acquire file lock on start. + # Default: false + allow-serial-runners: true + + go: '1.21' + # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - formats: colored-line-number + formats: + - format: "colored-line-number" + path: stdout + # print lines of code with issue, default is true print-issued-lines: true # print linter name in the end of issue text, default is true print-linter-name: true # make issues output unique by line, default is true uniq-by-line: true + + # Sort results by the order defined in `sort-order`. + # Default: false + sort-results: true + sort-order: + - linter + - severity + - file # filepath, line, and column. + show-stats: true + # all available settings of specific linters linters-settings: errcheck: @@ -67,26 +82,22 @@ linters-settings: # path to a file containing a list of functions to exclude from checking # see https://github.com/kisielk/errcheck#excluding-functions for details #exclude: /path/to/file.txt - funlen: - lines: 60 - statements: 40 - gocognit: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 - nestif: - # minimal complexity of if statements to report, 5 by default - min-complexity: 4 + goconst: # minimal length of string constant, 3 by default - min-len: 3 - # minimal occurrences count to trigger, 3 by default + min-len: 5 + # Minimum occurrences of constant string count to trigger issue, 3 by default min-occurrences: 3 + # Exclude strings matching the given regular expression. + # Default: "" + ignore-strings: "get|post|put|delete|patch|options|head" + gocritic: # Which checks should be enabled; can't be combined with 'disabled-checks'; # See https://go-critic.github.io/overview#checks-overview # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` # By default list of stable checks is used. - enabled-checks: + enabled-checks: [] #- rangeValCopy # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty disabled-checks: @@ -94,17 +105,31 @@ linters-settings: # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". enabled-tags: + - diagnostic - performance disabled-tags: - experimental - settings: # settings passed to gocritic + + # settings passed to gocritic + # The settings key is the name of a supported gocritic checker. + # The list of supported checkers can be find in https://go-critic.github.io/overview. + settings: captLocal: # must be valid enabled check name + # Whether to restrict checker to params only. paramsOnly: true rangeValCopy: - sizeThreshold: 32 - gocyclo: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 + # Size in bytes that makes the warning trigger. Default: 128 + # This size shoulb be smaller + sizeThreshold: 512 + hugeParam: + # Size in bytes that makes the warning trigger. Default: 80 + # This size shoulb be smaller + sizeThreshold: 512 + ifElseChain: + # Min number of if-else blocks that makes the warning trigger. + # Default: 2 + minThreshold: 4 + godox: # report any comments starting with keywords, this is useful for TODO or FIXME comments that # might be left in the code accidentally and should be resolved before merging @@ -116,166 +141,183 @@ linters-settings: #- OPTIMIZE # marks code that should be optimized before merging #- HACK # marks hack-arounds that should be removed before merging - XXX # Fatal! Important problem + gofmt: # simplify code: gofmt with `-s` option, true by default simplify: true - goimports: - # put imports beginning with prefix after 3rd-party packages; - # it's a comma-separated list of prefixes - local-prefixes: github.com/org/project - golint: - # minimal confidence for issues, default is 0.8 - min-confidence: 0.8 - gomnd: - settings: - mnd: - # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. - checks: argument,case,condition,operation,return,assign - gomodguard: - allowed: - modules: # List of allowed modules - # - gopkg.in/yaml.v2 - domains: # List of allowed module domains - # - golang.org - blocked: - modules: # List of blocked modules - # - github.com/uudashr/go-module: # Blocked module - # recommendations: # Recommended modules that should be used instead (Optional) - # - golang.org/x/mod - # reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional) - versions: # List of blocked module version constraints - # - github.com/mitchellh/go-homedir: # Blocked module with version constraint - # version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons - # reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional) + govet: - # report about shadowed variables - check-shadowing: true + enable-all: false + # enable or disable analyzers by name + enable: + - atomicalign + - shadow + - printf + # settings per analyzer settings: - printf: # analyzer name, run `go tool vet help` to see all analyzers + # analyzer name, run `go tool vet help` to see all analyzers + printf: funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - # enable or disable analyzers by name - enable: - - atomicalign - - shadow - enable-all: false - disable-all: false + shadow: + # Whether to be strict about shadowing; can be noisy. + # Default: false + strict: true + depguard: - list-type: blacklist - include-go-root: false - packages: - - github.com/sirupsen/logrus - packages-with-error-message: - # specify an error message to output when a blacklisted package is used - - github.com/sirupsen/logrus: "logging is allowed only by logutils.Log" + rules: + # Name of a rule. + main: + # Used to determine the package matching priority. + # There are three different modes: `original`, `strict`, and `lax`. + # Default: "original" + list-mode: original + deny: + - pkg: github.com/sirupsen/logrus + desc: "logging is allowed only by logutils.Log" + lll: # max line length, lines longer will be reported. Default is 120. # '\t' is counted as 1 character by default, and can be changed with the tab-width option line-length: 120 # tab width in spaces. Default to 1. tab-width: 1 - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true + nakedret: # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 max-func-lines: 30 + testpackage: # regexp pattern to skip files skip-regexp: (export|internal)_test\.go + unused: - # treat code as a program (not a library) and report unused exported identifiers; default is false. - # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find funcs usages. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false + # Mark all struct fields that have been written to as used. + # Default: true + field-writes-are-uses: true + # Treat IncDec statement (e.g. `i++` or `i--`) as both read and write operation instead of just write. + # Default: false + post-statements-are-reads: true + # Mark all exported identifiers as used. + # Default: true + exported-is-used: true + # Mark all exported fields as used. + # default: true + exported-fields-are-used: true + # Mark all function parameters as used. + # default: true + parameters-are-used: true + # Mark all local variables as used. + # default: true + local-variables-are-used: true + # Mark all identifiers inside generated files as used. + # Default: true + generated-is-used: true + whitespace: multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature + gci: sections: - standard - default - prefix(github.com/free5gc) - section-separators: - - newLine + + # Skip generated files. + # Default: true + skip-generated: true + + # Enable custom order of sections. + # If `true`, make the section order the same as the order of `sections`. + # Default: false + custom-order: true + misspell: - #locale: US - ignore-words: - wsl: - # If true append is only allowed to be cuddled if appending value is - # matching variables, fields or types on line above. Default is true. - strict-append: true - # Allow calls and assignments to be cuddled as long as the lines have any - # matching variables, fields or types. Default is true. - allow-assign-and-call: true - # Allow multiline assignments to be cuddled. Default is true. - allow-multiline-assign: true - # Allow declarations (var) to be cuddled. - allow-cuddle-declarations: false - # Allow trailing comments in ending of blocks - allow-trailing-comment: true - # Force newlines in end of case at this limit (0 = never). - force-case-trailing-whitespace: 0 - # Force cuddling of err checks with err var assignment - force-err-cuddling: false - # Allow leading comments to be separated with empty liens - allow-separated-leading-comment: false - custom: + locale: US + ignore-words: [] + + gomnd: + # !important in golangci-lint v1.58.0, gomnd is replaced by mnd + # List of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. + # Default: ["argument", "case", "condition", "operation", "return", "assign"] + checks: + # - argument + - case + # - condition + - operation + - return + # - assign + # List of numbers to exclude from analysis. + # The numbers should be written as string. + # Values always ignored: "1", "1.0", "0" and "0.0" + # Default: [] + ignored-numbers: [] + # List of file patterns to exclude from analysis. + # Values always ignored: `.+_test.go` + # Default: [] + ignored-files: [] + # List of function patterns to exclude from analysis. + # Following functions are always ignored: `time.Date`, + # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, + # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. + # Default: [] + ignored-functions: + - 'os\.Mkdir' + - 'os\.MkdirAll' + - '^math\.' + - '^http\.StatusText$' + + # custom: # Each custom linter should have a unique name. linters: + disable-all: true enable: + - errcheck + - goconst + - gocritic + - godox - gofmt - govet - - errcheck + - lll + - nakedret + # - testpackage - staticcheck - unused + - whitespace + - gci + - misspell - gosimple - - structcheck - - varcheck + # - gomnd - ineffassign - - deadcode - typecheck - # Additional - - lll - - godox - # - gomnd - # - goconst - # - gocognit - # - maligned - # - nestif - # - gomodguard - - nakedret - # - golint - - gci - - misspell - gofumpt - - whitespace - unconvert - predeclared - noctx - dogsled - bodyclose - asciicheck - # - stylecheck - # - unparam - # - wsl + # - dupl - #disable-all: false + # Enable only fast linters from enabled linters set (first run won't be fast) + # Default: false fast: true + + issues: # List of regexps of issue texts to exclude, empty list by default. # But independently from this option we use default exclude patterns, # it can be disabled by `exclude-use-default: false`. To list all # excluded by default patterns execute `golangci-lint run --help` - exclude: + exclude: [] # Excluding configuration per-path, per-linter, per-text and per-source - exclude-rules: + exclude-rules: [] # Exclude some linters from running on tests files. # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all @@ -286,7 +328,7 @@ issues: # regular expressions become case sensitive. exclude-case-sensitive: false # The list of ids of default excludes to include or disable. By default it's empty. - include: + include: [] #- EXC0002 # disable excluding of issues about comments from golint # Maximum issues count per one linter. Set to 0 to disable. Default is 50. #max-issues-per-linter: 0 @@ -303,25 +345,37 @@ issues: new-from-rev: "" # Show only new issues created in git patch with set file path. #new-from-patch: path/to/patch/file + severity: - # Default value is empty string. - # Set the default severity for issues. If severity rules are defined and the issues - # do not match or no severity is provided to the rule this will be the default - # severity applied. Severities should match the supported severity names of the - # selected out format. + # Set the default severity for issues. + # + # If severity rules are defined and the issues do not match or no severity is provided to the rule + # this will be the default severity applied. + # Severities should match the supported severity names of the selected out format. # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity - # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity - # - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#SeverityLevel + # - GitHub: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + # - TeamCity: https://www.jetbrains.com/help/teamcity/service-messages.html#Inspection+Instance + # + # `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...) + # + # Default: "" default-severity: error + # The default value is false. # If set to true severity-rules regular expressions become case sensitive. case-sensitive: false - # Default value is empty list. - # When a list of severity rules are provided, severity information will be added to lint - # issues. Severity rules have the same filtering capability as exclude rules except you - # are allowed to specify one matcher per severity rule. + + # When a list of severity rules are provided, severity information will be added to lint issues. + # Severity rules have the same filtering capability as exclude rules + # except you are allowed to specify one matcher per severity rule. + # + # `@linter` can be used as severity value to keep the severity from linters (e.g. revive, gosec, ...) + # # Only affects out formats that support setting severity information. + # + # Default: [] rules: - linters: - gomnd - severity: ignore + severity: info \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index f4137688..bdf68e88 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,9 +1,12 @@ package main import ( + "context" "os" + "os/signal" "path/filepath" "runtime/debug" + "syscall" "github.com/urfave/cli" @@ -52,19 +55,28 @@ func action(cliCtx *cli.Context) error { logger.MainLog.Infoln("AMF version: ", version.GetVersion()) + ctx, cancel := context.WithCancel(context.Background()) + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) + + go func() { + <-sigCh // Wait for interrupt signal to gracefully shutdown + cancel() // Notify each goroutine and wait them stopped + }() + cfg, err := factory.ReadConfig(cliCtx.String("config")) if err != nil { return err } factory.AmfConfig = cfg - amf, err := service.NewApp(cfg) + amf, err := service.NewApp(ctx, cfg, tlsKeyLogPath) if err != nil { return err } AMF = amf - amf.Start(tlsKeyLogPath) + amf.Start() return nil } diff --git a/go.mod b/go.mod index 386c7b4f..65e6a074 100644 --- a/go.mod +++ b/go.mod @@ -4,66 +4,68 @@ go 1.21 require ( github.com/antihax/optional v1.0.0 - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/davecgh/go-spew v1.1.1 github.com/free5gc/aper v1.0.5 github.com/free5gc/nas v1.1.3 github.com/free5gc/ngap v1.0.9-0.20240414165820-453b0aa37228 github.com/free5gc/openapi v1.0.8 - github.com/free5gc/sctp v1.0.0 + github.com/free5gc/sctp v1.0.1 github.com/free5gc/util v1.0.6 - github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.9.1 - github.com/google/uuid v1.3.0 - github.com/mitchellh/mapstructure v1.4.2 + github.com/google/uuid v1.6.0 + github.com/mitchellh/mapstructure v1.5.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/pkg/errors v0.9.1 - github.com/sirupsen/logrus v1.8.1 - github.com/smartystreets/goconvey v1.6.4 - github.com/stretchr/testify v1.8.3 - github.com/urfave/cli v1.22.5 + github.com/sirupsen/logrus v1.9.3 + github.com/smartystreets/goconvey v1.8.1 + github.com/stretchr/testify v1.9.0 + github.com/urfave/cli v1.22.14 + go.uber.org/mock v0.4.0 gopkg.in/yaml.v2 v2.4.0 ) require ( github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 // indirect github.com/antonfisher/nested-logrus-formatter v1.3.1 // indirect - github.com/bytedance/sonic v1.9.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/bytedance/sonic v1.11.5 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.3 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.19.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang-jwt/jwt v3.2.1+incompatible // indirect - github.com/golang/protobuf v1.5.0 // indirect - github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/leodido/go-urn v1.2.4 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.2.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/russross/blackfriday/v2 v2.0.1 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect + github.com/rogpeppe/go-internal v1.8.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/smarty/assertions v1.15.1 // indirect github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 // indirect - golang.org/x/sys v0.18.0 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.7.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/oauth2 v0.19.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/h2non/gock.v1 v1.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 15d1b4a0..b2112231 100644 --- a/go.sum +++ b/go.sum @@ -1,67 +1,28 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 h1:+JkXLHME8vLJafGhOH4aoV2Iu8bR55nU6iKMVfYVLjY= github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/bytedance/sonic v1.11.5 h1:G00FYjjqll5iQ1PYXynbg/hyzqBqavH8Mo9/oTopd9k= +github.com/bytedance/sonic v1.11.5/go.mod h1:X2PC2giUdj/Cv2lliWFLk6c/DUQok5rViJSemeB0wDw= +github.com/bytedance/sonic/loader v0.1.0/go.mod h1:UmRT+IRTGKz/DAkzcEGzyVqQFJ7H9BqwBO3pm9H/+HY= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.3 h1:b5J/l8xolB7dyDTTmhJP2oTs5LdrjyrUFuNxdfq5hAg= +github.com/cloudwego/base64x v0.1.3/go.mod h1:1+1K5BUHIQzyapgpF7LwvOGAEDicKtt1umPV+aN8pi8= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/free5gc/aper v1.0.5 h1:sUYFFmOXDLjyL4rU6zFnq81M4YluqP90Pso5e/J4UhA= github.com/free5gc/aper v1.0.5/go.mod h1:ybHxhYnRqQ9wD4yB9r/3MZdbCYCjtqUyfLpSnJpwWd4= github.com/free5gc/nas v1.1.3 h1:eYkvT8GGieD06MExw3JLeIPA88Yg89DFjptVBnadIyQ= @@ -70,447 +31,137 @@ github.com/free5gc/ngap v1.0.9-0.20240414165820-453b0aa37228 h1:47Wa0ZdDI1r+IXbU github.com/free5gc/ngap v1.0.9-0.20240414165820-453b0aa37228/go.mod h1:d5u7tYsBwxmLr3zw7wyBruRjc/gbdsHVhmdGFnVmfBU= github.com/free5gc/openapi v1.0.8 h1:QjfQdB6VVA1GRnzOJ7nILzrI7gMiY0lH64JHVW7vF34= github.com/free5gc/openapi v1.0.8/go.mod h1:w6y9P/uySczc1d9OJZAEuB2FImR/z60Wg2BekPAVt3M= -github.com/free5gc/sctp v1.0.0 h1:V868MT9yyF2I8uotLCEjLULmhTzrLKxPBvsqFk82xGI= -github.com/free5gc/sctp v1.0.0/go.mod h1:3wEzH3L0tljQCLaqEqEalLdW2290B8D5Aw4orsKHxUs= +github.com/free5gc/sctp v1.0.1 h1:g8WDO97r8B9ubkT5Hyk9b4I1fZUOii9Z39gQ2eRaASo= +github.com/free5gc/sctp v1.0.1/go.mod h1:7QXfRWCmlkBGD0EIu3qL5o71bslfIakydz4h2QDZdjQ= github.com/free5gc/util v1.0.6 h1:dBt9drcXtYKE/cY5XuQcuffgsYclPIpIArhSeS6M+DQ= github.com/free5gc/util v1.0.6/go.mod h1:eSGN7POUM8LNTvg/E591XR6447a6/w1jFWGKNZPHcXw= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA= -github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= 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.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -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= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= +github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= -github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/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= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg= +github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smarty/assertions v1.15.1 h1:812oFiXI+G55vxsFf+8bIZ1ux30qtkdqzKbEFwyX3Tk= +github.com/smarty/assertions v1.15.1/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= +github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= +github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= -github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= +github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -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.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -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= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 h1:Ati8dO7+U7mxpkPSxBZQEvzHVUYB/MqCklCN8ig5w/o= -golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= +golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -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= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -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= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/context/amf_ran.go b/internal/context/amf_ran.go index 9fb3905a..51197ed4 100644 --- a/internal/context/amf_ran.go +++ b/internal/context/amf_ran.go @@ -57,7 +57,7 @@ func (ran *AmfRan) NewRanUe(ranUeNgapID int64) (*RanUe, error) { self := GetSelf() amfUeNgapID, err := self.AllocateAmfUeNgapID() if err != nil { - return nil, fmt.Errorf("Allocate AMF UE NGAP ID error: %+v", err) + return nil, fmt.Errorf("allocate AMF UE NGAP ID error: %+v", err) } ranUe.AmfUeNgapId = amfUeNgapID ranUe.RanUeNgapId = ranUeNgapID diff --git a/internal/context/amf_ue.go b/internal/context/amf_ue.go index 52615fd5..b0ef7df8 100644 --- a/internal/context/amf_ue.go +++ b/internal/context/amf_ue.go @@ -571,7 +571,7 @@ func (ue *AmfUe) UpdateNH() { ue.NCC++ // TS33.501 6.2.3.2 Key identification // The next hop chaining count, NCC, represents the 3 least significant bits of this counter. - ue.NCC = ue.NCC & 0x7 + ue.NCC &= 0x7 ue.DerivateNH(ue.NH) } diff --git a/internal/context/context.go b/internal/context/context.go index 6e66350c..c22ed2a9 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -572,11 +572,6 @@ func (c *AMFContext) AuthorizationCheck(token string, serviceName models.Service logger.UtilLog.Debugf("AMFContext::AuthorizationCheck: OAuth2 not required\n") return nil } - // TODO: free5gc webconsole uses namf-oam but it can't get token since it's not an NF. - if serviceName == models.ServiceName_NAMF_OAM { - logger.UtilLog.Warnf("OAuth2 is enable but namf-oam didn't check token now.") - return nil - } logger.UtilLog.Debugf("AMFContext::AuthorizationCheck: token[%s] serviceName[%s]\n", token, serviceName) return oauth.VerifyOAuth(token, string(serviceName), c.NrfCertPem) diff --git a/internal/gmm/common/user_profile.go b/internal/gmm/common/user_profile.go index 5a9caa1b..48e1b209 100644 --- a/internal/gmm/common/user_profile.go +++ b/internal/gmm/common/user_profile.go @@ -15,7 +15,7 @@ func RemoveAmfUe(ue *context.AmfUe, notifyNF bool) { ue.SmContextList.Range(func(key, value interface{}) bool { smContext := value.(*context.SmContext) - problemDetail, err := consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) + problemDetail, err := consumer.GetConsumer().SendReleaseSmContextRequest(ue, smContext, nil, "", nil) if problemDetail != nil { ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetail) } else if err != nil { @@ -26,7 +26,7 @@ func RemoveAmfUe(ue *context.AmfUe, notifyNF bool) { // notify PCF to terminate AmPolicy association if ue.AmPolicyAssociation != nil { - problemDetails, err := consumer.AMPolicyControlDelete(ue) + problemDetails, err := consumer.GetConsumer().AMPolicyControlDelete(ue) if problemDetails != nil { ue.GmmLog.Errorf("AM Policy Control Delete Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -77,7 +77,7 @@ func PurgeSubscriberData(ue *context.AmfUe, accessType models.AccessType) error } // Purge of subscriber data in AMF described in TS 23.502 4.5.3 if ue.SdmSubscriptionId != "" { - problemDetails, err := consumer.SDMUnsubscribe(ue) + problemDetails, err := consumer.GetConsumer().SDMUnsubscribe(ue) if problemDetails != nil { logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -87,7 +87,7 @@ func PurgeSubscriberData(ue *context.AmfUe, accessType models.AccessType) error } if ue.UeCmRegistered[accessType] { - problemDetails, err := consumer.UeCmDeregistration(ue, accessType) + problemDetails, err := consumer.GetConsumer().UeCmDeregistration(ue, accessType) if problemDetails != nil { logger.GmmLog.Errorf("UECM Deregistration Failed Problem[%+v]", problemDetails) } else if err != nil { diff --git a/internal/gmm/handler.go b/internal/gmm/handler.go index c9e0665b..ed93dff3 100644 --- a/internal/gmm/handler.go +++ b/internal/gmm/handler.go @@ -22,7 +22,7 @@ import ( "github.com/free5gc/amf/internal/logger" ngap_message "github.com/free5gc/amf/internal/ngap/message" "github.com/free5gc/amf/internal/sbi/consumer" - "github.com/free5gc/amf/internal/sbi/producer/callback" + callback "github.com/free5gc/amf/internal/sbi/processor/notifier" "github.com/free5gc/amf/internal/util" "github.com/free5gc/amf/pkg/factory" "github.com/free5gc/nas" @@ -69,7 +69,7 @@ func HandleULNASTransport(ue *context.AmfUe, anType models.AccessType, if err != nil { return err } - err = consumer.PutUpuAck(ue, upuMac) + err = consumer.GetConsumer().PutUpuAck(ue, upuMac) if err != nil { return err } @@ -133,7 +133,7 @@ func transport5GSMMessage(ue *context.AmfUe, anType models.AccessType, } ue.GmmLog.Warningf("Duplicated PDU session ID[%d]", pduSessionID) smContext.SetDuplicatedPduSessionID(true) - response, _, _, err := consumer.SendUpdateSmContextRequest(smContext, updateData, nil, nil) + response, _, _, err := consumer.GetConsumer().SendUpdateSmContextRequest(smContext, updateData, nil, nil) if err != nil { ue.GmmLog.Errorf("Failed to update smContext, local release SmContext[%d]", pduSessionID) ue.SmContextList.Delete(pduSessionID) @@ -146,8 +146,7 @@ func transport5GSMMessage(ue *context.AmfUe, anType models.AccessType, responseData := response.JsonData n2Info := response.BinaryDataN2SmInformation if n2Info != nil { - switch responseData.N2SmInfoType { - case models.N2SmInfoType_PDU_RES_REL_CMD: + if responseData.N2SmInfoType == models.N2SmInfoType_PDU_RES_REL_CMD { ue.GmmLog.Debugln("AMF Transfer NGAP PDU Session Resource Release Command from SMF") list := ngapType.PDUSessionResourceToReleaseListRelCmd{} ngap_message.AppendPDUSessionResourceToReleaseListRelCmd(&list, pduSessionID, n2Info) @@ -260,22 +259,23 @@ func CreatePDUSession(ulNasTransport *nasMessage.ULNASTransport, } } - if newSmContext, cause, err := consumer.SelectSmf(ue, anType, pduSessionID, snssai, dnn); err != nil { - ue.GmmLog.Errorf("Select SMF failed: %+v", err) + if newSmContext, cause, errSelectSmf := consumer.GetConsumer().SelectSmf( + ue, anType, pduSessionID, snssai, dnn); errSelectSmf != nil { + ue.GmmLog.Errorf("Select SMF failed: %+v", errSelectSmf) gmm_message.SendDLNASTransport(ue.RanUe[anType], nasMessage.PayloadContainerTypeN1SMInfo, smMessage, pduSessionID, cause, nil, 0) } else { ue.Lock.Lock() defer ue.Lock.Unlock() - _, smContextRef, errResponse, problemDetail, err := consumer.SendCreateSmContextRequest( + _, smContextRef, errResponse, problemDetail, errSendReq := consumer.GetConsumer().SendCreateSmContextRequest( ue, newSmContext, nil, smMessage) - if err != nil { - ue.GmmLog.Errorf("CreateSmContextRequest Error: %+v", err) + if errSendReq != nil { + ue.GmmLog.Errorf("CreateSmContextRequest Error: %+v", errSendReq) return false, nil } else if problemDetail != nil { // TODO: error handling - return false, fmt.Errorf("Failed to Create smContext[pduSessionID: %d], Error[%v]", pduSessionID, problemDetail) + return false, fmt.Errorf("failed to Create smContext[pduSessionID: %d], Error[%v]", pduSessionID, problemDetail) } else if errResponse != nil { ue.GmmLog.Warnf("PDU Session Establishment Request is rejected by SMF[pduSessionId:%d]", pduSessionID) @@ -315,7 +315,7 @@ func forward5GSMMessageToSMF( smContextUpdateData.AnType = accessType } - response, errResponse, problemDetail, err := consumer.SendUpdateSmContextRequest(smContext, + response, errResponse, problemDetail, err := consumer.GetConsumer().SendUpdateSmContextRequest(smContext, smContextUpdateData, smMessage, nil) if err != nil { @@ -414,8 +414,8 @@ func HandleRegistrationRequest(ue *context.AmfUe, anType models.AccessType, proc ue.SecurityContextAvailable = false } else { m := nas.NewMessage() - if err := m.GmmMessageDecode(&contents); err != nil { - return err + if errGmmMessageDecode := m.GmmMessageDecode(&contents); errGmmMessageDecode != nil { + return errGmmMessageDecode } messageType := m.GmmMessage.GmmHeader.GetMessageType() @@ -547,13 +547,11 @@ func HandleRegistrationRequest(ue *context.AmfUe, anType models.AccessType, proc if registrationRequest.UESecurityCapability != nil { ue.UESecurityCapability = *registrationRequest.UESecurityCapability - } else { + } else if registrationRequest.GetRegistrationType5GS() != nasMessage.RegistrationType5GSPeriodicRegistrationUpdating { // TS 23.501 8.2.6.4 // The UE shall include this IE, unless the UE performs a periodic registration updating procedure. - if registrationRequest.GetRegistrationType5GS() != nasMessage.RegistrationType5GSPeriodicRegistrationUpdating { - gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "") - return fmt.Errorf("UESecurityCapability is nil") - } + gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "") + return fmt.Errorf("UESecurityCapability is nil") } // TODO (TS 23.502 4.2.2.2 step 4): if UE's 5g-GUTI is included & serving AMF has changed @@ -577,7 +575,7 @@ func contextTransferFromOldAmf(ue *context.AmfUe, anType models.AccessType, oldA searchOpt := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ Guami: optional.NewInterface(openapi.MarshToJsonString(oldAmfGuami)), } - if err := consumer.SearchAmfCommunicationInstance(ue, amfSelf.NrfUri, models.NfType_AMF, + if err := consumer.GetConsumer().SearchAmfCommunicationInstance(ue, amfSelf.NrfUri, models.NfType_AMF, models.NfType_AMF, &searchOpt); err != nil { return err } @@ -591,15 +589,16 @@ func contextTransferFromOldAmf(ue *context.AmfUe, anType models.AccessType, oldA case nasMessage.RegistrationType5GSPeriodicRegistrationUpdating: transferReason = models.TransferReason_MOBI_REG } - ueContextTransferRspData, problemDetails, err := consumer.UEContextTransferRequest(ue, anType, transferReason) - if problemDetails != nil { - if problemDetails.Cause == "INTEGRITY_CHECK_FAIL" || problemDetails.Cause == "CONTEXT_NOT_FOUND" { + + ueContextTransferRspData, pd, err := consumer.GetConsumer().UEContextTransferRequest(ue, anType, transferReason) + if pd != nil { + if pd.Cause == "INTEGRITY_CHECK_FAIL" || pd.Cause == "CONTEXT_NOT_FOUND" { // TODO 9a. After successful authentication in new AMF, which is triggered by the integrity check failure // in old AMF at step 5, the new AMF invokes step 4 above again and indicates that the UE is validated - //(i.e. through the reason parameter as specified in clause 5.2.2.2.2). - return fmt.Errorf("Can not retrieve UE Context from old AMF[Cause: %s]", problemDetails.Cause) + // (i.e. through the reason parameter as specified in clause 5.2.2.2.2). + return fmt.Errorf("Can not retrieve UE Context from old AMF[Cause: %s]", pd.Cause) } - return fmt.Errorf("UE Context Transfer Request Failed Problem[%+v]", problemDetails) + return fmt.Errorf("UE Context Transfer Request Failed Problem[%+v]", pd) } else if err != nil { return fmt.Errorf("UE Context Transfer Request Error[%+v]", err) } else { @@ -659,15 +658,13 @@ func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) erro TransferStatus: models.UeContextTransferStatus_TRANSFERRED, } // TODO: based on locol policy, decide if need to change serving PCF for UE - regStatusTransferComplete, problemDetails, err := consumer.RegistrationStatusUpdate(ue, req) + regStatusTransferComplete, problemDetails, err := consumer.GetConsumer().RegistrationStatusUpdate(ue, req) if problemDetails != nil { ue.GmmLog.Errorf("Registration Status Update Failed Problem[%+v]", problemDetails) } else if err != nil { ue.GmmLog.Errorf("Registration Status Update Error[%+v]", err) - } else { - if regStatusTransferComplete { - ue.GmmLog.Infof("Registration Status Transfer complete") - } + } else if regStatusTransferComplete { + ue.GmmLog.Infof("Registration Status Transfer complete") } } @@ -701,7 +698,8 @@ func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) erro // } for { - resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, ¶m) + resp, err := consumer.GetConsumer().SendSearchNFInstances( + amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, ¶m) if err != nil { ue.GmmLog.Error("AMF can not select an PCF by NRF") } else { @@ -724,7 +722,7 @@ func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) erro time.Sleep(500 * time.Millisecond) // sleep a while when search NF Instance fail } - problemDetails, err := consumer.AMPolicyControlCreate(ue, anType) + problemDetails, err := consumer.GetConsumer().AMPolicyControlCreate(ue, anType) if problemDetails != nil { ue.GmmLog.Errorf("AM Policy Control Create Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -795,11 +793,9 @@ func HandleMobilityAndPeriodicRegistrationUpdating(ue *context.AmfUe, anType mod if ue.RegistrationRequest.Capability5GMM != nil { ue.Capability5GMM = *ue.RegistrationRequest.Capability5GMM - } else { - if ue.RegistrationType5GS != nasMessage.RegistrationType5GSPeriodicRegistrationUpdating { - gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "") - return fmt.Errorf("Capability5GMM is nil") - } + } else if ue.RegistrationType5GS != nasMessage.RegistrationType5GSPeriodicRegistrationUpdating { + gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "") + return fmt.Errorf("Capability5GMM is nil") } storeLastVisitedRegisteredTAI(ue, ue.RegistrationRequest.LastVisitedRegisteredTAI) @@ -884,7 +880,7 @@ func HandleMobilityAndPeriodicRegistrationUpdating(ue *context.AmfUe, anType mod n2Info := ue.N1N2Message.Request.BinaryDataN2Information if n2Info == nil { - // SMF has indicated pending downlink signalling only, + // SMF has indicated pending downlink signaling only, // forward the received 5GSM message via 3GPP access to the UE // after the REGISTRATION ACCEPT message is sent gmm_message.SendRegistrationAccept(ue, anType, pduSessionStatus, @@ -925,7 +921,7 @@ func HandleMobilityAndPeriodicRegistrationUpdating(ue *context.AmfUe, anType mod updateReq := models.PolicyAssociationUpdateRequest{} updateReq.Triggers = append(updateReq.Triggers, models.RequestTrigger_LOC_CH) updateReq.UserLoc = &ue.Location - problemDetails, err := consumer.AMPolicyControlUpdate(ue, updateReq) + problemDetails, err := consumer.GetConsumer().AMPolicyControlUpdate(ue, updateReq) if problemDetails != nil { ue.GmmLog.Errorf("AM Policy Control Update Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -1006,7 +1002,8 @@ func communicateWithUDM(ue *context.AmfUe, accessType models.AccessType) error { param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{ Supi: optional.NewString(ue.Supi), } - resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, ¶m) + resp, err := consumer.GetConsumer().SendSearchNFInstances( + amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, ¶m) if err != nil { return errors.Errorf("AMF can not select an UDM by NRF: SendSearchNFInstances failed") } @@ -1026,7 +1023,7 @@ func communicateWithUDM(ue *context.AmfUe, accessType models.AccessType) error { return errors.Errorf("AMF can not select an UDM by NRF: SearchNFServiceUri failed") } - problemDetails, err := consumer.UeCmRegistration(ue, accessType, true) + problemDetails, err := consumer.GetConsumer().UeCmRegistration(ue, accessType, true) if problemDetails != nil { return errors.Errorf(problemDetails.Cause) } else if err != nil { @@ -1036,28 +1033,28 @@ func communicateWithUDM(ue *context.AmfUe, accessType models.AccessType) error { // TS 23.502 4.2.2.2.1 14a-c. // "After a successful response is received, the AMF subscribes to be notified // using Nudm_SDM_Subscribe when the data requested is modified" - problemDetails, err = consumer.SDMGetAmData(ue) + problemDetails, err = consumer.GetConsumer().SDMGetAmData(ue) if problemDetails != nil { return errors.Errorf(problemDetails.Cause) } else if err != nil { return errors.Wrap(err, "SDM_Get AmData Error") } - problemDetails, err = consumer.SDMGetSmfSelectData(ue) + problemDetails, err = consumer.GetConsumer().SDMGetSmfSelectData(ue) if problemDetails != nil { return errors.Errorf(problemDetails.Cause) } else if err != nil { return errors.Wrap(err, "SDM_Get SmfSelectData Error") } - problemDetails, err = consumer.SDMGetUeContextInSmfData(ue) + problemDetails, err = consumer.GetConsumer().SDMGetUeContextInSmfData(ue) if problemDetails != nil { return errors.Errorf(problemDetails.Cause) } else if err != nil { return errors.Wrap(err, "SDM_Get UeContextInSmfData Error") } - problemDetails, err = consumer.SDMSubscribe(ue) + problemDetails, err = consumer.GetConsumer().SDMSubscribe(ue) if problemDetails != nil { return errors.Errorf(problemDetails.Cause) } else if err != nil { @@ -1074,7 +1071,8 @@ func getSubscribedNssai(ue *context.AmfUe) { Supi: optional.NewString(ue.Supi), } for { - err := consumer.SearchUdmSdmInstance(ue, amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, ¶m) + err := consumer.GetConsumer().SearchUdmSdmInstance( + ue, amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, ¶m) if err != nil { ue.GmmLog.Errorf("AMF can not select an Nudm_SDM Instance by NRF[Error: %+v]", err) time.Sleep(2 * time.Second) @@ -1083,7 +1081,7 @@ func getSubscribedNssai(ue *context.AmfUe) { } } } - problemDetails, err := consumer.SDMGetSliceSelectionSubscriptionData(ue) + problemDetails, err := consumer.GetConsumer().SDMGetSliceSelectionSubscriptionData(ue) if problemDetails != nil { ue.GmmLog.Errorf("SDM_Get Slice Selection Subscription Data Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -1137,9 +1135,10 @@ func handleRequestedNssai(ue *context.AmfUe, anType models.AccessType) error { if needSliceSelection { if ue.NssfUri == "" { for { - err := consumer.SearchNssfNSSelectionInstance(ue, amfSelf.NrfUri, models.NfType_NSSF, models.NfType_AMF, nil) - if err != nil { - ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", err) + errSearchNssf := consumer.GetConsumer().SearchNssfNSSelectionInstance( + ue, amfSelf.NrfUri, models.NfType_NSSF, models.NfType_AMF, nil) + if errSearchNssf != nil { + ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", errSearchNssf) time.Sleep(2 * time.Second) } else { break @@ -1148,22 +1147,22 @@ func handleRequestedNssai(ue *context.AmfUe, anType models.AccessType) error { } // Step 4 - problemDetails, err := consumer.NSSelectionGetForRegistration(ue, requestedNssai) + problemDetails, errNssfGetReg := consumer.GetConsumer().NSSelectionGetForRegistration(ue, requestedNssai) if problemDetails != nil { ue.GmmLog.Errorf("NSSelection Get Failed Problem[%+v]", problemDetails) gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "") - return fmt.Errorf("Handle Requested Nssai of UE failed") - } else if err != nil { - ue.GmmLog.Errorf("NSSelection Get Error[%+v]", err) + return fmt.Errorf("handle Requested Nssai of UE failed") + } else if errNssfGetReg != nil { + ue.GmmLog.Errorf("NSSelection Get Error[%+v]", errNssfGetReg) gmm_message.SendRegistrationReject(ue.RanUe[anType], nasMessage.Cause5GMMProtocolErrorUnspecified, "") - return fmt.Errorf("Handle Requested Nssai of UE failed") + return fmt.Errorf("handle Requested Nssai of UE failed") } // Step 5: Initial AMF send Namf_Communication_RegistrationCompleteNotify to old AMF req := models.UeRegStatusUpdateReqData{ TransferStatus: models.UeContextTransferStatus_NOT_TRANSFERRED, } - _, problemDetails, err = consumer.RegistrationStatusUpdate(ue, req) + _, problemDetails, err = consumer.GetConsumer().RegistrationStatusUpdate(ue, req) if problemDetails != nil { ue.GmmLog.Errorf("Registration Status Update Failed Problem[%+v]", problemDetails) } else if err != nil { @@ -1201,12 +1200,12 @@ func handleRequestedNssai(ue *context.AmfUe, anType models.AccessType) error { } sendReroute := true - err = consumer.SearchAmfCommunicationInstance(ue, amfSelf.NrfUri, + err = consumer.GetConsumer().SearchAmfCommunicationInstance(ue, amfSelf.NrfUri, models.NfType_AMF, models.NfType_AMF, &searchTargetAmfQueryParam) if err == nil { // Condition (A) Step 7: initial AMF find Target AMF via NRF -> // Send Namf_Communication_N1MessageNotify to Target AMF - ueContext := consumer.BuildUeContextModel(ue) + ueContext := consumer.GetConsumer().BuildUeContextModel(ue) registerContext := models.RegistrationContextContainer{ UeContext: &ueContext, AnType: anType, @@ -1344,7 +1343,7 @@ func reactivatePendingULDataPDUSession(ue *context.AmfUe, anType models.AccessTy // TODO: determine the UE presence in LADN service area and forward the UE presence // in LADN service area towards the SMF, if the corresponding PDU session is // a PDU session for LADN - response, errRsp, problemDetail, err := consumer.SendUpdateSmContextActivateUpCnxState( + response, errRsp, problemDetail, err := consumer.GetConsumer().SendUpdateSmContextActivateUpCnxState( ue, smContext, anType) if err != nil { reactivationResult[pduSessionID] = true @@ -1402,7 +1401,7 @@ func releaseInactivePDUSession(ue *context.AmfUe, anType models.AccessType, uePd Cause: &cause, } ue.GmmLog.Infof("Release Inactive PDU Session[%d] over %q", pduSessionID, smContext.AccessType()) - problemDetail, err := consumer.SendReleaseSmContextRequest(ue, smContext, causeAll, "", nil) + problemDetail, err := consumer.GetConsumer().SendReleaseSmContextRequest(ue, smContext, causeAll, "", nil) if problemDetail != nil { ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetail) } else if err != nil { @@ -1438,7 +1437,7 @@ func reestablishAllowedPDUSessionOver3GPP(ue *context.AmfUe, anType models.Acces // notify the SMF if the corresponding PDU session ID(s) associated with non-3GPP access // are indicated in the Allowed PDU session status IE // TODO: error handling - response, errRes, _, err := consumer.SendUpdateSmContextChangeAccessType(ue, smContext, true) + response, errRes, _, err := consumer.GetConsumer().SendUpdateSmContextChangeAccessType(ue, smContext, true) if err != nil { reactivationResult[requestData.PduSessionId] = true ue.GmmLog.Errorf("SendUpdateSmContextActivateUpCnxState[pduSessionID:%d] Error: %+v", @@ -1595,7 +1594,7 @@ func HandleNotificationResponse(ue *context.AmfUe, notificationResponse *nasMess causeAll := &context.CauseAll{ Cause: &cause, } - problemDetail, err := consumer.SendReleaseSmContextRequest(ue, smContext, causeAll, "", nil) + problemDetail, err := consumer.GetConsumer().SendReleaseSmContextRequest(ue, smContext, causeAll, "", nil) if problemDetail != nil { ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetail) } else if err != nil { @@ -1646,7 +1645,8 @@ func AuthenticationProcedure(ue *context.AmfUe, accessType models.AccessType) (b // TODO: consider ausf group id, Routing ID part of SUCI param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{} - resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_AUSF, models.NfType_AMF, ¶m) + resp, err := consumer.GetConsumer().SendSearchNFInstances( + amfSelf.NrfUri, models.NfType_AUSF, models.NfType_AMF, ¶m) if err != nil { ue.GmmLog.Error("AMF can not select an AUSF by NRF") gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "") @@ -1670,7 +1670,7 @@ func AuthenticationProcedure(ue *context.AmfUe, accessType models.AccessType) (b } ue.AusfUri = ausfUri - response, problemDetails, err := consumer.SendUEAuthenticationAuthenticateRequest(ue, nil) + response, problemDetails, err := consumer.GetConsumer().SendUEAuthenticationAuthenticateRequest(ue, nil) if err != nil { ue.GmmLog.Errorf("Nausf_UEAU Authenticate Request Error: %+v", err) gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "") @@ -1752,8 +1752,8 @@ func HandleServiceRequest(ue *context.AmfUe, anType models.AccessType, ue.SecurityContextAvailable = false } else { m := nas.NewMessage() - if err := m.GmmMessageDecode(&contents); err != nil { - return err + if errGmmMessageDecode := m.GmmMessageDecode(&contents); errGmmMessageDecode != nil { + return errGmmMessageDecode } messageType := m.GmmMessage.GmmHeader.GetMessageType() @@ -1824,7 +1824,7 @@ func HandleServiceRequest(ue *context.AmfUe, anType models.AccessType, switch serviceType { case nasMessage.ServiceTypeMobileTerminatedServices: // Trigger by Network if ue.N1N2Message != nil { - // downlink signalling only + // downlink signaling only if n2Info == nil { err := gmm_message.SendServiceAccept(ue, anType, cxtList, pduStatusResult, reactivationResult, errPduSessionId, errCause) @@ -1962,7 +1962,9 @@ func HandleAuthenticationResponse(ue *context.AmfUe, accessType models.AccessTyp return err } p1 := resStar[:] - concat := append(p0, p1...) + concat := []byte{} + concat = append(concat, p0...) + concat = append(concat, p1...) hResStarBytes := sha256.Sum256(concat) hResStar := hex.EncodeToString(hResStarBytes[16:]) @@ -1982,7 +1984,8 @@ func HandleAuthenticationResponse(ue *context.AmfUe, accessType models.AccessTyp } } - response, problemDetails, err := consumer.SendAuth5gAkaConfirmRequest(ue, hex.EncodeToString(resStar[:])) + response, problemDetails, err := consumer.GetConsumer().SendAuth5gAkaConfirmRequest( + ue, hex.EncodeToString(resStar[:])) if err != nil { return err } else if problemDetails != nil { @@ -2016,11 +2019,11 @@ func HandleAuthenticationResponse(ue *context.AmfUe, accessType models.AccessTyp } } case models.AuthType_EAP_AKA_PRIME: - response, problemDetails, err := consumer.SendEapAuthConfirmRequest(ue, *authenticationResponse.EAPMessage) + response, pd, err := consumer.GetConsumer().SendEapAuthConfirmRequest(ue, *authenticationResponse.EAPMessage) if err != nil { return err - } else if problemDetails != nil { - ue.GmmLog.Debugf("EapAuthConfirm Error[Problem Detail: %+v]", problemDetails) + } else if pd != nil { + ue.GmmLog.Debugf("EapAuthConfirm Error[Problem Detail: %+v]", pd) return nil } @@ -2151,11 +2154,11 @@ func HandleAuthenticationFailure(ue *context.AmfUe, anType models.AccessType, Rand: av5gAka.Rand, } - response, problemDetails, err := consumer.SendUEAuthenticationAuthenticateRequest(ue, resynchronizationInfo) + response, pd, err := consumer.GetConsumer().SendUEAuthenticationAuthenticateRequest(ue, resynchronizationInfo) if err != nil { return err - } else if problemDetails != nil { - ue.GmmLog.Errorf("Nausf_UEAU Authenticate Request Error[Problem Detail: %+v]", problemDetails) + } else if pd != nil { + ue.GmmLog.Errorf("Nausf_UEAU Authenticate Request Error[Problem Detail: %+v]", pd) return nil } ue.AuthenticationCtx = response @@ -2173,6 +2176,7 @@ func HandleAuthenticationFailure(ue *context.AmfUe, anType models.AccessType, ue.NgKsi.Ksi = 0 } gmm_message.SendAuthenticationRequest(ue.RanUe[anType]) + default: } } @@ -2192,7 +2196,7 @@ func HandleRegistrationComplete(ue *context.AmfUe, accessType models.AccessType, smContext := value.(*context.SmContext) if smContext.AccessType() == accessType { - problemDetail, err := consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) + problemDetail, err := consumer.GetConsumer().SendReleaseSmContextRequest(ue, smContext, nil, "", nil) if problemDetail != nil { ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetail) } else if err != nil { @@ -2318,7 +2322,7 @@ func HandleDeregistrationRequest(ue *context.AmfUe, anType models.AccessType, if smContext.AccessType() == anType || targetDeregistrationAccessType == nasMessage.AccessTypeBoth { - problemDetail, err := consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) + problemDetail, err := consumer.GetConsumer().SendReleaseSmContextRequest(ue, smContext, nil, "", nil) if problemDetail != nil { ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetail) } else if err != nil { @@ -2338,7 +2342,7 @@ func HandleDeregistrationRequest(ue *context.AmfUe, anType models.AccessType, } if terminateAmPolicyAssocaition { - problemDetails, err := consumer.AMPolicyControlDelete(ue) + problemDetails, err := consumer.GetConsumer().AMPolicyControlDelete(ue) if problemDetails != nil { ue.GmmLog.Errorf("AM Policy Control Delete Failed Problem[%+v]", problemDetails) } else if err != nil { diff --git a/internal/gmm/message/send.go b/internal/gmm/message/send.go index 9297716e..f129b305 100644 --- a/internal/gmm/message/send.go +++ b/internal/gmm/message/send.go @@ -7,7 +7,7 @@ import ( gmm_common "github.com/free5gc/amf/internal/gmm/common" "github.com/free5gc/amf/internal/logger" ngap_message "github.com/free5gc/amf/internal/ngap/message" - "github.com/free5gc/amf/internal/sbi/producer/callback" + callback "github.com/free5gc/amf/internal/sbi/processor/notifier" "github.com/free5gc/nas/nasMessage" "github.com/free5gc/ngap/ngapType" "github.com/free5gc/openapi/models" diff --git a/internal/gmm/sm.go b/internal/gmm/sm.go index f8685922..2c104516 100644 --- a/internal/gmm/sm.go +++ b/internal/gmm/sm.go @@ -33,12 +33,12 @@ func DeRegistered(state *fsm.State, event fsm.EventType, args fsm.ArgsType) { if err := HandleRegistrationRequest(amfUe, accessType, procedureCode, gmmMessage.RegistrationRequest); err != nil { logger.GmmLog.Errorln(err) } else { - if err := GmmFSM.SendEvent(state, StartAuthEvent, fsm.ArgsType{ + if errSendEvent := GmmFSM.SendEvent(state, StartAuthEvent, fsm.ArgsType{ ArgAmfUe: amfUe, ArgAccessType: accessType, ArgProcedureCode: procedureCode, - }, logger.GmmLog); err != nil { - logger.GmmLog.Errorln(err) + }, logger.GmmLog); errSendEvent != nil { + logger.GmmLog.Errorln(errSendEvent) } } // If UE that considers itself Registared and CM-IDLE throws a ServiceRequest @@ -79,12 +79,12 @@ func Registered(state *fsm.State, event fsm.EventType, args fsm.ArgsType) { if err := HandleRegistrationRequest(amfUe, accessType, procedureCode, gmmMessage.RegistrationRequest); err != nil { logger.GmmLog.Errorln(err) } else { - if err := GmmFSM.SendEvent(state, StartAuthEvent, fsm.ArgsType{ + if errSendEvent := GmmFSM.SendEvent(state, StartAuthEvent, fsm.ArgsType{ ArgAmfUe: amfUe, ArgAccessType: accessType, ArgProcedureCode: procedureCode, - }, logger.GmmLog); err != nil { - logger.GmmLog.Errorln(err) + }, logger.GmmLog); errSendEvent != nil { + logger.GmmLog.Errorln(errSendEvent) } } case nas.MsgTypeULNASTransport: @@ -144,19 +144,19 @@ func Authentication(state *fsm.State, event fsm.EventType, args fsm.ArgsType) { pass, err := AuthenticationProcedure(amfUe, accessType) if err != nil { - if err := GmmFSM.SendEvent(state, AuthErrorEvent, fsm.ArgsType{ + if errSendEvent := GmmFSM.SendEvent(state, AuthErrorEvent, fsm.ArgsType{ ArgAmfUe: amfUe, ArgAccessType: accessType, - }, logger.GmmLog); err != nil { - logger.GmmLog.Errorln(err) + }, logger.GmmLog); errSendEvent != nil { + logger.GmmLog.Errorln(errSendEvent) } } if pass { - if err := GmmFSM.SendEvent(state, AuthSuccessEvent, fsm.ArgsType{ + if errSendEvent := GmmFSM.SendEvent(state, AuthSuccessEvent, fsm.ArgsType{ ArgAmfUe: amfUe, ArgAccessType: accessType, - }, logger.GmmLog); err != nil { - logger.GmmLog.Errorln(err) + }, logger.GmmLog); errSendEvent != nil { + logger.GmmLog.Errorln(errSendEvent) } } case GmmMessageEvent: @@ -174,7 +174,7 @@ func Authentication(state *fsm.State, event fsm.EventType, args fsm.ArgsType) { mobileIdentityContents := gmmMessage.IdentityResponse.MobileIdentity.GetMobileIdentityContents() amfUe.IdentityTypeUsedForRegistration = nasConvert.GetTypeOfIdentity(mobileIdentityContents[0]) - err := GmmFSM.SendEvent( + errSendEvent := GmmFSM.SendEvent( state, AuthRestartEvent, fsm.ArgsType{ @@ -182,8 +182,8 @@ func Authentication(state *fsm.State, event fsm.EventType, args fsm.ArgsType) { ArgAccessType: accessType, }, logger.GmmLog, ) - if err != nil { - logger.GmmLog.Errorln(err) + if errSendEvent != nil { + logger.GmmLog.Errorln(errSendEvent) } } case nas.MsgTypeAuthenticationResponse: @@ -375,27 +375,27 @@ func ContextSetup(state *fsm.State, event fsm.EventType, args fsm.ArgsType) { } else { switch amfUe.RegistrationType5GS { case nasMessage.RegistrationType5GSInitialRegistration: - if err := HandleInitialRegistration(amfUe, accessType); err != nil { - logger.GmmLog.Errorln(err) - err = GmmFSM.SendEvent(state, ContextSetupFailEvent, fsm.ArgsType{ + if err2 := HandleInitialRegistration(amfUe, accessType); err2 != nil { + logger.GmmLog.Errorln(err2) + err2 = GmmFSM.SendEvent(state, ContextSetupFailEvent, fsm.ArgsType{ ArgAmfUe: amfUe, ArgAccessType: accessType, }, logger.GmmLog) - if err != nil { - logger.GmmLog.Errorln(err) + if err2 != nil { + logger.GmmLog.Errorln(err2) } } case nasMessage.RegistrationType5GSMobilityRegistrationUpdating: fallthrough case nasMessage.RegistrationType5GSPeriodicRegistrationUpdating: - if err := HandleMobilityAndPeriodicRegistrationUpdating(amfUe, accessType); err != nil { - logger.GmmLog.Errorln(err) - err = GmmFSM.SendEvent(state, ContextSetupFailEvent, fsm.ArgsType{ + if err2 := HandleMobilityAndPeriodicRegistrationUpdating(amfUe, accessType); err2 != nil { + logger.GmmLog.Errorln(err2) + err2 = GmmFSM.SendEvent(state, ContextSetupFailEvent, fsm.ArgsType{ ArgAmfUe: amfUe, ArgAccessType: accessType, }, logger.GmmLog) - if err != nil { - logger.GmmLog.Errorln(err) + if err2 != nil { + logger.GmmLog.Errorln(err2) } } } @@ -419,7 +419,7 @@ func ContextSetup(state *fsm.State, event fsm.EventType, args fsm.ArgsType) { amfUe := args[ArgAmfUe].(*context.AmfUe) accessType := args[ArgAccessType].(models.AccessType) if amfUe.UeCmRegistered[accessType] { - problemDetails, err := consumer.UeCmDeregistration(amfUe, accessType) + problemDetails, err := consumer.GetConsumer().UeCmDeregistration(amfUe, accessType) if problemDetails != nil { if problemDetails.Cause != "CONTEXT_NOT_FOUND" { amfUe.GmmLog.Errorf("UECM_Registration Failed Problem[%+v]", problemDetails) diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 6800e814..9af803b3 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -20,6 +20,7 @@ var ( GmmLog *logrus.Entry MtLog *logrus.Entry ProducerLog *logrus.Entry + SBILog *logrus.Entry LocationLog *logrus.Entry CommLog *logrus.Entry CallbackLog *logrus.Entry @@ -54,6 +55,7 @@ func init() { GmmLog = NfLog.WithField(logger_util.FieldCategory, "Gmm") MtLog = NfLog.WithField(logger_util.FieldCategory, "Mt") ProducerLog = NfLog.WithField(logger_util.FieldCategory, "Producer") + SBILog = NfLog.WithField(logger_util.FieldCategory, "SBI") LocationLog = NfLog.WithField(logger_util.FieldCategory, "Location") CommLog = NfLog.WithField(logger_util.FieldCategory, "Comm") CallbackLog = NfLog.WithField(logger_util.FieldCategory, "Callback") diff --git a/internal/nas/dispatch.go b/internal/nas/dispatch.go index 198e846c..5818f72c 100644 --- a/internal/nas/dispatch.go +++ b/internal/nas/dispatch.go @@ -14,7 +14,7 @@ import ( func Dispatch(ue *context.AmfUe, accessType models.AccessType, procedureCode int64, msg *nas.Message) error { if msg.GmmMessage == nil { - return errors.New("Gmm Message is nil") + return errors.New("gmm Message is nil") } if msg.GsmMessage != nil { diff --git a/internal/nas/fuzz_test.go b/internal/nas/fuzz_test.go index 8c533d68..224fa98a 100644 --- a/internal/nas/fuzz_test.go +++ b/internal/nas/fuzz_test.go @@ -7,10 +7,13 @@ import ( "testing" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" amf_context "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" amf_nas "github.com/free5gc/amf/internal/nas" + "github.com/free5gc/amf/internal/sbi/consumer" + "github.com/free5gc/amf/pkg/service" "github.com/free5gc/nas" "github.com/free5gc/nas/nasMessage" "github.com/free5gc/nas/nasType" @@ -129,6 +132,7 @@ func FuzzHandleNAS2(f *testing.F) { Tac: "1", } amfSelf.SupportTaiLists = []models.Tai{tai} + amfSelf.NrfUri = "test" msg := nas.NewMessage() msg.GmmMessage = nas.NewGmmMessage() @@ -211,6 +215,17 @@ func FuzzHandleNAS2(f *testing.F) { f.Add(buf) f.Fuzz(func(t *testing.T, d []byte) { + ctrl := gomock.NewController(t) + // m := app.NewMockApp(ctrl) + m := service.NewMockAmfAppInterface(ctrl) + c, errc := consumer.NewConsumer(m) + service.AMF = m + require.NoError(t, errc) + m.EXPECT(). + Consumer(). + AnyTimes(). + Return(c) + ue := new(amf_context.RanUe) ue.Ran = new(amf_context.AmfRan) ue.Ran.AnType = models.AccessType__3_GPP_ACCESS diff --git a/internal/nas/handler.go b/internal/nas/handler.go index dee9a22b..1b77c880 100644 --- a/internal/nas/handler.go +++ b/internal/nas/handler.go @@ -36,8 +36,8 @@ func HandleNAS(ue *amf_context.RanUe, procedureCode int64, nasPdu []byte, initia ue.AmfUe.NasPduValue = nasPdu ue.AmfUe.MacFailed = !integrityProtected - if err := Dispatch(ue.AmfUe, ue.Ran.AnType, procedureCode, msg); err != nil { - ue.AmfUe.NASLog.Errorf("Handle NAS Error: %v", err) + if errDispatch := Dispatch(ue.AmfUe, ue.Ran.AnType, procedureCode, msg); errDispatch != nil { + ue.AmfUe.NASLog.Errorf("Handle NAS Error: %v", errDispatch) } } diff --git a/internal/nas/nas_security/fuzz_test.go b/internal/nas/nas_security/fuzz_test.go index e9098785..520e3005 100755 --- a/internal/nas/nas_security/fuzz_test.go +++ b/internal/nas/nas_security/fuzz_test.go @@ -37,8 +37,8 @@ func FuzzNASSecurity(f *testing.F) { ue.CipheringAlg = security.AlgCiphering128NEA2 if err := security.NASEncrypt(ue.CipheringAlg, ue.KnasEnc, uint32(d[6]), security.AccessType3GPP, security.DirectionUplink, d[7:]); err == nil { - if mac32, err := security.NASMacCalculate(ue.IntegrityAlg, ue.KnasInt, uint32(d[6]), - security.AccessType3GPP, security.DirectionUplink, d[6:]); err == nil { + if mac32, errNASMacCalculate := security.NASMacCalculate(ue.IntegrityAlg, ue.KnasInt, uint32(d[6]), + security.AccessType3GPP, security.DirectionUplink, d[6:]); errNASMacCalculate == nil { copy(d[2:6], mac32) msg2, integrityProtected2, err2 := nas_security.Decode(ue, models.AccessType__3_GPP_ACCESS, d, true) if err0 == nil && integrityProtected0 && diff --git a/internal/nas/nas_security/security.go b/internal/nas/nas_security/security.go index 1d08c4cd..e017871b 100644 --- a/internal/nas/nas_security/security.go +++ b/internal/nas/nas_security/security.go @@ -81,7 +81,10 @@ func Encode(ue *context.AmfUe, msg *nas.Message, accessType models.AccessType) ( } // add sequece number - payload = append([]byte{ue.DLCount.SQN()}, payload[:]...) + addsqn := []byte{} + addsqn = append(addsqn, []byte{ue.DLCount.SQN()}...) + addsqn = append(addsqn, payload...) + payload = addsqn ue.NASLog.Debugf("Calculate NAS MAC (algorithm: %+v, DLCount: 0x%0x)", ue.IntegrityAlg, ue.DLCount.Get()) ue.NASLog.Tracef("NAS integrity key: %0x", ue.KnasInt) @@ -92,11 +95,17 @@ func Encode(ue *context.AmfUe, msg *nas.Message, accessType models.AccessType) ( } // Add mac value ue.NASLog.Tracef("MAC: 0x%08x", mac32) - payload = append(mac32, payload[:]...) + addmac := []byte{} + addmac = append(addmac, mac32...) + addmac = append(addmac, payload...) + payload = addmac // Add EPD and Security Type msgSecurityHeader := []byte{msg.SecurityHeader.ProtocolDiscriminator, msg.SecurityHeader.SecurityHeaderType} - payload = append(msgSecurityHeader, payload[:]...) + encodepayload := []byte{} + encodepayload = append(encodepayload, msgSecurityHeader...) + encodepayload = append(encodepayload, payload...) + payload = encodepayload // Increase DL Count ue.DLCount.AddOne() diff --git a/internal/ngap/handler.go b/internal/ngap/handler.go index f0888f3e..bc61c6b0 100644 --- a/internal/ngap/handler.go +++ b/internal/ngap/handler.go @@ -292,7 +292,7 @@ func handleUEContextReleaseCompleteMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - response, _, _, err := consumer.SendUpdateSmContextDeactivateUpCnxState(amfUe, smContext, cause) + response, _, _, err := consumer.GetConsumer().SendUpdateSmContextDeactivateUpCnxState(amfUe, smContext, cause) if err != nil { ran.Log.Errorf("Send Update SmContextDeactivate UpCnxState Error[%s]", err.Error()) } else if response == nil { @@ -373,7 +373,7 @@ func handlePDUSessionResourceReleaseResponseMain(ran *context.AmfRan, continue } - _, responseErr, problemDetail, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + _, responseErr, problemDetail, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_REL_RSP, transfer) // TODO: error handling if err != nil { @@ -620,7 +620,7 @@ func handlePDUSessionResourceSetupResponseMain(ran *context.AmfRan, ranUe.Log.Errorf("SmContext[PDU Session ID:%d] not found", pduSessionID) continue } - _, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_SETUP_RSP, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceSetupResponseTransfer] Error: %+v", err) @@ -645,7 +645,7 @@ func handlePDUSessionResourceSetupResponseMain(ran *context.AmfRan, ranUe.Log.Errorf("SmContext[PDU Session ID:%d] not found", pduSessionID) continue } - _, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_SETUP_FAIL, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceSetupUnsuccessfulTransfer] Error: %+v", err) @@ -693,7 +693,7 @@ func handlePDUSessionResourceModifyResponseMain(ran *context.AmfRan, ranUe.Log.Errorf("SmContext[PDU Session ID:%d] not found", pduSessionID) continue } - _, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_MOD_RSP, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceModifyResponseTransfer] Error: %+v", err) @@ -717,8 +717,7 @@ func handlePDUSessionResourceModifyResponseMain(ran *context.AmfRan, ranUe.Log.Errorf("SmContext[PDU Session ID:%d] not found", pduSessionID) continue } - // response, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, pduSessionID, - _, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_MOD_FAIL, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceModifyUnsuccessfulTransfer] Error: %+v", err) @@ -766,7 +765,7 @@ func handlePDUSessionResourceNotifyMain(ran *context.AmfRan, ranUe.Log.Errorf("SmContext[PDU Session ID:%d] not found", pduSessionID) continue } - response, errResponse, problemDetail, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + response, errResponse, problemDetail, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_NTY, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceNotifyTransfer] Error: %+v", err) @@ -792,6 +791,7 @@ func handlePDUSessionResourceNotifyMain(ran *context.AmfRan, list := ngapType.PDUSessionResourceModifyListModReq{} ngap_message.AppendPDUSessionResourceModifyListModReq(&list, pduSessionID, nasPdu, n2Info) ngap_message.SendPDUSessionResourceModifyRequest(ranUe, list) + default: } } } else if errResponse != nil { @@ -825,7 +825,7 @@ func handlePDUSessionResourceNotifyMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - response, errResponse, problemDetail, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + response, errResponse, problemDetail, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_NTY_REL, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceNotifyReleasedTransfer] Error: %+v", err) @@ -835,8 +835,7 @@ func handlePDUSessionResourceNotifyMain(ran *context.AmfRan, n2Info := response.BinaryDataN1SmMessage n1Msg := response.BinaryDataN2SmInformation if n2Info != nil { - switch responseData.N2SmInfoType { - case models.N2SmInfoType_PDU_RES_REL_CMD: + if responseData.N2SmInfoType == models.N2SmInfoType_PDU_RES_REL_CMD { ranUe.Log.Debugln("AMF Transfer NGAP PDU Session Resource Rel Co from SMF") var nasPdu []byte if n1Msg != nil { @@ -896,7 +895,7 @@ func handlePDUSessionResourceModifyIndicationMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - response, errResponse, _, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + response, errResponse, _, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_MOD_IND, transfer) if err != nil { ran.Log.Errorf("SendUpdateSmContextN2Info Error:\n%s", err.Error()) @@ -951,8 +950,7 @@ func handleInitialContextSetupResponseMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - // response, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, pduSessionID, - _, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_SETUP_RSP, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceSetupResponseTransfer] Error: %+v", err) @@ -978,8 +976,7 @@ func handleInitialContextSetupResponseMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - // response, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, pduSessionID, - _, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_SETUP_FAIL, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceSetupUnsuccessfulTransfer] Error: %+v", err) @@ -1039,7 +1036,7 @@ func handleInitialContextSetupFailureMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - _, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, smContext, + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2Info(amfUe, smContext, models.N2SmInfoType_PDU_RES_SETUP_FAIL, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceSetupUnsuccessfulTransfer] Error: %+v", err) @@ -1093,10 +1090,10 @@ func handleUEContextReleaseRequestMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - response, _, _, err := consumer.SendUpdateSmContextDeactivateUpCnxState(amfUe, smContext, causeAll) + rsp, _, _, err := consumer.GetConsumer().SendUpdateSmContextDeactivateUpCnxState(amfUe, smContext, causeAll) if err != nil { ranUe.Log.Errorf("Send Update SmContextDeactivate UpCnxState Error[%s]", err.Error()) - } else if response == nil { + } else if rsp == nil { ranUe.Log.Errorln("Send Update SmContextDeactivate UpCnxState Error") } } @@ -1105,7 +1102,7 @@ func handleUEContextReleaseRequestMain(ran *context.AmfRan, ranUe.Log.Info("Ue Context in Non GMM-Registered") amfUe.SmContextList.Range(func(key, value interface{}) bool { smContext := value.(*context.SmContext) - detail, err := consumer.SendReleaseSmContextRequest(amfUe, smContext, &causeAll, "", nil) + detail, err := consumer.GetConsumer().SendReleaseSmContextRequest(amfUe, smContext, &causeAll, "", nil) if err != nil { ranUe.Log.Errorf("Send ReleaseSmContextRequest Error[%s]", err.Error()) } else if detail != nil { @@ -1209,7 +1206,7 @@ func handleHandoverNotifyMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - _, _, _, err := consumer.SendUpdateSmContextN2HandoverComplete(amfUe, smContext, "", nil) + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2HandoverComplete(amfUe, smContext, "", nil) if err != nil { ran.Log.Errorf("Send UpdateSmContextN2HandoverComplete Error[%s]", err.Error()) } @@ -1288,7 +1285,7 @@ func handlePathSwitchRequestMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - response, errResponse, _, err := consumer.SendUpdateSmContextXnHandover(amfUe, smContext, + response, errResponse, _, err := consumer.GetConsumer().SendUpdateSmContextXnHandover(amfUe, smContext, models.N2SmInfoType_PATH_SWITCH_REQ, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextXnHandover[PathSwitchRequestTransfer] Error:\n%s", err.Error()) @@ -1320,7 +1317,7 @@ func handlePathSwitchRequestMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - response, errResponse, _, err := consumer.SendUpdateSmContextXnHandoverFailed(amfUe, smContext, + response, errResponse, _, err := consumer.GetConsumer().SendUpdateSmContextXnHandoverFailed(amfUe, smContext, models.N2SmInfoType_PATH_SWITCH_SETUP_FAIL, transfer) if err != nil { ranUe.Log.Errorf("SendUpdateSmContextXnHandoverFailed[PathSwitchRequestSetupFailedTransfer] Error: %+v", err) @@ -1405,7 +1402,7 @@ func handleHandoverRequestAcknowledgeMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - response, errResponse, problemDetails, err := consumer.SendUpdateSmContextN2HandoverPrepared(amfUe, + resp, errResponse, problemDetails, err := consumer.GetConsumer().SendUpdateSmContextN2HandoverPrepared(amfUe, smContext, models.N2SmInfoType_HANDOVER_REQ_ACK, transfer) if err != nil { targetUe.Log.Errorf("Send HandoverRequestAcknowledgeTransfer error: %v", err) @@ -1413,10 +1410,10 @@ func handleHandoverRequestAcknowledgeMain(ran *context.AmfRan, if problemDetails != nil { targetUe.Log.Warnf("ProblemDetails[status: %d, Cause: %s]", problemDetails.Status, problemDetails.Cause) } - if response != nil && response.BinaryDataN2SmInformation != nil { + if resp != nil && resp.BinaryDataN2SmInformation != nil { handoverItem := ngapType.PDUSessionResourceHandoverItem{} handoverItem.PDUSessionID = item.PDUSessionID - handoverItem.HandoverCommandTransfer = response.BinaryDataN2SmInformation + handoverItem.HandoverCommandTransfer = resp.BinaryDataN2SmInformation pduSessionResourceHandoverList.List = append(pduSessionResourceHandoverList.List, handoverItem) targetUe.SuccessPduSessionId = append(targetUe.SuccessPduSessionId, pduSessionID) } @@ -1440,7 +1437,7 @@ func handleHandoverRequestAcknowledgeMain(ran *context.AmfRan, // TODO: Check if doing error handling here continue } - _, _, problemDetails, err := consumer.SendUpdateSmContextN2HandoverPrepared(amfUe, smContext, + _, _, problemDetails, err := consumer.GetConsumer().SendUpdateSmContextN2HandoverPrepared(amfUe, smContext, models.N2SmInfoType_HANDOVER_RES_ALLOC_FAIL, transfer) if err != nil { targetUe.Log.Errorf("Send HandoverResourceAllocationUnsuccessfulTransfer error: %v", err) @@ -1512,7 +1509,7 @@ func handleHandoverFailureMain(ran *context.AmfRan, Value: int32(causeValue), }, } - _, _, _, err := consumer.SendUpdateSmContextN2HandoverCanceled(amfUe, smContext, causeAll) + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2HandoverCanceled(amfUe, smContext, causeAll) if err != nil { ran.Log.Errorf("Send UpdateSmContextN2HandoverCanceled Error for pduSessionID[%d]", pduSessionID) } @@ -1591,17 +1588,17 @@ func handleHandoverRequiredMain(ran *context.AmfRan, sourceUe.Log.Infof("Send HandoverRequiredTransfer to SMF") for _, pDUSessionResourceHoItem := range pDUSessionResourceListHORqd.List { pduSessionID := int32(pDUSessionResourceHoItem.PDUSessionID.Value) - smContext, ok := amfUe.SmContextFindByPDUSessionID(pduSessionID) - if !ok { + smContext, okSmContextFindByPDUSessionID := amfUe.SmContextFindByPDUSessionID(pduSessionID) + if !okSmContextFindByPDUSessionID { sourceUe.Log.Warnf("SmContext[PDU Session ID:%d] not found", pduSessionID) // TODO: Check if doing error handling here continue } - response, _, _, err := consumer.SendUpdateSmContextN2HandoverPreparing(amfUe, smContext, + response, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2HandoverPreparing(amfUe, smContext, models.N2SmInfoType_HANDOVER_REQUIRED, pDUSessionResourceHoItem.HandoverRequiredTransfer, "", &targetId) if err != nil { - sourceUe.Log.Errorf("consumer.SendUpdateSmContextN2HandoverPreparing Error: %+v", err) + sourceUe.Log.Errorf("consumer.GetConsumer().SendUpdateSmContextN2HandoverPreparing Error: %+v", err) } if response == nil { sourceUe.Log.Errorf("SendUpdateSmContextN2HandoverPreparing Error for pduSessionID[%d]", pduSessionID) @@ -1666,7 +1663,7 @@ func handleHandoverCancelMain(ran *context.AmfRan, Value: int32(causeValue), }, } - _, _, _, err := consumer.SendUpdateSmContextN2HandoverCanceled(amfUe, smContext, causeAll) + _, _, _, err := consumer.GetConsumer().SendUpdateSmContextN2HandoverCanceled(amfUe, smContext, causeAll) if err != nil { sourceUe.Log.Errorf("Send UpdateSmContextN2HandoverCanceled Error for pduSessionID[%d]", pduSessionID) } @@ -1851,7 +1848,7 @@ func handleLocationReportMain(ran *context.AmfRan, case ngapType.EventTypePresentStopUePresenceInAreaOfInterest: ranUe.Log.Trace("To stop reporting UE presence in the area of interest") - ranUe.Log.Tracef("ReferenceID To Be Cancelled[%d]", + ranUe.Log.Tracef("ReferenceID To Be Canceled[%d]", locationReportingRequestType.LocationReportingReferenceIDToBeCancelled.Value) // TODO: Clear location report @@ -1999,7 +1996,7 @@ func handleCellTrafficTraceMain(ran *context.AmfRan, } // TODO: TS 32.422 4.2.2.10 - // When AMF receives this new NG signalling message containing the Trace Recording Session Reference (TRSR) + // When AMF receives this new NG signaling message containing the Trace Recording Session Reference (TRSR) // and Trace Reference (TR), the AMF shall look up the SUPI/IMEI(SV) of the given call from its database and // shall send the SUPI/IMEI(SV) numbers together with the Trace Recording Session Reference and Trace Reference // to the Trace Collection Entity. diff --git a/internal/ngap/message/build.go b/internal/ngap/message/build.go index 3770497e..5c4cf125 100644 --- a/internal/ngap/message/build.go +++ b/internal/ngap/message/build.go @@ -642,15 +642,15 @@ func BuildHandoverCancelAcknowledge( // Criticality Diagnostics [optional] if criticalityDiagnostics != nil { - ie := ngapType.HandoverCancelAcknowledgeIEs{} - ie.Id.Value = ngapType.ProtocolIEIDCriticalityDiagnostics - ie.Criticality.Value = ngapType.CriticalityPresentIgnore - ie.Value.Present = ngapType.HandoverCancelAcknowledgeIEsPresentCriticalityDiagnostics - ie.Value.CriticalityDiagnostics = new(ngapType.CriticalityDiagnostics) + handoverCancelAcknowledgeIEsie := ngapType.HandoverCancelAcknowledgeIEs{} + handoverCancelAcknowledgeIEsie.Id.Value = ngapType.ProtocolIEIDCriticalityDiagnostics + handoverCancelAcknowledgeIEsie.Criticality.Value = ngapType.CriticalityPresentIgnore + handoverCancelAcknowledgeIEsie.Value.Present = ngapType.HandoverCancelAcknowledgeIEsPresentCriticalityDiagnostics + handoverCancelAcknowledgeIEsie.Value.CriticalityDiagnostics = new(ngapType.CriticalityDiagnostics) - ie.Value.CriticalityDiagnostics = criticalityDiagnostics + handoverCancelAcknowledgeIEsie.Value.CriticalityDiagnostics = criticalityDiagnostics - handoverCancelAcknowledgeIEs.List = append(handoverCancelAcknowledgeIEs.List, ie) + handoverCancelAcknowledgeIEs.List = append(handoverCancelAcknowledgeIEs.List, handoverCancelAcknowledgeIEsie) } return ngap.Encoder(pdu) @@ -1497,15 +1497,15 @@ func BuildHandoverCommand( // Criticality Diagnostics [optional] if criticalityDiagnostics != nil { - ie := ngapType.HandoverCommandIEs{} - ie.Id.Value = ngapType.ProtocolIEIDCriticalityDiagnostics - ie.Criticality.Value = ngapType.CriticalityPresentIgnore - ie.Value.Present = ngapType.HandoverCancelAcknowledgeIEsPresentCriticalityDiagnostics - ie.Value.CriticalityDiagnostics = new(ngapType.CriticalityDiagnostics) + handoverCommandIEsie := ngapType.HandoverCommandIEs{} + handoverCommandIEsie.Id.Value = ngapType.ProtocolIEIDCriticalityDiagnostics + handoverCommandIEsie.Criticality.Value = ngapType.CriticalityPresentIgnore + handoverCommandIEsie.Value.Present = ngapType.HandoverCancelAcknowledgeIEsPresentCriticalityDiagnostics + handoverCommandIEsie.Value.CriticalityDiagnostics = new(ngapType.CriticalityDiagnostics) - ie.Value.CriticalityDiagnostics = criticalityDiagnostics + handoverCommandIEsie.Value.CriticalityDiagnostics = criticalityDiagnostics - handoverCommandIEs.List = append(handoverCommandIEs.List, ie) + handoverCommandIEs.List = append(handoverCommandIEs.List, handoverCommandIEsie) } return ngap.Encoder(pdu) @@ -1569,15 +1569,15 @@ func BuildHandoverPreparationFailure(sourceUe *context.RanUe, cause ngapType.Cau // Criticality Diagnostics [optional] if criticalityDiagnostics != nil { - ie := ngapType.HandoverPreparationFailureIEs{} - ie.Id.Value = ngapType.ProtocolIEIDCriticalityDiagnostics - ie.Criticality.Value = ngapType.CriticalityPresentIgnore - ie.Value.Present = ngapType.HandoverCancelAcknowledgeIEsPresentCriticalityDiagnostics - ie.Value.CriticalityDiagnostics = new(ngapType.CriticalityDiagnostics) + HandoverPreparationFailureIEsie := ngapType.HandoverPreparationFailureIEs{} + HandoverPreparationFailureIEsie.Id.Value = ngapType.ProtocolIEIDCriticalityDiagnostics + HandoverPreparationFailureIEsie.Criticality.Value = ngapType.CriticalityPresentIgnore + HandoverPreparationFailureIEsie.Value.Present = ngapType.HandoverCancelAcknowledgeIEsPresentCriticalityDiagnostics + HandoverPreparationFailureIEsie.Value.CriticalityDiagnostics = new(ngapType.CriticalityDiagnostics) - ie.Value.CriticalityDiagnostics = criticalityDiagnostics + HandoverPreparationFailureIEsie.Value.CriticalityDiagnostics = criticalityDiagnostics - handoverPreparationFailureIEs.List = append(handoverPreparationFailureIEs.List, ie) + handoverPreparationFailureIEs.List = append(handoverPreparationFailureIEs.List, HandoverPreparationFailureIEsie) } return ngap.Encoder(pdu) @@ -1859,8 +1859,8 @@ func BuildHandoverRequest(ue *context.RanUe, cause ngapType.Cause, // newSecurityContextIndicator: if AMF has activated a new 5G NAS security context, // set it to true, otherwise set to false // coreNetworkAssistanceInformation: provided by AMF, -// based on collection of UE behaviour statistics and/or other available -// information about the expected UE behaviour. TS 23.501 5.4.6, 5.4.6.2 +// based on collection of UE behavior statistics and/or other available +// information about the expected UE behavior. TS 23.501 5.4.6, 5.4.6.2 // rrcInactiveTransitionReportRequest: configured by amf // criticalityDiagnostics: from received node when received not comprehended IE or missing IE func BuildPathSwitchRequestAcknowledge( @@ -2575,7 +2575,7 @@ func BuildAMFStatusIndication(unavailableGUAMIList ngapType.UnavailableGUAMIList } // TS 23.501 5.19.5.2 -// amfOverloadResponse: the required behaviour of NG-RAN, provided by AMF +// amfOverloadResponse: the required behavior of NG-RAN, provided by AMF // amfTrafficLoadReductionIndication(int 1~99): indicates the percentage of the type // of traffic relative to the instantaneous incoming rate at the NG-RAN node, provided by AMF // overloadStartNSSAIList: overload slices, provide by AMF @@ -2805,14 +2805,17 @@ func BuildDeactivateTrace(amfUe *context.AmfUe, anType models.AccessType) ([]byt } tmp := ngapConvert.PlmnIdToNgap(plmnID) - traceReference := append(tmp.Value, traceID...) + traceReference := []byte{} + traceReference = append(traceReference, tmp.Value...) + traceReference = append(traceReference, traceID...) trsr := ranUe.Trsr trsrNgap, err := hex.DecodeString(trsr) if err != nil { logger.NgapLog.Errorf( "[Build Error] DecodeString trsr error: %+v", err) } - ie.Value.NGRANTraceID.Value = append(traceReference, trsrNgap...) + ie.Value.NGRANTraceID.Value = append(ie.Value.NGRANTraceID.Value, traceReference...) + ie.Value.NGRANTraceID.Value = append(ie.Value.NGRANTraceID.Value, trsrNgap...) deactivateTraceIEs.List = append(deactivateTraceIEs.List, ie) } return ngap.Encoder(pdu) @@ -2827,12 +2830,12 @@ func BuildDeactivateTrace(amfUe *context.AmfUe, anType models.AccessType) ([]byt // The AMF may request the NG-RAN location reporting with event reporting type // (e.g. UE location or UE presence in Area of Interest), // reporting mode and its related parameters (e.g. number of reporting) TS 23.501 5.4.7 -// Location Reference ID To Be Cancelled IE shall be present if +// Location Reference ID To Be Canceled IE shall be present if // the Event Type IE is set to "Stop UE presence in the area of interest". func BuildLocationReportingControl( ue *context.RanUe, - AOIList *ngapType.AreaOfInterestList, - LocationReportingReferenceIDToBeCancelled int64, + aoiList *ngapType.AreaOfInterestList, + locationReportingReferenceIDToBeCancelled int64, eventType ngapType.EventType, ) ([]byte, error) { var pdu ngapType.NGAPPDU @@ -2890,18 +2893,18 @@ func BuildLocationReportingControl( locationReportingRequestType.ReportArea.Value = ngapType.ReportAreaPresentCell // only this enum // AOI List in Location Reporting Request Type - if AOIList != nil { + if aoiList != nil { locationReportingRequestType.AreaOfInterestList = new(ngapType.AreaOfInterestList) areaOfInterestList := locationReportingRequestType.AreaOfInterestList - areaOfInterestList.List = AOIList.List + areaOfInterestList.List = aoiList.List } - // location reference ID to be Cancelled [Conditional] + // location reference ID to be Canceled [Conditional] if locationReportingRequestType.EventType.Value == ngapType.EventTypePresentStopUePresenceInAreaOfInterest { locationReportingRequestType.LocationReportingReferenceIDToBeCancelled = new(ngapType.LocationReportingReferenceID) locationReportingRequestType. - LocationReportingReferenceIDToBeCancelled.Value = LocationReportingReferenceIDToBeCancelled + LocationReportingReferenceIDToBeCancelled.Value = locationReportingReferenceIDToBeCancelled } locationReportingControlIEs.List = append(locationReportingControlIEs.List, ie) diff --git a/internal/ngap/message/send.go b/internal/ngap/message/send.go index 84a1b3c9..198166ce 100644 --- a/internal/ngap/message/send.go +++ b/internal/ngap/message/send.go @@ -3,7 +3,7 @@ package message import ( "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer/callback" + callback "github.com/free5gc/amf/internal/sbi/processor/notifier" "github.com/free5gc/aper" "github.com/free5gc/ngap/ngapType" "github.com/free5gc/openapi/models" @@ -542,9 +542,9 @@ func SendHandoverRequest(sourceUe *context.RanUe, targetRan *context.AmfRan, cau // pduSessionResourceReleasedList: provided by AMF, and the transfer data is from SMF // newSecurityContextIndicator: if AMF has activated a new 5G NAS security context, set it to true, // otherwise set to false -// coreNetworkAssistanceInformation: provided by AMF, based on collection of UE behaviour statistics +// coreNetworkAssistanceInformation: provided by AMF, based on collection of UE behavior statistics // and/or other available -// information about the expected UE behaviour. TS 23.501 5.4.6, 5.4.6.2 +// information about the expected UE behavior. TS 23.501 5.4.6, 5.4.6.2 // rrcInactiveTransitionReportRequest: configured by amf // criticalityDiagnostics: from received node when received not comprehended IE or missing IE func SendPathSwitchRequestAcknowledge( @@ -790,7 +790,7 @@ func SendAMFStatusIndication(ran *context.AmfRan, unavailableGUAMIList ngapType. } // TS 23.501 5.19.5.2 -// amfOverloadResponse: the required behaviour of NG-RAN, provided by AMF +// amfOverloadResponse: the required behavior of NG-RAN, provided by AMF // amfTrafficLoadReductionIndication(int 1~99): indicates the percentage of the type, set to 0 if does not need this ie // of traffic relative to the instantaneous incoming rate at the NG-RAN node, provided by AMF // overloadStartNSSAIList: overload slices, provide by AMF @@ -912,12 +912,12 @@ func SendDeactivateTrace(amfUe *context.AmfUe, anType models.AccessType) { // TS 23.502 4.10 LocationReportingProcedure // The AMF may request the NG-RAN location reporting with event reporting type (e.g. UE location or UE presence // in Area of Interest), reporting mode and its related parameters (e.g. number of reporting) TS 23.501 5.4.7 -// Location Reference ID To Be Cancelled IE shall be present if the Event Type IE is set to "Stop UE presence +// Location Reference ID To Be Canceled IE shall be present if the Event Type IE is set to "Stop UE presence // in the area of interest". otherwise set it to 0 func SendLocationReportingControl( ue *context.RanUe, - AOIList *ngapType.AreaOfInterestList, - LocationReportingReferenceIDToBeCancelled int64, + aoiList *ngapType.AreaOfInterestList, + locationReportingReferenceIDToBeCancelled int64, eventType ngapType.EventType, ) { if ue == nil { @@ -927,19 +927,19 @@ func SendLocationReportingControl( ue.Log.Info("Send Location Reporting Control") - if AOIList != nil && len(AOIList.List) > context.MaxNumOfAOI { + if aoiList != nil && len(aoiList.List) > context.MaxNumOfAOI { ue.Log.Error("AOI List out of range") return } if eventType.Value == ngapType.EventTypePresentStopUePresenceInAreaOfInterest { - if LocationReportingReferenceIDToBeCancelled < 1 || LocationReportingReferenceIDToBeCancelled > 64 { + if locationReportingReferenceIDToBeCancelled < 1 || locationReportingReferenceIDToBeCancelled > 64 { ue.Log.Error("LocationReportingReferenceIDToBeCancelled out of range (should be 1 ~ 64)") return } } - pkt, err := BuildLocationReportingControl(ue, AOIList, LocationReportingReferenceIDToBeCancelled, eventType) + pkt, err := BuildLocationReportingControl(ue, aoiList, locationReportingReferenceIDToBeCancelled, eventType) if err != nil { ue.Log.Errorf("Build LocationReportingControl failed : %s", err.Error()) return diff --git a/internal/ngap/service/service.go b/internal/ngap/service/service.go index 0a33f17b..f5f5f504 100644 --- a/internal/ngap/service/service.go +++ b/internal/ngap/service/service.go @@ -20,7 +20,10 @@ type NGAPHandler struct { HandleConnectionError func(conn net.Conn) } -const readBufSize uint32 = 262144 +const ( + notimeout int = -1 + readBufSize uint32 = 262144 +) // set default read timeout to 2 seconds var readTimeout syscall.Timeval = syscall.Timeval{Sec: 2, Usec: 0} @@ -87,7 +90,7 @@ func listenAndServe(addr *sctp.SCTPAddr, handler NGAPHandler, sctpConfig *sctp.S logger.NgapLog.Infof("Listen on %s", sctpListener.Addr()) for { - newConn, err := sctpListener.AcceptSCTP() + newConn, err := sctpListener.AcceptSCTP(notimeout) if err != nil { switch err { case syscall.EINTR, syscall.EAGAIN: @@ -99,10 +102,10 @@ func listenAndServe(addr *sctp.SCTPAddr, handler NGAPHandler, sctpConfig *sctp.S } var info *sctp.SndRcvInfo - if infoTmp, err := newConn.GetDefaultSentParam(); err != nil { - logger.NgapLog.Errorf("Get default sent param error: %+v, accept failed", err) - if err = newConn.Close(); err != nil { - logger.NgapLog.Errorf("Close error: %+v", err) + if infoTmp, errGetDefaultSentParam := newConn.GetDefaultSentParam(); errGetDefaultSentParam != nil { + logger.NgapLog.Errorf("Get default sent param error: %+v, accept failed", errGetDefaultSentParam) + if errGetDefaultSentParam = newConn.Close(); errGetDefaultSentParam != nil { + logger.NgapLog.Errorf("Close error: %+v", errGetDefaultSentParam) } continue } else { @@ -111,10 +114,10 @@ func listenAndServe(addr *sctp.SCTPAddr, handler NGAPHandler, sctpConfig *sctp.S } info.PPID = ngap.PPID - if err := newConn.SetDefaultSentParam(info); err != nil { - logger.NgapLog.Errorf("Set default sent param error: %+v, accept failed", err) - if err = newConn.Close(); err != nil { - logger.NgapLog.Errorf("Close error: %+v", err) + if errSetDefaultSentParam := newConn.SetDefaultSentParam(info); errSetDefaultSentParam != nil { + logger.NgapLog.Errorf("Set default sent param error: %+v, accept failed", errSetDefaultSentParam) + if errSetDefaultSentParam = newConn.Close(); errSetDefaultSentParam != nil { + logger.NgapLog.Errorf("Close error: %+v", errSetDefaultSentParam) } continue } else { @@ -122,30 +125,30 @@ func listenAndServe(addr *sctp.SCTPAddr, handler NGAPHandler, sctpConfig *sctp.S } events := sctp.SCTP_EVENT_DATA_IO | sctp.SCTP_EVENT_SHUTDOWN | sctp.SCTP_EVENT_ASSOCIATION - if err := newConn.SubscribeEvents(events); err != nil { - logger.NgapLog.Errorf("Failed to accept: %+v", err) - if err = newConn.Close(); err != nil { - logger.NgapLog.Errorf("Close error: %+v", err) + if errSubscribeEvents := newConn.SubscribeEvents(events); errSubscribeEvents != nil { + logger.NgapLog.Errorf("Failed to accept: %+v", errSubscribeEvents) + if errSubscribeEvents = newConn.Close(); errSubscribeEvents != nil { + logger.NgapLog.Errorf("Close error: %+v", errSubscribeEvents) } continue } else { logger.NgapLog.Debugln("Subscribe SCTP event[DATA_IO, SHUTDOWN_EVENT, ASSOCIATION_CHANGE]") } - if err := newConn.SetReadBuffer(int(readBufSize)); err != nil { - logger.NgapLog.Errorf("Set read buffer error: %+v, accept failed", err) - if err = newConn.Close(); err != nil { - logger.NgapLog.Errorf("Close error: %+v", err) + if errSetReadBuffer := newConn.SetReadBuffer(int(readBufSize)); errSetReadBuffer != nil { + logger.NgapLog.Errorf("Set read buffer error: %+v, accept failed", errSetReadBuffer) + if errSetReadBuffer = newConn.Close(); errSetReadBuffer != nil { + logger.NgapLog.Errorf("Close error: %+v", errSetReadBuffer) } continue } else { logger.NgapLog.Debugf("Set read buffer to %d bytes", readBufSize) } - if err := newConn.SetReadTimeout(readTimeout); err != nil { - logger.NgapLog.Errorf("Set read timeout error: %+v, accept failed", err) - if err = newConn.Close(); err != nil { - logger.NgapLog.Errorf("Close error: %+v", err) + if errSetReadTimeout := newConn.SetReadTimeout(readTimeout); errSetReadTimeout != nil { + logger.NgapLog.Errorf("Set read timeout error: %+v, accept failed", errSetReadTimeout) + if errSetReadTimeout = newConn.Close(); errSetReadTimeout != nil { + logger.NgapLog.Errorf("Close error: %+v", errSetReadTimeout) } continue } else { diff --git a/internal/sbi/api_communication.go b/internal/sbi/api_communication.go new file mode 100644 index 00000000..4e58649e --- /dev/null +++ b/internal/sbi/api_communication.go @@ -0,0 +1,447 @@ +package sbi + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + + "github.com/free5gc/amf/internal/logger" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/models" +) + +func Index(c *gin.Context) { + c.String(http.StatusOK, "Hello World!") +} + +func (s *Server) getCommunicationRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: func(c *gin.Context) { + c.String(http.StatusOK, "Hello World!") + }, + }, + { + Method: http.MethodPut, + Pattern: "/subscriptions/:subscriptionId", + APIFunc: s.HTTPAMFStatusChangeSubscribeModify, + }, + { + Method: http.MethodDelete, + Pattern: "/subscriptions/:subscriptionId", + APIFunc: s.HTTPAMFStatusChangeUnSubscribe, + }, + { + Method: http.MethodPut, + Pattern: "/ue-contexts/:ueContextId", + APIFunc: s.HTTPCreateUEContext, + }, + { + Method: http.MethodPost, + Pattern: "/ue-contexts/:ueContextId/assign-ebi", + APIFunc: s.HTTPEBIAssignment, + }, + { + Method: http.MethodPost, + Pattern: "/ue-contexts/:ueContextId/transfer-update", + APIFunc: s.HTTPRegistrationStatusUpdate, + }, + { + Method: http.MethodPost, + Pattern: "/ue-contexts/:ueContextId/release", + APIFunc: s.HTTPReleaseUEContext, + }, + { + Method: http.MethodPost, + Pattern: "/ue-contexts/:ueContextId/transfer", + APIFunc: s.HTTPUEContextTransfer, + }, + { + Method: http.MethodDelete, + Pattern: "/ue-contexts/:ueContextId/n1-n2-messages/subscriptions/:subscriptionId", + APIFunc: s.HTTPN1N2MessageUnSubscribe, + }, + { + Method: http.MethodPost, + Pattern: "/ue-contexts/:ueContextId/n1-n2-messages", + APIFunc: s.HTTPN1N2MessageTransfer, + }, + { + Method: http.MethodGet, + Pattern: "/ue-contexts/:ueContextId/n1-n2-messages/:n1N2MessageId", + APIFunc: s.HTTPN1N2MessageTransferStatus, + }, + { + Method: http.MethodPost, + Pattern: "/ue-contexts/:ueContextId/n1-n2-messages/subscriptions", + APIFunc: s.HTTPN1N2MessageSubscribe, + }, + { + Method: http.MethodDelete, + Pattern: "/non-ue-n2-messages/subscriptions/:n2NotifySubscriptionId", + APIFunc: s.HTTPNonUeN2InfoUnSubscribe, + }, + { + Method: http.MethodPost, + Pattern: "/non-ue-n2-messages/transfer", + APIFunc: s.HTTPNonUeN2MessageTransfer, + }, + { + Method: http.MethodPost, + Pattern: "/non-ue-n2-messages/subscriptions", + APIFunc: s.HTTPNonUeN2InfoSubscribe, + }, + { + Method: http.MethodPost, + Pattern: "/subscriptions", + APIFunc: s.HTTPAMFStatusChangeSubscribe, + }, + } +} + +// AMFStatusChangeSubscribeModify - Namf_Communication AMF Status Change Subscribe Modify service Operation +func (s *Server) HTTPAMFStatusChangeSubscribeModify(c *gin.Context) { + var subscriptionData models.SubscriptionData + + requestBody, err := c.GetRawData() + if err != nil { + logger.CommLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&subscriptionData, requestBody, applicationjson) + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleAMFStatusChangeSubscribeModify(c, subscriptionData) +} + +// AMFStatusChangeUnSubscribe - Namf_Communication AMF Status Change UnSubscribe service Operation +func (s *Server) HTTPAMFStatusChangeUnSubscribe(c *gin.Context) { + s.Processor().HandleAMFStatusChangeUnSubscribeRequest(c) +} + +func (s *Server) HTTPCreateUEContext(c *gin.Context) { + var createUeContextRequest models.CreateUeContextRequest + createUeContextRequest.JsonData = new(models.UeContextCreateData) + + requestBody, err := c.GetRawData() + if err != nil { + logger.CommLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + contentType := c.GetHeader("Content-Type") + str := strings.Split(contentType, ";") + switch str[0] { + case applicationjson: + err = openapi.Deserialize(createUeContextRequest.JsonData, requestBody, contentType) + case multipartrelate: + err = openapi.Deserialize(&createUeContextRequest, requestBody, contentType) + default: + err = fmt.Errorf("wrong content type") + } + + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleCreateUEContextRequest(c, createUeContextRequest) +} + +// EBIAssignment - Namf_Communication EBI Assignment service Operation +func (s *Server) HTTPEBIAssignment(c *gin.Context) { + var assignEbiData models.AssignEbiData + + requestBody, err := c.GetRawData() + if err != nil { + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + logger.CommLog.Errorf("Get Request Body error: %+v", err) + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&assignEbiData, requestBody, applicationjson) + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleAssignEbiDataRequest(c, assignEbiData) +} + +// RegistrationStatusUpdate - Namf_Communication RegistrationStatusUpdate service Operation +func (s *Server) HTTPRegistrationStatusUpdate(c *gin.Context) { + var ueRegStatusUpdateReqData models.UeRegStatusUpdateReqData + + requestBody, err := c.GetRawData() + if err != nil { + logger.CommLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&ueRegStatusUpdateReqData, requestBody, applicationjson) + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleRegistrationStatusUpdateRequest(c, ueRegStatusUpdateReqData) +} + +// ReleaseUEContext - Namf_Communication ReleaseUEContext service Operation +func (s *Server) HTTPReleaseUEContext(c *gin.Context) { + var ueContextRelease models.UeContextRelease + + requestBody, err := c.GetRawData() + if err != nil { + logger.CommLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&ueContextRelease, requestBody, applicationjson) + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleReleaseUEContextRequest(c, ueContextRelease) +} + +// UEContextTransfer - Namf_Communication UEContextTransfer service Operation +func (s *Server) HTTPUEContextTransfer(c *gin.Context) { + var ueContextTransferRequest models.UeContextTransferRequest + ueContextTransferRequest.JsonData = new(models.UeContextTransferReqData) + + requestBody, err := c.GetRawData() + if err != nil { + logger.CommLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + contentType := c.GetHeader("Content-Type") + str := strings.Split(contentType, ";") + switch str[0] { + case applicationjson: + err = openapi.Deserialize(ueContextTransferRequest.JsonData, requestBody, contentType) + case multipartrelate: + err = openapi.Deserialize(&ueContextTransferRequest, requestBody, contentType) + } + + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleUEContextTransferRequest(c, ueContextTransferRequest) +} + +func (s *Server) HTTPN1N2MessageUnSubscribe(c *gin.Context) { + s.Processor().HandleN1N2MessageUnSubscribeRequest(c) +} + +func (s *Server) HTTPN1N2MessageTransfer(c *gin.Context) { + var n1n2MessageTransferRequest models.N1N2MessageTransferRequest + n1n2MessageTransferRequest.JsonData = new(models.N1N2MessageTransferReqData) + + requestBody, err := c.GetRawData() + if err != nil { + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + logger.CommLog.Errorf("Get Request Body error: %+v", err) + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + contentType := c.GetHeader("Content-Type") + str := strings.Split(contentType, ";") + switch str[0] { + case applicationjson: + err = fmt.Errorf("N1 and N2 datas are both Empty in N1N2MessgeTransfer") + case multipartrelate: + err = openapi.Deserialize(&n1n2MessageTransferRequest, requestBody, contentType) + default: + err = fmt.Errorf("wrong content type") + } + + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleN1N2MessageTransferRequest(c, n1n2MessageTransferRequest) +} + +func (s *Server) HTTPN1N2MessageTransferStatus(c *gin.Context) { + s.Processor().HandleN1N2MessageTransferStatusRequest(c) +} + +func (s *Server) HTTPN1N2MessageSubscribe(c *gin.Context) { + var ueN1N2InfoSubscriptionCreateData models.UeN1N2InfoSubscriptionCreateData + + requestBody, err := c.GetRawData() + if err != nil { + logger.CommLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&ueN1N2InfoSubscriptionCreateData, requestBody, applicationjson) + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleN1N2MessageSubscribeRequest(c, ueN1N2InfoSubscriptionCreateData) +} + +func (s *Server) HTTPNonUeN2InfoUnSubscribe(c *gin.Context) { + logger.CommLog.Warnf("Handle Non Ue N2 Info UnSubscribe is not implemented.") + c.JSON(http.StatusNotImplemented, gin.H{}) +} + +func (s *Server) HTTPNonUeN2MessageTransfer(c *gin.Context) { + logger.CommLog.Warnf("Handle Non Ue N2 Message Transfer is not implemented.") + c.JSON(http.StatusNotImplemented, gin.H{}) +} + +func (s *Server) HTTPNonUeN2InfoSubscribe(c *gin.Context) { + logger.CommLog.Warnf("Handle Non Ue N2 Info Subscribe is not implemented.") + c.JSON(http.StatusNotImplemented, gin.H{}) +} + +func (s *Server) HTTPAMFStatusChangeSubscribe(c *gin.Context) { + var subscriptionData models.SubscriptionData + + requestBody, err := c.GetRawData() + if err != nil { + logger.CommLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&subscriptionData, requestBody, applicationjson) + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CommLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleAMFStatusChangeSubscribeRequest(c, subscriptionData) +} diff --git a/internal/sbi/api_eventexposure.go b/internal/sbi/api_eventexposure.go new file mode 100644 index 00000000..1f019f81 --- /dev/null +++ b/internal/sbi/api_eventexposure.go @@ -0,0 +1,106 @@ +package sbi + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + "github.com/free5gc/amf/internal/logger" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/models" +) + +func (s *Server) getEventexposureRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: func(c *gin.Context) { + c.String(http.StatusOK, "Hello World!") + }, + }, + { + Method: http.MethodDelete, + Pattern: "/subscriptions/:subscriptionId", + APIFunc: s.HTTPDeleteSubscription, + }, + { + Method: http.MethodPatch, + Pattern: "/subscriptions/:subscriptionId", + APIFunc: s.HTTPModifySubscription, + }, + { + Method: http.MethodPost, + Pattern: "/subscriptions", + APIFunc: s.HTTPCreateSubscription, + }, + } +} + +// DeleteSubscription - Namf_EventExposure Unsubscribe service Operation +func (s *Server) HTTPDeleteSubscription(c *gin.Context) { + s.Processor().HandleDeleteAMFEventSubscription(c) +} + +// ModifySubscription - Namf_EventExposure Subscribe Modify service Operation +func (s *Server) HTTPModifySubscription(c *gin.Context) { + var modifySubscriptionRequest models.ModifySubscriptionRequest + + requestBody, err := c.GetRawData() + if err != nil { + logger.EeLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&modifySubscriptionRequest, requestBody, "application/json") + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.EeLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleModifyAMFEventSubscription(c, modifySubscriptionRequest) +} + +func (s *Server) HTTPCreateSubscription(c *gin.Context) { + var createEventSubscription models.AmfCreateEventSubscription + + requestBody, err := c.GetRawData() + if err != nil { + logger.EeLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&createEventSubscription, requestBody, "application/json") + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.EeLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleCreateAMFEventSubscription(c, createEventSubscription) +} diff --git a/internal/sbi/api_httpcallback.go b/internal/sbi/api_httpcallback.go new file mode 100644 index 00000000..fb47e2a8 --- /dev/null +++ b/internal/sbi/api_httpcallback.go @@ -0,0 +1,249 @@ +package sbi + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + amf_context "github.com/free5gc/amf/internal/context" + "github.com/free5gc/amf/internal/logger" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/models" +) + +func (s *Server) getHttpCallBackRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: func(c *gin.Context) { + c.String(http.StatusOK, "Hello World!") + }, + }, + { + Method: http.MethodPost, + Pattern: "/am-policy/:polAssoId/update", + APIFunc: s.HTTPAmPolicyControlUpdateNotifyUpdate, + }, + { + Method: http.MethodPost, + Pattern: "/am-policy/:polAssoId/terminate", + APIFunc: s.HTTPAmPolicyControlUpdateNotifyTerminate, + }, + { + Method: http.MethodPost, + Pattern: "/n1-message-notify", + APIFunc: s.HTTPN1MessageNotify, + }, + { + Method: http.MethodPost, + Pattern: "/deregistration/:ueid", + APIFunc: s.HTTPHandleDeregistrationNotification, + }, + } +} + +func (s *Server) HTTPAmPolicyControlUpdateNotifyUpdate(c *gin.Context) { + var policyUpdate models.PolicyUpdate + + requestBody, err := c.GetRawData() + if err != nil { + logger.CallbackLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&policyUpdate, requestBody, "application/json") + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CallbackLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleAmPolicyControlUpdateNotifyUpdate(c, policyUpdate) +} + +func (s *Server) HTTPAmPolicyControlUpdateNotifyTerminate(c *gin.Context) { + var terminationNotification models.TerminationNotification + + requestBody, err := c.GetRawData() + if err != nil { + logger.CallbackLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&terminationNotification, requestBody, "application/json") + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CallbackLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleAmPolicyControlUpdateNotifyTerminate(c, terminationNotification) +} + +func (s *Server) HTTPN1MessageNotify(c *gin.Context) { + var n1MessageNotify models.N1MessageNotify + + requestBody, err := c.GetRawData() + if err != nil { + logger.CallbackLog.Errorf("Get Request Body error: %+v", err) + problemDetail := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetail) + return + } + + err = openapi.Deserialize(&n1MessageNotify, requestBody, "application/json") + if err != nil { + problemDetail := reqbody + err.Error() + rsp := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: problemDetail, + } + logger.CallbackLog.Errorln(problemDetail) + c.JSON(http.StatusBadRequest, rsp) + return + } + s.Processor().HandleN1MessageNotify(c, n1MessageNotify) +} + +func (s *Server) HTTPHandleDeregistrationNotification(c *gin.Context) { + // TS 23.502 - 4.2.2.2.2 - step 14d + logger.CallbackLog.Traceln("Handle Deregistration Notification") + + var deregData models.DeregistrationData + + requestBody, err := c.GetRawData() + if err != nil { + logger.CallbackLog.Errorf("Get Request Body error: %+v", err) + problemDetails := models.ProblemDetails{ + Title: "System failure", + Status: http.StatusInternalServerError, + Detail: err.Error(), + Cause: "SYSTEM_FAILURE", + } + c.JSON(http.StatusInternalServerError, problemDetails) + return + } + + err = openapi.Deserialize(&deregData, requestBody, "application/json") + if err != nil { + problemDetails := models.ProblemDetails{ + Title: "Malformed request syntax", + Status: http.StatusBadRequest, + Detail: reqbody + err.Error(), + } + logger.CallbackLog.Errorln(problemDetails.Detail) + c.JSON(http.StatusBadRequest, problemDetails) + return + } + + ueid := c.Param("ueid") + ue, ok := amf_context.GetSelf().AmfUeFindByUeContextID(ueid) + if !ok { + logger.CallbackLog.Errorf("AmfUe Context[%s] not found", ueid) + problemDetails := models.ProblemDetails{ + Status: http.StatusNotFound, + Cause: "CONTEXT_NOT_FOUND", + } + c.JSON(http.StatusNotFound, problemDetails) + return + } + + problemDetails, err := s.DeregistrationNotificationProcedure(ue, deregData) + if problemDetails != nil { + ue.GmmLog.Errorf("Deregistration Notification Procedure Failed Problem[%+v]", problemDetails) + } else if err != nil { + ue.GmmLog.Errorf("Deregistration Notification Procedure Error[%v]", err.Error()) + } + // TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration + // The AMF acknowledges the Nudm_UECM_DeRegistrationNotification to the UDM. + c.JSON(http.StatusNoContent, nil) +} + +// TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration +// The AMF can initiate this procedure for either explicit (e.g. by O&M intervention) or +// implicit (e.g. expiring of Implicit Deregistration timer) +func (s *Server) DeregistrationNotificationProcedure(ue *amf_context.AmfUe, deregData models.DeregistrationData) ( + problemDetails *models.ProblemDetails, err error, +) { + // The AMF does not send the Deregistration Request message to the UE for Implicit Deregistration. + if deregData.DeregReason == models.DeregistrationReason_UE_INITIAL_REGISTRATION { + // TS 23.502 - 4.2.2.2.2 General Registration + // Invokes the Nsmf_PDUSession_ReleaseSMContext for the corresponding access type + ue.SmContextList.Range(func(key, value interface{}) bool { + smContext := value.(*amf_context.SmContext) + if smContext.AccessType() == deregData.AccessType { + problemDetails, err = s.Consumer().SendReleaseSmContextRequest(ue, smContext, nil, "", nil) + if problemDetails != nil { + ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails) + } else if err != nil { + ue.GmmLog.Errorf("Release SmContext Error[%v]", err.Error()) + } + } + return true + }) + } + // TS 23.502 - 4.2.2.2.2 General Registration - 14e + // TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access), + // the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe + if ue.SdmSubscriptionId != "" { + problemDetails, err = s.Consumer().SDMUnsubscribe(ue) + if problemDetails != nil { + logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails) + } else if err != nil { + logger.GmmLog.Errorf("SDM Unubscribe Error[%+v]", err) + } + ue.SdmSubscriptionId = "" + } + + // TS 23.502 - 4.2.2.2.2 General Registration - 20 AMF-Initiated Policy Association Termination + // For UE_INITIAL_REGISTRATION and SUBSCRIPTION_WITHDRAW, do AMF-Initiated Policy Association Termination directly. + if ue.PolicyAssociationId != "" { + // TODO: For REGISTRATION_AREA_CHANGE, old AMF performs an AMF-initiated Policy Association Termination + // procedure if the old AMF has established an AM Policy Association and a UE Policy Association with the PCF(s) + // and the old AMF did not transfer the PCF ID(s) to the new AMF. (Ref: TS 23.502 - 4.2.2.2.2) + // Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID + problemDetailsAMPolicyControlDelete, errAMPolicyControlDelete := s.Consumer().AMPolicyControlDelete(ue) + if problemDetailsAMPolicyControlDelete != nil { + logger.GmmLog.Errorf("Delete AM policy Failed Problem[%+v]", problemDetailsAMPolicyControlDelete) + } else if err != nil { + logger.GmmLog.Errorf("Delete AM policy Error[%+v]", errAMPolicyControlDelete) + } + } + + // The old AMF should clean the UE context + // TODO: (R16) Only remove the target access UE context + ue.Remove() + + return nil, nil +} diff --git a/internal/sbi/location/api_individual_ue_context_document.go b/internal/sbi/api_location.go similarity index 62% rename from internal/sbi/location/api_individual_ue_context_document.go rename to internal/sbi/api_location.go index 8717ceab..c5d455a6 100644 --- a/internal/sbi/location/api_individual_ue_context_document.go +++ b/internal/sbi/api_location.go @@ -7,7 +7,7 @@ * Generated by: OpenAPI Generator (https://openapi-generator.tech) */ -package location +package sbi import ( "net/http" @@ -15,14 +15,34 @@ import ( "github.com/gin-gonic/gin" "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" "github.com/free5gc/openapi" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) +func (s *Server) getLocationRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: func(c *gin.Context) { + c.String(http.StatusOK, "Hello World!") + }, + }, + { + Method: http.MethodPost, + Pattern: "/:ueContextId/provide-loc-info", + APIFunc: s.HTTPProvideLocationInfo, + }, + { + Method: http.MethodPost, + Pattern: "/:ueContextId/provide-pos-info", + APIFunc: s.HTTPProvidePositioningInfo, + }, + } +} + // ProvideLocationInfo - Namf_Location ProvideLocationInfo service Operation -func HTTPProvideLocationInfo(c *gin.Context) { +func (s *Server) HTTPProvideLocationInfo(c *gin.Context) { var requestLocInfo models.RequestLocInfo requestBody, err := c.GetRawData() @@ -50,28 +70,11 @@ func HTTPProvideLocationInfo(c *gin.Context) { c.JSON(http.StatusBadRequest, rsp) return } - - req := httpwrapper.NewRequest(c.Request, requestLocInfo) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - - rsp := producer.HandleProvideLocationInfoRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } + s.Processor().HandleProvideLocationInfoRequest(c, requestLocInfo) } // ProvidePositioningInfo - Namf_Location ProvidePositioningInfo service Operation -func HTTPProvidePositioningInfo(c *gin.Context) { +func (s *Server) HTTPProvidePositioningInfo(c *gin.Context) { logger.LocationLog.Warnf("Handle Provide Positioning Info is not implemented.") - c.JSON(http.StatusOK, gin.H{}) + c.JSON(http.StatusNotImplemented, gin.H{}) } diff --git a/internal/sbi/api_mt.go b/internal/sbi/api_mt.go new file mode 100644 index 00000000..54cbf8c2 --- /dev/null +++ b/internal/sbi/api_mt.go @@ -0,0 +1,41 @@ +package sbi + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + "github.com/free5gc/amf/internal/logger" +) + +func (s *Server) getMTRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: func(c *gin.Context) { + c.String(http.StatusOK, "Hello World!") + }, + }, + { + Method: http.MethodGet, + Pattern: "/ue-contexts/:ueContextId", + APIFunc: s.HTTPProvideDomainSelectionInfo, + }, + { + Method: http.MethodPost, + Pattern: "/ue-contexts/:ueContextId/ue-reachind", + APIFunc: s.HTTPEnableUeReachability, + }, + } +} + +// ProvideDomainSelectionInfo - Namf_MT Provide Domain Selection Info service Operation +func (s *Server) HTTPProvideDomainSelectionInfo(c *gin.Context) { + s.Processor().HandleProvideDomainSelectionInfoRequest(c) +} + +func (s *Server) HTTPEnableUeReachability(c *gin.Context) { + logger.MtLog.Warnf("Handle Enable Ue Reachability is not implemented.") + c.JSON(http.StatusNotImplemented, gin.H{}) +} diff --git a/internal/sbi/api_oam.go b/internal/sbi/api_oam.go new file mode 100644 index 00000000..1fcc9a07 --- /dev/null +++ b/internal/sbi/api_oam.go @@ -0,0 +1,43 @@ +package sbi + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +func (s *Server) getOAMRoutes() []Route { + return []Route{ + { + Method: http.MethodGet, + Pattern: "/", + APIFunc: func(c *gin.Context) { + c.String(http.StatusOK, "Hello World!") + }, + }, + { + Method: http.MethodGet, + Pattern: "/registered-ue-context", + APIFunc: s.HTTPRegisteredUEContext, + }, + { + Method: http.MethodGet, + Pattern: "/registered-ue-context/:supi", + APIFunc: s.HTTPRegisteredUEContext, + }, + } +} + +func (s *Server) setCorsHeader(c *gin.Context) { + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") + c.Writer.Header().Set("Access-Control-Allow-Headers", + "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, "+ + "Authorization, accept, origin, Cache-Control, X-Requested-With") + c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, PATCH, DELETE") +} + +func (s *Server) HTTPRegisteredUEContext(c *gin.Context) { + s.setCorsHeader(c) + s.Processor().HandleOAMRegisteredUEContext(c) +} diff --git a/internal/sbi/communication/api_individual_subscription_document.go b/internal/sbi/communication/api_individual_subscription_document.go deleted file mode 100644 index 4ec76b3f..00000000 --- a/internal/sbi/communication/api_individual_subscription_document.go +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// AMFStatusChangeSubscribeModify - Namf_Communication AMF Status Change Subscribe Modify service Operation -func HTTPAMFStatusChangeSubscribeModify(c *gin.Context) { - var subscriptionData models.SubscriptionData - - requestBody, err := c.GetRawData() - if err != nil { - logger.CommLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&subscriptionData, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, subscriptionData) - req.Params["subscriptionId"] = c.Params.ByName("subscriptionId") - - rsp := producer.HandleAMFStatusChangeSubscribeModify(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} - -// AMFStatusChangeUnSubscribe - Namf_Communication AMF Status Change UnSubscribe service Operation -func HTTPAMFStatusChangeUnSubscribe(c *gin.Context) { - req := httpwrapper.NewRequest(c.Request, nil) - req.Params["subscriptionId"] = c.Params.ByName("subscriptionId") - - rsp := producer.HandleAMFStatusChangeUnSubscribeRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/communication/api_individual_ue_context_document.go b/internal/sbi/communication/api_individual_ue_context_document.go deleted file mode 100644 index a63d0fb0..00000000 --- a/internal/sbi/communication/api_individual_ue_context_document.go +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "fmt" - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// CreateUEContext - Namf_Communication CreateUEContext service Operation -func HTTPCreateUEContext(c *gin.Context) { - var createUeContextRequest models.CreateUeContextRequest - createUeContextRequest.JsonData = new(models.UeContextCreateData) - - requestBody, err := c.GetRawData() - if err != nil { - logger.CommLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - contentType := c.GetHeader("Content-Type") - s := strings.Split(contentType, ";") - switch s[0] { - case "application/json": - err = openapi.Deserialize(createUeContextRequest.JsonData, requestBody, contentType) - case "multipart/related": - err = openapi.Deserialize(&createUeContextRequest, requestBody, contentType) - default: - err = fmt.Errorf("Wrong content type") - } - - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, createUeContextRequest) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - rsp := producer.HandleCreateUEContextRequest(req) - - if rsp.Status == http.StatusCreated { - responseBody, contentType, err := openapi.MultipartSerialize(rsp.Body) - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, contentType, responseBody) - } - } else { - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } - } -} - -// EBIAssignment - Namf_Communication EBI Assignment service Operation -func HTTPEBIAssignment(c *gin.Context) { - var assignEbiData models.AssignEbiData - - requestBody, err := c.GetRawData() - if err != nil { - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - logger.CommLog.Errorf("Get Request Body error: %+v", err) - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&assignEbiData, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, assignEbiData) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - rsp := producer.HandleAssignEbiDataRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} - -// RegistrationStatusUpdate - Namf_Communication RegistrationStatusUpdate service Operation -func HTTPRegistrationStatusUpdate(c *gin.Context) { - var ueRegStatusUpdateReqData models.UeRegStatusUpdateReqData - - requestBody, err := c.GetRawData() - if err != nil { - logger.CommLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&ueRegStatusUpdateReqData, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, ueRegStatusUpdateReqData) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - rsp := producer.HandleRegistrationStatusUpdateRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} - -// ReleaseUEContext - Namf_Communication ReleaseUEContext service Operation -func HTTPReleaseUEContext(c *gin.Context) { - var ueContextRelease models.UeContextRelease - - requestBody, err := c.GetRawData() - if err != nil { - logger.CommLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&ueContextRelease, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, ueContextRelease) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - rsp := producer.HandleReleaseUEContextRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} - -// UEContextTransfer - Namf_Communication UEContextTransfer service Operation -func HTTPUEContextTransfer(c *gin.Context) { - var ueContextTransferRequest models.UeContextTransferRequest - ueContextTransferRequest.JsonData = new(models.UeContextTransferReqData) - - requestBody, err := c.GetRawData() - if err != nil { - logger.CommLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - contentType := c.GetHeader("Content-Type") - s := strings.Split(contentType, ";") - switch s[0] { - case "application/json": - err = openapi.Deserialize(ueContextTransferRequest.JsonData, requestBody, contentType) - case "multipart/related": - err = openapi.Deserialize(&ueContextTransferRequest, requestBody, contentType) - } - - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, ueContextTransferRequest) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - rsp := producer.HandleUEContextTransferRequest(req) - - if rsp.Status == http.StatusOK { - responseBody, contentType, err := openapi.MultipartSerialize(rsp.Body) - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, contentType, responseBody) - } - } else { - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } - } -} diff --git a/internal/sbi/communication/api_n1_n2_individual_subscription_document.go b/internal/sbi/communication/api_n1_n2_individual_subscription_document.go deleted file mode 100644 index 3ad153c7..00000000 --- a/internal/sbi/communication/api_n1_n2_individual_subscription_document.go +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// N1N2MessageUnSubscribe - Namf_Communication N1N2 Message UnSubscribe (UE Specific) service Operation -func HTTPN1N2MessageUnSubscribe(c *gin.Context) { - req := httpwrapper.NewRequest(c.Request, nil) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - req.Params["subscriptionId"] = c.Params.ByName("subscriptionId") - - rsp := producer.HandleN1N2MessageUnSubscribeRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/communication/api_n1_n2_message_collection_document.go b/internal/sbi/communication/api_n1_n2_message_collection_document.go deleted file mode 100644 index 1c53f4b1..00000000 --- a/internal/sbi/communication/api_n1_n2_message_collection_document.go +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "fmt" - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// N1N2MessageTransfer - Namf_Communication N1N2 Message Transfer (UE Specific) service Operation -func HTTPN1N2MessageTransfer(c *gin.Context) { - var n1n2MessageTransferRequest models.N1N2MessageTransferRequest - n1n2MessageTransferRequest.JsonData = new(models.N1N2MessageTransferReqData) - - requestBody, err := c.GetRawData() - if err != nil { - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - logger.CommLog.Errorf("Get Request Body error: %+v", err) - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - contentType := c.GetHeader("Content-Type") - s := strings.Split(contentType, ";") - switch s[0] { - case "application/json": - err = fmt.Errorf("N1 and N2 datas are both Empty in N1N2MessgeTransfer") - case "multipart/related": - err = openapi.Deserialize(&n1n2MessageTransferRequest, requestBody, contentType) - default: - err = fmt.Errorf("Wrong content type") - } - - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, n1n2MessageTransferRequest) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - req.Params["reqUri"] = c.Request.RequestURI - - rsp := producer.HandleN1N2MessageTransferRequest(req) - - for key, val := range rsp.Header { - c.Header(key, val[0]) - } - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} - -func HTTPN1N2MessageTransferStatus(c *gin.Context) { - req := httpwrapper.NewRequest(c.Request, nil) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - req.Params["reqUri"] = c.Request.RequestURI - - rsp := producer.HandleN1N2MessageTransferStatusRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/communication/api_n1_n2_subscriptions_collection_for_individual_ue_contexts_document.go b/internal/sbi/communication/api_n1_n2_subscriptions_collection_for_individual_ue_contexts_document.go deleted file mode 100644 index cdae9b7d..00000000 --- a/internal/sbi/communication/api_n1_n2_subscriptions_collection_for_individual_ue_contexts_document.go +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -func HTTPN1N2MessageSubscribe(c *gin.Context) { - var ueN1N2InfoSubscriptionCreateData models.UeN1N2InfoSubscriptionCreateData - - requestBody, err := c.GetRawData() - if err != nil { - logger.CommLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&ueN1N2InfoSubscriptionCreateData, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, ueN1N2InfoSubscriptionCreateData) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - - rsp := producer.HandleN1N2MessageSubscirbeRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/communication/api_non_uen2_message_notification_individual_subscription_document.go b/internal/sbi/communication/api_non_uen2_message_notification_individual_subscription_document.go deleted file mode 100644 index 1442cf2c..00000000 --- a/internal/sbi/communication/api_non_uen2_message_notification_individual_subscription_document.go +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" -) - -// NonUeN2InfoUnSubscribe - Namf_Communication Non UE N2 Info UnSubscribe service Operation -func HTTPNonUeN2InfoUnSubscribe(c *gin.Context) { - logger.CommLog.Warnf("Handle Non Ue N2 Info UnSubscribe is not implemented.") - c.JSON(http.StatusOK, gin.H{}) -} diff --git a/internal/sbi/communication/api_non_uen2_messages_collection_document.go b/internal/sbi/communication/api_non_uen2_messages_collection_document.go deleted file mode 100644 index b0a7130e..00000000 --- a/internal/sbi/communication/api_non_uen2_messages_collection_document.go +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" -) - -// NonUeN2MessageTransfer - Namf_Communication Non UE N2 Message Transfer service Operation -func HTTPNonUeN2MessageTransfer(c *gin.Context) { - logger.CommLog.Warnf("Handle Non Ue N2 Message Transfer is not implemented.") - c.JSON(http.StatusOK, gin.H{}) -} diff --git a/internal/sbi/communication/api_non_uen2_messages_subscriptions_collection_document.go b/internal/sbi/communication/api_non_uen2_messages_subscriptions_collection_document.go deleted file mode 100644 index d91fe436..00000000 --- a/internal/sbi/communication/api_non_uen2_messages_subscriptions_collection_document.go +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" -) - -// NonUeN2InfoSubscribe - Namf_Communication Non UE N2 Info Subscribe service Operation -func HTTPNonUeN2InfoSubscribe(c *gin.Context) { - logger.CommLog.Warnf("Handle Non Ue N2 Info Subscribe is not implemented.") - c.JSON(http.StatusOK, gin.H{}) -} diff --git a/internal/sbi/communication/api_subscriptions_collection_document.go b/internal/sbi/communication/api_subscriptions_collection_document.go deleted file mode 100644 index b659c463..00000000 --- a/internal/sbi/communication/api_subscriptions_collection_document.go +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// AMFStatusChangeSubscribe - Namf_Communication AMF Status Change Subscribe service Operation -func HTTPAMFStatusChangeSubscribe(c *gin.Context) { - var subscriptionData models.SubscriptionData - - requestBody, err := c.GetRawData() - if err != nil { - logger.CommLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&subscriptionData, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CommLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, subscriptionData) - rsp := producer.HandleAMFStatusChangeSubscribeRequest(req) - - for key, val := range rsp.Header { - c.Header(key, val[0]) - } - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CommLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/communication/routers.go b/internal/sbi/communication/routers.go deleted file mode 100644 index 0c4ffa11..00000000 --- a/internal/sbi/communication/routers.go +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Namf_Communication - * - * AMF Communication Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package communication - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/util" - "github.com/free5gc/amf/pkg/factory" - "github.com/free5gc/openapi/models" - logger_util "github.com/free5gc/util/logger" -) - -var HttpLog *logrus.Entry - -func init() { - HttpLog = logger.HttpLog -} - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AmfCommResUriPrefix) - - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAMF_COMM) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, amf_context.GetSelf()) - }) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - case "POST": - group.POST(route.Pattern, route.HandlerFunc) - case "PUT": - group.PUT(route.Pattern, route.HandlerFunc) - case "DELETE": - group.DELETE(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "AMFStatusChangeSubscribeModify", - strings.ToUpper("Put"), - "/subscriptions/:subscriptionId", - HTTPAMFStatusChangeSubscribeModify, - }, - - { - "AMFStatusChangeUnSubscribe", - strings.ToUpper("Delete"), - "/subscriptions/:subscriptionId", - HTTPAMFStatusChangeUnSubscribe, - }, - - { - "CreateUEContext", - strings.ToUpper("Put"), - "/ue-contexts/:ueContextId", - HTTPCreateUEContext, - }, - - { - "EBIAssignment", - strings.ToUpper("Post"), - "/ue-contexts/:ueContextId/assign-ebi", - HTTPEBIAssignment, - }, - - { - "RegistrationStatusUpdate", - strings.ToUpper("Post"), - "/ue-contexts/:ueContextId/transfer-update", - HTTPRegistrationStatusUpdate, - }, - - { - "ReleaseUEContext", - strings.ToUpper("Post"), - "/ue-contexts/:ueContextId/release", - HTTPReleaseUEContext, - }, - - { - "UEContextTransfer", - strings.ToUpper("Post"), - "/ue-contexts/:ueContextId/transfer", - HTTPUEContextTransfer, - }, - - { - "N1N2MessageUnSubscribe", - strings.ToUpper("Delete"), - "/ue-contexts/:ueContextId/n1-n2-messages/subscriptions/:subscriptionId", - HTTPN1N2MessageUnSubscribe, - }, - - { - "N1N2MessageTransfer", - strings.ToUpper("Post"), - "/ue-contexts/:ueContextId/n1-n2-messages", - HTTPN1N2MessageTransfer, - }, - - { - "N1N2MessageTransferStatus", - strings.ToUpper("Get"), - "/ue-contexts/:ueContextId/n1-n2-messages/:n1N2MessageId", - HTTPN1N2MessageTransferStatus, - }, - - { - "N1N2MessageSubscribe", - strings.ToUpper("Post"), - "/ue-contexts/:ueContextId/n1-n2-messages/subscriptions", - HTTPN1N2MessageSubscribe, - }, - - { - "NonUeN2InfoUnSubscribe", - strings.ToUpper("Delete"), - "/non-ue-n2-messages/subscriptions/:n2NotifySubscriptionId", - HTTPNonUeN2InfoUnSubscribe, - }, - - { - "NonUeN2MessageTransfer", - strings.ToUpper("Post"), - "/non-ue-n2-messages/transfer", - HTTPNonUeN2MessageTransfer, - }, - - { - "NonUeN2InfoSubscribe", - strings.ToUpper("Post"), - "/non-ue-n2-messages/subscriptions", - HTTPNonUeN2InfoSubscribe, - }, - - { - "AMFStatusChangeSubscribe", - strings.ToUpper("Post"), - "/subscriptions", - HTTPAMFStatusChangeSubscribe, - }, -} diff --git a/internal/sbi/consumer/communication.go b/internal/sbi/consumer/amf_service.go similarity index 82% rename from internal/sbi/consumer/communication.go rename to internal/sbi/consumer/amf_service.go index 97d72b57..e1acc760 100644 --- a/internal/sbi/consumer/communication.go +++ b/internal/sbi/consumer/amf_service.go @@ -2,6 +2,7 @@ package consumer import ( "fmt" + "sync" amf_context "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" @@ -11,13 +12,43 @@ import ( "github.com/free5gc/openapi/models" ) -func BuildUeContextCreateData(ue *amf_context.AmfUe, targetRanId models.NgRanTargetId, +type namfService struct { + consumer *Consumer + + ComMu sync.RWMutex + + ComClients map[string]*Namf_Communication.APIClient +} + +func (s *namfService) getComClient(uri string) *Namf_Communication.APIClient { + if uri == "" { + return nil + } + s.ComMu.RLock() + client, ok := s.ComClients[uri] + if ok { + s.ComMu.RUnlock() + return client + } + + configuration := Namf_Communication.NewConfiguration() + configuration.SetBasePath(uri) + client = Namf_Communication.NewAPIClient(configuration) + + s.ComMu.RUnlock() + s.ComMu.Lock() + defer s.ComMu.Unlock() + s.ComClients[uri] = client + return client +} + +func (s *namfService) BuildUeContextCreateData(ue *amf_context.AmfUe, targetRanId models.NgRanTargetId, sourceToTargetData models.N2InfoContent, pduSessionList []models.N2SmInformation, n2NotifyUri string, ngapCause *models.NgApCause, ) models.UeContextCreateData { var ueContextCreateData models.UeContextCreateData - ueContext := BuildUeContextModel(ue) + ueContext := s.BuildUeContextModel(ue) ueContextCreateData.UeContext = &ueContext ueContextCreateData.TargetId = &targetRanId ueContextCreateData.SourceToTargetData = &sourceToTargetData @@ -35,7 +66,7 @@ func BuildUeContextCreateData(ue *amf_context.AmfUe, targetRanId models.NgRanTar return ueContextCreateData } -func BuildUeContextModel(ue *amf_context.AmfUe) (ueContext models.UeContext) { +func (s *namfService) BuildUeContextModel(ue *amf_context.AmfUe) (ueContext models.UeContext) { ueContext.Supi = ue.Supi ueContext.SupiUnauthInd = ue.UnauthenticatedSupi @@ -81,7 +112,7 @@ func BuildUeContextModel(ue *amf_context.AmfUe) (ueContext models.UeContext) { if ue.AmPolicyAssociation != nil { if len(ue.AmPolicyAssociation.Triggers) > 0 { - ueContext.AmPolicyReqTriggerList = buildAmPolicyReqTriggers(ue.AmPolicyAssociation.Triggers) + ueContext.AmPolicyReqTriggerList = s.buildAmPolicyReqTriggers(ue.AmPolicyAssociation.Triggers) } } @@ -97,7 +128,9 @@ func BuildUeContextModel(ue *amf_context.AmfUe) (ueContext models.UeContext) { return ueContext } -func buildAmPolicyReqTriggers(triggers []models.RequestTrigger) (amPolicyReqTriggers []models.AmPolicyReqTrigger) { +func (s *namfService) buildAmPolicyReqTriggers( + triggers []models.RequestTrigger, +) (amPolicyReqTriggers []models.AmPolicyReqTrigger) { for _, trigger := range triggers { switch trigger { case models.RequestTrigger_LOC_CH: @@ -113,12 +146,13 @@ func buildAmPolicyReqTriggers(triggers []models.RequestTrigger) (amPolicyReqTrig return } -func CreateUEContextRequest(ue *amf_context.AmfUe, ueContextCreateData models.UeContextCreateData) ( +func (s *namfService) CreateUEContextRequest(ue *amf_context.AmfUe, ueContextCreateData models.UeContextCreateData) ( ueContextCreatedData *models.UeContextCreatedData, problemDetails *models.ProblemDetails, err error, ) { - configuration := Namf_Communication.NewConfiguration() - configuration.SetBasePath(ue.TargetAmfUri) - client := Namf_Communication.NewAPIClient(configuration) + client := s.getComClient(ue.TargetAmfUri) + if client == nil { + return nil, nil, openapi.ReportError("amf not found") + } req := models.CreateUeContextRequest{ JsonData: &ueContextCreateData, @@ -152,12 +186,13 @@ func CreateUEContextRequest(ue *amf_context.AmfUe, ueContextCreateData models.Ue return ueContextCreatedData, problemDetails, err } -func ReleaseUEContextRequest(ue *amf_context.AmfUe, ngapCause models.NgApCause) ( +func (s *namfService) ReleaseUEContextRequest(ue *amf_context.AmfUe, ngapCause models.NgApCause) ( problemDetails *models.ProblemDetails, err error, ) { - configuration := Namf_Communication.NewConfiguration() - configuration.SetBasePath(ue.TargetAmfUri) - client := Namf_Communication.NewAPIClient(configuration) + client := s.getComClient(ue.TargetAmfUri) + if client == nil { + return nil, openapi.ReportError("amf not found") + } var ueContextId string if ue.Supi != "" { @@ -202,13 +237,14 @@ func ReleaseUEContextRequest(ue *amf_context.AmfUe, ngapCause models.NgApCause) return problemDetails, err } -func UEContextTransferRequest( +func (s *namfService) UEContextTransferRequest( ue *amf_context.AmfUe, accessType models.AccessType, transferReason models.TransferReason) ( ueContextTransferRspData *models.UeContextTransferRspData, problemDetails *models.ProblemDetails, err error, ) { - configuration := Namf_Communication.NewConfiguration() - configuration.SetBasePath(ue.TargetAmfUri) - client := Namf_Communication.NewAPIClient(configuration) + client := s.getComClient(ue.TargetAmfUri) + if client == nil { + return nil, nil, openapi.ReportError("amf not found") + } ueContextTransferReqData := models.UeContextTransferReqData{ Reason: transferReason, @@ -260,13 +296,13 @@ func UEContextTransferRequest( return ueContextTransferRspData, problemDetails, err } -// This operation is called "RegistrationCompleteNotify" at TS 23.502 -func RegistrationStatusUpdate(ue *amf_context.AmfUe, request models.UeRegStatusUpdateReqData) ( +func (s *namfService) RegistrationStatusUpdate(ue *amf_context.AmfUe, request models.UeRegStatusUpdateReqData) ( regStatusTransferComplete bool, problemDetails *models.ProblemDetails, err error, ) { - configuration := Namf_Communication.NewConfiguration() - configuration.SetBasePath(ue.TargetAmfUri) - client := Namf_Communication.NewAPIClient(configuration) + client := s.getComClient(ue.TargetAmfUri) + if client == nil { + return false, nil, openapi.ReportError("amf not found") + } ueContextId := fmt.Sprintf("5g-guti-%s", ue.Guti) diff --git a/internal/sbi/consumer/ue_authentication.go b/internal/sbi/consumer/ausf_service.go similarity index 77% rename from internal/sbi/consumer/ue_authentication.go rename to internal/sbi/consumer/ausf_service.go index a5ea3c1f..63762256 100644 --- a/internal/sbi/consumer/ue_authentication.go +++ b/internal/sbi/consumer/ausf_service.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "strconv" + "sync" "github.com/antihax/optional" @@ -16,13 +17,43 @@ import ( "github.com/free5gc/openapi/models" ) -func SendUEAuthenticationAuthenticateRequest(ue *amf_context.AmfUe, - resynchronizationInfo *models.ResynchronizationInfo, -) (*models.UeAuthenticationCtx, *models.ProblemDetails, error) { +type nausfService struct { + consumer *Consumer + + UEAuthenticationMu sync.RWMutex + + UEAuthenticationClients map[string]*Nausf_UEAuthentication.APIClient +} + +func (s *nausfService) getUEAuthenticationClient(uri string) *Nausf_UEAuthentication.APIClient { + if uri == "" { + return nil + } + s.UEAuthenticationMu.RLock() + client, ok := s.UEAuthenticationClients[uri] + if ok { + s.UEAuthenticationMu.RUnlock() + return client + } + configuration := Nausf_UEAuthentication.NewConfiguration() - configuration.SetBasePath(ue.AusfUri) + configuration.SetBasePath(uri) + client = Nausf_UEAuthentication.NewAPIClient(configuration) + + s.UEAuthenticationMu.RUnlock() + s.UEAuthenticationMu.Lock() + defer s.UEAuthenticationMu.Unlock() + s.UEAuthenticationClients[uri] = client + return client +} - client := Nausf_UEAuthentication.NewAPIClient(configuration) +func (s *nausfService) SendUEAuthenticationAuthenticateRequest(ue *amf_context.AmfUe, + resynchronizationInfo *models.ResynchronizationInfo, +) (*models.UeAuthenticationCtx, *models.ProblemDetails, error) { + client := s.getUEAuthenticationClient(ue.AusfUri) + if client == nil { + return nil, nil, openapi.ReportError("ausf not found") + } amfSelf := amf_context.GetSelf() servedGuami := amfSelf.ServedGuamiList[0] @@ -64,7 +95,7 @@ func SendUEAuthenticationAuthenticateRequest(ue *amf_context.AmfUe, } } -func SendAuth5gAkaConfirmRequest(ue *amf_context.AmfUe, resStar string) ( +func (s *nausfService) SendAuth5gAkaConfirmRequest(ue *amf_context.AmfUe, resStar string) ( *models.ConfirmationDataResponse, *models.ProblemDetails, error, ) { var ausfUri string @@ -74,9 +105,10 @@ func SendAuth5gAkaConfirmRequest(ue *amf_context.AmfUe, resStar string) ( ausfUri = fmt.Sprintf("%s://%s", confirmUri.Scheme, confirmUri.Host) } - configuration := Nausf_UEAuthentication.NewConfiguration() - configuration.SetBasePath(ausfUri) - client := Nausf_UEAuthentication.NewAPIClient(configuration) + client := s.getUEAuthenticationClient(ausfUri) + if client == nil { + return nil, nil, openapi.ReportError("ausf not found") + } confirmData := &Nausf_UEAuthentication.UeAuthenticationsAuthCtxId5gAkaConfirmationPutParamOpts{ ConfirmationData: optional.NewInterface(models.ConfirmationData{ @@ -115,7 +147,7 @@ func SendAuth5gAkaConfirmRequest(ue *amf_context.AmfUe, resStar string) ( } } -func SendEapAuthConfirmRequest(ue *amf_context.AmfUe, eapMsg nasType.EAPMessage) ( +func (s *nausfService) SendEapAuthConfirmRequest(ue *amf_context.AmfUe, eapMsg nasType.EAPMessage) ( response *models.EapSession, problemDetails *models.ProblemDetails, err1 error, ) { confirmUri, err := url.Parse(ue.AuthenticationCtx.Links["eap-session"].Href) @@ -124,9 +156,10 @@ func SendEapAuthConfirmRequest(ue *amf_context.AmfUe, eapMsg nasType.EAPMessage) } ausfUri := fmt.Sprintf("%s://%s", confirmUri.Scheme, confirmUri.Host) - configuration := Nausf_UEAuthentication.NewConfiguration() - configuration.SetBasePath(ausfUri) - client := Nausf_UEAuthentication.NewAPIClient(configuration) + client := s.getUEAuthenticationClient(ausfUri) + if client == nil { + return nil, nil, openapi.ReportError("ausf not found") + } eapSessionReq := &Nausf_UEAuthentication.EapAuthMethodParamOpts{ EapSession: optional.NewInterface(models.EapSession{ diff --git a/internal/sbi/consumer/consumer.go b/internal/sbi/consumer/consumer.go new file mode 100644 index 00000000..7dfb4d3e --- /dev/null +++ b/internal/sbi/consumer/consumer.go @@ -0,0 +1,82 @@ +package consumer + +import ( + "github.com/free5gc/amf/pkg/app" + "github.com/free5gc/openapi/Namf_Communication" + "github.com/free5gc/openapi/Nausf_UEAuthentication" + "github.com/free5gc/openapi/Nnrf_NFDiscovery" + "github.com/free5gc/openapi/Nnrf_NFManagement" + "github.com/free5gc/openapi/Nnssf_NSSelection" + "github.com/free5gc/openapi/Npcf_AMPolicy" + "github.com/free5gc/openapi/Nsmf_PDUSession" + "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" + "github.com/free5gc/openapi/Nudm_UEContextManagement" +) + +var consumer *Consumer + +type ConsumerAmf interface { + app.App +} + +type Consumer struct { + ConsumerAmf + + // consumer services + *namfService + *nnrfService + *npcfService + *nssfService + *nsmfService + *nudmService + *nausfService +} + +func GetConsumer() *Consumer { + return consumer +} + +func NewConsumer(amf ConsumerAmf) (*Consumer, error) { + c := &Consumer{ + ConsumerAmf: amf, + } + + c.namfService = &namfService{ + consumer: c, + ComClients: make(map[string]*Namf_Communication.APIClient), + } + + c.nnrfService = &nnrfService{ + consumer: c, + nfMngmntClients: make(map[string]*Nnrf_NFManagement.APIClient), + nfDiscClients: make(map[string]*Nnrf_NFDiscovery.APIClient), + } + + c.npcfService = &npcfService{ + consumer: c, + AMPolicyClients: make(map[string]*Npcf_AMPolicy.APIClient), + } + + c.nssfService = &nssfService{ + consumer: c, + NSSelectionClients: make(map[string]*Nnssf_NSSelection.APIClient), + } + + c.nsmfService = &nsmfService{ + consumer: c, + PDUSessionClients: make(map[string]*Nsmf_PDUSession.APIClient), + } + + c.nudmService = &nudmService{ + consumer: c, + SubscriberDMngmntClients: make(map[string]*Nudm_SubscriberDataManagement.APIClient), + UEContextMngmntClients: make(map[string]*Nudm_UEContextManagement.APIClient), + } + + c.nausfService = &nausfService{ + consumer: c, + UEAuthenticationClients: make(map[string]*Nausf_UEAuthentication.APIClient), + } + consumer = c + return c, nil +} diff --git a/internal/sbi/consumer/nf_discovery.go b/internal/sbi/consumer/nf_discovery.go deleted file mode 100644 index 4db79828..00000000 --- a/internal/sbi/consumer/nf_discovery.go +++ /dev/null @@ -1,120 +0,0 @@ -package consumer - -import ( - "fmt" - "net/http" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/util" - "github.com/free5gc/openapi/Nnrf_NFDiscovery" - "github.com/free5gc/openapi/models" -) - -func SendSearchNFInstances(nrfUri string, targetNfType, requestNfType models.NfType, - param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, -) (*models.SearchResult, error) { - // Set client and set url - configuration := Nnrf_NFDiscovery.NewConfiguration() - configuration.SetBasePath(nrfUri) - client := Nnrf_NFDiscovery.NewAPIClient(configuration) - - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_DISC, models.NfType_NRF) - if err != nil { - return nil, err - } - - result, res, err := client.NFInstancesStoreApi.SearchNFInstances(ctx, targetNfType, requestNfType, param) - if res != nil && res.StatusCode == http.StatusTemporaryRedirect { - err = fmt.Errorf("Temporary Redirect For Non NRF Consumer") - } - if res == nil || res.Body == nil { - return &result, err - } - defer func() { - if res != nil { - if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil { - err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr) - } - } - }() - return &result, err -} - -func SearchUdmSdmInstance(ue *amf_context.AmfUe, nrfUri string, targetNfType, requestNfType models.NfType, - param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, -) error { - resp, localErr := SendSearchNFInstances(nrfUri, targetNfType, requestNfType, param) - if localErr != nil { - return localErr - } - - // select the first UDM_SDM, TODO: select base on other info - var sdmUri string - for _, nfProfile := range resp.NfInstances { - ue.UdmId = nfProfile.NfInstanceId - sdmUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NUDM_SDM, models.NfServiceStatus_REGISTERED) - if sdmUri != "" { - break - } - } - ue.NudmSDMUri = sdmUri - if ue.NudmSDMUri == "" { - err := fmt.Errorf("AMF can not select an UDM by NRF") - logger.ConsumerLog.Errorf(err.Error()) - return err - } - return nil -} - -func SearchNssfNSSelectionInstance(ue *amf_context.AmfUe, nrfUri string, targetNfType, requestNfType models.NfType, - param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, -) error { - resp, localErr := SendSearchNFInstances(nrfUri, targetNfType, requestNfType, param) - if localErr != nil { - return localErr - } - - // select the first NSSF, TODO: select base on other info - var nssfUri string - for _, nfProfile := range resp.NfInstances { - ue.NssfId = nfProfile.NfInstanceId - nssfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NNSSF_NSSELECTION, models.NfServiceStatus_REGISTERED) - if nssfUri != "" { - break - } - } - ue.NssfUri = nssfUri - if ue.NssfUri == "" { - return fmt.Errorf("AMF can not select an NSSF by NRF") - } - return nil -} - -func SearchAmfCommunicationInstance(ue *amf_context.AmfUe, nrfUri string, targetNfType, - requestNfType models.NfType, param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, -) (err error) { - resp, localErr := SendSearchNFInstances(nrfUri, targetNfType, requestNfType, param) - if localErr != nil { - err = localErr - return - } - - // select the first AMF, TODO: select base on other info - var amfUri string - for _, nfProfile := range resp.NfInstances { - if nfProfile.NfInstanceId == amf_context.GetSelf().NfId { - continue - } - ue.TargetAmfProfile = &nfProfile - amfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NAMF_COMM, models.NfServiceStatus_REGISTERED) - if amfUri != "" { - break - } - } - ue.TargetAmfUri = amfUri - if ue.TargetAmfUri == "" { - err = fmt.Errorf("AMF can not select an target AMF by NRF") - } - return -} diff --git a/internal/sbi/consumer/nf_mangement.go b/internal/sbi/consumer/nf_mangement.go deleted file mode 100644 index ea1bfd39..00000000 --- a/internal/sbi/consumer/nf_mangement.go +++ /dev/null @@ -1,165 +0,0 @@ -package consumer - -import ( - "context" - "fmt" - "net/http" - "strings" - "time" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/util" - "github.com/free5gc/amf/pkg/factory" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/Nnrf_NFManagement" - "github.com/free5gc/openapi/models" -) - -func BuildNFInstance(context *amf_context.AMFContext) (profile models.NfProfile, err error) { - profile.NfInstanceId = context.NfId - profile.NfType = models.NfType_AMF - profile.NfStatus = models.NfStatus_REGISTERED - var plmns []models.PlmnId - for _, plmnItem := range context.PlmnSupportList { - plmns = append(plmns, *plmnItem.PlmnId) - } - if len(plmns) > 0 { - profile.PlmnList = &plmns - // TODO: change to Per Plmn Support Snssai List - profile.SNssais = &context.PlmnSupportList[0].SNssaiList - } - amfInfo := models.AmfInfo{} - if len(context.ServedGuamiList) == 0 { - err = fmt.Errorf("Gumai List is Empty in AMF") - return profile, err - } - regionId, setId, _, err1 := util.SeperateAmfId(context.ServedGuamiList[0].AmfId) - if err1 != nil { - err = err1 - return profile, err - } - amfInfo.AmfRegionId = regionId - amfInfo.AmfSetId = setId - amfInfo.GuamiList = &context.ServedGuamiList - if len(context.SupportTaiLists) == 0 { - err = fmt.Errorf("SupportTaiList is Empty in AMF") - return profile, err - } - amfInfo.TaiList = &context.SupportTaiLists - profile.AmfInfo = &amfInfo - if context.RegisterIPv4 == "" { - err = fmt.Errorf("AMF Address is empty") - return profile, err - } - profile.Ipv4Addresses = append(profile.Ipv4Addresses, context.RegisterIPv4) - service := []models.NfService{} - for _, nfService := range context.NfService { - service = append(service, nfService) - } - if len(service) > 0 { - profile.NfServices = &service - } - - defaultNotificationSubscription := models.DefaultNotificationSubscription{ - CallbackUri: fmt.Sprintf("%s"+factory.AmfCallbackResUriPrefix+"/n1-message-notify", context.GetIPv4Uri()), - NotificationType: models.NotificationType_N1_MESSAGES, - N1MessageClass: models.N1MessageClass__5_GMM, - } - profile.DefaultNotificationSubscriptions = append(profile.DefaultNotificationSubscriptions, - defaultNotificationSubscription) - return profile, err -} - -func SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfile) ( - resouceNrfUri string, retrieveNfInstanceId string, err error, -) { - // Set client and set url - configuration := Nnrf_NFManagement.NewConfiguration() - configuration.SetBasePath(nrfUri) - client := Nnrf_NFManagement.NewAPIClient(configuration) - - var res *http.Response - var nf models.NfProfile - for { - nf, res, err = client.NFInstanceIDDocumentApi.RegisterNFInstance(context.TODO(), nfInstanceId, profile) - if err != nil || res == nil { - // TODO : add log - fmt.Println(fmt.Errorf("AMF register to NRF Error[%s]", err.Error())) - time.Sleep(2 * time.Second) - continue - } - defer func() { - if res != nil { - if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil { - err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr) - } - } - }() - status := res.StatusCode - if status == http.StatusOK { - // NFUpdate - break - } else if status == http.StatusCreated { - // NFRegister - resourceUri := res.Header.Get("Location") - resouceNrfUri = resourceUri[:strings.Index(resourceUri, "/nnrf-nfm/")] - retrieveNfInstanceId = resourceUri[strings.LastIndex(resourceUri, "/")+1:] - - oauth2 := false - if nf.CustomInfo != nil { - v, ok := nf.CustomInfo["oauth2"].(bool) - if ok { - oauth2 = v - logger.MainLog.Infoln("OAuth2 setting receive from NRF:", oauth2) - } - } - amf_context.GetSelf().OAuth2Required = oauth2 - if oauth2 && amf_context.GetSelf().NrfCertPem == "" { - logger.CfgLog.Error("OAuth2 enable but no nrfCertPem provided in config.") - } - - break - } else { - fmt.Println(fmt.Errorf("handler returned wrong status code %d", status)) - fmt.Println(fmt.Errorf("NRF return wrong status code %d", status)) - } - } - return resouceNrfUri, retrieveNfInstanceId, err -} - -func SendDeregisterNFInstance() (problemDetails *models.ProblemDetails, err error) { - logger.ConsumerLog.Infof("[AMF] Send Deregister NFInstance") - - ctx, pd, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_NFM, models.NfType_NRF) - if err != nil { - return pd, err - } - - amfSelf := amf_context.GetSelf() - // Set client and set url - configuration := Nnrf_NFManagement.NewConfiguration() - configuration.SetBasePath(amfSelf.NrfUri) - client := Nnrf_NFManagement.NewAPIClient(configuration) - - var res *http.Response - - res, err = client.NFInstanceIDDocumentApi.DeregisterNFInstance(ctx, amfSelf.NfId) - if err == nil { - return problemDetails, err - } else if res != nil { - defer func() { - if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil { - err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr) - } - }() - if res.Status != err.Error() { - return problemDetails, err - } - problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - problemDetails = &problem - } else { - err = openapi.ReportError("server no response") - } - return problemDetails, err -} diff --git a/internal/sbi/consumer/nrf_service.go b/internal/sbi/consumer/nrf_service.go new file mode 100644 index 00000000..ddf1bab8 --- /dev/null +++ b/internal/sbi/consumer/nrf_service.go @@ -0,0 +1,337 @@ +package consumer + +import ( + "context" + "fmt" + "net/http" + "strings" + "sync" + "time" + + amf_context "github.com/free5gc/amf/internal/context" + "github.com/free5gc/amf/internal/logger" + "github.com/free5gc/amf/internal/util" + "github.com/free5gc/amf/pkg/factory" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/Nnrf_NFDiscovery" + "github.com/free5gc/openapi/Nnrf_NFManagement" + "github.com/free5gc/openapi/models" +) + +type nnrfService struct { + consumer *Consumer + + nfMngmntMu sync.RWMutex + nfDiscMu sync.RWMutex + + nfMngmntClients map[string]*Nnrf_NFManagement.APIClient + nfDiscClients map[string]*Nnrf_NFDiscovery.APIClient +} + +func (s *nnrfService) getNFManagementClient(uri string) *Nnrf_NFManagement.APIClient { + if uri == "" { + return nil + } + s.nfMngmntMu.RLock() + client, ok := s.nfMngmntClients[uri] + if ok { + s.nfMngmntMu.RUnlock() + return client + } + + configuration := Nnrf_NFManagement.NewConfiguration() + configuration.SetBasePath(uri) + client = Nnrf_NFManagement.NewAPIClient(configuration) + + s.nfMngmntMu.RUnlock() + s.nfMngmntMu.Lock() + defer s.nfMngmntMu.Unlock() + s.nfMngmntClients[uri] = client + return client +} + +func (s *nnrfService) getNFDiscClient(uri string) *Nnrf_NFDiscovery.APIClient { + if uri == "" { + return nil + } + s.nfDiscMu.RLock() + client, ok := s.nfDiscClients[uri] + if ok { + s.nfDiscMu.RUnlock() + return client + } + + configuration := Nnrf_NFDiscovery.NewConfiguration() + configuration.SetBasePath(uri) + client = Nnrf_NFDiscovery.NewAPIClient(configuration) + + s.nfDiscMu.RUnlock() + s.nfDiscMu.Lock() + defer s.nfDiscMu.Unlock() + s.nfDiscClients[uri] = client + return client +} + +func (s *nnrfService) SendSearchNFInstances(nrfUri string, targetNfType, requestNfType models.NfType, + param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, +) (*models.SearchResult, error) { + // Set client and set url + client := s.getNFDiscClient(nrfUri) + if client == nil { + return nil, openapi.ReportError("nrf not found") + } + + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_DISC, models.NfType_NRF) + if err != nil { + return nil, err + } + + result, res, err := client.NFInstancesStoreApi.SearchNFInstances(ctx, targetNfType, requestNfType, param) + if res != nil && res.StatusCode == http.StatusTemporaryRedirect { + return nil, fmt.Errorf("temporary Redirect For Non NRF Consumer") + } + if res == nil || res.Body == nil { + return &result, err + } + defer func() { + if res != nil { + if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil { + err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr) + } + } + }() + return &result, err +} + +func (s *nnrfService) SearchUdmSdmInstance( + ue *amf_context.AmfUe, nrfUri string, targetNfType, requestNfType models.NfType, + param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, +) error { + resp, localErr := s.SendSearchNFInstances(nrfUri, targetNfType, requestNfType, param) + if localErr != nil { + return localErr + } + + // select the first UDM_SDM, TODO: select base on other info + var sdmUri string + for _, nfProfile := range resp.NfInstances { + ue.UdmId = nfProfile.NfInstanceId + sdmUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NUDM_SDM, models.NfServiceStatus_REGISTERED) + if sdmUri != "" { + break + } + } + ue.NudmSDMUri = sdmUri + if ue.NudmSDMUri == "" { + err := fmt.Errorf("AMF can not select an UDM by NRF") + logger.ConsumerLog.Errorf(err.Error()) + return err + } + return nil +} + +func (s *nnrfService) SearchNssfNSSelectionInstance( + ue *amf_context.AmfUe, nrfUri string, targetNfType, requestNfType models.NfType, + param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, +) error { + resp, localErr := s.SendSearchNFInstances(nrfUri, targetNfType, requestNfType, param) + if localErr != nil { + return localErr + } + + // select the first NSSF, TODO: select base on other info + var nssfUri string + for _, nfProfile := range resp.NfInstances { + ue.NssfId = nfProfile.NfInstanceId + nssfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NNSSF_NSSELECTION, models.NfServiceStatus_REGISTERED) + if nssfUri != "" { + break + } + } + ue.NssfUri = nssfUri + if ue.NssfUri == "" { + return fmt.Errorf("AMF can not select an NSSF by NRF") + } + return nil +} + +func (s *nnrfService) SearchAmfCommunicationInstance(ue *amf_context.AmfUe, nrfUri string, targetNfType, + requestNfType models.NfType, param *Nnrf_NFDiscovery.SearchNFInstancesParamOpts, +) (err error) { + resp, localErr := s.SendSearchNFInstances(nrfUri, targetNfType, requestNfType, param) + if localErr != nil { + err = localErr + return + } + + // select the first AMF, TODO: select base on other info + var amfUri string + for _, nfProfile := range resp.NfInstances { + if nfProfile.NfInstanceId == amf_context.GetSelf().NfId { + continue + } + ue.TargetAmfProfile = &nfProfile + amfUri = util.SearchNFServiceUri(nfProfile, models.ServiceName_NAMF_COMM, models.NfServiceStatus_REGISTERED) + if amfUri != "" { + break + } + } + ue.TargetAmfUri = amfUri + if ue.TargetAmfUri == "" { + err = fmt.Errorf("AMF can not select an target AMF by NRF") + } + return +} + +func (s *nnrfService) BuildNFInstance(context *amf_context.AMFContext) (profile models.NfProfile, err error) { + profile.NfInstanceId = context.NfId + profile.NfType = models.NfType_AMF + profile.NfStatus = models.NfStatus_REGISTERED + var plmns []models.PlmnId + for _, plmnItem := range context.PlmnSupportList { + plmns = append(plmns, *plmnItem.PlmnId) + } + if len(plmns) > 0 { + profile.PlmnList = &plmns + // TODO: change to Per Plmn Support Snssai List + profile.SNssais = &context.PlmnSupportList[0].SNssaiList + } + amfInfo := models.AmfInfo{} + if len(context.ServedGuamiList) == 0 { + err = fmt.Errorf("gumai List is Empty in AMF") + return profile, err + } + regionId, setId, _, err1 := util.SeperateAmfId(context.ServedGuamiList[0].AmfId) + if err1 != nil { + err = err1 + return profile, err + } + amfInfo.AmfRegionId = regionId + amfInfo.AmfSetId = setId + amfInfo.GuamiList = &context.ServedGuamiList + if len(context.SupportTaiLists) == 0 { + err = fmt.Errorf("SupportTaiList is Empty in AMF") + return profile, err + } + amfInfo.TaiList = &context.SupportTaiLists + profile.AmfInfo = &amfInfo + if context.RegisterIPv4 == "" { + err = fmt.Errorf("AMF Address is empty") + return profile, err + } + profile.Ipv4Addresses = append(profile.Ipv4Addresses, context.RegisterIPv4) + service := []models.NfService{} + for _, nfService := range context.NfService { + service = append(service, nfService) + } + if len(service) > 0 { + profile.NfServices = &service + } + + defaultNotificationSubscription := models.DefaultNotificationSubscription{ + CallbackUri: fmt.Sprintf("%s"+factory.AmfCallbackResUriPrefix+"/n1-message-notify", context.GetIPv4Uri()), + NotificationType: models.NotificationType_N1_MESSAGES, + N1MessageClass: models.N1MessageClass__5_GMM, + } + profile.DefaultNotificationSubscriptions = append(profile.DefaultNotificationSubscriptions, + defaultNotificationSubscription) + return profile, err +} + +func (s *nnrfService) SendRegisterNFInstance(nrfUri, nfInstanceId string, profile models.NfProfile) ( + resouceNrfUri string, retrieveNfInstanceId string, err error, +) { + // Set client and set url + client := s.getNFManagementClient(nrfUri) + if client == nil { + return "", "", openapi.ReportError("nrf not found") + } + + var res *http.Response + var nf models.NfProfile + for { + nf, res, err = client.NFInstanceIDDocumentApi.RegisterNFInstance(context.TODO(), nfInstanceId, profile) + if err != nil || res == nil { + // TODO : add log + fmt.Println(fmt.Errorf("AMF register to NRF Error[%s]", err.Error())) + time.Sleep(2 * time.Second) + continue + } + defer func() { + if res != nil { + if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil { + err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr) + } + } + }() + status := res.StatusCode + if status == http.StatusOK { + // NFUpdate + break + } else if status == http.StatusCreated { + // NFRegister + resourceUri := res.Header.Get("Location") + index := strings.Index(resourceUri, "/nnrf-nfm/") + if index >= 0 { + resouceNrfUri = resourceUri[:index] + } + // resouceNrfUri = resourceUri[:strings.Index(resourceUri, "/nnrf-nfm/")] + retrieveNfInstanceId = resourceUri[strings.LastIndex(resourceUri, "/")+1:] + + oauth2 := false + if nf.CustomInfo != nil { + v, ok := nf.CustomInfo["oauth2"].(bool) + if ok { + oauth2 = v + logger.MainLog.Infoln("OAuth2 setting receive from NRF:", oauth2) + } + } + amf_context.GetSelf().OAuth2Required = oauth2 + if oauth2 && amf_context.GetSelf().NrfCertPem == "" { + logger.CfgLog.Error("OAuth2 enable but no nrfCertPem provided in config.") + } + + break + } else { + fmt.Println(fmt.Errorf("handler returned wrong status code %d", status)) + fmt.Println(fmt.Errorf("NRF return wrong status code %d", status)) + } + } + return resouceNrfUri, retrieveNfInstanceId, err +} + +func (s *nnrfService) SendDeregisterNFInstance() (problemDetails *models.ProblemDetails, err error) { + logger.ConsumerLog.Infof("[AMF] Send Deregister NFInstance") + amfContext := s.consumer.Context() + + client := s.getNFManagementClient(amfContext.NrfUri) + if client == nil { + return nil, openapi.ReportError("nrf not found") + } + + ctx, pd, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NNRF_NFM, models.NfType_NRF) + if err != nil { + return pd, err + } + + var res *http.Response + + res, err = client.NFInstanceIDDocumentApi.DeregisterNFInstance(ctx, amfContext.NfId) + if err == nil { + return problemDetails, err + } else if res != nil { + defer func() { + if bodyCloseErr := res.Body.Close(); bodyCloseErr != nil { + err = fmt.Errorf("SearchNFInstances' response body cannot close: %+w", bodyCloseErr) + } + }() + if res.Status != err.Error() { + return problemDetails, err + } + problem := err.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + return problemDetails, err +} diff --git a/internal/sbi/consumer/nsselection.go b/internal/sbi/consumer/nssf_service.go similarity index 64% rename from internal/sbi/consumer/nsselection.go rename to internal/sbi/consumer/nssf_service.go index 65c8b3a8..dac7f967 100644 --- a/internal/sbi/consumer/nsselection.go +++ b/internal/sbi/consumer/nssf_service.go @@ -2,6 +2,7 @@ package consumer import ( "encoding/json" + "sync" "github.com/antihax/optional" @@ -12,12 +13,43 @@ import ( "github.com/free5gc/openapi/models" ) -func NSSelectionGetForRegistration(ue *amf_context.AmfUe, requestedNssai []models.MappingOfSnssai) ( +type nssfService struct { + consumer *Consumer + + NSSelectionMu sync.RWMutex + + NSSelectionClients map[string]*Nnssf_NSSelection.APIClient +} + +func (s *nssfService) getNSSelectionClient(uri string) *Nnssf_NSSelection.APIClient { + if uri == "" { + return nil + } + s.NSSelectionMu.RLock() + client, ok := s.NSSelectionClients[uri] + if ok { + s.NSSelectionMu.RUnlock() + return client + } + + configuration := Nnssf_NSSelection.NewConfiguration() + configuration.SetBasePath(uri) + client = Nnssf_NSSelection.NewAPIClient(configuration) + + s.NSSelectionMu.RUnlock() + s.NSSelectionMu.Lock() + defer s.NSSelectionMu.Unlock() + s.NSSelectionClients[uri] = client + return client +} + +func (s *nssfService) NSSelectionGetForRegistration(ue *amf_context.AmfUe, requestedNssai []models.MappingOfSnssai) ( *models.ProblemDetails, error, ) { - configuration := Nnssf_NSSelection.NewConfiguration() - configuration.SetBasePath(ue.NssfUri) - client := Nnssf_NSSelection.NewAPIClient(configuration) + client := s.getNSSelectionClient(ue.NssfUri) + if client == nil { + return nil, openapi.ReportError("nssf not found") + } amfSelf := amf_context.GetSelf() ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NNSSF_NSSELECTION, models.NfType_NSSF) @@ -36,11 +68,16 @@ func NSSelectionGetForRegistration(ue *amf_context.AmfUe, requestedNssai []model } var paramOpt Nnssf_NSSelection.NSSelectionGetParamOpts - if e, err := json.Marshal(sliceInfo); err != nil { - logger.ConsumerLog.Warnf("json marshal failed: %+v", err) + if e, errsliceinfo := json.Marshal(sliceInfo); errsliceinfo != nil { + logger.ConsumerLog.Warnf("slice json marshal failed: %+v", errsliceinfo) } else { + tai, taierr := json.Marshal(ue.Tai) + if taierr != nil { + logger.ConsumerLog.Warnf("tai json marshal failed: %+v", taierr) + } paramOpt = Nnssf_NSSelection.NSSelectionGetParamOpts{ SliceInfoRequestForRegistration: optional.NewInterface(string(e)), + Tai: optional.NewInterface(string(tai)), // TS 29.531 R15.3 6.1.3.2.3.1 } } @@ -62,8 +99,8 @@ func NSSelectionGetForRegistration(ue *amf_context.AmfUe, requestedNssai []model ue.ConfiguredNssai = res.ConfiguredNssai } else if httpResp != nil { if httpResp.Status != localErr.Error() { - err := localErr - return nil, err + errlocal := localErr + return nil, errlocal } problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) return &problem, nil @@ -74,12 +111,13 @@ func NSSelectionGetForRegistration(ue *amf_context.AmfUe, requestedNssai []model return nil, nil } -func NSSelectionGetForPduSession(ue *amf_context.AmfUe, snssai models.Snssai) ( +func (s *nssfService) NSSelectionGetForPduSession(ue *amf_context.AmfUe, snssai models.Snssai) ( *models.AuthorizedNetworkSliceInfo, *models.ProblemDetails, error, ) { - configuration := Nnssf_NSSelection.NewConfiguration() - configuration.SetBasePath(ue.NssfUri) - client := Nnssf_NSSelection.NewAPIClient(configuration) + client := s.getNSSelectionClient(ue.NssfUri) + if client == nil { + return nil, nil, openapi.ReportError("nssf not found") + } amfSelf := amf_context.GetSelf() sliceInfoForPduSession := models.SliceInfoForPduSession{ @@ -89,11 +127,17 @@ func NSSelectionGetForPduSession(ue *amf_context.AmfUe, snssai models.Snssai) ( e, err := json.Marshal(sliceInfoForPduSession) if err != nil { - logger.ConsumerLog.Warnf("json marshal failed: %+v", err) + logger.ConsumerLog.Warnf("slice json marshal failed: %+v", err) + } + tai, taierr := json.Marshal(ue.Tai) + if taierr != nil { + logger.ConsumerLog.Warnf("tai json marshal failed: %+v", taierr) } paramOpt := Nnssf_NSSelection.NSSelectionGetParamOpts{ SliceInfoRequestForPduSession: optional.NewInterface(string(e)), + Tai: optional.NewInterface(string(tai)), // TS 29.531 R15.3 6.1.3.2.3.1 } + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NNSSF_NSSELECTION, models.NfType_NSSF) if err != nil { return nil, nil, err diff --git a/internal/sbi/consumer/am_policy.go b/internal/sbi/consumer/pcf_service.go similarity index 76% rename from internal/sbi/consumer/am_policy.go rename to internal/sbi/consumer/pcf_service.go index 6ea83b66..a22c4b2e 100644 --- a/internal/sbi/consumer/am_policy.go +++ b/internal/sbi/consumer/pcf_service.go @@ -2,6 +2,7 @@ package consumer import ( "regexp" + "sync" amf_context "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" @@ -11,11 +12,43 @@ import ( "github.com/free5gc/openapi/models" ) -func AMPolicyControlCreate(ue *amf_context.AmfUe, anType models.AccessType) (*models.ProblemDetails, error) { +type npcfService struct { + consumer *Consumer + + AMPolicyMu sync.RWMutex + + AMPolicyClients map[string]*Npcf_AMPolicy.APIClient +} + +func (s *npcfService) getAMPolicyClient(uri string) *Npcf_AMPolicy.APIClient { + if uri == "" { + return nil + } + s.AMPolicyMu.RLock() + client, ok := s.AMPolicyClients[uri] + if ok { + s.AMPolicyMu.RUnlock() + return client + } + configuration := Npcf_AMPolicy.NewConfiguration() - configuration.SetBasePath(ue.PcfUri) - client := Npcf_AMPolicy.NewAPIClient(configuration) + configuration.SetBasePath(uri) + client = Npcf_AMPolicy.NewAPIClient(configuration) + + s.AMPolicyMu.RUnlock() + s.AMPolicyMu.Lock() + defer s.AMPolicyMu.Unlock() + s.AMPolicyClients[uri] = client + return client +} +func (s *npcfService) AMPolicyControlCreate( + ue *amf_context.AmfUe, anType models.AccessType, +) (*models.ProblemDetails, error) { + client := s.getAMPolicyClient(ue.PcfUri) + if client == nil { + return nil, openapi.ReportError("pcf not found") + } amfSelf := amf_context.GetSelf() ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NPCF_AM_POLICY_CONTROL, models.NfType_PCF) if err != nil { @@ -63,9 +96,9 @@ func AMPolicyControlCreate(ue *amf_context.AmfUe, anType models.AccessType) (*mo if trigger == models.RequestTrigger_LOC_CH { ue.RequestTriggerLocationChange = true } - //if trigger == models.RequestTrigger_PRA_CH { + // if trigger == models.RequestTrigger_PRA_CH { // TODO: Presence Reporting Area handling (TS 23.503 6.1.2.5, TS 23.501 5.6.11) - //} + // } } } @@ -83,12 +116,14 @@ func AMPolicyControlCreate(ue *amf_context.AmfUe, anType models.AccessType) (*mo return nil, nil } -func AMPolicyControlUpdate(ue *amf_context.AmfUe, updateRequest models.PolicyAssociationUpdateRequest) ( - problemDetails *models.ProblemDetails, err error, -) { - configuration := Npcf_AMPolicy.NewConfiguration() - configuration.SetBasePath(ue.PcfUri) - client := Npcf_AMPolicy.NewAPIClient(configuration) +func (s *npcfService) AMPolicyControlUpdate( + ue *amf_context.AmfUe, updateRequest models.PolicyAssociationUpdateRequest, +) (problemDetails *models.ProblemDetails, err error) { + client := s.getAMPolicyClient(ue.PcfUri) + if client == nil { + return nil, openapi.ReportError("pcf not found") + } + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NPCF_AM_POLICY_CONTROL, models.NfType_PCF) if err != nil { return nil, err @@ -135,10 +170,12 @@ func AMPolicyControlUpdate(ue *amf_context.AmfUe, updateRequest models.PolicyAss return problemDetails, err } -func AMPolicyControlDelete(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { - configuration := Npcf_AMPolicy.NewConfiguration() - configuration.SetBasePath(ue.PcfUri) - client := Npcf_AMPolicy.NewAPIClient(configuration) +func (s *npcfService) AMPolicyControlDelete(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { + client := s.getAMPolicyClient(ue.PcfUri) + if client == nil { + return nil, openapi.ReportError("pcf not found") + } + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NPCF_AM_POLICY_CONTROL, models.NfType_PCF) if err != nil { return nil, err diff --git a/internal/sbi/consumer/sm_context.go b/internal/sbi/consumer/smf_service.go similarity index 79% rename from internal/sbi/consumer/sm_context.go rename to internal/sbi/consumer/smf_service.go index bbd5c4ba..1f295fe4 100644 --- a/internal/sbi/consumer/sm_context.go +++ b/internal/sbi/consumer/smf_service.go @@ -4,6 +4,7 @@ import ( "fmt" "net/url" "strconv" + "sync" "time" "github.com/antihax/optional" @@ -19,7 +20,39 @@ import ( "github.com/free5gc/openapi/models" ) -func SelectSmf( +var n2sminfocon = "N2SmInfo" + +type nsmfService struct { + consumer *Consumer + + PDUSessionMu sync.RWMutex + + PDUSessionClients map[string]*Nsmf_PDUSession.APIClient +} + +func (s *nsmfService) getPDUSessionClient(uri string) *Nsmf_PDUSession.APIClient { + if uri == "" { + return nil + } + s.PDUSessionMu.RLock() + client, ok := s.PDUSessionClients[uri] + if ok { + s.PDUSessionMu.RUnlock() + return client + } + + configuration := Nsmf_PDUSession.NewConfiguration() + configuration.SetBasePath(uri) + client = Nsmf_PDUSession.NewAPIClient(configuration) + + s.PDUSessionMu.RUnlock() + s.PDUSessionMu.Lock() + defer s.PDUSessionMu.Unlock() + s.PDUSessionClients[uri] = client + return client +} + +func (s *nsmfService) SelectSmf( ue *amf_context.AmfUe, anType models.AccessType, pduSessionID int32, @@ -40,7 +73,7 @@ func SelectSmf( if ue.NssfUri == "" { // TODO: Set a timeout of NSSF Selection or will starvation here for { - if err := SearchNssfNSSelectionInstance(ue, nrfUri, models.NfType_NSSF, + if err := s.consumer.SearchNssfNSSelectionInstance(ue, nrfUri, models.NfType_NSSF, models.NfType_AMF, nil); err != nil { ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", err) time.Sleep(2 * time.Second) @@ -50,7 +83,7 @@ func SelectSmf( } } - response, problemDetails, err := NSSelectionGetForPduSession(ue, snssai) + response, problemDetails, err := s.consumer.NSSelectionGetForPduSession(ue, snssai) if err != nil { err = fmt.Errorf("NSSelection Get Error[%+v]", err) return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err @@ -92,7 +125,7 @@ func SelectSmf( ue.GmmLog.Debugf("Search SMF from NRF[%s]", nrfUri) - result, err := SendSearchNFInstances(nrfUri, models.NfType_SMF, models.NfType_AMF, ¶m) + result, err := s.consumer.SendSearchNFInstances(nrfUri, models.NfType_SMF, models.NfType_AMF, ¶m) if err != nil { return nil, nasMessage.Cause5GMMPayloadWasNotForwarded, err } @@ -114,21 +147,23 @@ func SelectSmf( return smContext, 0, nil } -func SendCreateSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.SmContext, +func (s *nsmfService) SendCreateSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.SmContext, requestType *models.RequestType, nasPdu []byte) ( response *models.PostSmContextsResponse, smContextRef string, errorResponse *models.PostSmContextsErrorResponse, problemDetail *models.ProblemDetails, err1 error, ) { - smContextCreateData := buildCreateSmContextRequest(ue, smContext, nil) + smContextCreateData := s.buildCreateSmContextRequest(ue, smContext, nil) postSmContextsRequest := models.PostSmContextsRequest{ JsonData: &smContextCreateData, BinaryDataN1SmMessage: nasPdu, } - configuration := Nsmf_PDUSession.NewConfiguration() - configuration.SetBasePath(smContext.SmfUri()) - client := Nsmf_PDUSession.NewAPIClient(configuration) + client := s.getPDUSessionClient(smContext.SmfUri()) + if client == nil { + return nil, "", nil, nil, openapi.ReportError("smf not found") + } + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NSMF_PDUSESSION, models.NfType_SMF) if err != nil { return nil, "", nil, nil, err @@ -165,7 +200,7 @@ func SendCreateSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.Sm return response, smContextRef, errorResponse, problemDetail, err1 } -func buildCreateSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.SmContext, +func (s *nsmfService) buildCreateSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.SmContext, requestType *models.RequestType, ) (smContextCreateData models.SmContextCreateData) { context := amf_context.GetSelf() @@ -217,7 +252,7 @@ func buildCreateSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.S // a Downlink NAS Transport message carrying 5GSM payload // anTypeCanBeChanged -func SendUpdateSmContextActivateUpCnxState( +func (s *nsmfService) SendUpdateSmContextActivateUpCnxState( ue *amf_context.AmfUe, smContext *amf_context.SmContext, accessType models.AccessType) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { @@ -234,10 +269,10 @@ func SendUpdateSmContextActivateUpCnxState( updateData.PresenceInLadn = models.PresenceState_IN_AREA } } - return SendUpdateSmContextRequest(smContext, updateData, nil, nil) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, nil) } -func SendUpdateSmContextDeactivateUpCnxState(ue *amf_context.AmfUe, +func (s *nsmfService) SendUpdateSmContextDeactivateUpCnxState(ue *amf_context.AmfUe, smContext *amf_context.SmContext, cause amf_context.CauseAll) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { @@ -253,39 +288,39 @@ func SendUpdateSmContextDeactivateUpCnxState(ue *amf_context.AmfUe, if cause.Var5GmmCause != nil { updateData.Var5gMmCauseValue = *cause.Var5GmmCause } - return SendUpdateSmContextRequest(smContext, updateData, nil, nil) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, nil) } -func SendUpdateSmContextChangeAccessType(ue *amf_context.AmfUe, +func (s *nsmfService) SendUpdateSmContextChangeAccessType(ue *amf_context.AmfUe, smContext *amf_context.SmContext, anTypeCanBeChanged bool) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { updateData := models.SmContextUpdateData{} updateData.AnTypeCanBeChanged = anTypeCanBeChanged - return SendUpdateSmContextRequest(smContext, updateData, nil, nil) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, nil) } -func SendUpdateSmContextN2Info( - ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, N2SmInfo []byte) ( +func (s *nsmfService) SendUpdateSmContextN2Info( + ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, n2SmInfo []byte) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { updateData := models.SmContextUpdateData{} updateData.N2SmInfoType = n2SmType updateData.N2SmInfo = new(models.RefToBinaryData) - updateData.N2SmInfo.ContentId = "N2SmInfo" + updateData.N2SmInfo.ContentId = n2sminfocon updateData.UeLocation = &ue.Location - return SendUpdateSmContextRequest(smContext, updateData, nil, N2SmInfo) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, n2SmInfo) } -func SendUpdateSmContextXnHandover( - ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, N2SmInfo []byte) ( +func (s *nsmfService) SendUpdateSmContextXnHandover( + ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, n2SmInfo []byte) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { updateData := models.SmContextUpdateData{} if n2SmType != "" { updateData.N2SmInfoType = n2SmType updateData.N2SmInfo = new(models.RefToBinaryData) - updateData.N2SmInfo.ContentId = "N2SmInfo" + updateData.N2SmInfo.ContentId = n2sminfocon } updateData.ToBeSwitched = true updateData.UeLocation = &ue.Location @@ -296,35 +331,35 @@ func SendUpdateSmContextXnHandover( updateData.PresenceInLadn = models.PresenceState_OUT_OF_AREA } } - return SendUpdateSmContextRequest(smContext, updateData, nil, N2SmInfo) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, n2SmInfo) } -func SendUpdateSmContextXnHandoverFailed( - ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, N2SmInfo []byte) ( +func (s *nsmfService) SendUpdateSmContextXnHandoverFailed( + ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, n2SmInfo []byte) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { updateData := models.SmContextUpdateData{} if n2SmType != "" { updateData.N2SmInfoType = n2SmType updateData.N2SmInfo = new(models.RefToBinaryData) - updateData.N2SmInfo.ContentId = "N2SmInfo" + updateData.N2SmInfo.ContentId = n2sminfocon } updateData.FailedToBeSwitched = true - return SendUpdateSmContextRequest(smContext, updateData, nil, N2SmInfo) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, n2SmInfo) } -func SendUpdateSmContextN2HandoverPreparing( +func (s *nsmfService) SendUpdateSmContextN2HandoverPreparing( ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, - N2SmInfo []byte, amfid string, targetId *models.NgRanTargetId) ( + n2SmInfo []byte, amfid string, targetId *models.NgRanTargetId) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { updateData := models.SmContextUpdateData{} if n2SmType != "" { updateData.N2SmInfoType = n2SmType updateData.N2SmInfo = new(models.RefToBinaryData) - updateData.N2SmInfo.ContentId = "N2SmInfo" + updateData.N2SmInfo.ContentId = n2sminfocon } updateData.HoState = models.HoState_PREPARING updateData.TargetId = targetId @@ -332,24 +367,24 @@ func SendUpdateSmContextN2HandoverPreparing( if amfid != "" { updateData.TargetServingNfId = amfid } - return SendUpdateSmContextRequest(smContext, updateData, nil, N2SmInfo) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, n2SmInfo) } -func SendUpdateSmContextN2HandoverPrepared( - ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, N2SmInfo []byte) ( +func (s *nsmfService) SendUpdateSmContextN2HandoverPrepared( + ue *amf_context.AmfUe, smContext *amf_context.SmContext, n2SmType models.N2SmInfoType, n2SmInfo []byte) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { updateData := models.SmContextUpdateData{} if n2SmType != "" { updateData.N2SmInfoType = n2SmType updateData.N2SmInfo = new(models.RefToBinaryData) - updateData.N2SmInfo.ContentId = "N2SmInfo" + updateData.N2SmInfo.ContentId = n2sminfocon } updateData.HoState = models.HoState_PREPARED - return SendUpdateSmContextRequest(smContext, updateData, nil, N2SmInfo) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, n2SmInfo) } -func SendUpdateSmContextN2HandoverComplete( +func (s *nsmfService) SendUpdateSmContextN2HandoverComplete( ue *amf_context.AmfUe, smContext *amf_context.SmContext, amfid string, guami *models.Guami) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { @@ -367,14 +402,15 @@ func SendUpdateSmContextN2HandoverComplete( updateData.PresenceInLadn = models.PresenceState_OUT_OF_AREA } } - return SendUpdateSmContextRequest(smContext, updateData, nil, nil) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, nil) } -func SendUpdateSmContextN2HandoverCanceled(ue *amf_context.AmfUe, +func (s *nsmfService) SendUpdateSmContextN2HandoverCanceled(ue *amf_context.AmfUe, smContext *amf_context.SmContext, cause amf_context.CauseAll) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { updateData := models.SmContextUpdateData{} + // nolint openapi/model misspelling updateData.HoState = models.HoState_CANCELLED if cause.Cause != nil { updateData.Cause = *cause.Cause @@ -385,23 +421,23 @@ func SendUpdateSmContextN2HandoverCanceled(ue *amf_context.AmfUe, if cause.Var5GmmCause != nil { updateData.Var5gMmCauseValue = *cause.Var5GmmCause } - return SendUpdateSmContextRequest(smContext, updateData, nil, nil) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, nil) } -func SendUpdateSmContextHandoverBetweenAccessType( - ue *amf_context.AmfUe, smContext *amf_context.SmContext, targetAccessType models.AccessType, N1SmMsg []byte) ( +func (s *nsmfService) SendUpdateSmContextHandoverBetweenAccessType( + ue *amf_context.AmfUe, smContext *amf_context.SmContext, targetAccessType models.AccessType, n1SmMsg []byte) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { updateData := models.SmContextUpdateData{} updateData.AnType = targetAccessType - if N1SmMsg != nil { + if n1SmMsg != nil { updateData.N1SmMsg = new(models.RefToBinaryData) updateData.N1SmMsg.ContentId = "N1Msg" } - return SendUpdateSmContextRequest(smContext, updateData, N1SmMsg, nil) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, n1SmMsg, nil) } -func SendUpdateSmContextHandoverBetweenAMF( +func (s *nsmfService) SendUpdateSmContextHandoverBetweenAMF( ue *amf_context.AmfUe, smContext *amf_context.SmContext, amfid string, guami *models.Guami, activate bool) ( *models.UpdateSmContextResponse, *models.UpdateSmContextErrorResponse, *models.ProblemDetails, error, ) { @@ -420,17 +456,18 @@ func SendUpdateSmContextHandoverBetweenAMF( } } } - return SendUpdateSmContextRequest(smContext, updateData, nil, nil) + return s.consumer.SendUpdateSmContextRequest(smContext, updateData, nil, nil) } -func SendUpdateSmContextRequest(smContext *amf_context.SmContext, +func (s *nsmfService) SendUpdateSmContextRequest(smContext *amf_context.SmContext, updateData models.SmContextUpdateData, n1Msg []byte, n2Info []byte) ( response *models.UpdateSmContextResponse, errorResponse *models.UpdateSmContextErrorResponse, problemDetail *models.ProblemDetails, err1 error, ) { - configuration := Nsmf_PDUSession.NewConfiguration() - configuration.SetBasePath(smContext.SmfUri()) - client := Nsmf_PDUSession.NewAPIClient(configuration) + client := s.getPDUSessionClient(smContext.SmfUri()) + if client == nil { + return nil, nil, nil, openapi.ReportError("smf not found") + } var updateSmContextRequest models.UpdateSmContextRequest updateSmContextRequest.JsonData = &updateData @@ -475,15 +512,16 @@ func SendUpdateSmContextRequest(smContext *amf_context.SmContext, // Release SmContext Request -func SendReleaseSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.SmContext, +func (s *nsmfService) SendReleaseSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.SmContext, cause *amf_context.CauseAll, n2SmInfoType models.N2SmInfoType, n2Info []byte, ) (detail *models.ProblemDetails, err error) { - configuration := Nsmf_PDUSession.NewConfiguration() - configuration.SetBasePath(smContext.SmfUri()) - client := Nsmf_PDUSession.NewAPIClient(configuration) + client := s.getPDUSessionClient(smContext.SmfUri()) + if client == nil { + return nil, openapi.ReportError("smf not found") + } - releaseData := buildReleaseSmContextRequest(ue, cause, n2SmInfoType, n2Info) + releaseData := s.buildReleaseSmContextRequest(ue, cause, n2SmInfoType, n2Info) releaseSmContextRequest := models.ReleaseSmContextRequest{ JsonData: &releaseData, } @@ -517,7 +555,7 @@ func SendReleaseSmContextRequest(ue *amf_context.AmfUe, smContext *amf_context.S return detail, err } -func buildReleaseSmContextRequest( +func (s *nsmfService) buildReleaseSmContextRequest( ue *amf_context.AmfUe, cause *amf_context.CauseAll, n2SmInfoType models.N2SmInfoType, n2Info []byte) ( releaseData models.SmContextReleaseData, ) { @@ -538,7 +576,7 @@ func buildReleaseSmContextRequest( if n2Info != nil { releaseData.N2SmInfoType = n2SmInfoType releaseData.N2SmInfo = &models.RefToBinaryData{ - ContentId: "n2SmInfo", + ContentId: n2sminfocon, } } // TODO: other param(ueLocation...) diff --git a/internal/sbi/consumer/subscriber_data_management.go b/internal/sbi/consumer/subscriber_data_management.go deleted file mode 100644 index 3c49d00b..00000000 --- a/internal/sbi/consumer/subscriber_data_management.go +++ /dev/null @@ -1,290 +0,0 @@ -package consumer - -import ( - "github.com/antihax/optional" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" - "github.com/free5gc/openapi/models" -) - -func PutUpuAck(ue *amf_context.AmfUe, upuMacIue string) error { - configuration := Nudm_SubscriberDataManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmSDMUri) - client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) - if err != nil { - return err - } - - ackInfo := models.AcknowledgeInfo{ - UpuMacIue: upuMacIue, - } - upuOpt := Nudm_SubscriberDataManagement.PutUpuAckParamOpts{ - AcknowledgeInfo: optional.NewInterface(ackInfo), - } - httpResp, err := client.ProvidingAcknowledgementOfUEParametersUpdateApi. - PutUpuAck(ctx, ue.Supi, &upuOpt) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("PutUpuAck response body cannot close: %+v", - rspCloseErr) - } - } - }() - return err -} - -func SDMGetAmData(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { - configuration := Nudm_SubscriberDataManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmSDMUri) - client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - - getAmDataParamOpt := Nudm_SubscriberDataManagement.GetAmDataParamOpts{ - PlmnId: optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId)), - } - - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) - if err != nil { - return nil, err - } - - data, httpResp, localErr := client.AccessAndMobilitySubscriptionDataRetrievalApi.GetAmData( - ctx, ue.Supi, &getAmDataParamOpt) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("GetAmData response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - ue.AccessAndMobilitySubscriptionData = &data - ue.Gpsi = data.Gpsis[0] // TODO: select GPSI - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - err = localErr - return problemDetails, err - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - problemDetails = &problem - } else { - err = openapi.ReportError("server no response") - } - return problemDetails, err -} - -func SDMGetSmfSelectData(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { - configuration := Nudm_SubscriberDataManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmSDMUri) - client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - - paramOpt := Nudm_SubscriberDataManagement.GetSmfSelectDataParamOpts{ - PlmnId: optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId)), - } - - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) - if err != nil { - return nil, err - } - - data, httpResp, localErr := client.SMFSelectionSubscriptionDataRetrievalApi. - GetSmfSelectData(ctx, ue.Supi, ¶mOpt) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("GetSmfSelectData response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - ue.SmfSelectionData = &data - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - err = localErr - return problemDetails, err - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - problemDetails = &problem - } else { - err = openapi.ReportError("server no response") - } - - return problemDetails, err -} - -func SDMGetUeContextInSmfData(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { - configuration := Nudm_SubscriberDataManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmSDMUri) - client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) - if err != nil { - return nil, err - } - - data, httpResp, localErr := client.UEContextInSMFDataRetrievalApi. - GetUeContextInSmfData(ctx, ue.Supi, nil) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("GetUeContextInSmfData response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - ue.UeContextInSmfData = &data - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - err = localErr - return nil, err - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - problemDetails = &problem - } else { - err = openapi.ReportError("server no response") - } - - return problemDetails, err -} - -func SDMSubscribe(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { - configuration := Nudm_SubscriberDataManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmSDMUri) - client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - - amfSelf := amf_context.GetSelf() - sdmSubscription := models.SdmSubscription{ - NfInstanceId: amfSelf.NfId, - PlmnId: &ue.PlmnId, - } - - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) - if err != nil { - return nil, err - } - - resSubscription, httpResp, localErr := client.SubscriptionCreationApi.Subscribe( - ctx, ue.Supi, sdmSubscription) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("Subscribe response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - ue.SdmSubscriptionId = resSubscription.SubscriptionId - return problemDetails, err - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - err = localErr - return problemDetails, err - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - problemDetails = &problem - } else { - err = openapi.ReportError("server no response") - } - return problemDetails, err -} - -func SDMGetSliceSelectionSubscriptionData(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { - configuration := Nudm_SubscriberDataManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmSDMUri) - client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - - paramOpt := Nudm_SubscriberDataManagement.GetNssaiParamOpts{ - PlmnId: optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId)), - } - - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) - if err != nil { - return nil, err - } - - nssai, httpResp, localErr := client.SliceSelectionSubscriptionDataRetrievalApi. - GetNssai(ctx, ue.Supi, ¶mOpt) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("GetNssai response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - for _, defaultSnssai := range nssai.DefaultSingleNssais { - subscribedSnssai := models.SubscribedSnssai{ - SubscribedSnssai: &models.Snssai{ - Sst: defaultSnssai.Sst, - Sd: defaultSnssai.Sd, - }, - DefaultIndication: true, - } - ue.SubscribedNssai = append(ue.SubscribedNssai, subscribedSnssai) - } - for _, snssai := range nssai.SingleNssais { - subscribedSnssai := models.SubscribedSnssai{ - SubscribedSnssai: &models.Snssai{ - Sst: snssai.Sst, - Sd: snssai.Sd, - }, - DefaultIndication: false, - } - ue.SubscribedNssai = append(ue.SubscribedNssai, subscribedSnssai) - } - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - err = localErr - return problemDetails, err - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - problemDetails = &problem - } else { - err = openapi.ReportError("server no response") - } - return problemDetails, err -} - -func SDMUnsubscribe(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { - configuration := Nudm_SubscriberDataManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmSDMUri) - client := Nudm_SubscriberDataManagement.NewAPIClient(configuration) - - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) - if err != nil { - return nil, err - } - - httpResp, localErr := client.SubscriptionDeletionApi.Unsubscribe(ctx, ue.Supi, ue.SdmSubscriptionId) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("Unsubscribe response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - return problemDetails, err - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - err = localErr - return nil, err - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - problemDetails = &problem - } else { - err = openapi.ReportError("server no response") - } - return problemDetails, err -} diff --git a/internal/sbi/consumer/udm_service.go b/internal/sbi/consumer/udm_service.go new file mode 100644 index 00000000..331cc1a6 --- /dev/null +++ b/internal/sbi/consumer/udm_service.go @@ -0,0 +1,522 @@ +package consumer + +import ( + "fmt" + "sync" + + "github.com/antihax/optional" + + amf_context "github.com/free5gc/amf/internal/context" + "github.com/free5gc/amf/internal/logger" + "github.com/free5gc/amf/pkg/factory" + "github.com/free5gc/openapi" + "github.com/free5gc/openapi/Nudm_SubscriberDataManagement" + "github.com/free5gc/openapi/Nudm_UEContextManagement" + "github.com/free5gc/openapi/models" +) + +type nudmService struct { + consumer *Consumer + + SubscriberDMngmntMu sync.RWMutex + UEContextMngmntMu sync.RWMutex + + SubscriberDMngmntClients map[string]*Nudm_SubscriberDataManagement.APIClient + UEContextMngmntClients map[string]*Nudm_UEContextManagement.APIClient +} + +func (s *nudmService) getSubscriberDMngmntClients(uri string) *Nudm_SubscriberDataManagement.APIClient { + if uri == "" { + return nil + } + s.SubscriberDMngmntMu.RLock() + client, ok := s.SubscriberDMngmntClients[uri] + if ok { + s.SubscriberDMngmntMu.RUnlock() + return client + } + + configuration := Nudm_SubscriberDataManagement.NewConfiguration() + configuration.SetBasePath(uri) + client = Nudm_SubscriberDataManagement.NewAPIClient(configuration) + + s.SubscriberDMngmntMu.RUnlock() + s.SubscriberDMngmntMu.Lock() + defer s.SubscriberDMngmntMu.Unlock() + s.SubscriberDMngmntClients[uri] = client + return client +} + +func (s *nudmService) getUEContextMngmntClient(uri string) *Nudm_UEContextManagement.APIClient { + if uri == "" { + return nil + } + s.UEContextMngmntMu.RLock() + client, ok := s.UEContextMngmntClients[uri] + if ok { + s.UEContextMngmntMu.RUnlock() + return client + } + + configuration := Nudm_UEContextManagement.NewConfiguration() + configuration.SetBasePath(uri) + client = Nudm_UEContextManagement.NewAPIClient(configuration) + + s.UEContextMngmntMu.RUnlock() + s.UEContextMngmntMu.Lock() + defer s.UEContextMngmntMu.Unlock() + s.UEContextMngmntClients[uri] = client + return client +} + +func (s *nudmService) PutUpuAck(ue *amf_context.AmfUe, upuMacIue string) error { + client := s.getSubscriberDMngmntClients(ue.NudmSDMUri) + if client == nil { + return openapi.ReportError("udm not found") + } + + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) + if err != nil { + return err + } + + ackInfo := models.AcknowledgeInfo{ + UpuMacIue: upuMacIue, + } + upuOpt := Nudm_SubscriberDataManagement.PutUpuAckParamOpts{ + AcknowledgeInfo: optional.NewInterface(ackInfo), + } + httpResp, err := client.ProvidingAcknowledgementOfUEParametersUpdateApi. + PutUpuAck(ctx, ue.Supi, &upuOpt) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("PutUpuAck response body cannot close: %+v", + rspCloseErr) + } + } + }() + return err +} + +func (s *nudmService) SDMGetAmData(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { + client := s.getSubscriberDMngmntClients(ue.NudmSDMUri) + if client == nil { + return nil, openapi.ReportError("udm not found") + } + + getAmDataParamOpt := Nudm_SubscriberDataManagement.GetAmDataParamOpts{ + PlmnId: optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId)), + } + + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) + if err != nil { + return nil, err + } + + data, httpResp, localErr := client.AccessAndMobilitySubscriptionDataRetrievalApi.GetAmData( + ctx, ue.Supi, &getAmDataParamOpt) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("GetAmData response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + ue.AccessAndMobilitySubscriptionData = &data + ue.Gpsi = data.Gpsis[0] // TODO: select GPSI + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + err = localErr + return problemDetails, err + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + return problemDetails, err +} + +func (s *nudmService) SDMGetSmfSelectData(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { + client := s.getSubscriberDMngmntClients(ue.NudmSDMUri) + if client == nil { + return nil, openapi.ReportError("udm not found") + } + + paramOpt := Nudm_SubscriberDataManagement.GetSmfSelectDataParamOpts{ + PlmnId: optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId)), + } + + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) + if err != nil { + return nil, err + } + + data, httpResp, localErr := client.SMFSelectionSubscriptionDataRetrievalApi. + GetSmfSelectData(ctx, ue.Supi, ¶mOpt) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("GetSmfSelectData response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + ue.SmfSelectionData = &data + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + err = localErr + return problemDetails, err + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + + return problemDetails, err +} + +func (s *nudmService) SDMGetUeContextInSmfData( + ue *amf_context.AmfUe, +) (problemDetails *models.ProblemDetails, err error) { + client := s.getSubscriberDMngmntClients(ue.NudmSDMUri) + if client == nil { + return nil, openapi.ReportError("udm not found") + } + + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) + if err != nil { + return nil, err + } + + data, httpResp, localErr := client.UEContextInSMFDataRetrievalApi. + GetUeContextInSmfData(ctx, ue.Supi, nil) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("GetUeContextInSmfData response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + ue.UeContextInSmfData = &data + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + err = localErr + return nil, err + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + + return problemDetails, err +} + +func (s *nudmService) SDMSubscribe(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { + client := s.getSubscriberDMngmntClients(ue.NudmSDMUri) + if client == nil { + return nil, openapi.ReportError("udm not found") + } + + amfSelf := amf_context.GetSelf() + sdmSubscription := models.SdmSubscription{ + NfInstanceId: amfSelf.NfId, + PlmnId: &ue.PlmnId, + } + + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) + if err != nil { + return nil, err + } + + resSubscription, httpResp, localErr := client.SubscriptionCreationApi.Subscribe( + ctx, ue.Supi, sdmSubscription) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("Subscribe response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + ue.SdmSubscriptionId = resSubscription.SubscriptionId + return problemDetails, err + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + err = localErr + return problemDetails, err + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + return problemDetails, err +} + +func (s *nudmService) SDMGetSliceSelectionSubscriptionData( + ue *amf_context.AmfUe, +) (problemDetails *models.ProblemDetails, err error) { + client := s.getSubscriberDMngmntClients(ue.NudmSDMUri) + if client == nil { + return nil, openapi.ReportError("udm not found") + } + + paramOpt := Nudm_SubscriberDataManagement.GetNssaiParamOpts{ + PlmnId: optional.NewInterface(openapi.MarshToJsonString(ue.PlmnId)), + } + + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) + if err != nil { + return nil, err + } + + nssai, httpResp, localErr := client.SliceSelectionSubscriptionDataRetrievalApi. + GetNssai(ctx, ue.Supi, ¶mOpt) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("GetNssai response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + for _, defaultSnssai := range nssai.DefaultSingleNssais { + subscribedSnssai := models.SubscribedSnssai{ + SubscribedSnssai: &models.Snssai{ + Sst: defaultSnssai.Sst, + Sd: defaultSnssai.Sd, + }, + DefaultIndication: true, + } + ue.SubscribedNssai = append(ue.SubscribedNssai, subscribedSnssai) + } + for _, snssai := range nssai.SingleNssais { + subscribedSnssai := models.SubscribedSnssai{ + SubscribedSnssai: &models.Snssai{ + Sst: snssai.Sst, + Sd: snssai.Sd, + }, + DefaultIndication: false, + } + ue.SubscribedNssai = append(ue.SubscribedNssai, subscribedSnssai) + } + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + err = localErr + return problemDetails, err + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + return problemDetails, err +} + +func (s *nudmService) SDMUnsubscribe(ue *amf_context.AmfUe) (problemDetails *models.ProblemDetails, err error) { + client := s.getSubscriberDMngmntClients(ue.NudmSDMUri) + if client == nil { + return nil, openapi.ReportError("udm not found") + } + + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_SDM, models.NfType_UDM) + if err != nil { + return nil, err + } + + httpResp, localErr := client.SubscriptionDeletionApi.Unsubscribe(ctx, ue.Supi, ue.SdmSubscriptionId) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("Unsubscribe response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + return problemDetails, err + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + err = localErr + return nil, err + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + problemDetails = &problem + } else { + err = openapi.ReportError("server no response") + } + return problemDetails, err +} + +func (s *nudmService) UeCmRegistration( + ue *amf_context.AmfUe, accessType models.AccessType, initialRegistrationInd bool, +) (*models.ProblemDetails, error) { + client := s.getUEContextMngmntClient(ue.NudmUECMUri) + if client == nil { + return nil, openapi.ReportError("udm not found") + } + + amfSelf := amf_context.GetSelf() + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UEAU, models.NfType_UDM) + if err != nil { + return nil, err + } + + switch accessType { + case models.AccessType__3_GPP_ACCESS: + deregCallbackUri := fmt.Sprintf("%s%s/deregistration/%s", + amfSelf.GetIPv4Uri(), + factory.AmfCallbackResUriPrefix, + ue.Supi, + ) + + registrationData := models.Amf3GppAccessRegistration{ + AmfInstanceId: amfSelf.NfId, + InitialRegistrationInd: initialRegistrationInd, + Guami: &amfSelf.ServedGuamiList[0], + RatType: ue.RatType, + DeregCallbackUri: deregCallbackUri, + // TODO: not support Homogenous Support of IMS Voice over PS Sessions this stage + ImsVoPs: models.ImsVoPs_HOMOGENEOUS_NON_SUPPORT, + } + + _, httpResp, localErr := client.AMFRegistrationFor3GPPAccessApi.Registration(ctx, + ue.Supi, registrationData) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("Registration response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + ue.UeCmRegistered[accessType] = true + return nil, nil + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + return nil, localErr + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + return &problem, nil + } else { + return nil, openapi.ReportError("server no response") + } + case models.AccessType_NON_3_GPP_ACCESS: + registrationData := models.AmfNon3GppAccessRegistration{ + AmfInstanceId: amfSelf.NfId, + Guami: &amfSelf.ServedGuamiList[0], + RatType: ue.RatType, + } + + _, httpResp, localErr := client.AMFRegistrationForNon3GPPAccessApi. + Register(ctx, ue.Supi, registrationData) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("Register response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + ue.UeCmRegistered[accessType] = true + return nil, nil + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + return nil, localErr + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + return &problem, nil + } else { + return nil, openapi.ReportError("server no response") + } + } + + return nil, nil +} + +func (s *nudmService) UeCmDeregistration( + ue *amf_context.AmfUe, accessType models.AccessType, +) (*models.ProblemDetails, error) { + client := s.getUEContextMngmntClient(ue.NudmUECMUri) + if client == nil { + return nil, openapi.ReportError("udm not found") + } + + amfSelf := amf_context.GetSelf() + ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UECM, models.NfType_UDM) + if err != nil { + return nil, err + } + + switch accessType { + case models.AccessType__3_GPP_ACCESS: + modificationData := models.Amf3GppAccessRegistrationModification{ + Guami: &amfSelf.ServedGuamiList[0], + PurgeFlag: true, + } + + httpResp, localErr := client.ParameterUpdateInTheAMFRegistrationFor3GPPAccessApi.Update(ctx, + ue.Supi, modificationData) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("Update response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + return nil, nil + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + return nil, localErr + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + return &problem, nil + } else { + return nil, openapi.ReportError("server no response") + } + case models.AccessType_NON_3_GPP_ACCESS: + modificationData := models.AmfNon3GppAccessRegistrationModification{ + Guami: &amfSelf.ServedGuamiList[0], + PurgeFlag: true, + } + + httpResp, localErr := client.ParameterUpdateInTheAMFRegistrationForNon3GPPAccessApi.UpdateAmfNon3gppAccess( + ctx, ue.Supi, modificationData) + defer func() { + if httpResp != nil { + if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { + logger.ConsumerLog.Errorf("UpdateAmfNon3gppAccess response body cannot close: %+v", + rspCloseErr) + } + } + }() + if localErr == nil { + return nil, nil + } else if httpResp != nil { + if httpResp.Status != localErr.Error() { + return nil, localErr + } + problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) + return &problem, nil + } else { + return nil, openapi.ReportError("server no response") + } + } + + return nil, nil +} diff --git a/internal/sbi/consumer/ue_context_management.go b/internal/sbi/consumer/ue_context_management.go deleted file mode 100644 index d407cea4..00000000 --- a/internal/sbi/consumer/ue_context_management.go +++ /dev/null @@ -1,172 +0,0 @@ -package consumer - -import ( - "fmt" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/pkg/factory" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/Nudm_UEContextManagement" - "github.com/free5gc/openapi/models" -) - -func UeCmRegistration(ue *amf_context.AmfUe, accessType models.AccessType, initialRegistrationInd bool) ( - *models.ProblemDetails, error, -) { - configuration := Nudm_UEContextManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmUECMUri) - client := Nudm_UEContextManagement.NewAPIClient(configuration) - - amfSelf := amf_context.GetSelf() - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UEAU, models.NfType_UDM) - if err != nil { - return nil, err - } - - switch accessType { - case models.AccessType__3_GPP_ACCESS: - deregCallbackUri := fmt.Sprintf("%s%s/deregistration/%s", - amfSelf.GetIPv4Uri(), - factory.AmfCallbackResUriPrefix, - ue.Supi, - ) - - registrationData := models.Amf3GppAccessRegistration{ - AmfInstanceId: amfSelf.NfId, - InitialRegistrationInd: initialRegistrationInd, - Guami: &amfSelf.ServedGuamiList[0], - RatType: ue.RatType, - DeregCallbackUri: deregCallbackUri, - // TODO: not support Homogenous Support of IMS Voice over PS Sessions this stage - ImsVoPs: models.ImsVoPs_HOMOGENEOUS_NON_SUPPORT, - } - - _, httpResp, localErr := client.AMFRegistrationFor3GPPAccessApi.Registration(ctx, - ue.Supi, registrationData) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("Registration response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - ue.UeCmRegistered[accessType] = true - return nil, nil - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - return nil, localErr - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - return &problem, nil - } else { - return nil, openapi.ReportError("server no response") - } - case models.AccessType_NON_3_GPP_ACCESS: - registrationData := models.AmfNon3GppAccessRegistration{ - AmfInstanceId: amfSelf.NfId, - Guami: &amfSelf.ServedGuamiList[0], - RatType: ue.RatType, - } - - _, httpResp, localErr := client.AMFRegistrationForNon3GPPAccessApi. - Register(ctx, ue.Supi, registrationData) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("Register response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - ue.UeCmRegistered[accessType] = true - return nil, nil - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - return nil, localErr - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - return &problem, nil - } else { - return nil, openapi.ReportError("server no response") - } - } - - return nil, nil -} - -func UeCmDeregistration(ue *amf_context.AmfUe, accessType models.AccessType) ( - *models.ProblemDetails, error, -) { - configuration := Nudm_UEContextManagement.NewConfiguration() - configuration.SetBasePath(ue.NudmUECMUri) - client := Nudm_UEContextManagement.NewAPIClient(configuration) - - amfSelf := amf_context.GetSelf() - ctx, _, err := amf_context.GetSelf().GetTokenCtx(models.ServiceName_NUDM_UECM, models.NfType_UDM) - if err != nil { - return nil, err - } - - switch accessType { - case models.AccessType__3_GPP_ACCESS: - modificationData := models.Amf3GppAccessRegistrationModification{ - Guami: &amfSelf.ServedGuamiList[0], - PurgeFlag: true, - } - - httpResp, localErr := client.ParameterUpdateInTheAMFRegistrationFor3GPPAccessApi.Update(ctx, - ue.Supi, modificationData) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("Update response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - return nil, nil - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - return nil, localErr - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - return &problem, nil - } else { - return nil, openapi.ReportError("server no response") - } - case models.AccessType_NON_3_GPP_ACCESS: - modificationData := models.AmfNon3GppAccessRegistrationModification{ - Guami: &amfSelf.ServedGuamiList[0], - PurgeFlag: true, - } - - httpResp, localErr := client.ParameterUpdateInTheAMFRegistrationForNon3GPPAccessApi.UpdateAmfNon3gppAccess( - ctx, ue.Supi, modificationData) - defer func() { - if httpResp != nil { - if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil { - logger.ConsumerLog.Errorf("UpdateAmfNon3gppAccess response body cannot close: %+v", - rspCloseErr) - } - } - }() - if localErr == nil { - return nil, nil - } else if httpResp != nil { - if httpResp.Status != localErr.Error() { - return nil, localErr - } - problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails) - return &problem, nil - } else { - return nil, openapi.ReportError("server no response") - } - } - - return nil, nil -} diff --git a/internal/sbi/eventexposure/api_individual_subscription_document.go b/internal/sbi/eventexposure/api_individual_subscription_document.go deleted file mode 100644 index e5a05d38..00000000 --- a/internal/sbi/eventexposure/api_individual_subscription_document.go +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Namf_EventExposure - * - * AMF Event Exposure Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package eventexposure - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// DeleteSubscription - Namf_EventExposure Unsubscribe service Operation -func HTTPDeleteSubscription(c *gin.Context) { - req := httpwrapper.NewRequest(c.Request, nil) - req.Params["subscriptionId"] = c.Param("subscriptionId") - - rsp := producer.HandleDeleteAMFEventSubscription(req) - - if rsp.Status == http.StatusOK { - c.JSON(http.StatusOK, gin.H{}) - } else { - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.EeLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } - } -} - -// ModifySubscription - Namf_EventExposure Subscribe Modify service Operation -func HTTPModifySubscription(c *gin.Context) { - var modifySubscriptionRequest models.ModifySubscriptionRequest - - requestBody, err := c.GetRawData() - if err != nil { - logger.EeLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&modifySubscriptionRequest, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.EeLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, modifySubscriptionRequest) - req.Params["subscriptionId"] = c.Param("subscriptionId") - - rsp := producer.HandleModifyAMFEventSubscription(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.EeLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/eventexposure/api_subscriptions_collection_document.go b/internal/sbi/eventexposure/api_subscriptions_collection_document.go deleted file mode 100644 index 8e618277..00000000 --- a/internal/sbi/eventexposure/api_subscriptions_collection_document.go +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Namf_EventExposure - * - * AMF Event Exposure Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package eventexposure - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// CreateSubscription - Namf_EventExposure Subscribe service Operation -func HTTPCreateSubscription(c *gin.Context) { - var createEventSubscription models.AmfCreateEventSubscription - - requestBody, err := c.GetRawData() - if err != nil { - logger.EeLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&createEventSubscription, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.EeLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, createEventSubscription) - - rsp := producer.HandleCreateAMFEventSubscription(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.EeLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/eventexposure/routers.go b/internal/sbi/eventexposure/routers.go deleted file mode 100644 index d366cf9f..00000000 --- a/internal/sbi/eventexposure/routers.go +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Namf_EventExposure - * - * AMF Event Exposure Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package eventexposure - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/util" - "github.com/free5gc/amf/pkg/factory" - "github.com/free5gc/openapi/models" - logger_util "github.com/free5gc/util/logger" -) - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AmfEvtsResUriPrefix) - - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAMF_EVTS) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, amf_context.GetSelf()) - }) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - case "POST": - group.POST(route.Pattern, route.HandlerFunc) - case "PUT": - group.PUT(route.Pattern, route.HandlerFunc) - case "DELETE": - group.DELETE(route.Pattern, route.HandlerFunc) - case "PATCH": - group.PATCH(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "HTTPDeleteSubscription", - strings.ToUpper("Delete"), - "/subscriptions/:subscriptionId", - HTTPDeleteSubscription, - }, - - { - "HTTPModifySubscription", - strings.ToUpper("Patch"), - "/subscriptions/:subscriptionId", - HTTPModifySubscription, - }, - - { - "HTTPCreateSubscription", - strings.ToUpper("Post"), - "/subscriptions", - HTTPCreateSubscription, - }, -} diff --git a/internal/sbi/httpcallback/api_am_policy_control_update_notify.go b/internal/sbi/httpcallback/api_am_policy_control_update_notify.go deleted file mode 100644 index 9ac404ba..00000000 --- a/internal/sbi/httpcallback/api_am_policy_control_update_notify.go +++ /dev/null @@ -1,109 +0,0 @@ -package httpcallback - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -func HTTPAmPolicyControlUpdateNotifyUpdate(c *gin.Context) { - var policyUpdate models.PolicyUpdate - - requestBody, err := c.GetRawData() - if err != nil { - logger.CallbackLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&policyUpdate, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CallbackLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, policyUpdate) - req.Params["polAssoId"] = c.Params.ByName("polAssoId") - - rsp := producer.HandleAmPolicyControlUpdateNotifyUpdate(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CallbackLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} - -func HTTPAmPolicyControlUpdateNotifyTerminate(c *gin.Context) { - var terminationNotification models.TerminationNotification - - requestBody, err := c.GetRawData() - if err != nil { - logger.CallbackLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&terminationNotification, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CallbackLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, terminationNotification) - req.Params["polAssoId"] = c.Params.ByName("polAssoId") - - rsp := producer.HandleAmPolicyControlUpdateNotifyTerminate(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CallbackLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/httpcallback/api_handle_dereg_notification.go b/internal/sbi/httpcallback/api_handle_dereg_notification.go deleted file mode 100644 index 835beccb..00000000 --- a/internal/sbi/httpcallback/api_handle_dereg_notification.go +++ /dev/null @@ -1,126 +0,0 @@ -package httpcallback - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/consumer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" -) - -func HTTPHandleDeregistrationNotification(c *gin.Context) { - // TS 23.502 - 4.2.2.2.2 - step 14d - logger.CallbackLog.Infoln("Handle Deregistration Notification") - - var deregData models.DeregistrationData - - requestBody, err := c.GetRawData() - if err != nil { - logger.CallbackLog.Errorf("Get Request Body error: %+v", err) - problemDetails := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetails) - return - } - - err = openapi.Deserialize(&deregData, requestBody, "application/json") - if err != nil { - problemDetails := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: "[Request Body] " + err.Error(), - } - logger.CallbackLog.Errorln(problemDetails.Detail) - c.JSON(http.StatusBadRequest, problemDetails) - return - } - - ueid := c.Param("ueid") - ue, ok := amf_context.GetSelf().AmfUeFindByUeContextID(ueid) - if !ok { - logger.CallbackLog.Errorf("AmfUe Context[%s] not found", ueid) - problemDetails := models.ProblemDetails{ - Status: http.StatusNotFound, - Cause: "CONTEXT_NOT_FOUND", - } - c.JSON(http.StatusNotFound, problemDetails) - return - } - - problemDetails, err := DeregistrationNotificationProcedure(ue, deregData) - if problemDetails != nil { - ue.GmmLog.Errorf("Deregistration Notification Procedure Failed Problem[%+v]", problemDetails) - } else if err != nil { - ue.GmmLog.Errorf("Deregistration Notification Procedure Error[%v]", err.Error()) - } - // TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration - // The AMF acknowledges the Nudm_UECM_DeRegistrationNotification to the UDM. - c.JSON(http.StatusNoContent, nil) -} - -// TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration -// The AMF can initiate this procedure for either explicit (e.g. by O&M intervention) or -// implicit (e.g. expiring of Implicit Deregistration timer) -func DeregistrationNotificationProcedure(ue *amf_context.AmfUe, deregData models.DeregistrationData) ( - problemDetails *models.ProblemDetails, err error, -) { - // The AMF does not send the Deregistration Request message to the UE for Implicit Deregistration. - switch deregData.DeregReason { - case models.DeregistrationReason_UE_INITIAL_REGISTRATION: - // TS 23.502 - 4.2.2.2.2 General Registration - // Invokes the Nsmf_PDUSession_ReleaseSMContext for the corresponding access type - ue.SmContextList.Range(func(key, value interface{}) bool { - smContext := value.(*amf_context.SmContext) - if smContext.AccessType() == deregData.AccessType { - problemDetails, err = consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil) - if problemDetails != nil { - ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails) - } else if err != nil { - ue.GmmLog.Errorf("Release SmContext Error[%v]", err.Error()) - } - } - return true - }) - } - // TS 23.502 - 4.2.2.2.2 General Registration - 14e - // TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access), - // the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe - if ue.SdmSubscriptionId != "" { - problemDetails, err = consumer.SDMUnsubscribe(ue) - if problemDetails != nil { - logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails) - } else if err != nil { - logger.GmmLog.Errorf("SDM Unubscribe Error[%+v]", err) - } - ue.SdmSubscriptionId = "" - } - - // TS 23.502 - 4.2.2.2.2 General Registration - 20 AMF-Initiated Policy Association Termination - // For UE_INITIAL_REGISTRATION and SUBSCRIPTION_WITHDRAW, do AMF-Initiated Policy Association Termination directly. - if ue.PolicyAssociationId != "" { - // TODO: For REGISTRATION_AREA_CHANGE, old AMF performs an AMF-initiated Policy Association Termination - // procedure if the old AMF has established an AM Policy Association and a UE Policy Association with the PCF(s) - // and the old AMF did not transfer the PCF ID(s) to the new AMF. (Ref: TS 23.502 - 4.2.2.2.2) - // Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID - problemDetails, err := consumer.AMPolicyControlDelete(ue) - if problemDetails != nil { - logger.GmmLog.Errorf("Delete AM policy Failed Problem[%+v]", problemDetails) - } else if err != nil { - logger.GmmLog.Errorf("Delete AM policy Error[%+v]", err) - } - } - - // The old AMF should clean the UE context - // TODO: (R16) Only remove the target access UE context - ue.Remove() - - return nil, nil -} diff --git a/internal/sbi/httpcallback/api_n1_message_notify.go b/internal/sbi/httpcallback/api_n1_message_notify.go deleted file mode 100644 index e12f5e5c..00000000 --- a/internal/sbi/httpcallback/api_n1_message_notify.go +++ /dev/null @@ -1,60 +0,0 @@ -package httpcallback - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -func HTTPN1MessageNotify(c *gin.Context) { - var n1MessageNotification models.N1MessageNotification - - requestBody, err := c.GetRawData() - if err != nil { - logger.CallbackLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&n1MessageNotification, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CallbackLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, n1MessageNotification) - - rsp := producer.HandleN1MessageNotify(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CallbackLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/httpcallback/api_sm_context_status_notify.go b/internal/sbi/httpcallback/api_sm_context_status_notify.go deleted file mode 100644 index 7973c355..00000000 --- a/internal/sbi/httpcallback/api_sm_context_status_notify.go +++ /dev/null @@ -1,62 +0,0 @@ -package httpcallback - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -func HTTPSmContextStatusNotify(c *gin.Context) { - var smContextStatusNotification models.SmContextStatusNotification - - requestBody, err := c.GetRawData() - if err != nil { - logger.CallbackLog.Errorf("Get Request Body error: %+v", err) - problemDetail := models.ProblemDetails{ - Title: "System failure", - Status: http.StatusInternalServerError, - Detail: err.Error(), - Cause: "SYSTEM_FAILURE", - } - c.JSON(http.StatusInternalServerError, problemDetail) - return - } - - err = openapi.Deserialize(&smContextStatusNotification, requestBody, "application/json") - if err != nil { - problemDetail := "[Request Body] " + err.Error() - rsp := models.ProblemDetails{ - Title: "Malformed request syntax", - Status: http.StatusBadRequest, - Detail: problemDetail, - } - logger.CallbackLog.Errorln(problemDetail) - c.JSON(http.StatusBadRequest, rsp) - return - } - - req := httpwrapper.NewRequest(c.Request, smContextStatusNotification) - req.Params["supi"] = c.Params.ByName("supi") - req.Params["pduSessionId"] = c.Params.ByName("pduSessionId") - - rsp := producer.HandleSmContextStatusNotify(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.CallbackLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/httpcallback/routers.go b/internal/sbi/httpcallback/routers.go deleted file mode 100644 index 80ba64ff..00000000 --- a/internal/sbi/httpcallback/routers.go +++ /dev/null @@ -1,110 +0,0 @@ -package httpcallback - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/pkg/factory" - logger_util "github.com/free5gc/util/logger" -) - -var HttpLog *logrus.Entry - -func init() { - HttpLog = logger.HttpLog -} - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AmfCallbackResUriPrefix) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - case "POST": - group.POST(route.Pattern, route.HandlerFunc) - case "PUT": - group.PUT(route.Pattern, route.HandlerFunc) - case "PATCH": - group.PATCH(route.Pattern, route.HandlerFunc) - case "DELETE": - group.DELETE(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "SmContextStatusNotify", - strings.ToUpper("Post"), - "/smContextStatus/:supi/:pduSessionId", - HTTPSmContextStatusNotify, - }, - - { - "AmPolicyControlUpdateNotifyUpdate", - strings.ToUpper("Post"), - "/am-policy/:polAssoId/update", - HTTPAmPolicyControlUpdateNotifyUpdate, - }, - - { - "AmPolicyControlUpdateNotifyTerminate", - strings.ToUpper("Post"), - "/am-policy/:polAssoId/terminate", - HTTPAmPolicyControlUpdateNotifyTerminate, - }, - - { - "N1MessageNotify", - strings.ToUpper("Post"), - "/n1-message-notify", - HTTPN1MessageNotify, - }, - - { - "HandleDeregistrationNotification", - strings.ToUpper("Post"), - "/deregistration/:ueid", - HTTPHandleDeregistrationNotification, - }, -} diff --git a/internal/sbi/location/routers.go b/internal/sbi/location/routers.go deleted file mode 100644 index 3acb7246..00000000 --- a/internal/sbi/location/routers.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Namf_Location - * - * AMF Location Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package location - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/util" - "github.com/free5gc/amf/pkg/factory" - "github.com/free5gc/openapi/models" - logger_util "github.com/free5gc/util/logger" -) - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AmfLocResUriPrefix) - - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAMF_LOC) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, amf_context.GetSelf()) - }) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - case "POST": - group.POST(route.Pattern, route.HandlerFunc) - case "PUT": - group.PUT(route.Pattern, route.HandlerFunc) - case "DELETE": - group.DELETE(route.Pattern, route.HandlerFunc) - case "PATCH": - group.PATCH(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "ProvideLocationInfo", - strings.ToUpper("Post"), - "/:ueContextId/provide-loc-info", - HTTPProvideLocationInfo, - }, - - { - "ProvidePositioningInfo", - strings.ToUpper("Post"), - "/:ueContextId/provide-pos-info", - HTTPProvidePositioningInfo, - }, -} diff --git a/internal/sbi/mt/api_ue_context_document.go b/internal/sbi/mt/api_ue_context_document.go deleted file mode 100644 index ab7c915d..00000000 --- a/internal/sbi/mt/api_ue_context_document.go +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Namf_MT - * - * AMF Mobile Termination Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package mt - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -// ProvideDomainSelectionInfo - Namf_MT Provide Domain Selection Info service Operation -func HTTPProvideDomainSelectionInfo(c *gin.Context) { - req := httpwrapper.NewRequest(c.Request, nil) - req.Params["ueContextId"] = c.Params.ByName("ueContextId") - infoClassQuery := c.Query("info-class") - req.Query.Add("info-class", infoClassQuery) - supportedFeaturesQuery := c.Query("supported-features") - req.Query.Add("supported-features", supportedFeaturesQuery) - - rsp := producer.HandleProvideDomainSelectionInfoRequest(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.MtLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/mt/api_ue_reach_ind_document.go b/internal/sbi/mt/api_ue_reach_ind_document.go deleted file mode 100644 index 12020e26..00000000 --- a/internal/sbi/mt/api_ue_reach_ind_document.go +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Namf_MT - * - * AMF Mobile Termination Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package mt - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" -) - -// EnableUeReachability - Namf_MT EnableUEReachability service Operation -func HTTPEnableUeReachability(c *gin.Context) { - logger.MtLog.Warnf("Handle Enable Ue Reachability is not implemented.") - c.JSON(http.StatusOK, gin.H{}) -} diff --git a/internal/sbi/mt/routers.go b/internal/sbi/mt/routers.go deleted file mode 100644 index f031db61..00000000 --- a/internal/sbi/mt/routers.go +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Namf_MT - * - * AMF Mobile Termination Service - * - * API version: 1.0.0 - * Generated by: OpenAPI Generator (https://openapi-generator.tech) - */ - -package mt - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/util" - "github.com/free5gc/amf/pkg/factory" - "github.com/free5gc/openapi/models" - logger_util "github.com/free5gc/util/logger" -) - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AmfMtResUriPrefix) - - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAMF_MT) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, amf_context.GetSelf()) - }) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - case "POST": - group.POST(route.Pattern, route.HandlerFunc) - case "PUT": - group.PUT(route.Pattern, route.HandlerFunc) - case "DELETE": - group.DELETE(route.Pattern, route.HandlerFunc) - case "PATCH": - group.PATCH(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "ProvideDomainSelectionInfo", - strings.ToUpper("Get"), - "/ue-contexts/:ueContextId", - HTTPProvideDomainSelectionInfo, - }, - - { - "EnableUeReachability", - strings.ToUpper("Post"), - "/ue-contexts/:ueContextId/ue-reachind", - HTTPEnableUeReachability, - }, -} diff --git a/internal/sbi/oam/api_registered_ue_context.go b/internal/sbi/oam/api_registered_ue_context.go deleted file mode 100644 index 77e0ab45..00000000 --- a/internal/sbi/oam/api_registered_ue_context.go +++ /dev/null @@ -1,46 +0,0 @@ -package oam - -import ( - "net/http" - - "github.com/gin-gonic/gin" - - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/sbi/producer" - "github.com/free5gc/openapi" - "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" -) - -func setCorsHeader(c *gin.Context) { - c.Writer.Header().Set("Access-Control-Allow-Origin", "*") - c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") - c.Writer.Header().Set("Access-Control-Allow-Headers", - "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, "+ - "Authorization, accept, origin, Cache-Control, X-Requested-With") - c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, PATCH, DELETE") -} - -func HTTPRegisteredUEContext(c *gin.Context) { - setCorsHeader(c) - - req := httpwrapper.NewRequest(c.Request, nil) - if supi, exists := c.Params.Get("supi"); exists { - req.Params["supi"] = supi - } - - rsp := producer.HandleOAMRegisteredUEContext(req) - - responseBody, err := openapi.Serialize(rsp.Body, "application/json") - if err != nil { - logger.MtLog.Errorln(err) - problemDetails := models.ProblemDetails{ - Status: http.StatusInternalServerError, - Cause: "SYSTEM_FAILURE", - Detail: err.Error(), - } - c.JSON(http.StatusInternalServerError, problemDetails) - } else { - c.Data(rsp.Status, "application/json", responseBody) - } -} diff --git a/internal/sbi/oam/routers.go b/internal/sbi/oam/routers.go deleted file mode 100644 index 0f4875d4..00000000 --- a/internal/sbi/oam/routers.go +++ /dev/null @@ -1,95 +0,0 @@ -package oam - -import ( - "net/http" - - "github.com/gin-contrib/cors" - "github.com/gin-gonic/gin" - - amf_context "github.com/free5gc/amf/internal/context" - "github.com/free5gc/amf/internal/logger" - "github.com/free5gc/amf/internal/util" - "github.com/free5gc/amf/pkg/factory" - "github.com/free5gc/openapi/models" - logger_util "github.com/free5gc/util/logger" -) - -// Route is the information for every URI. -type Route struct { - // Name is the name of this Route. - Name string - // Method is the string for the HTTP method. ex) GET, POST etc.. - Method string - // Pattern is the pattern of the URI. - Pattern string - // HandlerFunc is the handler function of this route. - HandlerFunc gin.HandlerFunc -} - -// Routes is the list of the generated Route. -type Routes []Route - -// NewRouter returns a new router. -func NewRouter() *gin.Engine { - router := logger_util.NewGinWithLogrus(logger.GinLog) - AddService(router) - - router.Use(cors.New(cors.Config{ - AllowMethods: []string{"GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE"}, - AllowHeaders: []string{ - "Origin", "Content-Length", "Content-Type", "User-Agent", "Referrer", "Host", - "Token", "X-Requested-With", - }, - ExposeHeaders: []string{"Content-Length"}, - AllowCredentials: true, - AllowAllOrigins: true, - MaxAge: 86400, - })) - - return router -} - -func AddService(engine *gin.Engine) *gin.RouterGroup { - group := engine.Group(factory.AmfOamResUriPrefix) - - routerAuthorizationCheck := util.NewRouterAuthorizationCheck(models.ServiceName_NAMF_OAM) - group.Use(func(c *gin.Context) { - routerAuthorizationCheck.Check(c, amf_context.GetSelf()) - }) - - for _, route := range routes { - switch route.Method { - case "GET": - group.GET(route.Pattern, route.HandlerFunc) - } - } - return group -} - -// Index is the index handler. -func Index(c *gin.Context) { - c.String(http.StatusOK, "Hello World!") -} - -var routes = Routes{ - { - "Index", - "GET", - "/", - Index, - }, - - { - "Registered UE Context", - "GET", - "/registered-ue-context", - HTTPRegisteredUEContext, - }, - - { - "Individual Registered UE Context", - "GET", - "/registered-ue-context/:supi", - HTTPRegisteredUEContext, - }, -} diff --git a/internal/sbi/producer/callback.go b/internal/sbi/processor/callback.go similarity index 78% rename from internal/sbi/producer/callback.go rename to internal/sbi/processor/callback.go index 3c2f1e84..84ce74ff 100644 --- a/internal/sbi/producer/callback.go +++ b/internal/sbi/processor/callback.go @@ -1,4 +1,4 @@ -package producer +package processor import ( "fmt" @@ -6,40 +6,41 @@ import ( "runtime/debug" "strconv" + "github.com/gin-gonic/gin" + "github.com/free5gc/amf/internal/context" gmm_common "github.com/free5gc/amf/internal/gmm/common" gmm_message "github.com/free5gc/amf/internal/gmm/message" "github.com/free5gc/amf/internal/logger" amf_nas "github.com/free5gc/amf/internal/nas" ngap_message "github.com/free5gc/amf/internal/ngap/message" - "github.com/free5gc/amf/internal/sbi/consumer" "github.com/free5gc/ngap/ngapType" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) -func HandleSmContextStatusNotify(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleSmContextStatusNotify(c *gin.Context, + smContextStatusNotification models.SmContextStatusNotification, +) { logger.ProducerLog.Infoln("[AMF] Handle SmContext Status Notify") - supi := request.Params["supi"] - pduSessionIDString := request.Params["pduSessionId"] + supi := c.Param("supi") + pduSessionIDString := c.Param("pduSessionId") var pduSessionID int if pduSessionIDTmp, err := strconv.Atoi(pduSessionIDString); err != nil { logger.ProducerLog.Warnf("PDU Session ID atoi failed: %+v", err) } else { pduSessionID = pduSessionIDTmp } - smContextStatusNotification := request.Body.(models.SmContextStatusNotification) - problemDetails := SmContextStatusNotifyProcedure(supi, int32(pduSessionID), smContextStatusNotification) + problemDetails := p.SmContextStatusNotifyProcedure(supi, int32(pduSessionID), smContextStatusNotification) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) + c.Status(http.StatusNoContent) } } -func SmContextStatusNotifyProcedure(supi string, pduSessionID int32, +func (p *Processor) SmContextStatusNotifyProcedure(supi string, pduSessionID int32, smContextStatusNotification models.SmContextStatusNotification, ) *models.ProblemDetails { amfSelf := context.GetSelf() @@ -90,22 +91,20 @@ func SmContextStatusNotifyProcedure(supi string, pduSessionID int32, return nil } -func HandleAmPolicyControlUpdateNotifyUpdate(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleAmPolicyControlUpdateNotifyUpdate(c *gin.Context, policyUpdate models.PolicyUpdate) { logger.ProducerLog.Infoln("Handle AM Policy Control Update Notify [Policy update notification]") - polAssoID := request.Params["polAssoId"] - policyUpdate := request.Body.(models.PolicyUpdate) - - problemDetails := AmPolicyControlUpdateNotifyUpdateProcedure(polAssoID, policyUpdate) + polAssoID := c.Param("polAssoId") + problemDetails := p.AmPolicyControlUpdateNotifyUpdateProcedure(polAssoID, policyUpdate) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) + c.Status(http.StatusNoContent) } } -func AmPolicyControlUpdateNotifyUpdateProcedure(polAssoID string, +func (p *Processor) AmPolicyControlUpdateNotifyUpdateProcedure(polAssoID string, policyUpdate models.PolicyUpdate, ) *models.ProblemDetails { amfSelf := context.GetSelf() @@ -130,9 +129,9 @@ func AmPolicyControlUpdateNotifyUpdateProcedure(polAssoID string, if trigger == models.RequestTrigger_LOC_CH { ue.RequestTriggerLocationChange = true } - //if trigger == models.RequestTrigger_PRA_CH { + // if trigger == models.RequestTrigger_PRA_CH { // TODO: Presence Reporting Area handling (TS 23.503 6.1.2.5, TS 23.501 5.6.11) - //} + // } } if policyUpdate.ServAreaRes != nil { @@ -190,21 +189,22 @@ func AmPolicyControlUpdateNotifyUpdateProcedure(polAssoID string, } // TS 29.507 4.2.4.3 -func HandleAmPolicyControlUpdateNotifyTerminate(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleAmPolicyControlUpdateNotifyTerminate(c *gin.Context, + terminationNotification models.TerminationNotification, +) { logger.ProducerLog.Infoln("Handle AM Policy Control Update Notify [Request for termination of the policy association]") - polAssoID := request.Params["polAssoId"] - terminationNotification := request.Body.(models.TerminationNotification) + polAssoID := c.Param("polAssoId") - problemDetails := AmPolicyControlUpdateNotifyTerminateProcedure(polAssoID, terminationNotification) + problemDetails := p.AmPolicyControlUpdateNotifyTerminateProcedure(polAssoID, terminationNotification) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) + c.Status(http.StatusNoContent) } } -func AmPolicyControlUpdateNotifyTerminateProcedure(polAssoID string, +func (p *Processor) AmPolicyControlUpdateNotifyTerminateProcedure(polAssoID string, terminationNotification models.TerminationNotification, ) *models.ProblemDetails { amfSelf := context.GetSelf() @@ -233,7 +233,7 @@ func AmPolicyControlUpdateNotifyTerminateProcedure(polAssoID string, } }() - problem, err := consumer.AMPolicyControlDelete(ue) + problem, err := p.Consumer().AMPolicyControlDelete(ue) if problem != nil { logger.ProducerLog.Errorf("AM Policy Control Delete Failed Problem[%+v]", problem) } else if err != nil { @@ -244,20 +244,18 @@ func AmPolicyControlUpdateNotifyTerminateProcedure(polAssoID string, } // TS 23.502 4.2.2.2.3 Registration with AMF re-allocation -func HandleN1MessageNotify(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleN1MessageNotify(c *gin.Context, n1MessageNotify models.N1MessageNotify) { logger.ProducerLog.Infoln("[AMF] Handle N1 Message Notify") - n1MessageNotify := request.Body.(models.N1MessageNotify) - - problemDetails := N1MessageNotifyProcedure(n1MessageNotify) + problemDetails := p.N1MessageNotifyProcedure(n1MessageNotify) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) + c.Status(http.StatusNoContent) } } -func N1MessageNotifyProcedure(n1MessageNotify models.N1MessageNotify) *models.ProblemDetails { +func (p *Processor) N1MessageNotifyProcedure(n1MessageNotify models.N1MessageNotify) *models.ProblemDetails { logger.ProducerLog.Debugf("n1MessageNotify: %+v", n1MessageNotify) amfSelf := context.GetSelf() diff --git a/internal/sbi/producer/event_exposure.go b/internal/sbi/processor/event_exposure.go similarity index 79% rename from internal/sbi/producer/event_exposure.go rename to internal/sbi/processor/event_exposure.go index cfc4f22a..92b0c1c7 100644 --- a/internal/sbi/producer/event_exposure.go +++ b/internal/sbi/processor/event_exposure.go @@ -1,35 +1,36 @@ -package producer +package processor import ( "net/http" "strconv" "time" + "github.com/gin-gonic/gin" + "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) -func HandleCreateAMFEventSubscription(request *httpwrapper.Request) *httpwrapper.Response { - createEventSubscription := request.Body.(models.AmfCreateEventSubscription) - - createdEventSubscription, problemDetails := CreateAMFEventSubscriptionProcedure(createEventSubscription) +func (p *Processor) HandleCreateAMFEventSubscription(c *gin.Context, + createEventSubscription models.AmfCreateEventSubscription, +) { + createdEventSubscription, problemDetails := p.CreateAMFEventSubscriptionProcedure(createEventSubscription) if createdEventSubscription != nil { - return httpwrapper.NewResponse(http.StatusCreated, nil, createdEventSubscription) + c.JSON(http.StatusCreated, createdEventSubscription) } else if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { problemDetails = &models.ProblemDetails{ Status: http.StatusInternalServerError, Cause: "UNSPECIFIED_NF_FAILURE", } - return httpwrapper.NewResponse(http.StatusInternalServerError, nil, problemDetails) + c.JSON(http.StatusInternalServerError, problemDetails) } } // TODO: handle event filter -func CreateAMFEventSubscriptionProcedure(createEventSubscription models.AmfCreateEventSubscription) ( +func (p *Processor) CreateAMFEventSubscriptionProcedure(createEventSubscription models.AmfCreateEventSubscription) ( *models.AmfCreatedEventSubscription, *models.ProblemDetails, ) { amfSelf := context.GetSelf() @@ -129,11 +130,11 @@ func CreateAMFEventSubscriptionProcedure(createEventSubscription models.AmfCreat defer ue.Lock.Unlock() if isImmediate { - subReports(ue, newSubscriptionID) + p.subReports(ue, newSubscriptionID) } for i, flag := range immediateFlags { if flag { - report, ok := newAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID) + report, ok := p.newAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID) if ok { reportlist = append(reportlist, report) } @@ -152,12 +153,12 @@ func CreateAMFEventSubscriptionProcedure(createEventSubscription models.AmfCreat defer ue.Lock.Unlock() if isImmediate { - subReports(ue, newSubscriptionID) + p.subReports(ue, newSubscriptionID) } if ue.GroupID == subscription.GroupId { for i, flag := range immediateFlags { if flag { - report, ok := newAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID) + report, ok := p.newAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID) if ok { reportlist = append(reportlist, report) } @@ -176,11 +177,11 @@ func CreateAMFEventSubscriptionProcedure(createEventSubscription models.AmfCreat defer ue.Lock.Unlock() if isImmediate { - subReports(ue, newSubscriptionID) + p.subReports(ue, newSubscriptionID) } for i, flag := range immediateFlags { if flag { - report, ok := newAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID) + report, ok := p.newAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID) if ok { reportlist = append(reportlist, report) } @@ -202,20 +203,20 @@ func CreateAMFEventSubscriptionProcedure(createEventSubscription models.AmfCreat return createdEventSubscription, nil } -func HandleDeleteAMFEventSubscription(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleDeleteAMFEventSubscription(c *gin.Context) { logger.EeLog.Infoln("Handle Delete AMF Event Subscription") - subscriptionID := request.Params["subscriptionId"] + subscriptionID := c.Param("subscriptionId") - problemDetails := DeleteAMFEventSubscriptionProcedure(subscriptionID) + problemDetails := p.DeleteAMFEventSubscriptionProcedure(subscriptionID) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusOK, nil, nil) + c.JSON(http.StatusOK, nil) } } -func DeleteAMFEventSubscriptionProcedure(subscriptionID string) *models.ProblemDetails { +func (p *Processor) DeleteAMFEventSubscriptionProcedure(subscriptionID string) *models.ProblemDetails { amfSelf := context.GetSelf() subscription, ok := amfSelf.FindEventSubscription(subscriptionID) @@ -228,7 +229,7 @@ func DeleteAMFEventSubscriptionProcedure(subscriptionID string) *models.ProblemD } for _, supi := range subscription.UeSupiList { - if ue, ok := amfSelf.AmfUeFindBySupi(supi); ok { + if ue, okAmfUeFindBySupi := amfSelf.AmfUeFindBySupi(supi); okAmfUeFindBySupi { ue.Lock.Lock() delete(ue.EventSubscriptionsInfo, subscriptionID) ue.Lock.Unlock() @@ -238,28 +239,29 @@ func DeleteAMFEventSubscriptionProcedure(subscriptionID string) *models.ProblemD return nil } -func HandleModifyAMFEventSubscription(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleModifyAMFEventSubscription(c *gin.Context, + modifySubscriptionRequest models.ModifySubscriptionRequest, +) { logger.EeLog.Infoln("Handle Modify AMF Event Subscription") - subscriptionID := request.Params["subscriptionId"] - modifySubscriptionRequest := request.Body.(models.ModifySubscriptionRequest) + subscriptionID := c.Param("subscriptionId") - updatedEventSubscription, problemDetails := ModifyAMFEventSubscriptionProcedure(subscriptionID, - modifySubscriptionRequest) + updatedEventSubscription, problemDetails := p. + ModifyAMFEventSubscriptionProcedure(subscriptionID, modifySubscriptionRequest) if updatedEventSubscription != nil { - return httpwrapper.NewResponse(http.StatusOK, nil, updatedEventSubscription) + c.JSON(http.StatusOK, updatedEventSubscription) } else if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { problemDetails = &models.ProblemDetails{ Status: http.StatusInternalServerError, Cause: "UNSPECIFIED_NF_FAILURE", } - return httpwrapper.NewResponse(http.StatusInternalServerError, nil, problemDetails) + c.JSON(http.StatusInternalServerError, problemDetails) } } -func ModifyAMFEventSubscriptionProcedure( +func (p *Processor) ModifyAMFEventSubscriptionProcedure( subscriptionID string, modifySubscriptionRequest models.ModifySubscriptionRequest) ( *models.AmfUpdatedEventSubscription, *models.ProblemDetails, @@ -280,7 +282,7 @@ func ModifyAMFEventSubscriptionProcedure( } else if modifySubscriptionRequest.SubscriptionItemInner != nil { subscription := &contextSubscription.EventSubscription if !contextSubscription.IsAnyUe && !contextSubscription.IsGroupUe { - if _, ok := amfSelf.AmfUeFindBySupi(subscription.Supi); !ok { + if _, okAmfUeFindBySupi := amfSelf.AmfUeFindBySupi(subscription.Supi); !okAmfUeFindBySupi { problemDetails := &models.ProblemDetails{ Status: http.StatusForbidden, Cause: "UE_NOT_SERVED_BY_AMF", @@ -307,11 +309,17 @@ func ModifyAMFEventSubscriptionProcedure( } case "remove": if index < eventlistLen { - *subscription.EventList = append(lists[:index], lists[index+1:]...) + eventlist := []models.AmfEvent{} + eventlist = append(eventlist, lists[:index]...) + eventlist = append(eventlist, lists[index+1:]...) + *subscription.EventList = eventlist } case "add": event := *modifySubscriptionRequest.SubscriptionItemInner.Value - *subscription.EventList = append(lists, event) + eventlist := []models.AmfEvent{} + eventlist = append(eventlist, lists...) + eventlist = append(eventlist, event) + *subscription.EventList = eventlist } } @@ -321,7 +329,7 @@ func ModifyAMFEventSubscriptionProcedure( return updatedEventSubscription, nil } -func subReports(ue *context.AmfUe, subscriptionId string) { +func (p *Processor) subReports(ue *context.AmfUe, subscriptionId string) { remainReport := ue.EventSubscriptionsInfo[subscriptionId].RemainReports if remainReport == nil { return @@ -330,7 +338,7 @@ func subReports(ue *context.AmfUe, subscriptionId string) { } // DO NOT handle AmfEventType_PRESENCE_IN_AOI_REPORT and AmfEventType_UES_IN_AREA_REPORT(about area) -func newAmfEventReport(ue *context.AmfUe, Type models.AmfEventType, subscriptionId string) ( +func (p *Processor) newAmfEventReport(ue *context.AmfUe, amfEventType models.AmfEventType, subscriptionId string) ( report models.AmfEventReport, ok bool, ) { ueSubscription, ok := ue.EventSubscriptionsInfo[subscriptionId] @@ -340,7 +348,7 @@ func newAmfEventReport(ue *context.AmfUe, Type models.AmfEventType, subscription report.AnyUe = ueSubscription.AnyUe report.Supi = ue.Supi - report.Type = Type + report.Type = amfEventType report.TimeStamp = &ueSubscription.Timestamp report.State = new(models.AmfEventState) mode := ueSubscription.EventSubscription.Options @@ -351,13 +359,13 @@ func newAmfEventReport(ue *context.AmfUe, Type models.AmfEventType, subscription } else if *ueSubscription.RemainReports <= 0 { report.State.Active = false } else { - report.State.Active = getDuration(mode.Expiry, &report.State.RemainDuration) + report.State.Active = p.getDuration(mode.Expiry, &report.State.RemainDuration) if report.State.Active { report.State.RemainReports = *ueSubscription.RemainReports } } - switch Type { + switch amfEventType { case models.AmfEventType_LOCATION_REPORT: report.Location = &ue.Location // case models.AmfEventType_PRESENCE_IN_AOI_REPORT: @@ -399,7 +407,7 @@ func newAmfEventReport(ue *context.AmfUe, Type models.AmfEventType, subscription return report, ok } -func getDuration(expiry *time.Time, remainDuration *int32) bool { +func (p *Processor) getDuration(expiry *time.Time, remainDuration *int32) bool { if expiry != nil { if time.Now().After(*expiry) { return false diff --git a/internal/sbi/producer/location_info.go b/internal/sbi/processor/location_info.go similarity index 69% rename from internal/sbi/producer/location_info.go rename to internal/sbi/processor/location_info.go index f91a5205..9fbac22e 100644 --- a/internal/sbi/producer/location_info.go +++ b/internal/sbi/processor/location_info.go @@ -1,29 +1,29 @@ -package producer +package processor import ( "net/http" + "github.com/gin-gonic/gin" + "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) -func HandleProvideLocationInfoRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleProvideLocationInfoRequest(c *gin.Context, requestLocInfo models.RequestLocInfo) { logger.ProducerLog.Info("Handle Provide Location Info Request") - requestLocInfo := request.Body.(models.RequestLocInfo) - ueContextID := request.Params["ueContextId"] + ueContextID := c.Param("ueContextId") - provideLocInfo, problemDetails := ProvideLocationInfoProcedure(requestLocInfo, ueContextID) + provideLocInfo, problemDetails := p.ProvideLocationInfoProcedure(requestLocInfo, ueContextID) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusOK, nil, provideLocInfo) + c.JSON(http.StatusOK, provideLocInfo) } } -func ProvideLocationInfoProcedure(requestLocInfo models.RequestLocInfo, ueContextID string) ( +func (p *Processor) ProvideLocationInfoProcedure(requestLocInfo models.RequestLocInfo, ueContextID string) ( *models.ProvideLocInfo, *models.ProblemDetails, ) { amfSelf := context.GetSelf() diff --git a/internal/sbi/producer/mt.go b/internal/sbi/processor/mt.go similarity index 64% rename from internal/sbi/producer/mt.go rename to internal/sbi/processor/mt.go index b7c33b8e..d91d0c3e 100644 --- a/internal/sbi/producer/mt.go +++ b/internal/sbi/processor/mt.go @@ -1,31 +1,33 @@ -package producer +package processor import ( "net/http" + "github.com/gin-gonic/gin" + "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) -func HandleProvideDomainSelectionInfoRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleProvideDomainSelectionInfoRequest(c *gin.Context) { logger.MtLog.Info("Handle Provide Domain Selection Info Request") - ueContextID := request.Params["ueContextId"] - infoClassQuery := request.Query.Get("info-class") - supportedFeaturesQuery := request.Query.Get("supported-features") + ueContextID := c.Param("ueContextId") + infoClassQuery := c.Query("info-class") + supportedFeaturesQuery := c.Query("supported-features") - ueContextInfo, problemDetails := ProvideDomainSelectionInfoProcedure(ueContextID, + ueContextInfo, problemDetails := p.ProvideDomainSelectionInfoProcedure(ueContextID, infoClassQuery, supportedFeaturesQuery) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusOK, nil, ueContextInfo) + c.JSON(http.StatusOK, ueContextInfo) } } -func ProvideDomainSelectionInfoProcedure(ueContextID string, infoClassQuery string, supportedFeaturesQuery string) ( +func (p *Processor) ProvideDomainSelectionInfoProcedure(ueContextID string, infoClassQuery string, + supportedFeaturesQuery string) ( *models.UeContextInfo, *models.ProblemDetails, ) { amfSelf := context.GetSelf() diff --git a/internal/sbi/producer/n1n2message.go b/internal/sbi/processor/n1n2message.go similarity index 87% rename from internal/sbi/producer/n1n2message.go rename to internal/sbi/processor/n1n2message.go index fa31690a..0c53a19c 100644 --- a/internal/sbi/producer/n1n2message.go +++ b/internal/sbi/processor/n1n2message.go @@ -1,47 +1,53 @@ -package producer +package processor import ( "net/http" "strconv" + "github.com/gin-gonic/gin" + "github.com/free5gc/amf/internal/context" gmm_message "github.com/free5gc/amf/internal/gmm/message" "github.com/free5gc/amf/internal/logger" ngap_message "github.com/free5gc/amf/internal/ngap/message" - "github.com/free5gc/amf/internal/sbi/producer/callback" + callback "github.com/free5gc/amf/internal/sbi/processor/notifier" "github.com/free5gc/aper" "github.com/free5gc/nas/nasMessage" "github.com/free5gc/ngap/ngapType" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) // TS23502 4.2.3.3, 4.2.4.3, 4.3.2.2, 4.3.2.3, 4.3.3.2, 4.3.7 -func HandleN1N2MessageTransferRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleN1N2MessageTransferRequest(c *gin.Context, + n1n2MessageTransferRequest models.N1N2MessageTransferRequest, +) { logger.ProducerLog.Infof("Handle N1N2 Message Transfer Request") - n1n2MessageTransferRequest := request.Body.(models.N1N2MessageTransferRequest) - ueContextID := request.Params["ueContextId"] - reqUri := request.Params["reqUri"] + ueContextID := c.Param("ueContextId") + reqUri := c.Param("reqUri") - n1n2MessageTransferRspData, locationHeader, problemDetails, transferErr := N1N2MessageTransferProcedure( + n1n2MessageTransferRspData, locationHeader, problemDetails, transferErr := p.N1N2MessageTransferProcedure( ueContextID, reqUri, n1n2MessageTransferRequest) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) + return } else if transferErr != nil { - return httpwrapper.NewResponse(int(transferErr.Error.Status), nil, transferErr) + c.JSON(int(transferErr.Error.Status), transferErr) + return } else if n1n2MessageTransferRspData != nil { switch n1n2MessageTransferRspData.Cause { case models.N1N2MessageTransferCause_N1_MSG_NOT_TRANSFERRED: fallthrough case models.N1N2MessageTransferCause_N1_N2_TRANSFER_INITIATED: - return httpwrapper.NewResponse(http.StatusOK, nil, n1n2MessageTransferRspData) + c.JSON(http.StatusOK, n1n2MessageTransferRspData) + return case models.N1N2MessageTransferCause_ATTEMPTING_TO_REACH_UE: headers := http.Header{ "Location": {locationHeader}, } - return httpwrapper.NewResponse(http.StatusAccepted, headers, n1n2MessageTransferRspData) + c.JSON(http.StatusAccepted, gin.H{"headers": headers, "data": n1n2MessageTransferRspData}) + return } } @@ -49,7 +55,7 @@ func HandleN1N2MessageTransferRequest(request *httpwrapper.Request) *httpwrapper Status: http.StatusForbidden, Cause: "UNSPECIFIED", } - return httpwrapper.NewResponse(http.StatusForbidden, nil, problemDetails) + c.JSON(http.StatusForbidden, problemDetails) } // There are 4 possible return value for this function: @@ -60,7 +66,7 @@ func HandleN1N2MessageTransferRequest(request *httpwrapper.Request) *httpwrapper // - TransferErr: if AMF reject the request due to procedure error, e.g. UE has an ongoing procedure. // // see TS 29.518 6.1.3.5.3.1 for more details. -func N1N2MessageTransferProcedure(ueContextID string, reqUri string, +func (p *Processor) N1N2MessageTransferProcedure(ueContextID string, reqUri string, n1n2MessageTransferRequest models.N1N2MessageTransferRequest) ( n1n2MessageTransferRspData *models.N1N2MessageTransferRspData, locationHeader string, problemDetails *models.ProblemDetails, @@ -371,21 +377,22 @@ func N1N2MessageTransferProcedure(ueContextID string, reqUri string, } } -func HandleN1N2MessageTransferStatusRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleN1N2MessageTransferStatusRequest(c *gin.Context) { logger.CommLog.Info("Handle N1N2Message Transfer Status Request") - ueContextID := request.Params["ueContextId"] - reqUri := request.Params["reqUri"] + ueContextID := c.Param("ueContextId") + reqUri := c.Param("reqUri") - status, problemDetails := N1N2MessageTransferStatusProcedure(ueContextID, reqUri) + status, problemDetails := p.N1N2MessageTransferStatusProcedure(ueContextID, reqUri) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusOK, nil, status) + c.JSON(http.StatusOK, status) } } -func N1N2MessageTransferStatusProcedure(ueContextID string, reqUri string) (models.N1N2MessageTransferCause, +func (p *Processor) N1N2MessageTransferStatusProcedure(ueContextID string, + reqUri string) (models.N1N2MessageTransferCause, *models.ProblemDetails, ) { amfSelf := context.GetSelf() @@ -417,20 +424,21 @@ func N1N2MessageTransferStatusProcedure(ueContextID string, reqUri string) (mode } // TS 29.518 5.2.2.3.3 -func HandleN1N2MessageSubscirbeRequest(request *httpwrapper.Request) *httpwrapper.Response { - ueN1N2InfoSubscriptionCreateData := request.Body.(models.UeN1N2InfoSubscriptionCreateData) - ueContextID := request.Params["ueContextId"] +func (p *Processor) HandleN1N2MessageSubscribeRequest(c *gin.Context, + ueN1N2InfoSubscriptionCreateData models.UeN1N2InfoSubscriptionCreateData, +) { + ueContextID := c.Param("ueContextId") - ueN1N2InfoSubscriptionCreatedData, problemDetails := N1N2MessageSubscribeProcedure(ueContextID, - ueN1N2InfoSubscriptionCreateData) + ueN1N2InfoSubscriptionCreatedData, problemDetails := p. + N1N2MessageSubscribeProcedure(ueContextID, ueN1N2InfoSubscriptionCreateData) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusCreated, nil, ueN1N2InfoSubscriptionCreatedData) + c.JSON(http.StatusCreated, ueN1N2InfoSubscriptionCreatedData) } } -func N1N2MessageSubscribeProcedure(ueContextID string, +func (p *Processor) N1N2MessageSubscribeProcedure(ueContextID string, ueN1N2InfoSubscriptionCreateData models.UeN1N2InfoSubscriptionCreateData) ( *models.UeN1N2InfoSubscriptionCreatedData, *models.ProblemDetails, ) { @@ -465,21 +473,21 @@ func N1N2MessageSubscribeProcedure(ueContextID string, return ueN1N2InfoSubscriptionCreatedData, nil } -func HandleN1N2MessageUnSubscribeRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleN1N2MessageUnSubscribeRequest(c *gin.Context) { logger.CommLog.Info("Handle N1N2Message Unsubscribe Request") - ueContextID := request.Params["ueContextId"] - subscriptionID := request.Params["subscriptionId"] + ueContextID := c.Param("ueContextId") + subscriptionID := c.Param("subscriptionId") - problemDetails := N1N2MessageUnSubscribeProcedure(ueContextID, subscriptionID) + problemDetails := p.N1N2MessageUnSubscribeProcedure(ueContextID, subscriptionID) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) + c.Status(http.StatusNoContent) } } -func N1N2MessageUnSubscribeProcedure(ueContextID string, subscriptionID string) *models.ProblemDetails { +func (p *Processor) N1N2MessageUnSubscribeProcedure(ueContextID string, subscriptionID string) *models.ProblemDetails { amfSelf := context.GetSelf() ue, ok := amfSelf.AmfUeFindByUeContextID(ueContextID) diff --git a/internal/sbi/producer/callback/n1n2message.go b/internal/sbi/processor/notifier/n1n2message.go similarity index 100% rename from internal/sbi/producer/callback/n1n2message.go rename to internal/sbi/processor/notifier/n1n2message.go diff --git a/internal/sbi/producer/callback/subscription.go b/internal/sbi/processor/notifier/subscription.go similarity index 100% rename from internal/sbi/producer/callback/subscription.go rename to internal/sbi/processor/notifier/subscription.go diff --git a/internal/sbi/producer/callback/ue_context.go b/internal/sbi/processor/notifier/ue_context.go similarity index 100% rename from internal/sbi/producer/callback/ue_context.go rename to internal/sbi/processor/notifier/ue_context.go diff --git a/internal/sbi/producer/oam.go b/internal/sbi/processor/oam.go similarity index 75% rename from internal/sbi/producer/oam.go rename to internal/sbi/processor/oam.go index 59a63832..321af1b4 100644 --- a/internal/sbi/producer/oam.go +++ b/internal/sbi/processor/oam.go @@ -1,13 +1,14 @@ -package producer +package processor import ( "net/http" "strconv" + "github.com/gin-gonic/gin" + "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) type PduSession struct { @@ -34,31 +35,31 @@ type UEContext struct { type UEContexts []UEContext -func HandleOAMRegisteredUEContext(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleOAMRegisteredUEContext(c *gin.Context) { logger.ProducerLog.Infof("[OAM] Handle Registered UE Context") - supi := request.Params["supi"] + supi := c.Query("supi") - ueContexts, problemDetails := OAMRegisteredUEContextProcedure(supi) + ueContexts, problemDetails := p.OAMRegisteredUEContextProcedure(supi) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusOK, nil, ueContexts) + c.JSON(http.StatusOK, ueContexts) } } -func OAMRegisteredUEContextProcedure(supi string) (UEContexts, *models.ProblemDetails) { +func (p *Processor) OAMRegisteredUEContextProcedure(supi string) (UEContexts, *models.ProblemDetails) { var ueContexts UEContexts amfSelf := context.GetSelf() if supi != "" { if ue, ok := amfSelf.AmfUeFindBySupi(supi); ok { ue.Lock.Lock() - ueContext := buildUEContext(ue, models.AccessType__3_GPP_ACCESS) + ueContext := p.buildUEContext(ue, models.AccessType__3_GPP_ACCESS) if ueContext != nil { ueContexts = append(ueContexts, *ueContext) } - ueContext = buildUEContext(ue, models.AccessType_NON_3_GPP_ACCESS) + ueContext = p.buildUEContext(ue, models.AccessType_NON_3_GPP_ACCESS) if ueContext != nil { ueContexts = append(ueContexts, *ueContext) } @@ -74,11 +75,11 @@ func OAMRegisteredUEContextProcedure(supi string) (UEContexts, *models.ProblemDe amfSelf.UePool.Range(func(key, value interface{}) bool { ue := value.(*context.AmfUe) ue.Lock.Lock() - ueContext := buildUEContext(ue, models.AccessType__3_GPP_ACCESS) + ueContext := p.buildUEContext(ue, models.AccessType__3_GPP_ACCESS) if ueContext != nil { ueContexts = append(ueContexts, *ueContext) } - ueContext = buildUEContext(ue, models.AccessType_NON_3_GPP_ACCESS) + ueContext = p.buildUEContext(ue, models.AccessType_NON_3_GPP_ACCESS) if ueContext != nil { ueContexts = append(ueContexts, *ueContext) } @@ -90,7 +91,7 @@ func OAMRegisteredUEContextProcedure(supi string) (UEContexts, *models.ProblemDe return ueContexts, nil } -func buildUEContext(ue *context.AmfUe, accessType models.AccessType) *UEContext { +func (p *Processor) buildUEContext(ue *context.AmfUe, accessType models.AccessType) *UEContext { if ue.State[accessType].Is(context.Registered) { ueContext := &UEContext{ AccessType: models.AccessType__3_GPP_ACCESS, diff --git a/internal/sbi/processor/processor.go b/internal/sbi/processor/processor.go new file mode 100644 index 00000000..1117d8b3 --- /dev/null +++ b/internal/sbi/processor/processor.go @@ -0,0 +1,29 @@ +package processor + +import ( + "github.com/free5gc/amf/internal/sbi/consumer" + "github.com/free5gc/amf/pkg/app" +) + +type ProcessorAmf interface { + app.App + + Consumer() *consumer.Consumer +} + +type Processor struct { + ProcessorAmf + consumer *consumer.Consumer +} + +func NewProcessor(amf ProcessorAmf) (*Processor, error) { + p := &Processor{ + ProcessorAmf: amf, + consumer: amf.Consumer(), + } + return p, nil +} + +func (p *Processor) Consumer() *consumer.Consumer { + return p.consumer +} diff --git a/internal/sbi/producer/subscription.go b/internal/sbi/processor/subscription.go similarity index 59% rename from internal/sbi/producer/subscription.go rename to internal/sbi/processor/subscription.go index 2c6b0c65..43b9f30d 100644 --- a/internal/sbi/producer/subscription.go +++ b/internal/sbi/processor/subscription.go @@ -1,33 +1,31 @@ -package producer +package processor import ( "net/http" "reflect" + "github.com/gin-gonic/gin" + "github.com/free5gc/amf/internal/context" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) // TS 29.518 5.2.2.5.1 -func HandleAMFStatusChangeSubscribeRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleAMFStatusChangeSubscribeRequest(c *gin.Context, subscriptionDataReq models.SubscriptionData) { logger.CommLog.Info("Handle AMF Status Change Subscribe Request") - subscriptionDataReq := request.Body.(models.SubscriptionData) - - subscriptionDataRsp, locationHeader, problemDetails := AMFStatusChangeSubscribeProcedure(subscriptionDataReq) + subscriptionDataRsp, locationHeader, problemDetails := p.AMFStatusChangeSubscribeProcedure(subscriptionDataReq) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) + return } - headers := http.Header{ - "Location": {locationHeader}, - } - return httpwrapper.NewResponse(http.StatusCreated, headers, subscriptionDataRsp) + c.Header("Location", locationHeader) + c.JSON(http.StatusCreated, subscriptionDataRsp) } -func AMFStatusChangeSubscribeProcedure(subscriptionDataReq models.SubscriptionData) ( +func (p *Processor) AMFStatusChangeSubscribeProcedure(subscriptionDataReq models.SubscriptionData) ( subscriptionDataRsp models.SubscriptionData, locationHeader string, problemDetails *models.ProblemDetails, ) { amfSelf := context.GetSelf() @@ -56,20 +54,20 @@ func AMFStatusChangeSubscribeProcedure(subscriptionDataReq models.SubscriptionDa } // TS 29.518 5.2.2.5.2 -func HandleAMFStatusChangeUnSubscribeRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleAMFStatusChangeUnSubscribeRequest(c *gin.Context) { logger.CommLog.Info("Handle AMF Status Change UnSubscribe Request") - subscriptionID := request.Params["subscriptionId"] + subscriptionID := c.Param("subscriptionId") - problemDetails := AMFStatusChangeUnSubscribeProcedure(subscriptionID) + problemDetails := p.AMFStatusChangeUnSubscribeProcedure(subscriptionID) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) + c.Status(http.StatusNoContent) } } -func AMFStatusChangeUnSubscribeProcedure(subscriptionID string) (problemDetails *models.ProblemDetails) { +func (p *Processor) AMFStatusChangeUnSubscribeProcedure(subscriptionID string) (problemDetails *models.ProblemDetails) { amfSelf := context.GetSelf() if _, ok := amfSelf.FindAMFStatusSubscription(subscriptionID); !ok { @@ -85,22 +83,25 @@ func AMFStatusChangeUnSubscribeProcedure(subscriptionID string) (problemDetails } // TS 29.518 5.2.2.5.1.3 -func HandleAMFStatusChangeSubscribeModify(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleAMFStatusChangeSubscribeModify(c *gin.Context, + updateSubscriptionData models.SubscriptionData, +) { logger.CommLog.Info("Handle AMF Status Change Subscribe Modify Request") - updateSubscriptionData := request.Body.(models.SubscriptionData) - subscriptionID := request.Params["subscriptionId"] + subscriptionID := c.Param("subscriptionId") - updatedSubscriptionData, problemDetails := AMFStatusChangeSubscribeModifyProcedure(subscriptionID, - updateSubscriptionData) + updatedSubscriptionData, problemDetails := p. + AMFStatusChangeSubscribeModifyProcedure(subscriptionID, updateSubscriptionData) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) - } else { - return httpwrapper.NewResponse(http.StatusAccepted, nil, updatedSubscriptionData) + c.JSON(int(problemDetails.Status), problemDetails) + return } + + c.JSON(http.StatusAccepted, updatedSubscriptionData) } -func AMFStatusChangeSubscribeModifyProcedure(subscriptionID string, subscriptionData models.SubscriptionData) ( +func (p *Processor) AMFStatusChangeSubscribeModifyProcedure(subscriptionID string, + subscriptionData models.SubscriptionData) ( *models.SubscriptionData, *models.ProblemDetails, ) { amfSelf := context.GetSelf() diff --git a/internal/sbi/producer/ue_context.go b/internal/sbi/processor/ue_context.go similarity index 76% rename from internal/sbi/producer/ue_context.go rename to internal/sbi/processor/ue_context.go index fb611824..63607043 100644 --- a/internal/sbi/producer/ue_context.go +++ b/internal/sbi/processor/ue_context.go @@ -1,4 +1,4 @@ -package producer +package processor import ( "encoding/base64" @@ -6,32 +6,31 @@ import ( "net/http" "strings" + "github.com/gin-gonic/gin" + "github.com/free5gc/amf/internal/context" gmm_common "github.com/free5gc/amf/internal/gmm/common" "github.com/free5gc/amf/internal/logger" "github.com/free5gc/amf/internal/nas/nas_security" - "github.com/free5gc/amf/internal/sbi/consumer" "github.com/free5gc/nas/security" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" ) // TS 29.518 5.2.2.2.3 -func HandleCreateUEContextRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleCreateUEContextRequest(c *gin.Context, createUeContextRequest models.CreateUeContextRequest) { logger.CommLog.Infof("Handle Create UE Context Request") - createUeContextRequest := request.Body.(models.CreateUeContextRequest) - ueContextID := request.Params["ueContextId"] + ueContextID := c.Param("ueContextId") - createUeContextResponse, ueContextCreateError := CreateUEContextProcedure(ueContextID, createUeContextRequest) + createUeContextResponse, ueContextCreateError := p.CreateUEContextProcedure(ueContextID, createUeContextRequest) if ueContextCreateError != nil { - return httpwrapper.NewResponse(int(ueContextCreateError.Error.Status), nil, ueContextCreateError) + c.JSON(int(ueContextCreateError.Error.Status), ueContextCreateError) } else { - return httpwrapper.NewResponse(http.StatusCreated, nil, createUeContextResponse) + c.JSON(http.StatusCreated, createUeContextResponse) } } -func CreateUEContextProcedure(ueContextID string, createUeContextRequest models.CreateUeContextRequest) ( +func (p *Processor) CreateUEContextProcedure(ueContextID string, createUeContextRequest models.CreateUeContextRequest) ( *models.CreateUeContextResponse, *models.UeContextCreateError, ) { amfSelf := context.GetSelf() @@ -74,11 +73,11 @@ func CreateUEContextProcedure(ueContextID string, createUeContextRequest models. ue.UnauthenticatedSupi = ueContextCreateData.UeContext.SupiUnauthInd // should be smInfo list - //for _, smInfo := range ueContextCreateData.PduSessionList { - //if smInfo.N2InfoContent.NgapIeType == "NgapIeType_HANDOVER_REQUIRED" { - // ue.N1N2Message[amfSelf.Uri].Request.JsonData.N2InfoContainer.SmInfo = &smInfo - //} - //} + // for _, smInfo := range ueContextCreateData.PduSessionList { + // if smInfo.N2InfoContent.NgapIeType == "NgapIeType_HANDOVER_REQUIRED" { + // ue.N1N2Message[amfSelf.Uri].Request.JsonData.N2InfoContainer.SmInfo = &smInfo + // } + // } ue.RoutingIndicator = ueContextCreateData.UeContext.RoutingIndicator @@ -123,10 +122,10 @@ func CreateUEContextProcedure(ueContextID string, createUeContextRequest models. createUeContextResponse.JsonData.PcfReselectedInd = false // TODO: When Target AMF selects a nw PCF for AM policy, set the flag to true. - //response.UeContext = ueContextCreateData.UeContext - //response.TargetToSourceData = ue.N1N2Message[amfSelf.Uri].Request.JsonData.N2InfoContainer.SmInfo.N2InfoContent - //response.PduSessionList = ueContextCreateData.PduSessionList - //response.PcfReselectedInd = false // TODO:When Target AMF selects a nw PCF for AM policy, set the flag to true. + // response.UeContext = ueContextCreateData.UeContext + // response.TargetToSourceData = ue.N1N2Message[amfSelf.Uri].Request.JsonData.N2InfoContainer.SmInfo.N2InfoContent + // response.PduSessionList = ueContextCreateData.PduSessionList + // response.PcfReselectedInd = false // TODO:When Target AMF selects a nw PCF for AM policy, set the flag to true. // // return httpwrapper.NewResponse(http.StatusCreated, nil, createUeContextResponse) @@ -134,21 +133,22 @@ func CreateUEContextProcedure(ueContextID string, createUeContextRequest models. } // TS 29.518 5.2.2.2.4 -func HandleReleaseUEContextRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleReleaseUEContextRequest(c *gin.Context, ueContextRelease models.UeContextRelease) { logger.CommLog.Info("Handle Release UE Context Request") - ueContextRelease := request.Body.(models.UeContextRelease) - ueContextID := request.Params["ueContextId"] + ueContextID := c.Param("ueContextId") - problemDetails := ReleaseUEContextProcedure(ueContextID, ueContextRelease) + problemDetails := p.ReleaseUEContextProcedure(ueContextID, ueContextRelease) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusNoContent, nil, nil) + c.Status(http.StatusNoContent) } } -func ReleaseUEContextProcedure(ueContextID string, ueContextRelease models.UeContextRelease) *models.ProblemDetails { +func (p *Processor) ReleaseUEContextProcedure(ueContextID string, + ueContextRelease models.UeContextRelease, +) *models.ProblemDetails { amfSelf := context.GetSelf() // TODO: UE is emergency registered and the SUPI is not authenticated @@ -195,7 +195,7 @@ func ReleaseUEContextProcedure(ueContextID string, ueContextRelease models.UeCon return nil } -func HandleMobiRegUe(ue *context.AmfUe, ueContextTransferRspData *models.UeContextTransferRspData, +func (p *Processor) HandleMobiRegUe(ue *context.AmfUe, ueContextTransferRspData *models.UeContextTransferRspData, ueContextTransferResponse *models.UeContextTransferResponse, ) { ueContextTransferRspData.UeRadioCapability = &models.N2InfoContent{ @@ -210,21 +210,23 @@ func HandleMobiRegUe(ue *context.AmfUe, ueContextTransferRspData *models.UeConte } // TS 29.518 5.2.2.2.1 -func HandleUEContextTransferRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleUEContextTransferRequest(c *gin.Context, + ueContextTransferRequest models.UeContextTransferRequest, +) { logger.CommLog.Info("Handle UE Context Transfer Request") - ueContextTransferRequest := request.Body.(models.UeContextTransferRequest) - ueContextID := request.Params["ueContextId"] + ueContextID := c.Param("ueContextId") - ueContextTransferResponse, problemDetails := UEContextTransferProcedure(ueContextID, ueContextTransferRequest) + ueContextTransferResponse, problemDetails := p.UEContextTransferProcedure(ueContextID, ueContextTransferRequest) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusOK, nil, ueContextTransferResponse) + c.JSON(http.StatusOK, ueContextTransferResponse) } } -func UEContextTransferProcedure(ueContextID string, ueContextTransferRequest models.UeContextTransferRequest) ( +func (p *Processor) UEContextTransferProcedure(ueContextID string, + ueContextTransferRequest models.UeContextTransferRequest) ( *models.UeContextTransferResponse, *models.ProblemDetails, ) { amfSelf := context.GetSelf() @@ -265,13 +267,13 @@ func UEContextTransferProcedure(ueContextID string, ueContextTransferRequest mod } ueContextTransferRspData := ueContextTransferResponse.JsonData - //if ue.GetAnType() != UeContextTransferReqData.AccessType { - //for _, tai := range ue.RegistrationArea[ue.GetAnType()] { - //if UeContextTransferReqData.PlmnId == tai.PlmnId { - // TODO : generate N2 signalling - //} - //} - //} + // if ue.GetAnType() != UeContextTransferReqData.AccessType { + // for _, tai := range ue.RegistrationArea[ue.GetAnType()] { + // if UeContextTransferReqData.PlmnId == tai.PlmnId { + // TODO : generate N2 signaling + // } + // } + // } switch UeContextTransferReqData.Reason { case models.TransferReason_INIT_REG: @@ -286,7 +288,7 @@ func UEContextTransferProcedure(ueContextID string, ueContextTransferRequest mod return nil, problemDetails } if integrityProtected { - ueContextTransferRspData.UeContext = buildUEContextModel(ue, UeContextTransferReqData.Reason) + ueContextTransferRspData.UeContext = p.buildUEContextModel(ue, UeContextTransferReqData.Reason) } else { problemDetails := &models.ProblemDetails{ Status: http.StatusForbidden, @@ -307,7 +309,7 @@ func UEContextTransferProcedure(ueContextID string, ueContextTransferRequest mod return nil, problemDetails } if integrityProtected { - ueContextTransferRspData.UeContext = buildUEContextModel(ue, UeContextTransferReqData.Reason) + ueContextTransferRspData.UeContext = p.buildUEContextModel(ue, UeContextTransferReqData.Reason) } else { problemDetails := &models.ProblemDetails{ Status: http.StatusForbidden, @@ -315,11 +317,11 @@ func UEContextTransferProcedure(ueContextID string, ueContextTransferRequest mod } return nil, problemDetails } - HandleMobiRegUe(ue, ueContextTransferRspData, ueContextTransferResponse) + p.HandleMobiRegUe(ue, ueContextTransferRspData, ueContextTransferResponse) case models.TransferReason_MOBI_REG_UE_VALIDATED: - ueContextTransferRspData.UeContext = buildUEContextModel(ue, UeContextTransferReqData.Reason) - HandleMobiRegUe(ue, ueContextTransferRspData, ueContextTransferResponse) + ueContextTransferRspData.UeContext = p.buildUEContextModel(ue, UeContextTransferReqData.Reason) + p.HandleMobiRegUe(ue, ueContextTransferRspData, ueContextTransferResponse) default: logger.ProducerLog.Warnf("Invalid Transfer Reason: %+v", UeContextTransferReqData.Reason) @@ -337,11 +339,11 @@ func UEContextTransferProcedure(ueContextID string, ueContextTransferRequest mod return ueContextTransferResponse, nil } -func buildUEContextModel(ue *context.AmfUe, Reason models.TransferReason) *models.UeContext { +func (p *Processor) buildUEContextModel(ue *context.AmfUe, reason models.TransferReason) *models.UeContext { ueContext := new(models.UeContext) ueContext.Supi = ue.Supi ueContext.SupiUnauthInd = ue.UnauthenticatedSupi - if Reason == models.TransferReason_INIT_REG || Reason == models.TransferReason_MOBI_REG { + if reason == models.TransferReason_INIT_REG || reason == models.TransferReason_MOBI_REG { var mmContext models.MmContext mmContext.AccessType = models.AccessType__3_GPP_ACCESS NasSecurityMode := new(models.NasSecurityMode) @@ -394,7 +396,7 @@ func buildUEContextModel(ue *context.AmfUe, Reason models.TransferReason) *model } ueContext.MmContextList = append(ueContext.MmContextList, mmContext) } - if Reason == models.TransferReason_MOBI_REG_UE_VALIDATED || Reason == models.TransferReason_MOBI_REG { + if reason == models.TransferReason_MOBI_REG_UE_VALIDATED || reason == models.TransferReason_MOBI_REG { sessionContextList := &ueContext.SessionContextList ue.SmContextList.Range(func(key, value interface{}) bool { smContext := value.(*context.SmContext) @@ -455,7 +457,7 @@ func buildUEContextModel(ue *context.AmfUe, Reason models.TransferReason) *model if ue.AmPolicyAssociation != nil { if len(ue.AmPolicyAssociation.Triggers) > 0 { - ueContext.AmPolicyReqTriggerList = buildAmPolicyReqTriggers(ue.AmPolicyAssociation.Triggers) + ueContext.AmPolicyReqTriggerList = p.buildAmPolicyReqTriggers(ue.AmPolicyAssociation.Triggers) } } @@ -471,7 +473,9 @@ func buildUEContextModel(ue *context.AmfUe, Reason models.TransferReason) *model return ueContext } -func buildAmPolicyReqTriggers(triggers []models.RequestTrigger) (amPolicyReqTriggers []models.AmPolicyReqTrigger) { +func (p *Processor) buildAmPolicyReqTriggers(triggers []models.RequestTrigger) ( + amPolicyReqTriggers []models.AmPolicyReqTrigger, +) { for _, trigger := range triggers { switch trigger { case models.RequestTrigger_LOC_CH: @@ -488,23 +492,22 @@ func buildAmPolicyReqTriggers(triggers []models.RequestTrigger) (amPolicyReqTrig } // TS 29.518 5.2.2.6 -func HandleAssignEbiDataRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleAssignEbiDataRequest(c *gin.Context, assignEbiData models.AssignEbiData) { logger.CommLog.Info("Handle Assign Ebi Data Request") - assignEbiData := request.Body.(models.AssignEbiData) - ueContextID := request.Params["ueContextId"] + ueContextID := c.Param("ueContextId") - assignedEbiData, assignEbiError, problemDetails := AssignEbiDataProcedure(ueContextID, assignEbiData) + assignedEbiData, assignEbiError, problemDetails := p.AssignEbiDataProcedure(ueContextID, assignEbiData) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else if assignEbiError != nil { - return httpwrapper.NewResponse(int(assignEbiError.Error.Status), nil, assignEbiError) + c.JSON(int(assignEbiError.Error.Status), assignEbiError) } else { - return httpwrapper.NewResponse(http.StatusOK, nil, assignedEbiData) + c.JSON(http.StatusOK, assignedEbiData) } } -func AssignEbiDataProcedure(ueContextID string, assignEbiData models.AssignEbiData) ( +func (p *Processor) AssignEbiDataProcedure(ueContextID string, assignEbiData models.AssignEbiData) ( *models.AssignedEbiData, *models.AssignEbiError, *models.ProblemDetails, ) { amfSelf := context.GetSelf() @@ -523,7 +526,7 @@ func AssignEbiDataProcedure(ueContextID string, assignEbiData models.AssignEbiDa defer ue.Lock.Unlock() // TODO: AssignEbiError not used, check it! - if _, ok := ue.SmContextFindByPDUSessionID(assignEbiData.PduSessionId); ok { + if _, okSmContextFind := ue.SmContextFindByPDUSessionID(assignEbiData.PduSessionId); okSmContextFind { var assignedEbiData *models.AssignedEbiData assignedEbiData.PduSessionId = assignEbiData.PduSessionId return assignedEbiData, nil, nil @@ -533,21 +536,23 @@ func AssignEbiDataProcedure(ueContextID string, assignEbiData models.AssignEbiDa } // TS 29.518 5.2.2.2.2 -func HandleRegistrationStatusUpdateRequest(request *httpwrapper.Request) *httpwrapper.Response { +func (p *Processor) HandleRegistrationStatusUpdateRequest(c *gin.Context, + ueRegStatusUpdateReqData models.UeRegStatusUpdateReqData, +) { logger.CommLog.Info("Handle Registration Status Update Request") - ueRegStatusUpdateReqData := request.Body.(models.UeRegStatusUpdateReqData) - ueContextID := request.Params["ueContextId"] + ueContextID := c.Param("ueContextId") - ueRegStatusUpdateRspData, problemDetails := RegistrationStatusUpdateProcedure(ueContextID, ueRegStatusUpdateReqData) + ueRegStatusUpdateRspData, problemDetails := p.RegistrationStatusUpdateProcedure(ueContextID, ueRegStatusUpdateReqData) if problemDetails != nil { - return httpwrapper.NewResponse(int(problemDetails.Status), nil, problemDetails) + c.JSON(int(problemDetails.Status), problemDetails) } else { - return httpwrapper.NewResponse(http.StatusOK, nil, ueRegStatusUpdateRspData) + c.JSON(http.StatusOK, ueRegStatusUpdateRspData) } } -func RegistrationStatusUpdateProcedure(ueContextID string, ueRegStatusUpdateReqData models.UeRegStatusUpdateReqData) ( +func (p *Processor) RegistrationStatusUpdateProcedure(ueContextID string, + ueRegStatusUpdateReqData models.UeRegStatusUpdateReqData) ( *models.UeRegStatusUpdateRspData, *models.ProblemDetails, ) { amfSelf := context.GetSelf() @@ -561,8 +566,8 @@ func RegistrationStatusUpdateProcedure(ueContextID string, ueRegStatusUpdateReqD return nil, problemDetails } - ue, ok := amfSelf.AmfUeFindByUeContextID(ueContextID) - if !ok { + ue, okAmfUeFindByUeContextID := amfSelf.AmfUeFindByUeContextID(ueContextID) + if !okAmfUeFindByUeContextID { logger.CtxLog.Warnf("AmfUe Context[%s] not found", ueContextID) problemDetails := &models.ProblemDetails{ Status: http.StatusNotFound, @@ -583,12 +588,12 @@ func RegistrationStatusUpdateProcedure(ueContextID string, ueRegStatusUpdateReqD causeAll := &context.CauseAll{ Cause: &cause, } - smContext, ok := ue.SmContextFindByPDUSessionID(pduSessionId) - if !ok { + smContext, okSmContextFindByPDUSessionID := ue.SmContextFindByPDUSessionID(pduSessionId) + if !okSmContextFindByPDUSessionID { ue.ProducerLog.Errorf("SmContext[PDU Session ID:%d] not found", pduSessionId) continue } - problem, err := consumer.SendReleaseSmContextRequest(ue, smContext, causeAll, "", nil) + problem, err := p.Consumer().SendReleaseSmContextRequest(ue, smContext, causeAll, "", nil) if problem != nil { logger.GmmLog.Errorf("Release SmContext[pduSessionId: %d] Failed Problem[%+v]", pduSessionId, problem) } else if err != nil { @@ -597,7 +602,7 @@ func RegistrationStatusUpdateProcedure(ueContextID string, ueRegStatusUpdateReqD } if ueRegStatusUpdateReqData.PcfReselectedInd { - problem, err := consumer.AMPolicyControlDelete(ue) + problem, err := p.Consumer().AMPolicyControlDelete(ue) if problem != nil { logger.GmmLog.Errorf("AM Policy Control Delete Failed Problem[%+v]", problem) } else if err != nil { diff --git a/internal/sbi/routes.go b/internal/sbi/routes.go new file mode 100644 index 00000000..124bbf8d --- /dev/null +++ b/internal/sbi/routes.go @@ -0,0 +1,26 @@ +package sbi + +import "github.com/gin-gonic/gin" + +type Route struct { + Method string + Pattern string + APIFunc gin.HandlerFunc +} + +func applyRoutes(group *gin.RouterGroup, routes []Route) { + for _, route := range routes { + switch route.Method { + case "GET": + group.GET(route.Pattern, route.APIFunc) + case "POST": + group.POST(route.Pattern, route.APIFunc) + case "PUT": + group.PUT(route.Pattern, route.APIFunc) + case "PATCH": + group.PATCH(route.Pattern, route.APIFunc) + case "DELETE": + group.DELETE(route.Pattern, route.APIFunc) + } + } +} diff --git a/internal/sbi/server.go b/internal/sbi/server.go new file mode 100644 index 00000000..8cec3d0e --- /dev/null +++ b/internal/sbi/server.go @@ -0,0 +1,184 @@ +package sbi + +import ( + "context" + "fmt" + "log" + "net/http" + "runtime/debug" + "sync" + "time" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + + amf_context "github.com/free5gc/amf/internal/context" + "github.com/free5gc/amf/internal/logger" + "github.com/free5gc/amf/internal/sbi/consumer" + "github.com/free5gc/amf/internal/sbi/processor" + util_oauth "github.com/free5gc/amf/internal/util" + "github.com/free5gc/amf/pkg/app" + "github.com/free5gc/amf/pkg/factory" + "github.com/free5gc/openapi/models" + "github.com/free5gc/util/httpwrapper" + logger_util "github.com/free5gc/util/logger" +) + +var ( + reqbody = "[Request Body] " + applicationjson = "application/json" + multipartrelate = "multipart/related" +) + +type ServerAmf interface { + app.App + + Consumer() *consumer.Consumer + Processor() *processor.Processor +} + +type Server struct { + ServerAmf + + httpServer *http.Server + router *gin.Engine +} + +func NewServer(amf ServerAmf, tlsKeyLogPath string) (*Server, error) { + s := &Server{ + ServerAmf: amf, + } + + s.router = newRouter(s) + + cfg := s.Config() + bindAddr := cfg.GetSbiBindingAddr() + logger.SBILog.Infof("Binding addr: [%s]", bindAddr) + var err error + if s.httpServer, err = httpwrapper.NewHttp2Server(bindAddr, tlsKeyLogPath, s.router); err != nil { + logger.InitLog.Errorf("Initialize HTTP server failed: %v", err) + return nil, err + } + s.httpServer.ErrorLog = log.New(logger.SBILog.WriterLevel(logrus.ErrorLevel), "HTTP2: ", 0) + + return s, nil +} + +func newRouter(s *Server) *gin.Engine { + router := logger_util.NewGinWithLogrus(logger.GinLog) + + amfHttpCallBackGroup := router.Group(factory.AmfCallbackResUriPrefix) + amfHttpCallBackRoutes := s.getHttpCallBackRoutes() + applyRoutes(amfHttpCallBackGroup, amfHttpCallBackRoutes) + + for _, serverName := range factory.AmfConfig.Configuration.ServiceNameList { + switch models.ServiceName(serverName) { + case models.ServiceName_NAMF_COMM: + amfCommunicationGroup := router.Group(factory.AmfCommResUriPrefix) + amfCommunicationRoutes := s.getCommunicationRoutes() + routerAuthorizationCheck := util_oauth.NewRouterAuthorizationCheck(models.ServiceName_NAMF_COMM) + amfCommunicationGroup.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, amf_context.GetSelf()) + }) + applyRoutes(amfCommunicationGroup, amfCommunicationRoutes) + case models.ServiceName_NAMF_EVTS: + amfEventExposureGroup := router.Group(factory.AmfEvtsResUriPrefix) + amfEventExposureRoutes := s.getEventexposureRoutes() + routerAuthorizationCheck := util_oauth.NewRouterAuthorizationCheck(models.ServiceName_NAMF_EVTS) + amfEventExposureGroup.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, amf_context.GetSelf()) + }) + applyRoutes(amfEventExposureGroup, amfEventExposureRoutes) + case models.ServiceName_NAMF_MT: + amfMTGroup := router.Group(factory.AmfMtResUriPrefix) + amfMTRoutes := s.getMTRoutes() + routerAuthorizationCheck := util_oauth.NewRouterAuthorizationCheck(models.ServiceName_NAMF_MT) + amfMTGroup.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, amf_context.GetSelf()) + }) + applyRoutes(amfMTGroup, amfMTRoutes) + case models.ServiceName_NAMF_LOC: + amfLocationGroup := router.Group(factory.AmfLocResUriPrefix) + amfLocationRoutes := s.getLocationRoutes() + routerAuthorizationCheck := util_oauth.NewRouterAuthorizationCheck(models.ServiceName_NAMF_LOC) + amfLocationGroup.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, amf_context.GetSelf()) + }) + applyRoutes(amfLocationGroup, amfLocationRoutes) + case models.ServiceName_NAMF_OAM: + amfOAMGroup := router.Group(factory.AmfOamResUriPrefix) + amfOAMRoutes := s.getOAMRoutes() + routerAuthorizationCheck := util_oauth.NewRouterAuthorizationCheck(models.ServiceName_NAMF_OAM) + amfOAMGroup.Use(func(c *gin.Context) { + routerAuthorizationCheck.Check(c, amf_context.GetSelf()) + }) + applyRoutes(amfOAMGroup, amfOAMRoutes) + } + } + + return router +} + +func (s *Server) Run(traceCtx context.Context, wg *sync.WaitGroup) error { + var profile models.NfProfile + if profileTmp, err1 := s.Consumer().BuildNFInstance(s.Context()); err1 != nil { + logger.InitLog.Error("Build AMF Profile Error") + } else { + profile = profileTmp + } + _, nfId, err_reg := s.Consumer().SendRegisterNFInstance(s.Context().NrfUri, s.Context().NfId, profile) + if err_reg != nil { + logger.InitLog.Warnf("Send Register NF Instance failed: %+v", err_reg) + } else { + s.Context().NfId = nfId + } + + wg.Add(1) + go s.startServer(wg) + + return nil +} + +func (s *Server) Stop() { + const defaultShutdownTimeout time.Duration = 2 * time.Second + + if s.httpServer != nil { + logger.SBILog.Infof("Stop SBI server (listen on %s)", s.httpServer.Addr) + toCtx, cancel := context.WithTimeout(context.Background(), defaultShutdownTimeout) + defer cancel() + if err := s.httpServer.Shutdown(toCtx); err != nil { + logger.SBILog.Errorf("Could not close SBI server: %#v", err) + } + } +} + +func (s *Server) startServer(wg *sync.WaitGroup) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.SBILog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + s.Terminate() + } + wg.Done() + }() + + logger.SBILog.Infof("Start SBI server (listen on %s)", s.httpServer.Addr) + + var err error + cfg := s.Config() + scheme := cfg.GetSbiScheme() + if scheme == "http" { + err = s.httpServer.ListenAndServe() + } else if scheme == "https" { + err = s.httpServer.ListenAndServeTLS( + cfg.GetCertPemPath(), + cfg.GetCertKeyPath()) + } else { + err = fmt.Errorf("no support this scheme[%s]", scheme) + } + + if err != nil && err != http.ErrServerClosed { + logger.SBILog.Errorf("SBI server error: %v", err) + } + logger.SBILog.Warnf("SBI server (listen on %s) stopped", s.httpServer.Addr) +} diff --git a/internal/util/router_auth_check_test.go b/internal/util/router_auth_check_test.go index 0c147232..045595e3 100644 --- a/internal/util/router_auth_check_test.go +++ b/internal/util/router_auth_check_test.go @@ -1,4 +1,4 @@ -package util +package util_test import ( "net/http" @@ -8,6 +8,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pkg/errors" + "github.com/free5gc/amf/internal/util" "github.com/free5gc/openapi/models" ) @@ -85,7 +86,7 @@ func TestRouterAuthorizationCheck_Check(t *testing.T) { var testService models.ServiceName = "testService" - rac := NewRouterAuthorizationCheck(testService) + rac := util.NewRouterAuthorizationCheck(testService) rac.Check(c, newMockAMFContext()) if w.Code != tt.want.statusCode { t.Errorf("StatusCode should be %d, but got %d", tt.want.statusCode, w.Code) diff --git a/pkg/app/app.go b/pkg/app/app.go new file mode 100644 index 00000000..3de4097e --- /dev/null +++ b/pkg/app/app.go @@ -0,0 +1,18 @@ +package app + +import ( + amf_context "github.com/free5gc/amf/internal/context" + "github.com/free5gc/amf/pkg/factory" +) + +type App interface { + SetLogEnable(enable bool) + SetLogLevel(level string) + SetReportCaller(reportCaller bool) + + Start() + Terminate() + + Context() *amf_context.AMFContext + Config() *factory.Config +} diff --git a/pkg/app/mock.go b/pkg/app/mock.go new file mode 100644 index 00000000..abe29b40 --- /dev/null +++ b/pkg/app/mock.go @@ -0,0 +1,129 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/app/app.go +// +// Generated by this command: +// +// mockgen -source=pkg/app/app.go -package=app +// + +// Package app is a generated GoMock package. +package app + +import ( + reflect "reflect" + + context "github.com/free5gc/amf/internal/context" + factory "github.com/free5gc/amf/pkg/factory" + gomock "go.uber.org/mock/gomock" +) + +// MockApp is a mock of App interface. +type MockApp struct { + ctrl *gomock.Controller + recorder *MockAppMockRecorder +} + +// MockAppMockRecorder is the mock recorder for MockApp. +type MockAppMockRecorder struct { + mock *MockApp +} + +// NewMockApp creates a new mock instance. +func NewMockApp(ctrl *gomock.Controller) *MockApp { + mock := &MockApp{ctrl: ctrl} + mock.recorder = &MockAppMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockApp) EXPECT() *MockAppMockRecorder { + return m.recorder +} + +// Config mocks base method. +func (m *MockApp) Config() *factory.Config { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Config") + ret0, _ := ret[0].(*factory.Config) + return ret0 +} + +// Config indicates an expected call of Config. +func (mr *MockAppMockRecorder) Config() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Config", reflect.TypeOf((*MockApp)(nil).Config)) +} + +// Context mocks base method. +func (m *MockApp) Context() *context.AMFContext { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(*context.AMFContext) + return ret0 +} + +// Context indicates an expected call of Context. +func (mr *MockAppMockRecorder) Context() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockApp)(nil).Context)) +} + +// SetLogEnable mocks base method. +func (m *MockApp) SetLogEnable(enable bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetLogEnable", enable) +} + +// SetLogEnable indicates an expected call of SetLogEnable. +func (mr *MockAppMockRecorder) SetLogEnable(enable any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLogEnable", reflect.TypeOf((*MockApp)(nil).SetLogEnable), enable) +} + +// SetLogLevel mocks base method. +func (m *MockApp) SetLogLevel(level string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetLogLevel", level) +} + +// SetLogLevel indicates an expected call of SetLogLevel. +func (mr *MockAppMockRecorder) SetLogLevel(level any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLogLevel", reflect.TypeOf((*MockApp)(nil).SetLogLevel), level) +} + +// SetReportCaller mocks base method. +func (m *MockApp) SetReportCaller(reportCaller bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetReportCaller", reportCaller) +} + +// SetReportCaller indicates an expected call of SetReportCaller. +func (mr *MockAppMockRecorder) SetReportCaller(reportCaller any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetReportCaller", reflect.TypeOf((*MockApp)(nil).SetReportCaller), reportCaller) +} + +// Start mocks base method. +func (m *MockApp) Start(tlsKeyLogPath string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Start", tlsKeyLogPath) +} + +// Start indicates an expected call of Start. +func (mr *MockAppMockRecorder) Start(tlsKeyLogPath any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockApp)(nil).Start), tlsKeyLogPath) +} + +// Terminate mocks base method. +func (m *MockApp) Terminate() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Terminate") +} + +// Terminate indicates an expected call of Terminate. +func (mr *MockAppMockRecorder) Terminate() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Terminate", reflect.TypeOf((*MockApp)(nil).Terminate)) +} diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 252a94bc..ed76da6f 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -106,7 +106,7 @@ func (c *Configuration) validate() (bool, error) { var errs govalidator.Errors for _, v := range c.NgapIpList { if result := govalidator.IsHost(v); !result { - err := fmt.Errorf("Invalid NgapIpList: %s, value should be in the form of IP", v) + err := fmt.Errorf("invalid NgapIpList: %s, value should be in the form of IP", v) errs = append(errs, err) } } @@ -125,7 +125,7 @@ func (c *Configuration) validate() (bool, error) { var errs govalidator.Errors for _, v := range c.ServiceNameList { if v != "namf-comm" && v != "namf-evts" && v != "namf-mt" && v != "namf-loc" && v != "namf-oam" { - err := fmt.Errorf("Invalid ServiceNameList: %s,"+ + err := fmt.Errorf("invalid ServiceNameList: %s,"+ " value should be namf-comm or namf-evts or namf-mt or namf-loc or namf-oam", v) errs = append(errs, err) } @@ -225,7 +225,7 @@ func (c *Configuration) validate() (bool, error) { } if n3gppVal := &(c.Non3gppDeregTimerValue); n3gppVal == nil { - err := fmt.Errorf("Invalid Non3gppDeregTimerValue: value is required") + err := fmt.Errorf("invalid Non3gppDeregTimerValue: value is required") return false, err } @@ -374,7 +374,7 @@ func (p *PlmnSupportItem) validate() (bool, error) { mnc := p.PlmnId.Mnc if result := govalidator.StringMatches(mnc, "^[0-9]{2,3}$"); !result { - err := fmt.Errorf("Invalid mnc: %s, should be a 2 or 3-digit number", mnc) + err := fmt.Errorf("invalid mnc: %s, should be a 2 or 3-digit number", mnc) errs = append(errs, err) } @@ -382,11 +382,11 @@ func (p *PlmnSupportItem) validate() (bool, error) { sst := snssai.Sst sd := snssai.Sd if result := govalidator.InRangeInt(sst, 0, 255); !result { - err := fmt.Errorf("Invalid sst: %d, should be in the range of 0~255", sst) + err := fmt.Errorf("invalid sst: %d, should be in the range of 0~255", sst) errs = append(errs, err) } if result := govalidator.StringMatches(sd, "^[A-Fa-f0-9]{6}$"); !result { - err := fmt.Errorf("Invalid sd: %s, should be 3 bytes hex string, range: 000000~FFFFFF", sd) + err := fmt.Errorf("invalid sd: %s, should be 3 bytes hex string, range: 000000~FFFFFF", sd) errs = append(errs, err) } } @@ -854,3 +854,15 @@ func (c *Config) GetSctpConfig() *Sctp { MaxInitTimeout: sctpDefaultMaxInitTimeout, } } + +func (c *Config) GetCertPemPath() string { + c.RLock() + defer c.RUnlock() + return c.Configuration.Sbi.Tls.Pem +} + +func (c *Config) GetCertKeyPath() string { + c.RLock() + defer c.RUnlock() + return c.Configuration.Sbi.Tls.Key +} diff --git a/pkg/service/init.go b/pkg/service/init.go index 00de516a..43b584f3 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -1,14 +1,12 @@ package service import ( - "fmt" + "context" "io" "os" - "os/signal" "runtime/debug" - "syscall" + "sync" - "github.com/gin-contrib/cors" "github.com/sirupsen/logrus" amf_context "github.com/free5gc/amf/internal/context" @@ -16,33 +14,67 @@ import ( "github.com/free5gc/amf/internal/ngap" ngap_message "github.com/free5gc/amf/internal/ngap/message" ngap_service "github.com/free5gc/amf/internal/ngap/service" - "github.com/free5gc/amf/internal/sbi/communication" + "github.com/free5gc/amf/internal/sbi" "github.com/free5gc/amf/internal/sbi/consumer" - "github.com/free5gc/amf/internal/sbi/eventexposure" - "github.com/free5gc/amf/internal/sbi/httpcallback" - "github.com/free5gc/amf/internal/sbi/location" - "github.com/free5gc/amf/internal/sbi/mt" - "github.com/free5gc/amf/internal/sbi/oam" - "github.com/free5gc/amf/internal/sbi/producer/callback" + "github.com/free5gc/amf/internal/sbi/processor" + callback "github.com/free5gc/amf/internal/sbi/processor/notifier" + "github.com/free5gc/amf/pkg/app" "github.com/free5gc/amf/pkg/factory" "github.com/free5gc/openapi/models" - "github.com/free5gc/util/httpwrapper" - logger_util "github.com/free5gc/util/logger" ) +type AmfAppInterface interface { + app.App + consumer.ConsumerAmf + Consumer() *consumer.Consumer + Processor() *processor.Processor +} + +var AMF AmfAppInterface + type AmfApp struct { + AmfAppInterface + cfg *factory.Config amfCtx *amf_context.AMFContext + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup + + processor *processor.Processor + consumer *consumer.Consumer + sbiServer *sbi.Server } -func NewApp(cfg *factory.Config) (*AmfApp, error) { - amf := &AmfApp{cfg: cfg} +func NewApp(ctx context.Context, cfg *factory.Config, tlsKeyLogPath string) (*AmfApp, error) { + amf := &AmfApp{ + cfg: cfg, + } amf.SetLogEnable(cfg.GetLogEnable()) amf.SetLogLevel(cfg.GetLogLevel()) amf.SetReportCaller(cfg.GetLogReportCaller()) + consumer, err := consumer.NewConsumer(amf) + if err != nil { + return amf, err + } + amf.consumer = consumer + + processor, err_p := processor.NewProcessor(amf) + if err_p != nil { + return amf, err_p + } + amf.processor = processor + + amf.ctx, amf.cancel = context.WithCancel(ctx) amf.amfCtx = amf_context.GetSelf() - amf_context.InitAmfContext(amf.amfCtx) + + if amf.sbiServer, err = sbi.NewServer(amf, tlsKeyLogPath); err != nil { + return nil, err + } + + AMF = amf + return amf, nil } @@ -88,50 +120,10 @@ func (a *AmfApp) SetReportCaller(reportCaller bool) { logger.Log.SetReportCaller(reportCaller) } -func (a *AmfApp) Start(tlsKeyLogPath string) { - logger.InitLog.Infoln("Server started") - - router := logger_util.NewGinWithLogrus(logger.GinLog) - router.Use(cors.New(cors.Config{ - AllowMethods: []string{"GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE"}, - AllowHeaders: []string{ - "Origin", "Content-Length", "Content-Type", "User-Agent", "Referrer", "Host", - "Token", "X-Requested-With", - }, - ExposeHeaders: []string{"Content-Length"}, - AllowCredentials: true, - AllowAllOrigins: true, - MaxAge: 86400, - })) - - httpcallback.AddService(router) - oam.AddService(router) - for _, serviceName := range factory.AmfConfig.Configuration.ServiceNameList { - switch models.ServiceName(serviceName) { - case models.ServiceName_NAMF_COMM: - communication.AddService(router) - case models.ServiceName_NAMF_EVTS: - eventexposure.AddService(router) - case models.ServiceName_NAMF_MT: - mt.AddService(router) - case models.ServiceName_NAMF_LOC: - location.AddService(router) - } - } - - pemPath := factory.AmfDefaultCertPemPath - keyPath := factory.AmfDefaultPrivateKeyPath - sbi := factory.AmfConfig.Configuration.Sbi - if sbi.Tls != nil { - pemPath = sbi.Tls.Pem - keyPath = sbi.Tls.Key - } - - self := a.amfCtx +func (a *AmfApp) Start() { + self := a.Context() amf_context.InitAmfContext(self) - addr := fmt.Sprintf("%s:%d", self.BindingIPv4, self.SBIPort) - ngapHandler := ngap_service.NGAPHandler{ HandleMessage: ngap.Dispatch, HandleNotification: ngap.HandleSCTPNotification, @@ -139,88 +131,92 @@ func (a *AmfApp) Start(tlsKeyLogPath string) { } sctpConfig := ngap_service.NewSctpConfig(factory.AmfConfig.GetSctpConfig()) - ngap_service.Run(self.NgapIpList, self.NgapPort, ngapHandler, sctpConfig) + ngap_service.Run(a.Context().NgapIpList, a.Context().NgapPort, ngapHandler, sctpConfig) + logger.InitLog.Infoln("Server started") - // Register to NRF - var profile models.NfProfile - if profileTmp, err := consumer.BuildNFInstance(self); err != nil { - logger.InitLog.Error("Build AMF Profile Error") - } else { - profile = profileTmp - } + a.wg.Add(1) + go a.listenShutdownEvent() - if _, nfId, err := consumer.SendRegisterNFInstance(self.NrfUri, self.NfId, profile); err != nil { - logger.InitLog.Warnf("Send Register NF Instance failed: %+v", err) - } else { - self.NfId = nfId + if err := a.sbiServer.Run(context.Background(), &a.wg); err != nil { + logger.MainLog.Fatalf("Run SBI server failed: %+v", err) } + a.WaitRoutineStopped() +} - 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 - a.Terminate() - os.Exit(0) - }() +// Used in AMF planned removal procedure +func (a *AmfApp) Terminate() { + a.cancel() +} - server, err := httpwrapper.NewHttp2Server(addr, tlsKeyLogPath, router) +func (a *AmfApp) Config() *factory.Config { + return a.cfg +} - if server == nil { - logger.InitLog.Errorf("Initialize HTTP server failed: %+v", err) - return - } +func (a *AmfApp) Context() *amf_context.AMFContext { + return a.amfCtx +} - if err != nil { - logger.InitLog.Warnf("Initialize HTTP server: %+v", err) - } +func (a *AmfApp) CancelContext() context.Context { + return a.ctx +} - serverScheme := factory.AmfConfig.GetSbiScheme() - if serverScheme == "http" { - err = server.ListenAndServe() - } else if serverScheme == "https" { - err = server.ListenAndServeTLS(pemPath, keyPath) - } +func (a *AmfApp) Consumer() *consumer.Consumer { + return a.consumer +} - if err != nil { - logger.InitLog.Fatalf("HTTP server setup failed: %+v", err) - } +func (a *AmfApp) Processor() *processor.Processor { + return a.processor } -// Used in AMF planned removal procedure -func (a *AmfApp) Terminate() { - logger.InitLog.Infof("Terminating AMF...") - amfSelf := amf_context.GetSelf() +func (a *AmfApp) listenShutdownEvent() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.MainLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + a.wg.Done() + }() - // TODO: forward registered UE contexts to target AMF in the same AMF set if there is one + <-a.ctx.Done() + a.terminateProcedure() +} + +func (a *AmfApp) CallServerStop() { + if a.sbiServer != nil { + a.sbiServer.Stop() + } +} + +func (a *AmfApp) WaitRoutineStopped() { + a.wg.Wait() + logger.MainLog.Infof("AMF App is terminated") +} +func (a *AmfApp) terminateProcedure() { + logger.MainLog.Infof("Terminating AMF...") + a.CallServerStop() // deregister with NRF - problemDetails, err := consumer.SendDeregisterNFInstance() + problemDetails, err_deg := a.Consumer().SendDeregisterNFInstance() if problemDetails != nil { - logger.InitLog.Errorf("Deregister NF instance Failed Problem[%+v]", problemDetails) - } else if err != nil { - logger.InitLog.Errorf("Deregister NF instance Error[%+v]", err) + logger.MainLog.Errorf("Deregister NF instance Failed Problem[%+v]", problemDetails) + } else if err_deg != nil { + logger.MainLog.Errorf("Deregister NF instance Error[%+v]", err_deg) } else { - logger.InitLog.Infof("[AMF] Deregister from NRF successfully") + logger.MainLog.Infof("[AMF] Deregister from NRF successfully") } + // TODO: forward registered UE contexts to target AMF in the same AMF set if there is one + + // ngap // send AMF status indication to ran to notify ran that this AMF will be unavailable - logger.InitLog.Infof("Send AMF Status Indication to Notify RANs due to AMF terminating") + logger.MainLog.Infof("Send AMF Status Indication to Notify RANs due to AMF terminating") + amfSelf := a.Context() unavailableGuamiList := ngap_message.BuildUnavailableGUAMIList(amfSelf.ServedGuamiList) amfSelf.AmfRanPool.Range(func(key, value interface{}) bool { ran := value.(*amf_context.AmfRan) ngap_message.SendAMFStatusIndication(ran, unavailableGuamiList) return true }) - ngap_service.Stop() - callback.SendAmfStatusChangeNotify((string)(models.StatusChange_UNAVAILABLE), amfSelf.ServedGuamiList) - logger.InitLog.Infof("AMF terminated") } diff --git a/pkg/service/mock.go b/pkg/service/mock.go new file mode 100644 index 00000000..53825d64 --- /dev/null +++ b/pkg/service/mock.go @@ -0,0 +1,159 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/service/init.go +// +// Generated by this command: +// +// mockgen -source=pkg/service/init.go -package=service +// + +// Package service is a generated GoMock package. +package service + +import ( + reflect "reflect" + + context "github.com/free5gc/amf/internal/context" + consumer "github.com/free5gc/amf/internal/sbi/consumer" + processor "github.com/free5gc/amf/internal/sbi/processor" + factory "github.com/free5gc/amf/pkg/factory" + gomock "go.uber.org/mock/gomock" +) + +// MockAmfAppInterface is a mock of AmfAppInterface interface. +type MockAmfAppInterface struct { + ctrl *gomock.Controller + recorder *MockAmfAppInterfaceMockRecorder +} + +// MockAmfAppInterfaceMockRecorder is the mock recorder for MockAmfAppInterface. +type MockAmfAppInterfaceMockRecorder struct { + mock *MockAmfAppInterface +} + +// NewMockAmfAppInterface creates a new mock instance. +func NewMockAmfAppInterface(ctrl *gomock.Controller) *MockAmfAppInterface { + mock := &MockAmfAppInterface{ctrl: ctrl} + mock.recorder = &MockAmfAppInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAmfAppInterface) EXPECT() *MockAmfAppInterfaceMockRecorder { + return m.recorder +} + +// Config mocks base method. +func (m *MockAmfAppInterface) Config() *factory.Config { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Config") + ret0, _ := ret[0].(*factory.Config) + return ret0 +} + +// Config indicates an expected call of Config. +func (mr *MockAmfAppInterfaceMockRecorder) Config() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Config", reflect.TypeOf((*MockAmfAppInterface)(nil).Config)) +} + +// Consumer mocks base method. +func (m *MockAmfAppInterface) Consumer() *consumer.Consumer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Consumer") + ret0, _ := ret[0].(*consumer.Consumer) + return ret0 +} + +// Consumer indicates an expected call of Consumer. +func (mr *MockAmfAppInterfaceMockRecorder) Consumer() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Consumer", reflect.TypeOf((*MockAmfAppInterface)(nil).Consumer)) +} + +// Context mocks base method. +func (m *MockAmfAppInterface) Context() *context.AMFContext { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(*context.AMFContext) + return ret0 +} + +// Context indicates an expected call of Context. +func (mr *MockAmfAppInterfaceMockRecorder) Context() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockAmfAppInterface)(nil).Context)) +} + +// Processor mocks base method. +func (m *MockAmfAppInterface) Processor() *processor.Processor { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Processor") + ret0, _ := ret[0].(*processor.Processor) + return ret0 +} + +// Processor indicates an expected call of Processor. +func (mr *MockAmfAppInterfaceMockRecorder) Processor() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Processor", reflect.TypeOf((*MockAmfAppInterface)(nil).Processor)) +} + +// SetLogEnable mocks base method. +func (m *MockAmfAppInterface) SetLogEnable(enable bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetLogEnable", enable) +} + +// SetLogEnable indicates an expected call of SetLogEnable. +func (mr *MockAmfAppInterfaceMockRecorder) SetLogEnable(enable any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLogEnable", reflect.TypeOf((*MockAmfAppInterface)(nil).SetLogEnable), enable) +} + +// SetLogLevel mocks base method. +func (m *MockAmfAppInterface) SetLogLevel(level string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetLogLevel", level) +} + +// SetLogLevel indicates an expected call of SetLogLevel. +func (mr *MockAmfAppInterfaceMockRecorder) SetLogLevel(level any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLogLevel", reflect.TypeOf((*MockAmfAppInterface)(nil).SetLogLevel), level) +} + +// SetReportCaller mocks base method. +func (m *MockAmfAppInterface) SetReportCaller(reportCaller bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetReportCaller", reportCaller) +} + +// SetReportCaller indicates an expected call of SetReportCaller. +func (mr *MockAmfAppInterfaceMockRecorder) SetReportCaller(reportCaller any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetReportCaller", reflect.TypeOf((*MockAmfAppInterface)(nil).SetReportCaller), reportCaller) +} + +// Start mocks base method. +func (m *MockAmfAppInterface) Start() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Start") +} + +// Start indicates an expected call of Start. +func (mr *MockAmfAppInterfaceMockRecorder) Start() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockAmfAppInterface)(nil).Start)) +} + +// Terminate mocks base method. +func (m *MockAmfAppInterface) Terminate() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Terminate") +} + +// Terminate indicates an expected call of Terminate. +func (mr *MockAmfAppInterfaceMockRecorder) Terminate() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Terminate", reflect.TypeOf((*MockAmfAppInterface)(nil).Terminate)) +}