├── .github ├── dependabot.yml └── workflows │ ├── go.yml │ └── golangci-lint.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── README.md ├── doc.go ├── errors.go ├── examples ├── gw-tester │ ├── README.md │ ├── docs │ │ └── diagram.png │ ├── enb │ │ ├── config.go │ │ ├── enb.go │ │ ├── enb.yml │ │ ├── main.go │ │ └── metrics.go │ ├── mme │ │ ├── config.go │ │ ├── handlers.go │ │ ├── main.go │ │ ├── metrics.go │ │ ├── mme.go │ │ └── mme.yml │ ├── pgw │ │ ├── config.go │ │ ├── handlers.go │ │ ├── main.go │ │ ├── metrics.go │ │ ├── pgw.go │ │ └── pgw.yml │ ├── s1mme │ │ ├── s1mme.pb.go │ │ └── s1mme.proto │ └── sgw │ │ ├── config.go │ │ ├── main.go │ │ ├── metrics.go │ │ ├── s11_handlers.go │ │ ├── s5_handlers.go │ │ ├── sgw.go │ │ └── sgw.yml ├── mme │ ├── main.go │ ├── mme.go │ └── mock.go ├── pgw │ ├── main.go │ └── pgw.go ├── sgw │ ├── main.go │ ├── s11.go │ └── s5.go └── utils │ └── mac_local_host_enabler.sh ├── go.mod ├── go.sum ├── gtp.go ├── gtp_fuzz_test.go ├── gtp_test.go ├── gtpv0 ├── README.md ├── constants.go ├── doc.go ├── ie │ ├── apn.go │ ├── cause.go │ ├── charging-gateway-address.go │ ├── charging-id.go │ ├── end-user-address.go │ ├── errors.go │ ├── flow-label.go │ ├── gsn-address.go │ ├── ie.go │ ├── ie_deprecated.go │ ├── ie_fuzz_test.go │ ├── ie_test.go │ ├── imsi.go │ ├── ms-not-reachable-reason.go │ ├── msisdn.go │ ├── p-tmsi-signature.go │ ├── p-tmsi.go │ ├── private-extension.go │ ├── qos-profile.go │ ├── rai.go │ ├── recovery.go │ ├── reordering-required.go │ ├── selection-mode.go │ └── tlli.go ├── message │ ├── create-pdp-context-req.go │ ├── create-pdp-context-req_deprecated.go │ ├── create-pdp-context-req_test.go │ ├── create-pdp-context-res.go │ ├── create-pdp-context-res_deprecated.go │ ├── create-pdp-context-res_test.go │ ├── delete-pdp-context-req.go │ ├── delete-pdp-context-req_deprecated.go │ ├── delete-pdp-context-req_test.go │ ├── delete-pdp-context-res.go │ ├── delete-pdp-context-res_deprecated.go │ ├── delete-pdp-context-res_test.go │ ├── echo-req.go │ ├── echo-req_deprecated.go │ ├── echo-req_test.go │ ├── echo-res.go │ ├── echo-res_deprecated.go │ ├── echo-res_test.go │ ├── errors.go │ ├── generic.go │ ├── generic_deprecated.go │ ├── generic_test.go │ ├── header.go │ ├── header_deprecated.go │ ├── header_test.go │ ├── message.go │ ├── message_deprecated.go │ ├── message_fuzz_test.go │ ├── t-pdu.go │ ├── t-pdu_deprecated.go │ ├── t-pdu_test.go │ ├── update-pdp-context-req.go │ ├── update-pdp-context-req_deprecated.go │ ├── update-pdp-context-req_test.go │ ├── update-pdp-context-res.go │ ├── update-pdp-context-res_deprecated.go │ └── update-pdp-context-res_test.go └── testutils │ └── testutils.go ├── gtpv1 ├── README.md ├── conn.go ├── constants.go ├── doc.go ├── errors.go ├── gtpv1_fuzz_test.go ├── handlers.go ├── ie │ ├── apn-restriction.go │ ├── apn.go │ ├── authentication-quintuplet.go │ ├── authentication-triplet.go │ ├── cause.go │ ├── charging-id.go │ ├── common-flags.go │ ├── end-user-address.go │ ├── errors.go │ ├── extended-common-flags-ii.go │ ├── extended-common-flags.go │ ├── extension-header-type-list.go │ ├── gsn-address.go │ ├── ie.go │ ├── ie_deprecated.go │ ├── ie_fuzz_test.go │ ├── ie_test.go │ ├── imei.go │ ├── imei_test.go │ ├── imsi.go │ ├── ip.go │ ├── lac.go │ ├── map-cause.go │ ├── mcc-mnc.go │ ├── ms-timezone.go │ ├── ms-validated.go │ ├── msisdn.go │ ├── nsapi.go │ ├── p-tmsi-signature.go │ ├── p-tmsi.go │ ├── pco.go │ ├── private-extension.go │ ├── qos-profile.go │ ├── rac.go │ ├── rai.go │ ├── rai_test.go │ ├── ranap-cause.go │ ├── rat-type.go │ ├── recovery.go │ ├── reordering-required.go │ ├── selection-mode.go │ ├── teardown-ind.go │ ├── teid.go │ ├── uli-timestamp.go │ ├── uli.go │ └── uli_test.go ├── logger.go ├── message │ ├── create-pdp-context-req.go │ ├── create-pdp-context-req_deprecated.go │ ├── create-pdp-context-req_test.go │ ├── create-pdp-context-res.go │ ├── create-pdp-context-res_deprecated.go │ ├── create-pdp-context-res_test.go │ ├── delete-pdp-context-req.go │ ├── delete-pdp-context-req_deprecated.go │ ├── delete-pdp-context-req_test.go │ ├── delete-pdp-context-res.go │ ├── delete-pdp-context-res_deprecated.go │ ├── delete-pdp-context-res_test.go │ ├── echo-req.go │ ├── echo-req_deprecated.go │ ├── echo-req_test.go │ ├── echo-res.go │ ├── echo-res_deprecated.go │ ├── echo-res_test.go │ ├── end-marker.go │ ├── end-marker_test.go │ ├── error-indication.go │ ├── error-indication_deprecated.go │ ├── error-indication_test.go │ ├── errors.go │ ├── extension-header.go │ ├── generic.go │ ├── generic_deprecated.go │ ├── generic_test.go │ ├── header.go │ ├── header_deprecated.go │ ├── header_test.go │ ├── message.go │ ├── message_deprecated.go │ ├── message_fuzz_test.go │ ├── supported-extension-header-notification.go │ ├── supported-extension-header-notification_test.go │ ├── t-pdu.go │ ├── t-pdu_deprecated.go │ ├── t-pdu_test.go │ ├── update-pdp-context-req.go │ ├── update-pdp-context-req_deprecated.go │ ├── update-pdp-context-req_test.go │ ├── update-pdp-context-res.go │ ├── update-pdp-context-res_deprecated.go │ ├── update-pdp-context-res_test.go │ ├── version-not-supported.go │ ├── version-not-supported_deprecated.go │ └── version-not-supported_test.go ├── relay.go ├── relay_test.go ├── testutils │ └── testutils.go ├── tunnel.go ├── tunnel_linux.go ├── u-conn.go ├── u-conn_test.go └── utils.go ├── gtpv2 ├── README.md ├── bearer.go ├── conn.go ├── conn_test.go ├── constants.go ├── doc.go ├── errors.go ├── handlers.go ├── helpers_test.go ├── ie │ ├── ambr.go │ ├── apn-restriction.go │ ├── apn.go │ ├── arp.go │ ├── bearer-context.go │ ├── bearer-flags.go │ ├── bearer-qos.go │ ├── bearer-tft.go │ ├── cause.go │ ├── charging-characteristics.go │ ├── charging-id.go │ ├── cmi.go │ ├── csg-id.go │ ├── delay-value.go │ ├── detach-type.go │ ├── ebi.go │ ├── epc-timer.go │ ├── errors.go │ ├── f-teid.go │ ├── flow-qos.go │ ├── fq-csid.go │ ├── fqdn.go │ ├── global-cn-id.go │ ├── guti.go │ ├── hop-counter.go │ ├── ie.go │ ├── ie_deprecated.go │ ├── ie_fuzz_test.go │ ├── ie_grouped.go │ ├── ie_test.go │ ├── imsi.go │ ├── indication.go │ ├── integer-number.go │ ├── ip-addr.go │ ├── ip-addr_test.go │ ├── ldn.go │ ├── mbms-flags.go │ ├── mcc-mnc.go │ ├── mcc-mnc_test.go │ ├── mei.go │ ├── msisdn.go │ ├── node-features.go │ ├── node-type.go │ ├── p-tmsi-signature.go │ ├── p-tmsi.go │ ├── paa.go │ ├── paging-and-service-information.go │ ├── pco-ppp.go │ ├── pco-ppp_test.go │ ├── pco.go │ ├── pdn-type.go │ ├── plmn-id.go │ ├── port-number.go │ ├── private-extension.go │ ├── pti.go │ ├── ran-nas-cause.go │ ├── rat-type.go │ ├── recovery.go │ ├── rfsp-index.go │ ├── s103pdf.go │ ├── s1udf.go │ ├── selection-mode.go │ ├── service-indicator.go │ ├── serving-nw.go │ ├── tad.go │ ├── tft.go │ ├── tft_test.go │ ├── throttling.go │ ├── tmsi.go │ ├── trace-reference.go │ ├── uci.go │ ├── ue-timezone.go │ ├── uli-timestamp.go │ ├── uli.go │ ├── uli_test.go │ └── utils.go ├── logger.go ├── message │ ├── change-notification-req.go │ ├── change-notification-req_test.go │ ├── change-notification-res.go │ ├── change-notification-res_test.go │ ├── context-ack.go │ ├── context-ack_deprecated.go │ ├── context-ack_test.go │ ├── context-req.go │ ├── context-req_deprecated.go │ ├── context-req_test.go │ ├── context-res.go │ ├── context-res_deprecated.go │ ├── context-res_test.go │ ├── create-bearer-req.go │ ├── create-bearer-req_deprecated.go │ ├── create-bearer-req_test.go │ ├── create-bearer-res.go │ ├── create-bearer-res_deprecated.go │ ├── create-bearer-res_test.go │ ├── create-session-req.go │ ├── create-session-req_deprecated.go │ ├── create-session-req_test.go │ ├── create-session-res.go │ ├── create-session-res_deprecated.go │ ├── create-session-res_test.go │ ├── delete-bearer-command.go │ ├── delete-bearer-command_test.go │ ├── delete-bearer-failure-indication.go │ ├── delete-bearer-failure-indication_test.go │ ├── delete-bearer-req.go │ ├── delete-bearer-req_deprecated.go │ ├── delete-bearer-req_test.go │ ├── delete-bearer-res.go │ ├── delete-bearer-res_deprecated.go │ ├── delete-bearer-res_test.go │ ├── delete-pdn-connection-set-req.go │ ├── delete-pdn-connection-set-req_test.go │ ├── delete-pdn-connection-set-res.go │ ├── delete-pdn-connection-set-res_test.go │ ├── delete-session-req.go │ ├── delete-session-req_deprecated.go │ ├── delete-session-req_test.go │ ├── delete-session-res.go │ ├── delete-session-res_deprecated.go │ ├── delete-session-res_test.go │ ├── detach-acknowledge.go │ ├── detach-acknowledge_test.go │ ├── detach-notification.go │ ├── detach-notification_test.go │ ├── downlink-data-notification-ack.go │ ├── downlink-data-notification-ack_test.go │ ├── downlink-data-notification-failure-indication.go │ ├── downlink-data-notification-failure-indication_test.go │ ├── downlink-data-notification.go │ ├── downlink-data-notification_test.go │ ├── echo-req.go │ ├── echo-req_deprecated.go │ ├── echo-req_test.go │ ├── echo-res.go │ ├── echo-res_deprecated.go │ ├── echo-res_test.go │ ├── errors.go │ ├── generic.go │ ├── generic_deprecated.go │ ├── generic_test.go │ ├── header.go │ ├── header_deprecated.go │ ├── header_test.go │ ├── message.go │ ├── message_deprecated.go │ ├── message_fuzz_test.go │ ├── message_test.go │ ├── modify-access-bearers-req.go │ ├── modify-access-bearers-req_deprecated.go │ ├── modify-access-bearers-req_test.go │ ├── modify-access-bearers-res.go │ ├── modify-access-bearers-res_deprecated.go │ ├── modify-access-bearers-res_test.go │ ├── modify-bearer-command.go │ ├── modify-bearer-command_test.go │ ├── modify-bearer-failure-indication.go │ ├── modify-bearer-failure-indication_test.go │ ├── modify-bearer-req.go │ ├── modify-bearer-req_deprecated.go │ ├── modify-bearer-req_test.go │ ├── modify-bearer-res.go │ ├── modify-bearer-res_deprecated.go │ ├── modify-bearer-res_test.go │ ├── pgw-restart-notification-acknowledge.go │ ├── pgw-restart-notification-acknowledge_test.go │ ├── pgw-restart-notification.go │ ├── pgw-restart-notification_test.go │ ├── release-access-bearers-req.go │ ├── release-access-bearers-req_deprecated.go │ ├── release-access-bearers-req_test.go │ ├── release-access-bearers-res.go │ ├── release-access-bearers-res_deprecated.go │ ├── release-access-bearers-res_test.go │ ├── resume-acknowledge.go │ ├── resume-acknowledge_test.go │ ├── resume-notification.go │ ├── resume-notification_test.go │ ├── stop-paging-indication.go │ ├── stop-paging-indication_deprecated.go │ ├── stop-paging-indication_test.go │ ├── suspend-acknowledge.go │ ├── suspend-acknowledge_test.go │ ├── suspend-notification.go │ ├── suspend-notification_test.go │ ├── update-bearer-req.go │ ├── update-bearer-req_test.go │ ├── update-bearer-res.go │ ├── update-bearer-res_test.go │ ├── update-pdn-connection-set-req.go │ ├── update-pdn-connection-set-req_test.go │ ├── update-pdn-connection-set-res.go │ ├── update-pdn-connection-set-res_test.go │ ├── version-not-supported.go │ ├── version-not-supported_deprecated.go │ └── version-not-supported_test.go ├── session.go └── testutils │ └── testutils.go └── utils ├── utils.go └── utils_test.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "20:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - main 8 | pull_request: 9 | jobs: 10 | golangci: 11 | name: lint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-go@v5 16 | with: 17 | go-version: '1.23' 18 | cache: false 19 | - name: golangci-lint 20 | uses: golangci/golangci-lint-action@v4 21 | with: 22 | version: "latest" 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | examples/mme/mme 2 | examples/pgw/pgw 3 | examples/sgw/sgw 4 | examples/gw-tester/enb/enb 5 | examples/gw-tester/pgw/pgw 6 | examples/gw-tester/sgw/sgw 7 | examples/gw-tester/mme/mme 8 | 9 | **/testdata/ 10 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable-all: true 3 | enable: 4 | - errcheck 5 | - gosimple 6 | - govet 7 | - ineffassign 8 | - staticcheck 9 | - typecheck 10 | - unused 11 | - bodyclose 12 | - dogsled 13 | - goconst 14 | - gocritic 15 | - gofmt 16 | - goimports 17 | - goprintffuncname 18 | - gosec 19 | - misspell 20 | - nakedret 21 | - prealloc 22 | - rowserrcheck 23 | - stylecheck 24 | - unconvert 25 | - unparam 26 | - gomodguard 27 | - asciicheck 28 | - errorlint 29 | run: 30 | timeout: 3m 31 | tests: false 32 | issues-exit-code: 1 33 | issues: 34 | max-issues-per-linter: 4095 35 | max-same-issues: 1023 36 | new: true 37 | linters-settings: 38 | gosec: 39 | excludes: 40 | # too noisy atm. see https://github.com/securego/gosec/issues/1185 41 | - G115 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2025 Yoshiyuki Kurauchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Package gtp provides simple and painless handling of GTP (GPRS Tunneling Protocol). 6 | // 7 | // This package is the wrapper for all versions of GTP. Please see the godocs of each version instead. 8 | // 9 | // GTPv0: https://pkg.go.dev/github.com/wmnsk/go-gtp/v0 10 | // 11 | // GTPv1: https://pkg.go.dev/github.com/wmnsk/go-gtp/v1 12 | // 13 | // GTPv2: https://pkg.go.dev/github.com/wmnsk/go-gtp/v2 14 | // 15 | // Please also see README.md for detailed usage of the APIs provided by this package, 16 | // as well as how to run the examples. 17 | // 18 | // https://github.com/wmnsk/go-gtp/blob/main/README.md 19 | // 20 | // https://github.com/wmnsk/go-gtp/tree/main/examples/gw-tester 21 | package gtp 22 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtp 6 | 7 | import "errors" 8 | 9 | // Common error definitions. 10 | var ( 11 | ErrInvalidVersion = errors.New("got invalid version") 12 | ErrInvalidLength = errors.New("length value is invalid") 13 | ErrTooShortToParse = errors.New("too short to decode as GTP") 14 | ErrTooShortToMarshal = errors.New("too short to serialize") 15 | ) 16 | -------------------------------------------------------------------------------- /examples/gw-tester/docs/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wmnsk/go-gtp/911372d217b604ac8e0f65931235178644488b7b/examples/gw-tester/docs/diagram.png -------------------------------------------------------------------------------- /examples/gw-tester/enb/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Command enb works as pseudo eNB that forwards packets through GTPv1 tunnel. 6 | package main 7 | 8 | import ( 9 | "context" 10 | "flag" 11 | "log" 12 | "os" 13 | "os/signal" 14 | "syscall" 15 | ) 16 | 17 | func main() { 18 | var configPath = flag.String("config", "./enb.yml", "Path to the configuration file.") 19 | flag.Parse() 20 | log.SetPrefix("[eNB] ") 21 | 22 | cfg, err := loadConfig(*configPath) 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | 27 | enb, err := newENB(cfg) 28 | if err != nil { 29 | log.Printf("failed to initialize eNB: %s", err) 30 | } 31 | defer enb.close() 32 | 33 | sigCh := make(chan os.Signal, 1) 34 | signal.Notify(sigCh, syscall.SIGINT, syscall.SIGHUP) 35 | 36 | ctx, cancel := context.WithCancel(context.Background()) 37 | defer cancel() 38 | 39 | fatalCh := make(chan error, 1) 40 | go func() { 41 | if err := enb.run(ctx); err != nil { 42 | fatalCh <- err 43 | } 44 | }() 45 | 46 | for { 47 | select { 48 | case sig := <-sigCh: 49 | switch sig { 50 | case syscall.SIGINT: 51 | return 52 | case syscall.SIGHUP: 53 | // reload config and attach/detach subscribers again 54 | newCfg, err := loadConfig(*configPath) 55 | if err != nil { 56 | log.Printf("Error reloading config %s", err) 57 | } 58 | 59 | if err := enb.reload(newCfg); err != nil { 60 | log.Printf("Error applying reloaded config %s", err) 61 | } 62 | } 63 | case err := <-enb.errCh: 64 | log.Printf("WARN: %s", err) 65 | case err := <-fatalCh: 66 | log.Printf("FATAL: %s", err) 67 | return 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /examples/gw-tester/mme/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "io/ioutil" 9 | 10 | "gopkg.in/yaml.v2" 11 | ) 12 | 13 | // Config is a configurations loaded from yaml. 14 | type Config struct { 15 | LocalAddrs struct { 16 | S1CAddr string `yaml:"s1c_addr"` 17 | S11IP string `yaml:"s11_ip"` 18 | } `yaml:"local_addresses"` 19 | 20 | PromAddr string `yaml:"prom_addr"` 21 | 22 | MCC string `yaml:"mcc"` 23 | MNC string `yaml:"mnc"` 24 | 25 | APN string `yaml:"apn"` 26 | 27 | SgwS11 string `yaml:"sgw_s11_ip"` 28 | PgwS5C string `yaml:"pgw_s5c_ip"` 29 | } 30 | 31 | func loadConfig(path string) (*Config, error) { 32 | buf, err := ioutil.ReadFile(path) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | c := &Config{} 38 | if err := yaml.Unmarshal(buf, c); err != nil { 39 | return nil, err 40 | } 41 | 42 | return c, nil 43 | } 44 | -------------------------------------------------------------------------------- /examples/gw-tester/mme/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Command mme works as pseudo MME/HSS communicates S/P-GW with GTPv2 signaling. 6 | package main 7 | 8 | import ( 9 | "context" 10 | "flag" 11 | "log" 12 | "os" 13 | "os/signal" 14 | "syscall" 15 | ) 16 | 17 | func main() { 18 | var configPath = flag.String("config", "./mme.yml", "Path to the configuration file.") 19 | flag.Parse() 20 | log.SetPrefix("[MME] ") 21 | 22 | sigCh := make(chan os.Signal, 1) 23 | signal.Notify(sigCh, syscall.SIGINT, syscall.SIGHUP) 24 | 25 | cfg, err := loadConfig(*configPath) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | 30 | mme, err := newMME(cfg) 31 | if err != nil { 32 | log.Printf("failed to initialize MME: %s", err) 33 | } 34 | 35 | ctx, cancel := context.WithCancel(context.Background()) 36 | defer cancel() 37 | 38 | fatalCh := make(chan error) 39 | go func() { 40 | if err := mme.run(ctx); err != nil { 41 | fatalCh <- err 42 | } 43 | }() 44 | 45 | for { 46 | select { 47 | case sig := <-sigCh: 48 | switch sig { 49 | case syscall.SIGINT: 50 | cancel() 51 | return 52 | case syscall.SIGHUP: 53 | // reload config and attach/detach subscribers 54 | newCfg, err := loadConfig(*configPath) 55 | if err != nil { 56 | log.Printf("Error reloading config %s", err) 57 | } 58 | 59 | if err := mme.reload(newCfg); err != nil { 60 | log.Printf("Error applying reloaded config %s", err) 61 | } 62 | } 63 | case err := <-mme.errCh: 64 | log.Printf("WARN: %s", err) 65 | case err := <-fatalCh: 66 | log.Printf("FATAL: %s", err) 67 | return 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /examples/gw-tester/mme/metrics.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "github.com/prometheus/client_golang/prometheus" 9 | "github.com/prometheus/client_golang/prometheus/promauto" 10 | ) 11 | 12 | type metricsCollector struct { 13 | activeSessions prometheus.GaugeFunc 14 | messagesSent *prometheus.CounterVec 15 | messagesReceived *prometheus.CounterVec 16 | } 17 | 18 | func (m *mme) runMetricsCollector() error { 19 | mc := &metricsCollector{} 20 | mc.activeSessions = promauto.NewGaugeFunc( 21 | prometheus.GaugeOpts{ 22 | Name: "mme_active_sessions", 23 | Help: "number of session established currently", 24 | }, 25 | func() float64 { 26 | return float64(m.s11Conn.SessionCount()) 27 | }, 28 | ) 29 | 30 | mc.messagesSent = promauto.NewCounterVec( 31 | prometheus.CounterOpts{ 32 | Name: "mme_messages_sent_total", 33 | Help: "number of message sent by messagge type", 34 | }, 35 | []string{"dst", "type"}, 36 | ) 37 | 38 | mc.messagesReceived = promauto.NewCounterVec( 39 | prometheus.CounterOpts{ 40 | Name: "mme_messages_received_total", 41 | Help: "number of message received by messagge type", 42 | }, 43 | []string{"src", "type"}, 44 | ) 45 | 46 | m.mc = mc 47 | return nil 48 | } 49 | -------------------------------------------------------------------------------- /examples/gw-tester/mme/mme.yml: -------------------------------------------------------------------------------- 1 | mcc: "001" 2 | mnc: "01" 3 | apn: "gw-tester.go-gtp.example" 4 | local_addresses: 5 | s1c_addr: "127.0.1.12:36412" 6 | s11_ip: "127.0.1.12" 7 | sgw_s11_ip: "127.0.1.13" 8 | pgw_s5c_ip: "127.0.1.15" 9 | prom_addr: "127.0.10.2:58080" 10 | -------------------------------------------------------------------------------- /examples/gw-tester/pgw/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "io/ioutil" 9 | 10 | "gopkg.in/yaml.v2" 11 | ) 12 | 13 | // Config is a configurations loaded from yaml. 14 | type Config struct { 15 | LocalAddrs struct { 16 | S5CIP string `yaml:"s5c_ip"` 17 | S5UIP string `yaml:"s5u_ip"` 18 | SGiIP string `yaml:"sgi_ip"` 19 | } `yaml:"local_addresses"` 20 | 21 | UseKernelGTP bool `yaml:"use_kernel_gtp"` 22 | 23 | SGiIFName string `yaml:"sgi_if_name"` 24 | RouteSubnet string `yaml:"route_subnet"` 25 | 26 | PromAddr string `yaml:"prom_addr"` 27 | } 28 | 29 | func loadConfig(path string) (*Config, error) { 30 | buf, err := ioutil.ReadFile(path) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | c := &Config{} 36 | if err := yaml.Unmarshal(buf, c); err != nil { 37 | return nil, err 38 | } 39 | 40 | return c, nil 41 | } 42 | -------------------------------------------------------------------------------- /examples/gw-tester/pgw/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Command pgw is a dead simple implementation of P-GW only with GTP-related features. 6 | package main 7 | 8 | import ( 9 | "context" 10 | "flag" 11 | "log" 12 | "os" 13 | "os/signal" 14 | "syscall" 15 | ) 16 | 17 | func main() { 18 | var configPath = flag.String("config", "./pgw.yml", "Path to the configuration file.") 19 | flag.Parse() 20 | log.SetPrefix("[P-GW] ") 21 | 22 | cfg, err := loadConfig(*configPath) 23 | if err != nil { 24 | log.Println(err) 25 | return 26 | } 27 | 28 | pgw, err := newPGW(cfg) 29 | if err != nil { 30 | log.Printf("failed to initialize P-GW: %s", err) 31 | return 32 | } 33 | defer pgw.close() 34 | 35 | sigCh := make(chan os.Signal, 1) 36 | signal.Notify(sigCh, syscall.SIGINT, syscall.SIGHUP) 37 | 38 | ctx, cancel := context.WithCancel(context.Background()) 39 | defer cancel() 40 | 41 | fatalCh := make(chan error) 42 | go func() { 43 | if err := pgw.run(ctx); err != nil { 44 | fatalCh <- err 45 | } 46 | }() 47 | 48 | for { 49 | select { 50 | case sig := <-sigCh: 51 | // TODO: reload config on receiving SIGHUP 52 | log.Println(sig) 53 | return 54 | case err := <-pgw.errCh: 55 | log.Printf("WARN: %s", err) 56 | case err := <-fatalCh: 57 | log.Printf("FATAL: %s", err) 58 | return 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/gw-tester/pgw/pgw.yml: -------------------------------------------------------------------------------- 1 | local_addresses: 2 | s5c_ip: "127.0.1.15" 3 | s5u_ip: "127.0.0.15" 4 | sgi_ip: "127.0.1.254" 5 | sgi_if_name: "lo" 6 | route_subnet: "192.168.101.0/24" 7 | use_kernel_gtp: false 8 | prom_addr: "127.0.10.4:58080" 9 | -------------------------------------------------------------------------------- /examples/gw-tester/s1mme/s1mme.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package s1mme; 4 | 5 | // Attacher defines the service to attach UE. 6 | service Attacher { 7 | rpc Attach (AttachRequest) returns (AttachResponse) {} 8 | rpc Detach (DetachRequest) returns (DetachResponse) {} 9 | } 10 | 11 | // AttachRequest is used to request MME to create a session/bearer. 12 | message AttachRequest { 13 | string imsi = 1; 14 | string msisdn = 2; 15 | string imeisv = 3; 16 | string s1u_addr = 4; 17 | string src_ip = 5; 18 | uint32 i_tei = 6; 19 | Location location = 7; 20 | bool reattach = 8; 21 | } 22 | 23 | // AttachResponse is used to respond to AttachRequest. 24 | message AttachResponse { 25 | Cause cause = 1; // result 26 | string sgw_addr = 2; 27 | uint32 o_tei = 3; 28 | } 29 | 30 | // Cause represents a result of attach / detach. 31 | enum Cause { 32 | INVALID = 0; 33 | SUCCESS = 1; 34 | GW_UNAVAILABLE = 2; 35 | } 36 | 37 | // Location represents a set of location-related information. 38 | message Location { 39 | string mcc = 1; 40 | string mnc = 2; 41 | RATType rat_type = 3; 42 | uint32 tai = 4; 43 | uint32 eci = 5; 44 | 45 | enum RATType { 46 | INVALID = 0; 47 | UTRAN = 1; 48 | GERAN = 2; 49 | WLAN = 3; 50 | GAN = 4; 51 | HSPA_EVOLUTION = 5; 52 | EUTRAN = 6; 53 | VIRTUAL = 7; 54 | EUTRAN_NB_IOT = 8; 55 | LTEM = 9; 56 | NR = 10; 57 | } 58 | } 59 | 60 | // DetachRequest is used to request MME to delete a session/bearer. 61 | message DetachRequest { 62 | string imsi = 1; 63 | } 64 | 65 | // DetachResponse is used to respond to DetachRequest. 66 | message DetachResponse { 67 | Cause cause = 1; 68 | } 69 | -------------------------------------------------------------------------------- /examples/gw-tester/sgw/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "io/ioutil" 9 | 10 | "gopkg.in/yaml.v2" 11 | ) 12 | 13 | // Config is a configurations loaded from yaml. 14 | type Config struct { 15 | LocalAddrs struct { 16 | S11IP string `yaml:"s11_ip"` 17 | S1UIP string `yaml:"s1u_ip"` 18 | S5CIP string `yaml:"s5c_ip"` 19 | S5UIP string `yaml:"s5u_ip"` 20 | } `yaml:"local_addresses"` 21 | 22 | UseKernelGTP bool `yaml:"use_kernel_gtp"` 23 | PromAddr string `yaml:"prom_addr"` 24 | } 25 | 26 | func loadConfig(path string) (*Config, error) { 27 | buf, err := ioutil.ReadFile(path) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | c := &Config{} 33 | if err := yaml.Unmarshal(buf, c); err != nil { 34 | return nil, err 35 | } 36 | 37 | return c, nil 38 | } 39 | -------------------------------------------------------------------------------- /examples/gw-tester/sgw/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Command sgw is a dead simple implementation of S-GW. 6 | package main 7 | 8 | import ( 9 | "context" 10 | "flag" 11 | "log" 12 | "os" 13 | "os/signal" 14 | "syscall" 15 | ) 16 | 17 | func main() { 18 | var configPath = flag.String("config", "./sgw.yml", "Path to the configuration file.") 19 | flag.Parse() 20 | log.SetPrefix("[S-GW] ") 21 | 22 | cfg, err := loadConfig(*configPath) 23 | if err != nil { 24 | log.Println(err) 25 | return 26 | } 27 | 28 | sgw, err := newSGW(cfg) 29 | if err != nil { 30 | log.Printf("failed to initialize SGW: %s", err) 31 | } 32 | defer sgw.close() 33 | 34 | sigCh := make(chan os.Signal, 1) 35 | signal.Notify(sigCh, syscall.SIGINT, syscall.SIGHUP) 36 | 37 | ctx, cancel := context.WithCancel(context.Background()) 38 | defer cancel() 39 | 40 | fatalCh := make(chan error) 41 | go func() { 42 | if err := sgw.run(ctx); err != nil { 43 | fatalCh <- err 44 | } 45 | }() 46 | 47 | for { 48 | select { 49 | case sig := <-sigCh: 50 | // TODO: reload config on receiving SIGHUP 51 | log.Println(sig) 52 | return 53 | case err := <-sgw.errCh: 54 | log.Printf("WARN: %s", err) 55 | case err := <-fatalCh: 56 | log.Printf("FATAL: %s", err) 57 | return 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/gw-tester/sgw/sgw.yml: -------------------------------------------------------------------------------- 1 | local_addresses: 2 | s11_ip: "127.0.1.13" 3 | s1u_ip: "127.0.0.13" 4 | s5c_ip: "127.0.1.14" 5 | s5u_ip: "127.0.0.14" 6 | use_kernel_gtp: false 7 | prom_addr: "127.0.10.3:58080" 8 | -------------------------------------------------------------------------------- /examples/utils/mac_local_host_enabler.sh: -------------------------------------------------------------------------------- 1 | # This script will enable 127.0.0.1 up to 127.0.0.256 interfaces 2 | for ((i=2;i<256;i++)) do 3 | sudo ifconfig lo0 alias 127.0.0.$i up 4 | done 5 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wmnsk/go-gtp 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/golang/protobuf v1.5.4 7 | github.com/google/go-cmp v0.7.0 8 | github.com/pascaldekloe/goe v0.1.1 9 | github.com/prometheus/client_golang v1.22.0 10 | github.com/vishvananda/netlink v1.3.0 11 | golang.org/x/net v0.40.0 12 | google.golang.org/grpc v1.72.0 13 | gopkg.in/yaml.v2 v2.4.0 14 | ) 15 | 16 | require ( 17 | github.com/beorn7/perks v1.0.1 // indirect 18 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 19 | github.com/kr/text v0.2.0 // indirect 20 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 21 | github.com/prometheus/client_model v0.6.2 // indirect 22 | github.com/prometheus/common v0.63.0 // indirect 23 | github.com/prometheus/procfs v0.16.1 // indirect 24 | github.com/vishvananda/netns v0.0.5 // indirect 25 | golang.org/x/sys v0.33.0 // indirect 26 | golang.org/x/text v0.25.0 // indirect 27 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f // indirect 28 | google.golang.org/protobuf v1.36.6 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /gtp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtp 6 | 7 | import ( 8 | v0msg "github.com/wmnsk/go-gtp/gtpv0/message" 9 | v1msg "github.com/wmnsk/go-gtp/gtpv1/message" 10 | v2msg "github.com/wmnsk/go-gtp/gtpv2/message" 11 | ) 12 | 13 | // Message is an interface that defines all versions of GTP message. 14 | type Message interface { 15 | MarshalTo([]byte) error 16 | UnmarshalBinary(b []byte) error 17 | MarshalLen() int 18 | Version() int 19 | MessageType() uint8 20 | MessageTypeName() string 21 | 22 | // deprecated 23 | SerializeTo([]byte) error 24 | DecodeFromBytes(b []byte) error 25 | } 26 | 27 | // Marshal returns the byte sequence generated from a Message instance. 28 | // Better to use (*MessageName).Marshal instead if you know the name of message to be serialized. 29 | func Marshal(m Message) ([]byte, error) { 30 | b := make([]byte, m.MarshalLen()) 31 | if err := m.MarshalTo(b); err != nil { 32 | return nil, err 33 | } 34 | 35 | return b, nil 36 | } 37 | 38 | // Parse decodes given bytes as Message. 39 | func Parse(b []byte) (Message, error) { 40 | if len(b) < 8 { 41 | return nil, ErrTooShortToParse 42 | } 43 | 44 | switch b[0] >> 5 { 45 | case 0: 46 | return v0msg.Parse(b) 47 | case 1: 48 | return v1msg.Parse(b) 49 | case 2: 50 | return v2msg.Parse(b) 51 | default: 52 | return nil, ErrInvalidVersion 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /gtp_fuzz_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtp_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp" 11 | ) 12 | 13 | func FuzzParse(f *testing.F) { 14 | f.Fuzz(func(t *testing.T, b []byte) { 15 | if _, err := gtp.Parse(b); err != nil { 16 | t.Skip() 17 | } 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /gtpv0/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtpv0 6 | 7 | // Cause definitions. 8 | const ( 9 | CauseRequestIMSI uint8 = 0 10 | CauseRequestIMEI uint8 = 1 11 | CauseRequestIMSIandIMEI uint8 = 2 12 | CauseNoIdentityNeeded uint8 = 3 13 | CauseRequestAccepted uint8 = 128 14 | CauseNonExistent uint8 = 192 15 | CauseInvalidMessageFormat uint8 = 193 16 | CauseIMSINotKnown uint8 = 194 17 | CauseMSIsGPRSDetached uint8 = 195 18 | CauseMSIsNotGPRSResponding uint8 = 196 19 | CauseMSRefuses uint8 = 197 20 | CauseVersionNotSupported uint8 = 198 21 | CauseNoResourcesAvailable uint8 = 199 22 | CauseServiceNotSupported uint8 = 200 23 | CauseMandatoryIEIncorrect uint8 = 201 24 | CauseMandatoryIEMissing uint8 = 202 25 | CauseOptionalIEIncorrect uint8 = 203 26 | CauseSystemFailure uint8 = 204 27 | CauseRoamingRestriction uint8 = 205 28 | CausePTMSISignatureMismatch uint8 = 206 29 | CauseGPRSConnectionSuspended uint8 = 207 30 | CauseAuthenticationFailure uint8 = 208 31 | CauseUserAuthenticationFailed uint8 = 209 32 | ) 33 | 34 | // PDP Type Organization definitions. 35 | const ( 36 | PDPTypeETSI uint8 = iota | 0xf0 37 | PDPTypeIETF 38 | ) 39 | 40 | // SelectionMode definitions. 41 | const ( 42 | SelectionModeMSorNetworkProvidedAPNSubscribedVerified uint8 = iota | 0xf0 43 | SelectionModeMSProvidedAPNSubscriptionNotVerified 44 | SelectionModeNetworkProvidedAPNSubscriptionNotVerified 45 | ) 46 | -------------------------------------------------------------------------------- /gtpv0/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Package gtpv0 provides simple and painless handling of GTPv0 protocol in pure Golang. 6 | // 7 | // This package is still under construction. The networking feature would be available in the future. 8 | // Please see README.md for detailed usage of the APIs provided by this package. 9 | // 10 | // https://github.com/wmnsk/go-gtp/blob/main/gtpv0/README.md 11 | package gtpv0 12 | -------------------------------------------------------------------------------- /gtpv0/ie/apn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | ) 11 | 12 | // NewAccessPointName creates a new AccessPointName IE. 13 | func NewAccessPointName(apn string) *IE { 14 | i := New(AccessPointName, make([]byte, len(apn)+1)) 15 | var offset = 0 16 | for _, label := range strings.Split(apn, ".") { 17 | l := len(label) 18 | i.Payload[offset] = uint8(l) 19 | copy(i.Payload[offset+1:], label) 20 | offset += l + 1 21 | } 22 | 23 | return i 24 | } 25 | 26 | // AccessPointName returns AccessPointName in string if type of IE matches. 27 | func (i *IE) AccessPointName() (string, error) { 28 | if i.Type != AccessPointName { 29 | return "", &InvalidTypeError{Type: i.Type} 30 | } 31 | if len(i.Payload) == 0 { 32 | return "", io.ErrUnexpectedEOF 33 | } 34 | 35 | var ( 36 | apn []string 37 | offset int 38 | ) 39 | 40 | max := len(i.Payload) 41 | for { 42 | if offset >= max { 43 | break 44 | } 45 | l := int(i.Payload[offset]) 46 | if offset+l+1 >= max { 47 | return "", io.ErrUnexpectedEOF 48 | } 49 | apn = append(apn, string(i.Payload[offset+1:offset+l+1])) 50 | offset += l + 1 51 | } 52 | 53 | return strings.Join(apn, "."), nil 54 | } 55 | 56 | // MustAccessPointName returns AccessPointName in string if type matches. 57 | // This should only be used if it is assured to have the value. 58 | func (i *IE) MustAccessPointName() string { 59 | v, _ := i.AccessPointName() 60 | return v 61 | } 62 | -------------------------------------------------------------------------------- /gtpv0/ie/cause.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewCause creates a new Cause IE. 10 | func NewCause(cause uint8) *IE { 11 | return newUint8ValIE(Cause, cause) 12 | } 13 | 14 | // Cause returns Cause value if type matches. 15 | func (i *IE) Cause() (uint8, error) { 16 | if i.Type != Cause { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustCause returns Cause in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustCause() uint8 { 29 | v, _ := i.Cause() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv0/ie/charging-gateway-address.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "net" 10 | ) 11 | 12 | // NewChargingGatewayAddress creates a new ChargingGatewayAddress IE from string. 13 | func NewChargingGatewayAddress(addr string) *IE { 14 | ip := net.ParseIP(addr) 15 | v4 := ip.To4() 16 | 17 | // IPv4 18 | if v4 != nil { 19 | return New(ChargingGatewayAddress, v4) 20 | } 21 | // IPv6 22 | return New(ChargingGatewayAddress, ip) 23 | } 24 | 25 | // ChargingGatewayAddress returns ChargingGatewayAddress value if type matches. 26 | func (i *IE) ChargingGatewayAddress() (string, error) { 27 | if i.Type != ChargingGatewayAddress { 28 | return "", &InvalidTypeError{Type: i.Type} 29 | } 30 | if len(i.Payload) < 4 { 31 | return "", io.ErrUnexpectedEOF 32 | } 33 | 34 | return net.IP(i.Payload).String(), nil 35 | } 36 | 37 | // MustChargingGatewayAddress returns ChargingGatewayAddress in string if type matches. 38 | // This should only be used if it is assured to have the value. 39 | func (i *IE) MustChargingGatewayAddress() string { 40 | v, _ := i.ChargingGatewayAddress() 41 | return v 42 | } 43 | -------------------------------------------------------------------------------- /gtpv0/ie/charging-id.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // NewChargingID creates a new ChargingID IE. 13 | func NewChargingID(id uint32) *IE { 14 | return newUint32ValIE(ChargingID, id) 15 | } 16 | 17 | // ChargingID returns ChargingID value in uint32 if type matches. 18 | func (i *IE) ChargingID() (uint32, error) { 19 | if i.Type != ChargingID { 20 | return 0, &InvalidTypeError{Type: i.Type} 21 | } 22 | if len(i.Payload) < 4 { 23 | return 0, io.ErrUnexpectedEOF 24 | } 25 | 26 | return binary.BigEndian.Uint32(i.Payload), nil 27 | } 28 | 29 | // MustChargingID returns ChargingID in uint32 if type matches. 30 | // This should only be used if it is assured to have the value. 31 | func (i *IE) MustChargingID() uint32 { 32 | v, _ := i.ChargingID() 33 | return v 34 | } 35 | -------------------------------------------------------------------------------- /gtpv0/ie/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | ) 11 | 12 | // Error definitions. 13 | var ( 14 | ErrInvalidLength = errors.New("got invalid length") 15 | ErrTooShortToMarshal = errors.New("too short to Marshal") 16 | ErrTooShortToParse = errors.New("too short to Parse as GTPv0 IE") 17 | 18 | ErrMalformed = errors.New("malformed IE") 19 | ) 20 | 21 | // InvalidTypeError indicates the type of IE is invalid. 22 | type InvalidTypeError struct { 23 | Type uint8 24 | } 25 | 26 | // Error returns message with the invalid type given. 27 | func (e *InvalidTypeError) Error() string { 28 | return fmt.Sprintf("got invalid type: %v", e.Type) 29 | } 30 | -------------------------------------------------------------------------------- /gtpv0/ie/gsn-address.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "net" 10 | ) 11 | 12 | // NewGSNAddress creates a new GSNAddress IE from string. 13 | func NewGSNAddress(addr string) *IE { 14 | ip := net.ParseIP(addr) 15 | v4 := ip.To4() 16 | 17 | // IPv4 18 | if v4 != nil { 19 | return New(GSNAddress, v4) 20 | } 21 | // IPv6 22 | return New(GSNAddress, ip) 23 | } 24 | 25 | // GSNAddress returns GSNAddress value if type matches. 26 | func (i *IE) GSNAddress() (string, error) { 27 | if i.Type != GSNAddress { 28 | return "", &InvalidTypeError{Type: i.Type} 29 | } 30 | if len(i.Payload) < 4 { 31 | return "", io.ErrUnexpectedEOF 32 | } 33 | 34 | return net.IP(i.Payload).String(), nil 35 | } 36 | 37 | // MustGSNAddress returns GSNAddress in string if type matches. 38 | // This should only be used if it is assured to have the value. 39 | func (i *IE) MustGSNAddress() string { 40 | v, _ := i.GSNAddress() 41 | return v 42 | } 43 | -------------------------------------------------------------------------------- /gtpv0/ie/ie_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "log" 8 | 9 | // Serialize serializes IE into bytes. 10 | // 11 | // Deprecated: use IE.Marshal instead. 12 | func (i *IE) Serialize() ([]byte, error) { 13 | log.Println("IE.Serialize is deprecated. use IE.Marshal instead") 14 | return i.Marshal() 15 | } 16 | 17 | // SerializeTo serializes IE into bytes given as b. 18 | // 19 | // Deprecated: use IE.MarshalTo instead. 20 | func (i *IE) SerializeTo(b []byte) error { 21 | log.Println("IE.SerializeTo is deprecated. use IE.MarshalTo instead") 22 | return i.MarshalTo(b) 23 | } 24 | 25 | // Decode decodes bytes as IE. 26 | // 27 | // Deprecated: use Parse instead. 28 | func Decode(b []byte) (*IE, error) { 29 | log.Println("Decode is deprecated. use Parse instead") 30 | return Parse(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as IE. 34 | // 35 | // Deprecated: use IE.UnmarshalBinary instead. 36 | func (i *IE) DecodeFromBytes(b []byte) error { 37 | log.Println("IE.DecodeFromBytes is deprecated. use IE.UnmarshalBinary instead") 38 | return i.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of IE. 42 | // 43 | // Deprecated: use IE.MarshalLen instead. 44 | func (i *IE) Len() int { 45 | log.Println("IE.Len is deprecated. use IE.MarshalLen instead") 46 | return i.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv0/ie/ie_fuzz_test.go: -------------------------------------------------------------------------------- 1 | package ie_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/wmnsk/go-gtp/gtpv0/ie" 7 | ) 8 | 9 | func FuzzParse(f *testing.F) { 10 | f.Fuzz(func(t *testing.T, b []byte) { 11 | if _, err := ie.Parse(b); err != nil { 12 | t.Skip() 13 | } 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /gtpv0/ie/imsi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewIMSI creates a new IMSI IE. 14 | func NewIMSI(imsi string) *IE { 15 | i, err := utils.StrToSwappedBytes(imsi, "f") 16 | if err != nil { 17 | return New(IMSI, nil) 18 | } 19 | return New(IMSI, i) 20 | } 21 | 22 | // IMSI returns IMSI value in string if type matches. 23 | func (i *IE) IMSI() (string, error) { 24 | if i.Type != IMSI { 25 | return "", &InvalidTypeError{Type: i.Type} 26 | } 27 | if len(i.Payload) == 0 { 28 | return "", io.ErrUnexpectedEOF 29 | } 30 | 31 | return utils.SwappedBytesToStr(i.Payload, true), nil 32 | } 33 | 34 | // MustIMSI returns IMSI in string if type matches. 35 | // This should only be used if it is assured to have the value. 36 | func (i *IE) MustIMSI() string { 37 | v, _ := i.IMSI() 38 | return v 39 | } 40 | -------------------------------------------------------------------------------- /gtpv0/ie/ms-not-reachable-reason.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewMSNotReachableReason creates a new MSNotReachableReason IE. 10 | func NewMSNotReachableReason(reason uint8) *IE { 11 | return newUint8ValIE(MSNotReachableReason, reason) 12 | } 13 | 14 | // MSNotReachableReason returns MSNotReachableReason value if type matches. 15 | func (i *IE) MSNotReachableReason() (uint8, error) { 16 | if i.Type != MSNotReachableReason { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustMSNotReachableReason returns MSNotReachableReason in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustMSNotReachableReason() uint8 { 29 | v, _ := i.MSNotReachableReason() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv0/ie/msisdn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewMSISDN creates a new MSISDN IE. 14 | func NewMSISDN(msisdn string) *IE { 15 | i, err := utils.StrToSwappedBytes("19"+msisdn, "f") 16 | if err != nil { 17 | return nil 18 | } 19 | return New(MSISDN, i) 20 | } 21 | 22 | // MSISDN returns MSISDN value if type matches. 23 | func (i *IE) MSISDN() (string, error) { 24 | if i.Type != MSISDN { 25 | return "", &InvalidTypeError{Type: i.Type} 26 | } 27 | if len(i.Payload) < 2 { 28 | return "", io.ErrUnexpectedEOF 29 | } 30 | 31 | return utils.SwappedBytesToStr(i.Payload[1:], false), nil 32 | } 33 | 34 | // MustMSISDN returns MSISDN in string if type matches. 35 | // This should only be used if it is assured to have the value. 36 | func (i *IE) MustMSISDN() string { 37 | v, _ := i.MSISDN() 38 | return v 39 | } 40 | -------------------------------------------------------------------------------- /gtpv0/ie/p-tmsi-signature.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewPTMSISignature creates a new PTMSISignature IE. 14 | func NewPTMSISignature(sig uint32) *IE { 15 | return New(PTMSISignature, utils.Uint32To24(sig)) 16 | } 17 | 18 | // PTMSISignature returns PTMSISignature value in uint32 if type matches. 19 | func (i *IE) PTMSISignature() (uint32, error) { 20 | if i.Type != PTMSISignature { 21 | return 0, &InvalidTypeError{Type: i.Type} 22 | } 23 | if len(i.Payload) < 3 { 24 | return 0, io.ErrUnexpectedEOF 25 | } 26 | 27 | return utils.Uint24To32(i.Payload), nil 28 | } 29 | 30 | // MustPTMSISignature returns PTMSISignature in uint32 if type matches. 31 | // This should only be used if it is assured to have the value. 32 | func (i *IE) MustPTMSISignature() uint32 { 33 | v, _ := i.PTMSISignature() 34 | return v 35 | } 36 | -------------------------------------------------------------------------------- /gtpv0/ie/p-tmsi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // NewPacketTMSI creates a new PacketTMSI IE. 13 | func NewPacketTMSI(ptmsi uint32) *IE { 14 | return newUint32ValIE(PacketTMSI, ptmsi) 15 | } 16 | 17 | // PacketTMSI returns PacketTMSI value in uint32 if type matches. 18 | func (i *IE) PacketTMSI() (uint32, error) { 19 | if i.Type != PacketTMSI { 20 | return 0, &InvalidTypeError{Type: i.Type} 21 | } 22 | if len(i.Payload) < 4 { 23 | return 0, io.ErrUnexpectedEOF 24 | } 25 | 26 | return binary.BigEndian.Uint32(i.Payload), nil 27 | } 28 | 29 | // MustPacketTMSI returns PacketTMSI in uint32 if type matches. 30 | // This should only be used if it is assured to have the value. 31 | func (i *IE) MustPacketTMSI() uint32 { 32 | v, _ := i.PacketTMSI() 33 | return v 34 | } 35 | -------------------------------------------------------------------------------- /gtpv0/ie/recovery.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewRecovery creates a new Recovery IE. 10 | func NewRecovery(recovery uint8) *IE { 11 | return newUint8ValIE(Recovery, recovery) 12 | } 13 | 14 | // Recovery returns Recovery value if type matches. 15 | func (i *IE) Recovery() (uint8, error) { 16 | if i.Type != Recovery { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustRecovery returns Recovery in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustRecovery() uint8 { 29 | v, _ := i.Recovery() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv0/ie/reordering-required.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewReorderingRequired creates a new ReorderingRequired IE. 8 | func NewReorderingRequired(required bool) *IE { 9 | if required { 10 | return New(ReorderingRequired, []byte{0xff}) 11 | } 12 | return New(ReorderingRequired, []byte{0xfe}) 13 | } 14 | 15 | // ReorderingRequired returns ReorderingRequired value in bool if type matches. 16 | func (i *IE) ReorderingRequired() bool { 17 | if i.Type != ReorderingRequired { 18 | return false 19 | } 20 | if len(i.Payload) == 0 { 21 | return false 22 | } 23 | 24 | return i.Payload[0]&0x01 == 1 25 | } 26 | -------------------------------------------------------------------------------- /gtpv0/ie/selection-mode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewSelectionMode creates a new SelectionMode IE. 10 | // Note that exactly one of the parameters should be set to true. 11 | // Otherwise, you'll get the unexpected result. 12 | func NewSelectionMode(mode uint8) *IE { 13 | return newUint8ValIE(SelectionMode, mode) 14 | } 15 | 16 | // SelectionMode returns SelectionMode value if type matches. 17 | func (i *IE) SelectionMode() (uint8, error) { 18 | if i.Type != SelectionMode { 19 | return 0, &InvalidTypeError{Type: i.Type} 20 | } 21 | if len(i.Payload) == 0 { 22 | return 0, io.ErrUnexpectedEOF 23 | } 24 | 25 | return i.Payload[0], nil 26 | } 27 | 28 | // MustSelectionMode returns SelectionMode in uint8 if type matches. 29 | // This should only be used if it is assured to have the value. 30 | func (i *IE) MustSelectionMode() uint8 { 31 | v, _ := i.SelectionMode() 32 | return v 33 | } 34 | -------------------------------------------------------------------------------- /gtpv0/ie/tlli.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // NewTemporaryLogicalLinkIdentity creates a new TemporaryLogicalLinkIdentity IE. 13 | func NewTemporaryLogicalLinkIdentity(tlli uint32) *IE { 14 | return newUint32ValIE(TemporaryLogicalLinkIdentity, tlli) 15 | } 16 | 17 | // TemporaryLogicalLinkIdentity returns TemporaryLogicalLinkIdentity value in uint32 if type matches. 18 | func (i *IE) TemporaryLogicalLinkIdentity() (uint32, error) { 19 | if i.Type != TemporaryLogicalLinkIdentity { 20 | return 0, &InvalidTypeError{Type: i.Type} 21 | } 22 | if len(i.Payload) < 4 { 23 | return 0, io.ErrUnexpectedEOF 24 | } 25 | 26 | return binary.BigEndian.Uint32(i.Payload), nil 27 | } 28 | 29 | // MustTemporaryLogicalLinkIdentity returns TemporaryLogicalLinkIdentity in uint32 if type matches. 30 | // This should only be used if it is assured to have the value. 31 | func (i *IE) MustTemporaryLogicalLinkIdentity() uint32 { 32 | v, _ := i.TemporaryLogicalLinkIdentity() 33 | return v 34 | } 35 | -------------------------------------------------------------------------------- /gtpv0/message/delete-pdp-context-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv0/message" 11 | "github.com/wmnsk/go-gtp/gtpv0/testutils" 12 | ) 13 | 14 | func TestDeletePDPContextRequest(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "normal", 18 | Structured: message.NewDeletePDPContextRequest( 19 | testutils.TestFlow.Seq, testutils.TestFlow.Label, testutils.TestFlow.TID, 20 | ), 21 | Serialized: []byte{ 22 | // Header 23 | 0x1e, 0x14, 0x00, 0x00, 24 | // SequenceNumber 25 | 0x00, 0x01, 0x00, 0x00, 26 | // Sndpd 27 | 0xff, 0xff, 0xff, 0xff, 28 | // TID 29 | 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0x55, 30 | }, 31 | }, 32 | } 33 | 34 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 35 | v, err := message.ParseDeletePDPContextRequest(b) 36 | if err != nil { 37 | return nil, err 38 | } 39 | v.Payload = nil 40 | return v, nil 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /gtpv0/message/delete-pdp-context-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv0" 11 | "github.com/wmnsk/go-gtp/gtpv0/ie" 12 | "github.com/wmnsk/go-gtp/gtpv0/message" 13 | "github.com/wmnsk/go-gtp/gtpv0/testutils" 14 | ) 15 | 16 | func TestDeletePDPContextResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "request-accepted", 20 | Structured: message.NewDeletePDPContextResponse( 21 | testutils.TestFlow.Seq, testutils.TestFlow.Label, testutils.TestFlow.TID, 22 | ie.NewCause(gtpv0.CauseRequestAccepted), 23 | ), 24 | Serialized: []byte{ 25 | // Hewader 26 | 0x1e, 0x15, 0x00, 0x02, 27 | // SequenceNumber 28 | 0x00, 0x01, 0x00, 0x00, 29 | // Sndpd 30 | 0xff, 0xff, 0xff, 0xff, 31 | // TID 32 | 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0x55, 33 | // Cause 34 | 0x01, 0x80, 35 | }, 36 | }, 37 | } 38 | 39 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 40 | v, err := message.ParseDeletePDPContextResponse(b) 41 | if err != nil { 42 | return nil, err 43 | } 44 | v.Payload = nil 45 | return v, nil 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /gtpv0/message/echo-req_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes EchoRequest into bytes. 10 | // 11 | // Deprecated: use EchoRequest.Marshal instead. 12 | func (e *EchoRequest) Serialize() ([]byte, error) { 13 | log.Println("EchoRequest.Serialize is deprecated. use EchoRequest.Marshal instead") 14 | return e.Marshal() 15 | } 16 | 17 | // SerializeTo serializes EchoRequest into bytes given as b. 18 | // 19 | // Deprecated: use EchoRequest.MarshalTo instead. 20 | func (e *EchoRequest) SerializeTo(b []byte) error { 21 | log.Println("EchoRequest.SerializeTo is deprecated. use EchoRequest.MarshalTo instead") 22 | return e.MarshalTo(b) 23 | } 24 | 25 | // DecodeEchoRequest decodes bytes as EchoRequest. 26 | // 27 | // Deprecated: use ParseEchoRequest instead. 28 | func DecodeEchoRequest(b []byte) (*EchoRequest, error) { 29 | log.Println("DecodeEchoRequest is deprecated. use ParseEchoRequest instead") 30 | return ParseEchoRequest(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as EchoRequest. 34 | // 35 | // Deprecated: use EchoRequest.UnmarshalBinary instead. 36 | func (e *EchoRequest) DecodeFromBytes(b []byte) error { 37 | log.Println("EchoRequest.DecodeFromBytes is deprecated. use EchoRequest.UnmarshalBinary instead") 38 | return e.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of EchoRequest. 42 | // 43 | // Deprecated: use EchoRequest.MarshalLen instead. 44 | func (e *EchoRequest) Len() int { 45 | log.Println("EchoRequest.Len is deprecated. use EchoRequest.MarshalLen instead") 46 | return e.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv0/message/echo-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv0/message" 11 | "github.com/wmnsk/go-gtp/gtpv0/testutils" 12 | ) 13 | 14 | func TestEchoRequest(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "normal", 18 | Structured: message.NewEchoRequest( 19 | testutils.TestFlow.Seq, testutils.TestFlow.Label, testutils.TestFlow.TID, 20 | ), 21 | Serialized: []byte{ 22 | // Header 23 | 0x1e, 0x01, 0x00, 0x00, 24 | // SequenceNumber 25 | 0x00, 0x01, 0x00, 0x00, 26 | // Sndpd 27 | 0xff, 0xff, 0xff, 0xff, 28 | // TID 29 | 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0x55, 30 | }, 31 | }, 32 | } 33 | 34 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 35 | v, err := message.ParseEchoRequest(b) 36 | if err != nil { 37 | return nil, err 38 | } 39 | v.Payload = nil 40 | return v, nil 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /gtpv0/message/echo-res_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes EchoResponse into bytes. 10 | // 11 | // Deprecated: use EchoResponse.Marshal instead. 12 | func (e *EchoResponse) Serialize() ([]byte, error) { 13 | log.Println("EchoResponse.Serialize is deprecated. use EchoResponse.Marshal instead") 14 | return e.Marshal() 15 | } 16 | 17 | // SerializeTo serializes EchoResponse into bytes given as b. 18 | // 19 | // Deprecated: use EchoResponse.MarshalTo instead. 20 | func (e *EchoResponse) SerializeTo(b []byte) error { 21 | log.Println("EchoResponse.SerializeTo is deprecated. use EchoResponse.MarshalTo instead") 22 | return e.MarshalTo(b) 23 | } 24 | 25 | // DecodeEchoResponse decodes bytes as EchoResponse. 26 | // 27 | // Deprecated: use ParseEchoResponse instead. 28 | func DecodeEchoResponse(b []byte) (*EchoResponse, error) { 29 | log.Println("DecodeEchoResponse is deprecated. use ParseEchoResponse instead") 30 | return ParseEchoResponse(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as EchoResponse. 34 | // 35 | // Deprecated: use EchoResponse.UnmarshalBinary instead. 36 | func (e *EchoResponse) DecodeFromBytes(b []byte) error { 37 | log.Println("EchoResponse.DecodeFromBytes is deprecated. use EchoResponse.UnmarshalBinary instead") 38 | return e.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of EchoResponse. 42 | // 43 | // Deprecated: use EchoResponse.MarshalLen instead. 44 | func (e *EchoResponse) Len() int { 45 | log.Println("EchoResponse.Len is deprecated. use EchoResponse.MarshalLen instead") 46 | return e.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv0/message/echo-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv0/ie" 11 | "github.com/wmnsk/go-gtp/gtpv0/message" 12 | "github.com/wmnsk/go-gtp/gtpv0/testutils" 13 | ) 14 | 15 | func TestEchoResponse(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "with-recovery", 19 | Structured: message.NewEchoResponse( 20 | testutils.TestFlow.Seq, testutils.TestFlow.Label, testutils.TestFlow.TID, 21 | ie.NewRecovery(0x80), 22 | ), 23 | Serialized: []byte{ 24 | // Hewader 25 | 0x1e, 0x02, 0x00, 0x02, 26 | // SequenceNumber 27 | 0x00, 0x01, 0x00, 0x00, 28 | // Sndpd 29 | 0xff, 0xff, 0xff, 0xff, 30 | // TID 31 | 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0x55, 32 | // Recovery 33 | 0x0e, 0x80, 34 | }, 35 | }, 36 | } 37 | 38 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 39 | v, err := message.ParseEchoResponse(b) 40 | if err != nil { 41 | return nil, err 42 | } 43 | v.Payload = nil 44 | return v, nil 45 | }) 46 | } 47 | -------------------------------------------------------------------------------- /gtpv0/message/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "errors" 8 | 9 | // Error definitions. 10 | var ( 11 | ErrInvalidLength = errors.New("got invalid length") 12 | ErrTooShortToMarshal = errors.New("too short to Marshal") 13 | ErrTooShortToParse = errors.New("too short to Parse as GTPv0") 14 | ) 15 | -------------------------------------------------------------------------------- /gtpv0/message/generic_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Generic into bytes. 10 | // 11 | // Deprecated: use Generic.Marshal instead. 12 | func (g *Generic) Serialize() ([]byte, error) { 13 | log.Println("Generic.Serialize is deprecated. use Generic.Marshal instead") 14 | return g.Marshal() 15 | } 16 | 17 | // SerializeTo serializes Generic into bytes given as b. 18 | // 19 | // Deprecated: use Generic.MarshalTo instead. 20 | func (g *Generic) SerializeTo(b []byte) error { 21 | log.Println("Generic.SerializeTo is deprecated. use Generic.MarshalTo instead") 22 | return g.MarshalTo(b) 23 | } 24 | 25 | // DecodeGeneric decodes bytes as Generic. 26 | // 27 | // Deprecated: use ParseGeneric instead. 28 | func DecodeGeneric(b []byte) (*Generic, error) { 29 | log.Println("DecodeGeneric is deprecated. use ParseGeneric instead") 30 | return ParseGeneric(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as Generic. 34 | // 35 | // Deprecated: use Generic.UnmarshalBinary instead. 36 | func (g *Generic) DecodeFromBytes(b []byte) error { 37 | log.Println("Generic.DecodeFromBytes is deprecated. use Generic.UnmarshalBinary instead") 38 | return g.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of Generic. 42 | // 43 | // Deprecated: use Generic.MarshalLen instead. 44 | func (g *Generic) Len() int { 45 | log.Println("Generic.Len is deprecated. use Generic.MarshalLen instead") 46 | return g.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv0/message/generic_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv0/ie" 11 | "github.com/wmnsk/go-gtp/gtpv0/message" 12 | "github.com/wmnsk/go-gtp/gtpv0/testutils" 13 | ) 14 | 15 | func TestGeneric(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "echo-req", 19 | Structured: message.NewGeneric( 20 | message.MsgTypeEchoRequest, testutils.TestFlow.Seq, testutils.TestFlow.Label, testutils.TestFlow.TID, 21 | ), 22 | Serialized: []byte{ 23 | // Header 24 | 0x1e, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 25 | 0xff, 0xff, 0xff, 0xff, 0x21, 0x43, 0x65, 0x87, 26 | 0x09, 0x21, 0x43, 0x55, 27 | }, 28 | }, { 29 | Description: "echo-res", 30 | Structured: message.NewGeneric( 31 | message.MsgTypeEchoResponse, testutils.TestFlow.Seq, testutils.TestFlow.Label, testutils.TestFlow.TID, 32 | ie.NewRecovery(0x80), 33 | ), 34 | Serialized: []byte{ 35 | // Hewader 36 | 0x1e, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 37 | 0xff, 0xff, 0xff, 0xff, 0x21, 0x43, 0x65, 0x87, 38 | 0x09, 0x21, 0x43, 0x55, 39 | // Recovery 40 | 0x0e, 0x80, 41 | }, 42 | }, 43 | } 44 | 45 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 46 | v, err := message.ParseGeneric(b) 47 | if err != nil { 48 | return nil, err 49 | } 50 | v.Payload = nil 51 | return v, nil 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /gtpv0/message/header_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Header into bytes. 10 | // 11 | // Deprecated: use Header.Marshal instead. 12 | func (h *Header) Serialize() ([]byte, error) { 13 | log.Println("Header.Serialize is deprecated. use Header.Marshal instead") 14 | return h.Marshal() 15 | } 16 | 17 | // SerializeTo serializes Header into bytes given as b. 18 | // 19 | // Deprecated: use Header.MarshalTo instead. 20 | func (h *Header) SerializeTo(b []byte) error { 21 | log.Println("Header.SerializeTo is deprecated. use Header.MarshalTo instead") 22 | return h.MarshalTo(b) 23 | } 24 | 25 | // DecodeHeader decodes bytes as Header. 26 | // 27 | // Deprecated: use ParseHeader instead. 28 | func DecodeHeader(b []byte) (*Header, error) { 29 | log.Println("DecodeHeader is deprecated. use ParseHeader instead") 30 | return ParseHeader(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as Header. 34 | // 35 | // Deprecated: use Header.UnmarshalBinary instead. 36 | func (h *Header) DecodeFromBytes(b []byte) error { 37 | log.Println("Header.DecodeFromBytes is deprecated. use Header.UnmarshalBinary instead") 38 | return h.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of Header. 42 | // 43 | // Deprecated: use Header.MarshalLen instead. 44 | func (h *Header) Len() int { 45 | log.Println("Header.Len is deprecated. use Header.MarshalLen instead") 46 | return h.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv0/message/header_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv0/message" 11 | "github.com/wmnsk/go-gtp/gtpv0/testutils" 12 | ) 13 | 14 | func TestHeader(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "normal", 18 | Structured: message.NewHeader( 19 | message.HeaderFlags( 20 | 0, // version 21 | 1, // Protocol Type 22 | 0, // N-PDU? 23 | ), //Flags 24 | 0x10, // Message type 25 | testutils.TestFlow.Seq, testutils.TestFlow.Label, testutils.TestFlow.TID, 26 | []byte{ // Payload 27 | 0xde, 0xad, 0xbe, 0xef, 28 | }, 29 | ), 30 | Serialized: []byte{ 31 | // Flags 32 | 0x1e, 33 | // MessageType 34 | 0x10, 35 | // SequenceNumber 36 | 0x00, 0x04, 0x00, 0x01, 37 | // FlowLabel 38 | 0x00, 0x00, 39 | // SndcpNumber 40 | 0xff, 0xff, 0xff, 0xff, 41 | // TID 42 | 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0x55, 43 | // dummy Payload 44 | 0xde, 0xad, 0xbe, 0xef, 45 | }, 46 | }, 47 | } 48 | 49 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 50 | v, err := message.ParseHeader(b) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | return v, nil 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /gtpv0/message/message_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Message into bytes. 10 | // 11 | // Deprecated: use Marshal instead. 12 | func Serialize(m Message) ([]byte, error) { 13 | log.Println("Serialize is deprecated. use Marshal instead") 14 | return Marshal(m) 15 | } 16 | 17 | // Decode decodes bytes as Message. 18 | // 19 | // Deprecated: use Parse instead. 20 | func Decode(b []byte) (Message, error) { 21 | log.Println("Decode is deprecated. use Parse instead") 22 | return Parse(b) 23 | } 24 | -------------------------------------------------------------------------------- /gtpv0/message/message_fuzz_test.go: -------------------------------------------------------------------------------- 1 | package message_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/wmnsk/go-gtp/gtpv0/message" 7 | ) 8 | 9 | func FuzzParse(f *testing.F) { 10 | f.Fuzz(func(t *testing.T, b []byte) { 11 | if _, err := message.Parse(b); err != nil { 12 | t.Skip() 13 | } 14 | }) 15 | } 16 | 17 | func FuzzHeaderParse(f *testing.F) { 18 | f.Fuzz(func(t *testing.T, b []byte) { 19 | if _, err := message.ParseHeader(b); err != nil { 20 | t.Skip() 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /gtpv0/message/t-pdu_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes TPDU into bytes. 10 | // 11 | // Deprecated: use TPDU.Marshal instead. 12 | func (t *TPDU) Serialize() ([]byte, error) { 13 | log.Println("TPDU.Serialize is deprecated. use TPDU.Marshal instead") 14 | return t.Marshal() 15 | } 16 | 17 | // SerializeTo serializes TPDU into bytes given as b. 18 | // 19 | // Deprecated: use TPDU.MarshalTo instead. 20 | func (t *TPDU) SerializeTo(b []byte) error { 21 | log.Println("TPDU.SerializeTo is deprecated. use TPDU.MarshalTo instead") 22 | return t.MarshalTo(b) 23 | } 24 | 25 | // DecodeTPDU decodes bytes as TPDU. 26 | // 27 | // Deprecated: use ParseTPDU instead. 28 | func DecodeTPDU(b []byte) (*TPDU, error) { 29 | log.Println("DecodeTPDU is deprecated. use ParseTPDU instead") 30 | return ParseTPDU(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as TPDU. 34 | // 35 | // Deprecated: use TPDU.UnmarshalBinary instead. 36 | func (t *TPDU) DecodeFromBytes(b []byte) error { 37 | log.Println("TPDU.DecodeFromBytes is deprecated. use TPDU.UnmarshalBinary instead") 38 | return t.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of TPDU. 42 | // 43 | // Deprecated: use TPDU.MarshalLen instead. 44 | func (t *TPDU) Len() int { 45 | log.Println("TPDU.Len is deprecated. use TPDU.MarshalLen instead") 46 | return t.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv0/message/t-pdu_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv0/message" 11 | "github.com/wmnsk/go-gtp/gtpv0/testutils" 12 | ) 13 | 14 | func TestTPDU(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "normal", 18 | Structured: message.NewTPDU( 19 | testutils.TestFlow.Seq, testutils.TestFlow.Label, testutils.TestFlow.TID, 20 | []byte{0xde, 0xad, 0xbe, 0xef}, 21 | ), 22 | Serialized: []byte{ 23 | // Header 24 | 0x1e, 0xff, 0x00, 0x04, 25 | // SequenceNumber 26 | 0x00, 0x01, 0x00, 0x00, 27 | // SNDPD 28 | 0xff, 0xff, 0xff, 0xff, 29 | // TID 30 | 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0x55, 31 | // Payload 32 | 0xde, 0xad, 0xbe, 0xef, 33 | }, 34 | }, 35 | } 36 | 37 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 38 | v, err := message.ParseTPDU(b) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return v, nil 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /gtpv1/conn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtpv1 6 | 7 | import ( 8 | "net" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/message" 11 | ) 12 | 13 | // Conn is an abstraction of both GTPv1-C and GTPv1-U Conn. 14 | type Conn interface { 15 | net.PacketConn 16 | AddHandler(uint8, HandlerFunc) 17 | RespondTo(net.Addr, message.Message, message.Message) error 18 | Restarts() uint8 19 | } 20 | -------------------------------------------------------------------------------- /gtpv1/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Package gtpv1 provides simple and painless handling of GTPv1-C and GTPv1-U protocol in pure Golang. 6 | // 7 | // Please see README.md for detailed usage of the APIs provided by this package. 8 | // 9 | // https://github.com/wmnsk/go-gtp/blob/main/gtpv1/README.md 10 | package gtpv1 11 | -------------------------------------------------------------------------------- /gtpv1/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtpv1 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | ) 11 | 12 | var ( 13 | // ErrUnexpectedType indicates that the type of incoming message is not expected. 14 | ErrUnexpectedType = errors.New("got unexpected type of message") 15 | 16 | // ErrInvalidConnection indicates that the connection type(C-Plane or U-Plane) is 17 | // not the expected one. 18 | ErrInvalidConnection = errors.New("got invalid connection type") 19 | 20 | // ErrConnNotOpened indicates that some operation is failed due to the status of 21 | // Conn is not valid. 22 | ErrConnNotOpened = errors.New("connection is not opened") 23 | ) 24 | 25 | // ErrorIndicatedError indicates that Error Indication message is received on U-Plane Connection. 26 | type ErrorIndicatedError struct { 27 | TEID uint32 28 | Peer string 29 | } 30 | 31 | func (e *ErrorIndicatedError) Error() string { 32 | return fmt.Sprintf("error received from %s, TEIDDataI: %#x", e.Peer, e.TEID) 33 | } 34 | 35 | // HandlerNotFoundError indicates that the handler func is not registered in *Conn 36 | // for the incoming GTPv2 message. In usual cases this error should not be taken 37 | // as fatal, as the other endpoint can make your program stop working just by 38 | // sending unregistered message. 39 | type HandlerNotFoundError struct { 40 | MsgType string 41 | } 42 | 43 | // Error returns violating message type to handle. 44 | func (e *HandlerNotFoundError) Error() string { 45 | return fmt.Sprintf("no handlers found for incoming message: %s, ignoring", e.MsgType) 46 | } 47 | -------------------------------------------------------------------------------- /gtpv1/gtpv1_fuzz_test.go: -------------------------------------------------------------------------------- 1 | package gtpv1_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/wmnsk/go-gtp/gtpv1" 7 | ) 8 | 9 | func FuzzDecapsulate(f *testing.F) { 10 | f.Fuzz(func(t *testing.T, b []byte) { 11 | if _, _, err := gtpv1.Decapsulate(b); err != nil { 12 | t.Skip() 13 | } 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /gtpv1/ie/apn-restriction.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewAPNRestriction creates a new APNRestriction IE. 10 | func NewAPNRestriction(restriction uint8) *IE { 11 | return newUint8ValIE(APNRestriction, restriction) 12 | } 13 | 14 | // APNRestriction returns APNRestriction in uint8 if type matches. 15 | func (i *IE) APNRestriction() (uint8, error) { 16 | if i.Type != APNRestriction { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustAPNRestriction returns APNRestriction in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustAPNRestriction() uint8 { 29 | v, _ := i.APNRestriction() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv1/ie/apn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | ) 11 | 12 | // NewAccessPointName creates a new AccessPointName IE. 13 | func NewAccessPointName(apn string) *IE { 14 | i := New(AccessPointName, make([]byte, len(apn)+1)) 15 | var offset = 0 16 | for _, label := range strings.Split(apn, ".") { 17 | l := len(label) 18 | i.Payload[offset] = uint8(l) 19 | copy(i.Payload[offset+1:], label) 20 | offset += l + 1 21 | } 22 | 23 | return i 24 | } 25 | 26 | // AccessPointName returns AccessPointName in string if type of IE matches. 27 | func (i *IE) AccessPointName() (string, error) { 28 | if i.Type != AccessPointName { 29 | return "", &InvalidTypeError{Type: i.Type} 30 | } 31 | 32 | var ( 33 | apn []string 34 | offset int 35 | ) 36 | 37 | max := len(i.Payload) 38 | for { 39 | if offset >= max { 40 | break 41 | } 42 | l := int(i.Payload[offset]) 43 | if offset+l+1 > max { 44 | return "", io.ErrUnexpectedEOF 45 | } 46 | apn = append(apn, string(i.Payload[offset+1:offset+l+1])) 47 | offset += l + 1 48 | } 49 | 50 | return strings.Join(apn, "."), nil 51 | } 52 | 53 | // MustAccessPointName returns AccessPointName in string if type matches. 54 | // This should only be used if it is assured to have the value. 55 | func (i *IE) MustAccessPointName() string { 56 | v, _ := i.AccessPointName() 57 | return v 58 | } 59 | -------------------------------------------------------------------------------- /gtpv1/ie/cause.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewCause creates a new Cause IE. 10 | func NewCause(cause uint8) *IE { 11 | return newUint8ValIE(Cause, cause) 12 | } 13 | 14 | // Cause returns the Cause value if type matches. 15 | func (i *IE) Cause() (uint8, error) { 16 | if i.Type != Cause { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustCause returns Cause in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustCause() uint8 { 29 | v, _ := i.Cause() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv1/ie/charging-id.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // NewChargingID creates a new ChargingID IE. 13 | func NewChargingID(id uint32) *IE { 14 | return newUint32ValIE(ChargingID, id) 15 | } 16 | 17 | // ChargingID returns the ChargingID value in uint32 if the type of IE matches. 18 | func (i *IE) ChargingID() (uint32, error) { 19 | if i.Type != ChargingID { 20 | return 0, &InvalidTypeError{Type: i.Type} 21 | } 22 | if len(i.Payload) < 4 { 23 | return 0, io.ErrUnexpectedEOF 24 | } 25 | 26 | return binary.BigEndian.Uint32(i.Payload), nil 27 | } 28 | 29 | // MustChargingID returns ChargingID in uint32, ignoring errors. 30 | // This should only be used if it is assured to have the value. 31 | func (i *IE) MustChargingID() uint32 { 32 | v, _ := i.ChargingID() 33 | return v 34 | } 35 | -------------------------------------------------------------------------------- /gtpv1/ie/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | ) 11 | 12 | // Error definitions. 13 | var ( 14 | ErrInvalidLength = errors.New("got invalid length ") 15 | ErrTooShortToMarshal = errors.New("too short to serialize") 16 | ErrTooShortToParse = errors.New("too short to decode as GTPv1 IE") 17 | 18 | ErrMalformed = errors.New("malformed IE") 19 | ) 20 | 21 | // InvalidTypeError indicates the type of IE is invalid. 22 | type InvalidTypeError struct { 23 | Type uint8 24 | } 25 | 26 | // Error returns message with the invalid type given. 27 | func (e *InvalidTypeError) Error() string { 28 | return fmt.Sprintf("got invalid type: %v", e.Type) 29 | } 30 | -------------------------------------------------------------------------------- /gtpv1/ie/extended-common-flags-ii.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewExtendedCommonFlagsII creates a new ExtendedCommonFlagsII IE. 10 | // 11 | // Note: each flag should be set in 1 or 0. 12 | func NewExtendedCommonFlagsII(pmtsmi, dtci, pnsi int) *IE { 13 | return New( 14 | ExtendedCommonFlagsII, 15 | []byte{uint8( 16 | pmtsmi<<2 | dtci<<1 | pnsi, 17 | )}, 18 | ) 19 | } 20 | 21 | // ExtendedCommonFlagsII returns ExtendedCommonFlagsII value if type matches. 22 | func (i *IE) ExtendedCommonFlagsII() (uint8, error) { 23 | if i.Type != ExtendedCommonFlagsII { 24 | return 0, &InvalidTypeError{Type: i.Type} 25 | } 26 | if len(i.Payload) == 0 { 27 | return 0, io.ErrUnexpectedEOF 28 | } 29 | 30 | return i.Payload[0], nil 31 | } 32 | 33 | // MustExtendedCommonFlagsII returns ExtendedCommonFlagsII in uint8 if type matches. 34 | // This should only be used if it is assured to have the value. 35 | func (i *IE) MustExtendedCommonFlagsII() uint8 { 36 | v, _ := i.ExtendedCommonFlagsII() 37 | return v 38 | } 39 | 40 | // IsPMTSMI checks if PMTSMI flag exists in ExtendedCommonFlagsII. 41 | func (i *IE) IsPMTSMI() bool { 42 | return ((i.MustExtendedCommonFlagsII() >> 2) & 0x01) != 0 43 | } 44 | 45 | // IsDTCI checks if DTCI flag exists in ExtendedCommonFlagsII. 46 | func (i *IE) IsDTCI() bool { 47 | return ((i.MustExtendedCommonFlagsII() >> 1) & 0x01) != 0 48 | } 49 | 50 | // IsPNSI checks if PNSI flag exists in ExtendedCommonFlagsII. 51 | func (i *IE) IsPNSI() bool { 52 | return (i.MustExtendedCommonFlagsII() & 0x01) != 0 53 | } 54 | -------------------------------------------------------------------------------- /gtpv1/ie/extension-header-type-list.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewExtensionHeaderTypeList creates a new ExtensionHeaderTypeList IE. 8 | func NewExtensionHeaderTypeList(types ...uint8) *IE { 9 | return New(ExtensionHeaderTypeList, types) 10 | } 11 | 12 | // ExtensionHeaderTypeList returns ExtensionHeaderTypeList in []uint8 if type matches. 13 | func (i *IE) ExtensionHeaderTypeList() ([]uint8, error) { 14 | if i.Type != ExtensionHeaderTypeList { 15 | return nil, &InvalidTypeError{Type: i.Type} 16 | } 17 | 18 | return i.Payload, nil 19 | } 20 | 21 | // MustExtensionHeaderTypeList returns ExtensionHeaderTypeList in []uint8 if type matches. 22 | // This should only be used if it is assured to have the value. 23 | func (i *IE) MustExtensionHeaderTypeList() []uint8 { 24 | v, _ := i.ExtensionHeaderTypeList() 25 | return v 26 | } 27 | -------------------------------------------------------------------------------- /gtpv1/ie/gsn-address.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "net" 10 | ) 11 | 12 | // NewGSNAddress creates a new GSNAddress IE. 13 | func NewGSNAddress(addr string) *IE { 14 | return NewGSNAddressByIP(net.ParseIP(addr)) 15 | } 16 | 17 | // NewGSNAddressByIP creates a new GSNAddress IE from net.IP. 18 | func NewGSNAddressByIP(ip net.IP) *IE { 19 | if ip == nil { 20 | return nil 21 | } 22 | 23 | v4 := ip.To4() 24 | 25 | // IPv4 26 | if v4 != nil { 27 | return New(GSNAddress, v4) 28 | } 29 | // IPv6 30 | return New(GSNAddress, ip) 31 | } 32 | 33 | // GSNAddress returns GSNAddress value if type matches. 34 | func (i *IE) GSNAddress() (string, error) { 35 | if i.Type != GSNAddress { 36 | return "", &InvalidTypeError{Type: i.Type} 37 | } 38 | if len(i.Payload) < 4 { 39 | return "", io.ErrUnexpectedEOF 40 | } 41 | 42 | return net.IP(i.Payload).String(), nil 43 | } 44 | 45 | // MustGSNAddress returns GSNAddress in string if type matches. 46 | // This should only be used if it is assured to have the value. 47 | func (i *IE) MustGSNAddress() string { 48 | v, _ := i.GSNAddress() 49 | return v 50 | } 51 | -------------------------------------------------------------------------------- /gtpv1/ie/ie_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "log" 8 | 9 | // Serialize serializes IE into bytes. 10 | // 11 | // Deprecated: use IE.Marshal instead. 12 | func (i *IE) Serialize() ([]byte, error) { 13 | log.Println("IE.Serialize is deprecated. use IE.Marshal instead") 14 | return i.Marshal() 15 | } 16 | 17 | // SerializeTo serializes IE into bytes given as b. 18 | // 19 | // Deprecated: use IE.MarshalTo instead. 20 | func (i *IE) SerializeTo(b []byte) error { 21 | log.Println("IE.SerializeTo is deprecated. use IE.MarshalTo instead") 22 | return i.MarshalTo(b) 23 | } 24 | 25 | // Decode decodes bytes as IE. 26 | // 27 | // Deprecated: use Parse instead. 28 | func Decode(b []byte) (*IE, error) { 29 | log.Println("Decode is deprecated. use Parse instead") 30 | return Parse(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as IE. 34 | // 35 | // Deprecated: use IE.UnmarshalBinary instead. 36 | func (i *IE) DecodeFromBytes(b []byte) error { 37 | log.Println("IE.DecodeFromBytes is deprecated. use IE.UnmarshalBinary instead") 38 | return i.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of IE. 42 | // 43 | // Deprecated: use IE.MarshalLen instead. 44 | func (i *IE) Len() int { 45 | log.Println("IE.Len is deprecated. use IE.MarshalLen instead") 46 | return i.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv1/ie/ie_fuzz_test.go: -------------------------------------------------------------------------------- 1 | package ie_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/wmnsk/go-gtp/gtpv1/ie" 7 | ) 8 | 9 | func FuzzParse(f *testing.F) { 10 | f.Fuzz(func(t *testing.T, b []byte) { 11 | if _, err := ie.Parse(b); err != nil { 12 | t.Skip() 13 | } 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /gtpv1/ie/imei.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | 11 | "github.com/wmnsk/go-gtp/utils" 12 | ) 13 | 14 | // NewIMEISV creates a new IMEISV IE. 15 | func NewIMEISV(imei string) *IE { 16 | i, err := utils.StrToSwappedBytes(imei, "f") 17 | if err != nil { 18 | return nil 19 | } 20 | return New(IMEISV, i) 21 | } 22 | 23 | // IMEISV returns IMEISV value if type matches. 24 | func (i *IE) IMEISV() (string, error) { 25 | if i.Type != IMEISV { 26 | return "", &InvalidTypeError{Type: i.Type} 27 | } 28 | if len(i.Payload) == 0 { 29 | return "", io.ErrUnexpectedEOF 30 | } 31 | str := utils.SwappedBytesToStr(i.Payload, false) 32 | return strings.TrimSuffix(str, "f"), nil 33 | } 34 | 35 | // MustIMEISV returns IMEISV in string if type matches. 36 | // This should only be used if it is assured to have the value. 37 | func (i *IE) MustIMEISV() string { 38 | v, _ := i.IMEISV() 39 | return v 40 | } 41 | -------------------------------------------------------------------------------- /gtpv1/ie/imei_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "testing" 8 | 9 | func TestIE_IMEISV(t *testing.T) { 10 | t.Run("Encode/Decode IMEI", func(t *testing.T) { 11 | ie := NewIMEISV("123456789012345") 12 | 13 | got := ie.MustIMEISV() 14 | if got != "123456789012345" { 15 | t.Errorf("wrong IMEI, got: %v", got) 16 | } 17 | }) 18 | 19 | t.Run("Encode/Decode IMEISV", func(t *testing.T) { 20 | ie := NewIMEISV("1234567890123456") 21 | 22 | got := ie.MustIMEISV() 23 | if got != "1234567890123456" { 24 | t.Errorf("wrong IMEISV, got: %v", got) 25 | } 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /gtpv1/ie/imsi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewIMSI creates a new IMSI IE. 14 | func NewIMSI(imsi string) *IE { 15 | i, err := utils.StrToSwappedBytes(imsi, "f") 16 | if err != nil { 17 | return nil 18 | } 19 | return New(IMSI, i) 20 | } 21 | 22 | // IMSI returns IMSI value if type matches. 23 | func (i *IE) IMSI() (string, error) { 24 | if i.Type != IMSI { 25 | return "", &InvalidTypeError{Type: i.Type} 26 | } 27 | if len(i.Payload) == 0 { 28 | return "", io.ErrUnexpectedEOF 29 | } 30 | 31 | return utils.SwappedBytesToStr(i.Payload, true), nil 32 | } 33 | 34 | // MustIMSI returns IMSI in string if type matches. 35 | // This should only be used if it is assured to have the value. 36 | func (i *IE) MustIMSI() string { 37 | v, _ := i.IMSI() 38 | return v 39 | } 40 | -------------------------------------------------------------------------------- /gtpv1/ie/ip.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "net" 10 | ) 11 | 12 | // IP returns IP in net.IP if type matches. 13 | func (i *IE) IP() (net.IP, error) { 14 | if len(i.Payload) < 4 { 15 | return nil, io.ErrUnexpectedEOF 16 | } 17 | 18 | switch i.Type { 19 | case EndUserAddress: 20 | if i.MustPDPTypeOrganization() != pdpTypeIETF { 21 | return nil, ErrMalformed 22 | } 23 | return net.IP(i.Payload[2:]), nil 24 | case GSNAddress: 25 | return net.IP(i.Payload), nil 26 | default: 27 | return nil, &InvalidTypeError{i.Type} 28 | } 29 | } 30 | 31 | func (i *IE) MustIP() net.IP { 32 | v, _ := i.IP() 33 | return v 34 | } 35 | 36 | // IPAddress returns IPAddress in string if type matches. 37 | func (i *IE) IPAddress() (string, error) { 38 | ip, err := i.IP() 39 | if err != nil { 40 | return "", err 41 | } 42 | 43 | return ip.String(), nil 44 | } 45 | 46 | // MustIPAddress returns IPAddress in string if type matches. 47 | // This should only be used if it is assured to have the value. 48 | func (i *IE) MustIPAddress() string { 49 | v, _ := i.IPAddress() 50 | return v 51 | } 52 | -------------------------------------------------------------------------------- /gtpv1/ie/lac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // LAC returns LAC value if type matches. 13 | func (i *IE) LAC() (uint16, error) { 14 | switch i.Type { 15 | case RouteingAreaIdentity: 16 | if len(i.Payload) < 5 { 17 | return 0, io.ErrUnexpectedEOF 18 | } 19 | return binary.BigEndian.Uint16(i.Payload[3:5]), nil 20 | case UserLocationInformation: 21 | if len(i.Payload) < 6 { 22 | return 0, io.ErrUnexpectedEOF 23 | } 24 | return binary.BigEndian.Uint16(i.Payload[4:6]), nil 25 | default: 26 | return 0, &InvalidTypeError{Type: i.Type} 27 | } 28 | } 29 | 30 | // MustLAC returns LAC in uint16 if type matches. 31 | // This should only be used if it is assured to have the value. 32 | func (i *IE) MustLAC() uint16 { 33 | v, _ := i.LAC() 34 | return v 35 | } 36 | -------------------------------------------------------------------------------- /gtpv1/ie/map-cause.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewMAPCause creates a new MAPCause IE. 10 | func NewMAPCause(cause uint8) *IE { 11 | return newUint8ValIE(MAPCause, cause) 12 | } 13 | 14 | // MAPCause returns MAPCause in uint8 if type matches. 15 | func (i *IE) MAPCause() (uint8, error) { 16 | if i.Type != MAPCause { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustMAPCause returns MAPCause in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustMAPCause() uint8 { 29 | v, _ := i.MAPCause() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv1/ie/mcc-mnc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // MCC returns MCC value if type matches. 14 | func (i *IE) MCC() (string, error) { 15 | switch i.Type { 16 | case RouteingAreaIdentity: 17 | if len(i.Payload) < 2 { 18 | return "", io.ErrUnexpectedEOF 19 | } 20 | return utils.DecodeMCC(i.Payload[0:2]), nil 21 | case UserLocationInformation: 22 | if len(i.Payload) < 3 { 23 | return "", io.ErrUnexpectedEOF 24 | } 25 | return utils.DecodeMCC(i.Payload[1:3]), nil 26 | default: 27 | return "", &InvalidTypeError{Type: i.Type} 28 | } 29 | } 30 | 31 | // MustMCC returns MCC in string if type matches. 32 | // This should only be used if it is assured to have the value. 33 | func (i *IE) MustMCC() string { 34 | v, _ := i.MCC() 35 | return v 36 | } 37 | 38 | // MNC returns MNC value if type matches. 39 | func (i *IE) MNC() (string, error) { 40 | switch i.Type { 41 | case RouteingAreaIdentity: 42 | if len(i.Payload) < 3 { 43 | return "", io.ErrUnexpectedEOF 44 | } 45 | return utils.DecodeMNC(i.Payload[1:3]), nil 46 | case UserLocationInformation: 47 | if len(i.Payload) < 4 { 48 | return "", io.ErrUnexpectedEOF 49 | } 50 | return utils.DecodeMNC(i.Payload[2:4]), nil 51 | default: 52 | return "", &InvalidTypeError{Type: i.Type} 53 | } 54 | } 55 | 56 | // MustMNC returns MNC in string if type matches. 57 | // This should only be used if it is assured to have the value. 58 | func (i *IE) MustMNC() string { 59 | v, _ := i.MNC() 60 | return v 61 | } 62 | -------------------------------------------------------------------------------- /gtpv1/ie/ms-validated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewMSValidated creates a new MSValidated IE. 8 | func NewMSValidated(validated bool) *IE { 9 | if validated { 10 | return newUint8ValIE(MSValidated, 0xff) 11 | } 12 | return newUint8ValIE(MSValidated, 0xfe) 13 | } 14 | 15 | // MSValidated returns MSValidated in bool if type matches. 16 | func (i *IE) MSValidated() bool { 17 | if i.Type != MSValidated { 18 | return false 19 | } 20 | if len(i.Payload) == 0 { 21 | return false 22 | } 23 | 24 | return i.Payload[0]%2 == 1 25 | } 26 | -------------------------------------------------------------------------------- /gtpv1/ie/msisdn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewMSISDN creates a new MSISDN IE. 14 | func NewMSISDN(msisdn string) *IE { 15 | i, err := utils.StrToSwappedBytes("19"+msisdn, "f") 16 | if err != nil { 17 | return nil 18 | } 19 | return New(MSISDN, i) 20 | } 21 | 22 | // MSISDN returns MSISDN value if type matches. 23 | func (i *IE) MSISDN() (string, error) { 24 | if i.Type != MSISDN { 25 | return "", &InvalidTypeError{Type: i.Type} 26 | } 27 | if len(i.Payload) < 2 { 28 | return "", io.ErrUnexpectedEOF 29 | } 30 | 31 | return utils.SwappedBytesToStr(i.Payload[1:], false), nil 32 | } 33 | 34 | // MustMSISDN returns MSISDN in string if type matches. 35 | // This should only be used if it is assured to have the value. 36 | func (i *IE) MustMSISDN() string { 37 | v, _ := i.MSISDN() 38 | return v 39 | } 40 | -------------------------------------------------------------------------------- /gtpv1/ie/nsapi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewNSAPI creates a new NSAPI IE. 10 | func NewNSAPI(nsapi uint8) *IE { 11 | return newUint8ValIE(NSAPI, nsapi) 12 | } 13 | 14 | // NSAPI returns NSAPI value if type matches. 15 | func (i *IE) NSAPI() (uint8, error) { 16 | if i.Type != NSAPI { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustNSAPI returns NSAPI in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustNSAPI() uint8 { 29 | v, _ := i.NSAPI() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv1/ie/p-tmsi-signature.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewPTMSISignature creates a new PTMSISignature IE. 14 | func NewPTMSISignature(sig uint32) *IE { 15 | return New(PTMSISignature, utils.Uint32To24(sig)) 16 | } 17 | 18 | // PTMSISignature returns PTMSISignature value in uint32 if type matches. 19 | func (i *IE) PTMSISignature() (uint32, error) { 20 | if i.Type != PTMSISignature { 21 | return 0, &InvalidTypeError{Type: i.Type} 22 | } 23 | if len(i.Payload) < 3 { 24 | return 0, io.ErrUnexpectedEOF 25 | } 26 | 27 | return utils.Uint24To32(i.Payload), nil 28 | } 29 | 30 | // MustPTMSISignature returns PTMSISignature in uint32 if type matches. 31 | // This should only be used if it is assured to have the value. 32 | func (i *IE) MustPTMSISignature() uint32 { 33 | v, _ := i.PTMSISignature() 34 | return v 35 | } 36 | -------------------------------------------------------------------------------- /gtpv1/ie/p-tmsi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // NewPacketTMSI creates a new PacketTMSI IE. 13 | func NewPacketTMSI(ptmsi uint32) *IE { 14 | return newUint32ValIE(PacketTMSI, ptmsi) 15 | } 16 | 17 | // PacketTMSI returns PacketTMSI value in uint32 if type matches. 18 | func (i *IE) PacketTMSI() (uint32, error) { 19 | if i.Type != PacketTMSI { 20 | return 0, &InvalidTypeError{Type: i.Type} 21 | } 22 | if len(i.Payload) < 4 { 23 | return 0, io.ErrUnexpectedEOF 24 | } 25 | 26 | return binary.BigEndian.Uint32(i.Payload), nil 27 | } 28 | 29 | // MustPacketTMSI returns PacketTMSI in uint32 if type matches. 30 | // This should only be used if it is assured to have the value. 31 | func (i *IE) MustPacketTMSI() uint32 { 32 | v, _ := i.PacketTMSI() 33 | return v 34 | } 35 | -------------------------------------------------------------------------------- /gtpv1/ie/qos-profile.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewQoSProfile creates a new QoSProfile IE. 8 | // 9 | // XXX - NOT Fully implemented. Users need to put the whole payload in []byte. 10 | func NewQoSProfile(payload []byte) *IE { 11 | return New(QoSProfile, payload) 12 | } 13 | 14 | // QoSProfile returns QoSProfile if type matches. 15 | // 16 | // XXX - NOT Fully implemented. This method just returns the whole payload in []byte. 17 | func (i *IE) QoSProfile() ([]byte, error) { 18 | if i.Type != QoSProfile { 19 | return nil, &InvalidTypeError{Type: i.Type} 20 | } 21 | return i.Payload, nil 22 | } 23 | 24 | // MustQoSProfile returns QoSProfile in []byte if type matches. 25 | // This should only be used if it is assured to have the value. 26 | func (i *IE) MustQoSProfile() []byte { 27 | v, _ := i.QoSProfile() 28 | return v 29 | } 30 | -------------------------------------------------------------------------------- /gtpv1/ie/rac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // RAC returns RAC value if type matches. 10 | func (i *IE) RAC() (uint8, error) { 11 | switch i.Type { 12 | case RouteingAreaIdentity: 13 | if len(i.Payload) < 6 { 14 | return 0, io.ErrUnexpectedEOF 15 | } 16 | return i.Payload[5], nil 17 | case UserLocationInformation: 18 | if len(i.Payload) < 7 { 19 | return 0, io.ErrUnexpectedEOF 20 | } 21 | if i.Payload[0] == locTypeRAI { 22 | return i.Payload[6], nil 23 | } 24 | } 25 | return 0, &InvalidTypeError{Type: i.Type} 26 | } 27 | 28 | // MustRAC returns RAC in uint8 if type matches. 29 | // This should only be used if it is assured to have the value. 30 | func (i *IE) MustRAC() uint8 { 31 | v, _ := i.RAC() 32 | return v 33 | } 34 | -------------------------------------------------------------------------------- /gtpv1/ie/rai.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewRouteingAreaIdentity creates a new RouteingAreaIdentity IE. 14 | func NewRouteingAreaIdentity(mcc, mnc string, lac uint16, rac uint8) *IE { 15 | mc, err := utils.StrToSwappedBytes(mcc, "f") 16 | if err != nil { 17 | return nil 18 | } 19 | mn, err := utils.StrToSwappedBytes(mnc, "f") 20 | if err != nil { 21 | return nil 22 | } 23 | 24 | rai := New( 25 | RouteingAreaIdentity, 26 | make([]byte, 6), 27 | ) 28 | copy(rai.Payload[0:2], mc) 29 | rai.Payload[2] = mn[0] 30 | binary.BigEndian.PutUint16(rai.Payload[3:5], lac) 31 | rai.Payload[5] = rac 32 | 33 | return rai 34 | } 35 | 36 | // RouteingAreaIdentity returns RouteingAreaIdentity value if type matches. 37 | func (i *IE) RouteingAreaIdentity() ([]byte, error) { 38 | if i.Type != RouteingAreaIdentity { 39 | return nil, &InvalidTypeError{Type: i.Type} 40 | } 41 | return i.Payload, nil 42 | } 43 | 44 | // MustRouteingAreaIdentity returns RouteingAreaIdentity in []byte if type matches. 45 | // This should only be used if it is assured to have the value. 46 | func (i *IE) MustRouteingAreaIdentity() []byte { 47 | v, _ := i.RouteingAreaIdentity() 48 | return v 49 | } 50 | -------------------------------------------------------------------------------- /gtpv1/ie/rai_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "testing" 9 | ) 10 | 11 | func TestRouteingAreaIdentity(t *testing.T) { 12 | t.Run("Routeing Area Identity", func(t *testing.T) { 13 | ie := NewRouteingAreaIdentity("123", "45", 111, 222) 14 | 15 | rac := ie.MustRAC() 16 | if rac != 222 { 17 | t.Errorf("wrong rac, got %v", rac) 18 | } 19 | 20 | lac := ie.MustLAC() 21 | if lac != 111 { 22 | t.Errorf("wrong lac, got %v", lac) 23 | } 24 | 25 | mcc := ie.MustMCC() 26 | if mcc != "123" { 27 | t.Errorf("wrong mcc, got %v", mcc) 28 | } 29 | 30 | mnc := ie.MustMNC() 31 | if mnc != "45" { 32 | t.Errorf("wrong mnc, got %v", mnc) 33 | } 34 | 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /gtpv1/ie/ranap-cause.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewRANAPCause creates a new RANAPCause IE. 10 | func NewRANAPCause(cause uint8) *IE { 11 | return newUint8ValIE(RANAPCause, cause) 12 | } 13 | 14 | // RANAPCause returns RANAPCause in uint8 if type matches. 15 | func (i *IE) RANAPCause() (uint8, error) { 16 | if i.Type != RANAPCause { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustRANAPCause returns RANAPCause in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustRANAPCause() uint8 { 29 | v, _ := i.RANAPCause() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv1/ie/rat-type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewRATType creates a new RATType IE. 10 | func NewRATType(ratType uint8) *IE { 11 | return New( 12 | RATType, 13 | []byte{ratType}, 14 | ) 15 | } 16 | 17 | // RATType returns RATType value if type matches. 18 | func (i *IE) RATType() (uint8, error) { 19 | if i.Type != RATType { 20 | return 0, &InvalidTypeError{Type: i.Type} 21 | } 22 | if len(i.Payload) == 0 { 23 | return 0, io.ErrUnexpectedEOF 24 | } 25 | 26 | return i.Payload[0], nil 27 | } 28 | 29 | // MustRATType returns RATType in uint8 if type matches. 30 | // This should only be used if it is assured to have the value. 31 | func (i *IE) MustRATType() uint8 { 32 | v, _ := i.RATType() 33 | return v 34 | } 35 | -------------------------------------------------------------------------------- /gtpv1/ie/recovery.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewRecovery creates a new Recovery IE. 10 | func NewRecovery(recovery uint8) *IE { 11 | return newUint8ValIE(Recovery, recovery) 12 | } 13 | 14 | // Recovery returns Recovery value if type matches. 15 | func (i *IE) Recovery() (uint8, error) { 16 | if i.Type != Recovery { 17 | return 0, &InvalidTypeError{Type: i.Type} 18 | } 19 | if len(i.Payload) == 0 { 20 | return 0, io.ErrUnexpectedEOF 21 | } 22 | 23 | return i.Payload[0], nil 24 | } 25 | 26 | // MustRecovery returns Recovery in uint8 if type matches. 27 | // This should only be used if it is assured to have the value. 28 | func (i *IE) MustRecovery() uint8 { 29 | v, _ := i.Recovery() 30 | return v 31 | } 32 | -------------------------------------------------------------------------------- /gtpv1/ie/reordering-required.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewReorderingRequired creates a new ReorderingRequired IE. 8 | func NewReorderingRequired(required bool) *IE { 9 | if required { 10 | return newUint8ValIE(ReorderingRequired, 0xff) 11 | } 12 | return newUint8ValIE(ReorderingRequired, 0xfe) 13 | } 14 | 15 | // ReorderingRequired returns ReorderingRequired or not if type matches. 16 | func (i *IE) ReorderingRequired() bool { 17 | if i.Type != ReorderingRequired { 18 | return false 19 | } 20 | if len(i.Payload) == 0 { 21 | return false 22 | } 23 | 24 | return i.Payload[0]&0x01 == 1 25 | } 26 | -------------------------------------------------------------------------------- /gtpv1/ie/selection-mode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewSelectionMode creates a new SelectionMode IE. 10 | // Note that exactly one of the parameters should be set to true. 11 | // Otherwise, you'll get the unexpected result. 12 | func NewSelectionMode(mode uint8) *IE { 13 | return newUint8ValIE(SelectionMode, mode) 14 | } 15 | 16 | // SelectionMode returns SelectionMode value if type matches. 17 | func (i *IE) SelectionMode() (uint8, error) { 18 | if i.Type != SelectionMode { 19 | return 0, &InvalidTypeError{Type: i.Type} 20 | } 21 | if len(i.Payload) == 0 { 22 | return 0, io.ErrUnexpectedEOF 23 | } 24 | 25 | return i.Payload[0], nil 26 | } 27 | 28 | // MustSelectionMode returns SelectionMode in uint8 if type matches. 29 | // This should only be used if it is assured to have the value. 30 | func (i *IE) MustSelectionMode() uint8 { 31 | v, _ := i.SelectionMode() 32 | return v 33 | } 34 | -------------------------------------------------------------------------------- /gtpv1/ie/teardown-ind.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewTeardownInd creates a new TeardownInd IE. 8 | func NewTeardownInd(teardown bool) *IE { 9 | if teardown { 10 | return newUint8ValIE(TeardownInd, 0xff) 11 | } 12 | return newUint8ValIE(TeardownInd, 0xfe) 13 | } 14 | 15 | // TeardownInd returns TeardownInd in bool if type matches. 16 | func (i *IE) TeardownInd() bool { 17 | if i.Type != TeardownInd { 18 | return false 19 | } 20 | if len(i.Payload) == 0 { 21 | return false 22 | } 23 | 24 | return i.Payload[0]%2 == 1 25 | } 26 | -------------------------------------------------------------------------------- /gtpv1/ie/teid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // NewTEIDDataI creates a new TEIDDataI IE. 13 | func NewTEIDDataI(teid uint32) *IE { 14 | return newUint32ValIE(TEIDDataI, teid) 15 | } 16 | 17 | // NewTEIDCPlane creates a new TEID C-Plane IE. 18 | func NewTEIDCPlane(teid uint32) *IE { 19 | return newUint32ValIE(TEIDCPlane, teid) 20 | } 21 | 22 | // NewTEIDDataII creates a new TEIDDataII IE. 23 | func NewTEIDDataII(teid uint32) *IE { 24 | return newUint32ValIE(TEIDDataII, teid) 25 | } 26 | 27 | // TEID returns TEID value if type matches. 28 | func (i *IE) TEID() (uint32, error) { 29 | if len(i.Payload) < 4 { 30 | return 0, io.ErrUnexpectedEOF 31 | } 32 | switch i.Type { 33 | case TEIDCPlane, TEIDDataI, TEIDDataII: 34 | return binary.BigEndian.Uint32(i.Payload), nil 35 | default: 36 | return 0, &InvalidTypeError{Type: i.Type} 37 | } 38 | } 39 | 40 | // MustTEID returns TEID in uint32 if type matches. 41 | // This should only be used if it is assured to have the value. 42 | func (i *IE) MustTEID() uint32 { 43 | v, _ := i.TEID() 44 | return v 45 | } 46 | -------------------------------------------------------------------------------- /gtpv1/ie/uli-timestamp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | "time" 11 | ) 12 | 13 | // NewULITimestamp creates a new ULITimestamp IE. 14 | func NewULITimestamp(ts time.Time) *IE { 15 | u64sec := uint64(ts.Sub(time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC))) / 1000000000 16 | return newUint32ValIE(ULITimestamp, uint32(u64sec)) 17 | } 18 | 19 | // Timestamp returns Timestamp in time.Time if the type of IE matches. 20 | func (i *IE) Timestamp() (time.Time, error) { 21 | if len(i.Payload) < 4 { 22 | return time.Time{}, io.ErrUnexpectedEOF 23 | } 24 | 25 | switch i.Type { 26 | case ULITimestamp: 27 | return time.Unix(int64(binary.BigEndian.Uint32(i.Payload)-2208988800), 0), nil 28 | default: 29 | return time.Time{}, &InvalidTypeError{Type: i.Type} 30 | } 31 | } 32 | 33 | // MustTimestamp returns Timestamp in time.Time if type matches. 34 | // This should only be used if it is assured to have the value. 35 | func (i *IE) MustTimestamp() time.Time { 36 | v, _ := i.Timestamp() 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /gtpv1/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtpv1 6 | 7 | import ( 8 | "io" 9 | "log" 10 | "os" 11 | "sync" 12 | ) 13 | 14 | var ( 15 | logger = log.New(os.Stderr, "", log.LstdFlags) 16 | logMu sync.Mutex 17 | ) 18 | 19 | // SetLogger replaces the standard logger with arbitrary *log.Logger. 20 | // 21 | // This package prints just informational logs from goroutines working background 22 | // that might help developers test the program but can be ignored safely. More 23 | // important ones that needs any action by caller would be returned as errors. 24 | func SetLogger(l *log.Logger) { 25 | if l == nil { 26 | log.Println("Don't pass nil to SetLogger: use DisableLogging instead.") 27 | } 28 | 29 | setLogger(l) 30 | } 31 | 32 | // EnableLogging enables the logging from the package. 33 | // If l is nil, it uses default logger provided by the package. 34 | // Logging is enabled by default. 35 | // 36 | // See also: SetLogger. 37 | func EnableLogging(l *log.Logger) { 38 | logMu.Lock() 39 | defer logMu.Unlock() 40 | 41 | setLogger(l) 42 | } 43 | 44 | // DisableLogging disables the logging from the package. 45 | // Logging is enabled by default. 46 | func DisableLogging() { 47 | logMu.Lock() 48 | defer logMu.Unlock() 49 | 50 | logger.SetOutput(io.Discard) 51 | } 52 | 53 | func setLogger(l *log.Logger) { 54 | if l == nil { 55 | l = log.New(os.Stderr, "", log.LstdFlags) 56 | } 57 | 58 | logMu.Lock() 59 | defer logMu.Unlock() 60 | 61 | logger = l 62 | } 63 | 64 | func logf(format string, v ...interface{}) { 65 | logMu.Lock() 66 | defer logMu.Unlock() 67 | 68 | logger.Printf(format, v...) 69 | } 70 | -------------------------------------------------------------------------------- /gtpv1/message/delete-pdp-context-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1" 11 | "github.com/wmnsk/go-gtp/gtpv1/ie" 12 | "github.com/wmnsk/go-gtp/gtpv1/message" 13 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 14 | ) 15 | 16 | func TestDeletePDPContextRequest(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewDeletePDPContextRequest( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv1.ReqCauseNetworkFailure), 23 | ie.NewNSAPI(5), 24 | ), 25 | Serialized: []byte{ 26 | // Header 27 | 0x32, 0x14, 0x00, 0x08, 0x11, 0x22, 0x33, 0x44, 28 | 0x00, 0x01, 0x00, 0x00, 29 | // Cause 30 | 0x01, 0x08, 31 | // NSAPI 32 | 0x14, 0x05, 33 | }, 34 | }, 35 | } 36 | 37 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 38 | v, err := message.ParseDeletePDPContextRequest(b) 39 | if err != nil { 40 | return nil, err 41 | } 42 | v.Payload = nil 43 | return v, nil 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /gtpv1/message/delete-pdp-context-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1" 11 | "github.com/wmnsk/go-gtp/gtpv1/ie" 12 | "github.com/wmnsk/go-gtp/gtpv1/message" 13 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 14 | ) 15 | 16 | func TestDeletePDPContextResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewDeletePDPContextResponse( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv1.ResCauseRequestAccepted), 23 | ), 24 | Serialized: []byte{ 25 | // Header 26 | 0x32, 0x15, 0x00, 0x06, 0x11, 0x22, 0x33, 0x44, 27 | 0x00, 0x01, 0x00, 0x00, 28 | // Cause 29 | 0x01, 0x80, 30 | }, 31 | }, 32 | } 33 | 34 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 35 | v, err := message.ParseDeletePDPContextResponse(b) 36 | if err != nil { 37 | return nil, err 38 | } 39 | v.Payload = nil 40 | return v, nil 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /gtpv1/message/echo-req_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes EchoRequest into bytes. 10 | // 11 | // Deprecated: use EchoRequest.Marshal instead. 12 | func (e *EchoRequest) Serialize() ([]byte, error) { 13 | log.Println("EchoRequest.Serialize is deprecated. use EchoRequest.Marshal instead") 14 | return e.Marshal() 15 | } 16 | 17 | // SerializeTo serializes EchoRequest into bytes given as b. 18 | // 19 | // Deprecated: use EchoRequest.MarshalTo instead. 20 | func (e *EchoRequest) SerializeTo(b []byte) error { 21 | log.Println("EchoRequest.SerializeTo is deprecated. use EchoRequest.MarshalTo instead") 22 | return e.MarshalTo(b) 23 | } 24 | 25 | // DecodeEchoRequest decodes bytes as EchoRequest. 26 | // 27 | // Deprecated: use ParseEchoRequest instead. 28 | func DecodeEchoRequest(b []byte) (*EchoRequest, error) { 29 | log.Println("DecodeEchoRequest is deprecated. use ParseEchoRequest instead") 30 | return ParseEchoRequest(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as EchoRequest. 34 | // 35 | // Deprecated: use EchoRequest.UnmarshalBinary instead. 36 | func (e *EchoRequest) DecodeFromBytes(b []byte) error { 37 | log.Println("EchoRequest.DecodeFromBytes is deprecated. use EchoRequest.UnmarshalBinary instead") 38 | return e.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of EchoRequest. 42 | // 43 | // Deprecated: use EchoRequest.MarshalLen instead. 44 | func (e *EchoRequest) Len() int { 45 | log.Println("EchoRequest.Len is deprecated. use EchoRequest.MarshalLen instead") 46 | return e.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv1/message/echo-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/message" 11 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 12 | ) 13 | 14 | func TestEchoRequest(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "Normal", 18 | Structured: message.NewEchoRequest(0), 19 | Serialized: []byte{ 20 | 0x32, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 21 | 0x00, 0x00, 0x00, 0x00, 22 | }, 23 | }, 24 | } 25 | 26 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 27 | v, err := message.ParseEchoRequest(b) 28 | if err != nil { 29 | return nil, err 30 | } 31 | v.Payload = nil 32 | return v, nil 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /gtpv1/message/echo-res_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes EchoResponse into bytes. 10 | // 11 | // Deprecated: use EchoResponse.Marshal instead. 12 | func (e *EchoResponse) Serialize() ([]byte, error) { 13 | log.Println("EchoResponse.Serialize is deprecated. use EchoResponse.Marshal instead") 14 | return e.Marshal() 15 | } 16 | 17 | // SerializeTo serializes EchoResponse into bytes given as b. 18 | // 19 | // Deprecated: use EchoResponse.MarshalTo instead. 20 | func (e *EchoResponse) SerializeTo(b []byte) error { 21 | log.Println("EchoResponse.SerializeTo is deprecated. use EchoResponse.MarshalTo instead") 22 | return e.MarshalTo(b) 23 | } 24 | 25 | // DecodeEchoResponse decodes bytes as EchoResponse. 26 | // 27 | // Deprecated: use ParseEchoResponse instead. 28 | func DecodeEchoResponse(b []byte) (*EchoResponse, error) { 29 | log.Println("DecodeEchoResponse is deprecated. use ParseEchoResponse instead") 30 | return ParseEchoResponse(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as EchoResponse. 34 | // 35 | // Deprecated: use EchoResponse.UnmarshalBinary instead. 36 | func (e *EchoResponse) DecodeFromBytes(b []byte) error { 37 | log.Println("EchoResponse.DecodeFromBytes is deprecated. use EchoResponse.UnmarshalBinary instead") 38 | return e.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of EchoResponse. 42 | // 43 | // Deprecated: use EchoResponse.MarshalLen instead. 44 | func (e *EchoResponse) Len() int { 45 | log.Println("EchoResponse.Len is deprecated. use EchoResponse.MarshalLen instead") 46 | return e.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv1/message/echo-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/ie" 11 | "github.com/wmnsk/go-gtp/gtpv1/message" 12 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 13 | ) 14 | 15 | func TestEchoResponse(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewEchoResponse(0, ie.NewRecovery(0x80)), 20 | Serialized: []byte{ 21 | 0x32, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 22 | 0x00, 0x00, 0x00, 0x00, 0x0e, 0x80, 23 | }, 24 | }, 25 | } 26 | 27 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 28 | v, err := message.ParseEchoResponse(b) 29 | if err != nil { 30 | return nil, err 31 | } 32 | v.Payload = nil 33 | return v, nil 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /gtpv1/message/end-marker_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/message" 11 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 12 | ) 13 | 14 | func TestEndMarker(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "Normal", 18 | Structured: message.NewEndMarker(), 19 | Serialized: []byte{ 20 | 0x30, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 21 | }, 22 | }, 23 | } 24 | 25 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 26 | v, err := message.ParseEndMarker(b) 27 | if err != nil { 28 | return nil, err 29 | } 30 | v.Payload = nil 31 | return v, nil 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /gtpv1/message/error-indication_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/ie" 11 | "github.com/wmnsk/go-gtp/gtpv1/message" 12 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 13 | ) 14 | 15 | func TestErrorIndication(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewErrorIndication( 20 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 21 | ie.NewTEIDDataI(0xdeadbeef), 22 | ie.NewGSNAddress("1.1.1.1"), 23 | ), 24 | Serialized: []byte{ 25 | // Header 26 | 0x32, 0x1a, 0x00, 0x10, 0x11, 0x22, 0x33, 0x44, 27 | 0x00, 0x01, 0x00, 0x00, 28 | // TEID-U 29 | 0x10, 0xde, 0xad, 0xbe, 0xef, 30 | // GSN Address 31 | 0x85, 0x00, 0x04, 0x01, 0x01, 0x01, 0x01, 32 | }, 33 | }, 34 | } 35 | 36 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 37 | v, err := message.ParseErrorIndication(b) 38 | if err != nil { 39 | return nil, err 40 | } 41 | v.Payload = nil 42 | return v, nil 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /gtpv1/message/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | ) 11 | 12 | // Error definitions. 13 | var ( 14 | ErrInvalidLength = errors.New("got invalid length ") 15 | ErrTooShortToMarshal = errors.New("too short to serialize") 16 | ErrTooShortToParse = errors.New("too short to decode as GTPv1") 17 | ErrInvalidMessageType = errors.New("got invalid message type") 18 | ) 19 | 20 | // InvalidTypeError indicates the type of an ExtensionHeader is invalid. 21 | type InvalidTypeError struct { 22 | Type uint8 23 | } 24 | 25 | // Error returns message with the invalid type given. 26 | func (e *InvalidTypeError) Error() string { 27 | return fmt.Sprintf("got invalid type: %v", e.Type) 28 | } 29 | -------------------------------------------------------------------------------- /gtpv1/message/generic_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Generic into bytes. 10 | // 11 | // Deprecated: use Generic.Marshal instead. 12 | func (g *Generic) Serialize() ([]byte, error) { 13 | log.Println("Generic.Serialize is deprecated. use Generic.Marshal instead") 14 | return g.Marshal() 15 | } 16 | 17 | // SerializeTo serializes Generic into bytes given as b. 18 | // 19 | // Deprecated: use Generic.MarshalTo instead. 20 | func (g *Generic) SerializeTo(b []byte) error { 21 | log.Println("Generic.SerializeTo is deprecated. use Generic.MarshalTo instead") 22 | return g.MarshalTo(b) 23 | } 24 | 25 | // DecodeGeneric decodes bytes as Generic. 26 | // 27 | // Deprecated: use ParseGeneric instead. 28 | func DecodeGeneric(b []byte) (*Generic, error) { 29 | log.Println("DecodeGeneric is deprecated. use ParseGeneric instead") 30 | return ParseGeneric(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as Generic. 34 | // 35 | // Deprecated: use Generic.UnmarshalBinary instead. 36 | func (g *Generic) DecodeFromBytes(b []byte) error { 37 | log.Println("Generic.DecodeFromBytes is deprecated. use Generic.UnmarshalBinary instead") 38 | return g.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of Generic. 42 | // 43 | // Deprecated: use Generic.MarshalLen instead. 44 | func (g *Generic) Len() int { 45 | log.Println("Generic.Len is deprecated. use Generic.MarshalLen instead") 46 | return g.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv1/message/generic_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/message" 11 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 12 | ) 13 | 14 | func TestGeneric(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "Normal", 18 | Structured: message.NewGeneric(message.MsgTypeEchoRequest, 0, 0), 19 | Serialized: []byte{ 20 | 0x32, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 21 | 0x00, 0x00, 0x00, 0x00, 22 | }, 23 | }, 24 | } 25 | 26 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 27 | v, err := message.ParseGeneric(b) 28 | if err != nil { 29 | return nil, err 30 | } 31 | v.Payload = nil 32 | return v, nil 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /gtpv1/message/header_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Header into bytes. 10 | // 11 | // Deprecated: use Header.Marshal instead. 12 | func (h *Header) Serialize() ([]byte, error) { 13 | log.Println("Header.Serialize is deprecated. use Header.Marshal instead") 14 | return h.Marshal() 15 | } 16 | 17 | // SerializeTo serializes Header into bytes given as b. 18 | // 19 | // Deprecated: use Header.MarshalTo instead. 20 | func (h *Header) SerializeTo(b []byte) error { 21 | log.Println("Header.SerializeTo is deprecated. use Header.MarshalTo instead") 22 | return h.MarshalTo(b) 23 | } 24 | 25 | // DecodeHeader decodes bytes as Header. 26 | // 27 | // Deprecated: use ParseHeader instead. 28 | func DecodeHeader(b []byte) (*Header, error) { 29 | log.Println("DecodeHeader is deprecated. use ParseHeader instead") 30 | return ParseHeader(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as Header. 34 | // 35 | // Deprecated: use Header.UnmarshalBinary instead. 36 | func (h *Header) DecodeFromBytes(b []byte) error { 37 | log.Println("Header.DecodeFromBytes is deprecated. use Header.UnmarshalBinary instead") 38 | return h.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of Header. 42 | // 43 | // Deprecated: use Header.MarshalLen instead. 44 | func (h *Header) Len() int { 45 | log.Println("Header.Len is deprecated. use Header.MarshalLen instead") 46 | return h.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv1/message/message_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Message into bytes. 10 | // 11 | // Deprecated: use Marshal instead. 12 | func Serialize(m Message) ([]byte, error) { 13 | log.Println("Serialize is deprecated. use Marshal instead") 14 | return Marshal(m) 15 | } 16 | 17 | // Decode decodes bytes as Message. 18 | // 19 | // Deprecated: use Parse instead. 20 | func Decode(b []byte) (Message, error) { 21 | log.Println("Decode is deprecated. use Parse instead") 22 | return Parse(b) 23 | } 24 | -------------------------------------------------------------------------------- /gtpv1/message/message_fuzz_test.go: -------------------------------------------------------------------------------- 1 | package message_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/wmnsk/go-gtp/gtpv1/message" 7 | ) 8 | 9 | func FuzzParse(f *testing.F) { 10 | f.Fuzz(func(t *testing.T, b []byte) { 11 | if _, err := message.Parse(b); err != nil { 12 | t.Skip() 13 | } 14 | }) 15 | } 16 | 17 | func FuzzHeaderParse(f *testing.F) { 18 | f.Add([]byte("10000000")) 19 | f.Add([]byte("70\x00\x0400000000\x000")) 20 | f.Add([]byte("70\x00\x0400000000\x0100\x00")) 21 | 22 | f.Fuzz(func(t *testing.T, pkt []byte) { 23 | header, err := message.ParseHeader(pkt) 24 | if header == nil && err == nil { 25 | t.Errorf("nil without error") 26 | } 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /gtpv1/message/supported-extension-header-notification_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/ie" 11 | "github.com/wmnsk/go-gtp/gtpv1/message" 12 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 13 | ) 14 | 15 | func TestSupportedExtensionHeaderNotification(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewSupportedExtensionHeaderNotification( 20 | testutils.TestBearerInfo.TEID, 0, 21 | ie.NewExtensionHeaderTypeList( 22 | message.ExtHeaderTypePDUSessionContainer, 23 | message.ExtHeaderTypeUDPPort, 24 | ), 25 | ), 26 | Serialized: []byte{ 27 | // Header 28 | 0x30, 0x1f, 0x00, 0x04, 0x11, 0x22, 0x33, 0x44, 29 | // ExtensionHeaderTypeList 30 | 0x8d, 0x02, 0x85, 0x40, 31 | }, 32 | }, 33 | } 34 | 35 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 36 | v, err := message.ParseSupportedExtensionHeaderNotification(b) 37 | if err != nil { 38 | return nil, err 39 | } 40 | v.Payload = nil 41 | return v, nil 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /gtpv1/message/t-pdu_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes TPDU into bytes. 10 | // 11 | // Deprecated: use TPDU.Marshal instead. 12 | func (t *TPDU) Serialize() ([]byte, error) { 13 | log.Println("TPDU.Serialize is deprecated. use TPDU.Marshal instead") 14 | return t.Marshal() 15 | } 16 | 17 | // SerializeTo serializes TPDU into bytes given as b. 18 | // 19 | // Deprecated: use TPDU.MarshalTo instead. 20 | func (t *TPDU) SerializeTo(b []byte) error { 21 | log.Println("TPDU.SerializeTo is deprecated. use TPDU.MarshalTo instead") 22 | return t.MarshalTo(b) 23 | } 24 | 25 | // DecodeTPDU decodes bytes as TPDU. 26 | // 27 | // Deprecated: use ParseTPDU instead. 28 | func DecodeTPDU(b []byte) (*TPDU, error) { 29 | log.Println("DecodeTPDU is deprecated. use ParseTPDU instead") 30 | return ParseTPDU(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as TPDU. 34 | // 35 | // Deprecated: use TPDU.UnmarshalBinary instead. 36 | func (t *TPDU) DecodeFromBytes(b []byte) error { 37 | log.Println("TPDU.DecodeFromBytes is deprecated. use TPDU.UnmarshalBinary instead") 38 | return t.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of TPDU. 42 | // 43 | // Deprecated: use TPDU.MarshalLen instead. 44 | func (t *TPDU) Len() int { 45 | log.Println("TPDU.Len is deprecated. use TPDU.MarshalLen instead") 46 | return t.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv1/message/update-pdp-context-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/ie" 11 | "github.com/wmnsk/go-gtp/gtpv1/message" 12 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 13 | ) 14 | 15 | func TestUpdatePDPContextRequest(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewUpdatePDPContextRequest( 20 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 21 | ie.NewIMSI("123450123456789"), 22 | ie.NewTEIDDataI(0xdeadbeef), 23 | ie.NewTEIDCPlane(0xdeadbeef), 24 | ie.NewNSAPI(5), 25 | ie.NewGSNAddress("1.1.1.1"), 26 | ie.NewGSNAddress("2.2.2.2"), 27 | ), 28 | Serialized: []byte{ 29 | // Header 30 | 0x32, 0x12, 0x00, 0x27, 0x11, 0x22, 0x33, 0x44, 31 | 0x00, 0x01, 0x00, 0x00, 32 | // IMSI 33 | 0x02, 0x21, 0x43, 0x05, 0x21, 0x43, 0x65, 0x87, 0xf9, 34 | // TEID-U 35 | 0x10, 0xde, 0xad, 0xbe, 0xef, 36 | // TEID-C 37 | 0x11, 0xde, 0xad, 0xbe, 0xef, 38 | // NSAPI 39 | 0x14, 0x05, 40 | // GSN Address 41 | 0x85, 0x00, 0x04, 0x01, 0x01, 0x01, 0x01, 42 | // GSN Address 43 | 0x85, 0x00, 0x04, 0x02, 0x02, 0x02, 0x02, 44 | }, 45 | }, 46 | } 47 | 48 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 49 | v, err := message.ParseUpdatePDPContextRequest(b) 50 | if err != nil { 51 | return nil, err 52 | } 53 | v.Payload = nil 54 | return v, nil 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /gtpv1/message/update-pdp-context-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1" 11 | "github.com/wmnsk/go-gtp/gtpv1/ie" 12 | "github.com/wmnsk/go-gtp/gtpv1/message" 13 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 14 | ) 15 | 16 | func TestUpdatePDPContextResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewUpdatePDPContextResponse( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv1.ResCauseRequestAccepted), 23 | ie.NewRecovery(0), 24 | ie.NewTEIDDataI(0xdeadbeef), 25 | ie.NewTEIDCPlane(0xdeadbeef), 26 | ie.NewGSNAddress("1.1.1.1"), 27 | ie.NewGSNAddress("2.2.2.2"), 28 | ), 29 | Serialized: []byte{ 30 | // Header 31 | 0x32, 0x13, 0x00, 0x20, 0x11, 0x22, 0x33, 0x44, 32 | 0x00, 0x01, 0x00, 0x00, 33 | // Cause 34 | 0x01, 0x80, 35 | // Recovery 36 | 0x0e, 0x00, 37 | // TEID-U 38 | 0x10, 0xde, 0xad, 0xbe, 0xef, 39 | // TEID-C 40 | 0x11, 0xde, 0xad, 0xbe, 0xef, 41 | // GSN Address 42 | 0x85, 0x00, 0x04, 0x01, 0x01, 0x01, 0x01, 43 | // GSN Address 44 | 0x85, 0x00, 0x04, 0x02, 0x02, 0x02, 0x02, 45 | }, 46 | }, 47 | } 48 | 49 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 50 | v, err := message.ParseUpdatePDPContextResponse(b) 51 | if err != nil { 52 | return nil, err 53 | } 54 | v.Payload = nil 55 | return v, nil 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /gtpv1/message/version-not-supported_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv1/message" 11 | "github.com/wmnsk/go-gtp/gtpv1/testutils" 12 | ) 13 | 14 | func TestVersionNotSupported(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "Normal", 18 | Structured: message.NewVersionNotSupported( 19 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 20 | ), 21 | Serialized: []byte{ 22 | // Header 23 | 0x32, 0x03, 0x00, 0x04, 0x11, 0x22, 0x33, 0x44, 24 | 0x00, 0x01, 0x00, 0x00, 25 | }, 26 | }, 27 | } 28 | 29 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 30 | v, err := message.ParseVersionNotSupported(b) 31 | if err != nil { 32 | return nil, err 33 | } 34 | v.Payload = nil 35 | return v, nil 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /gtpv1/relay_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtpv1_test 6 | 7 | import ( 8 | "context" 9 | "net" 10 | "testing" 11 | 12 | "github.com/wmnsk/go-gtp/gtpv1" 13 | ) 14 | 15 | func TestRelay(t *testing.T) { 16 | leftAddr, err := net.ResolveUDPAddr("udp", "127.0.0.11:2152") 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | rightAddr, err := net.ResolveUDPAddr("udp", "127.0.0.12:2152") 21 | if err != nil { 22 | t.Fatal(err) 23 | } 24 | 25 | ctx, cancel := context.WithCancel(context.Background()) 26 | defer cancel() 27 | 28 | leftConn := gtpv1.NewUPlaneConn(leftAddr) 29 | go func() { 30 | if err := leftConn.ListenAndServe(ctx); err != nil { 31 | t.Errorf("failed to listen on %s: %s", leftConn.LocalAddr(), err) 32 | return 33 | } 34 | }() 35 | 36 | rightConn := gtpv1.NewUPlaneConn(rightAddr) 37 | go func() { 38 | if err := rightConn.ListenAndServe(ctx); err != nil { 39 | t.Errorf("failed to listen on %s: %s", rightConn.LocalAddr(), err) 40 | return 41 | } 42 | }() 43 | 44 | if err := leftConn.RelayTo(rightConn, 0x22222222, 0x11111111, rightAddr); err != nil { 45 | t.Fatal(err) 46 | } 47 | if err := rightConn.RelayTo(leftConn, 0x11111111, 0x22222222, leftAddr); err != nil { 48 | t.Fatal(err) 49 | } 50 | 51 | // TODO: add tests to check if the traffic goes through conns. 52 | } 53 | -------------------------------------------------------------------------------- /gtpv1/tunnel.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtpv1 6 | 7 | import ( 8 | "errors" 9 | "net" 10 | ) 11 | 12 | type peer struct { 13 | teid uint32 14 | addr net.Addr 15 | srcConn *UPlaneConn 16 | } 17 | 18 | // RelayTo relays T-PDU type of packet to peer node(specified by raddr) from the UPlaneConn given. 19 | // 20 | // By using this, owner of UPlaneConn won't be able to Read and Write the packets that has teidIn. 21 | func (u *UPlaneConn) RelayTo(c *UPlaneConn, teidIn, teidOut uint32, raddr net.Addr) error { 22 | if u.KernelGTP.enabled { 23 | return errors.New("cannot call RelayTo when using Kernel GTP-U") 24 | } 25 | 26 | u.mu.Lock() 27 | defer u.mu.Unlock() 28 | if u.relayMap == nil { 29 | u.relayMap = map[uint32]*peer{} 30 | } 31 | u.relayMap[teidIn] = &peer{teid: teidOut, addr: raddr, srcConn: c} 32 | return nil 33 | } 34 | 35 | // CloseRelay stops relaying T-PDU from a conn to conn. 36 | func (u *UPlaneConn) CloseRelay(teidIn uint32) error { 37 | if u.KernelGTP.enabled { 38 | return errors.New("cannot call CloseRelay when using Kernel GTP-U") 39 | } 40 | 41 | u.mu.Lock() 42 | delete(u.relayMap, teidIn) 43 | u.mu.Unlock() 44 | 45 | u.iteiMap.delete(teidIn) 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Package gtpv2 provides the simple and painless handling of GTPv2-C protocol in pure Golang. 6 | // 7 | // Please see README.md for detailed usage of the APIs provided by this package. 8 | // 9 | // https://github.com/wmnsk/go-gtp/blob/main/gtpv2/README.md 10 | package gtpv2 11 | -------------------------------------------------------------------------------- /gtpv2/ie/apn-restriction.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewAPNRestriction creates a new APNRestriction IE. 8 | func NewAPNRestriction(restriction uint8) *IE { 9 | return NewUint8IE(APNRestriction, restriction) 10 | } 11 | 12 | // APNRestriction returns APNRestriction in uint8 if the type of IE matches. 13 | func (i *IE) APNRestriction() (uint8, error) { 14 | if i.Type != APNRestriction { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | 18 | return i.ValueAsUint8() 19 | } 20 | 21 | // MustAPNRestriction returns APNRestriction in uint8, ignoring errors. 22 | // This should only be used if it is assured to have the value. 23 | func (i *IE) MustAPNRestriction() uint8 { 24 | v, _ := i.APNRestriction() 25 | return v 26 | } 27 | 28 | // RestrictionType returns RestrictionType in uint8 if the type of IE matches. 29 | func (i *IE) RestrictionType() (uint8, error) { 30 | return i.APNRestriction() 31 | } 32 | -------------------------------------------------------------------------------- /gtpv2/ie/apn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewAccessPointName creates a new AccessPointName IE. 8 | func NewAccessPointName(apn string) *IE { 9 | return NewFQDNIE(AccessPointName, apn) 10 | } 11 | 12 | // AccessPointName returns AccessPointName in string if the type of IE matches. 13 | func (i *IE) AccessPointName() (string, error) { 14 | if i.Type != AccessPointName { 15 | return "", &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsFQDN() 18 | } 19 | 20 | // MustAccessPointName returns AccessPointName in string, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustAccessPointName() string { 23 | v, _ := i.AccessPointName() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/charging-characteristics.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewChargingCharacteristics creates a new ChargingCharacteristics IE. 8 | func NewChargingCharacteristics(chr uint16) *IE { 9 | return NewUint16IE(ChargingCharacteristics, chr) 10 | } 11 | 12 | // ChargingCharacteristics returns the ChargingCharacteristics value in uint16 if the type of IE matches. 13 | func (i *IE) ChargingCharacteristics() (uint16, error) { 14 | if i.Type != ChargingCharacteristics { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint16() 18 | } 19 | 20 | // MustChargingCharacteristics returns ChargingCharacteristics in uint16, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustChargingCharacteristics() uint16 { 23 | v, _ := i.ChargingCharacteristics() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/charging-id.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewChargingID creates a new ChargingID IE. 8 | func NewChargingID(id uint32) *IE { 9 | return NewUint32IE(ChargingID, id) 10 | } 11 | 12 | // ChargingID returns the ChargingID value in uint32 if the type of IE matches. 13 | func (i *IE) ChargingID() (uint32, error) { 14 | switch i.Type { 15 | case ChargingID: 16 | return i.ValueAsUint32() 17 | case BearerContext: 18 | ies, err := i.BearerContext() 19 | if err != nil { 20 | return 0, err 21 | } 22 | 23 | for _, child := range ies { 24 | if child.Type == ChargingID { 25 | return child.ChargingID() 26 | } 27 | } 28 | return 0, ErrIENotFound 29 | default: 30 | return 0, &InvalidTypeError{Type: i.Type} 31 | } 32 | } 33 | 34 | // MustChargingID returns ChargingID in uint32, ignoring errors. 35 | // This should only be used if it is assured to have the value. 36 | func (i *IE) MustChargingID() uint32 { 37 | v, _ := i.ChargingID() 38 | return v 39 | } 40 | -------------------------------------------------------------------------------- /gtpv2/ie/cmi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "io" 8 | 9 | // NewCSGMembershipIndication creates a new CSGMembershipIndication IE. 10 | func NewCSGMembershipIndication(cmi uint8) *IE { 11 | return NewUint8IE(CSGMembershipIndication, cmi) 12 | } 13 | 14 | // CMI returns CMI in uint8 if the type of IE matches. 15 | func (i *IE) CMI() (uint8, error) { 16 | switch i.Type { 17 | case CSGMembershipIndication: 18 | return i.ValueAsUint8() 19 | case UserCSGInformation: 20 | if len(i.Payload) < 8 { 21 | return 0, io.ErrUnexpectedEOF 22 | } 23 | return i.Payload[7], nil 24 | default: 25 | return 0, &InvalidTypeError{Type: i.Type} 26 | } 27 | } 28 | 29 | // MustCMI returns CMI in uint8, ignoring errors. 30 | // This should only be used if it is assured to have the value. 31 | func (i *IE) MustCMI() uint8 { 32 | v, _ := i.CMI() 33 | return v 34 | } 35 | -------------------------------------------------------------------------------- /gtpv2/ie/csg-id.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // NewCSGID creates a new CSGID IE. 13 | func NewCSGID(id uint32) *IE { 14 | return NewUint32IE(CSGID, id&0x7ffffff) 15 | } 16 | 17 | // CSGID returns CSGID in uint32 if the type of IE matches. 18 | func (i *IE) CSGID() (uint32, error) { 19 | switch i.Type { 20 | case CSGID: 21 | return i.ValueAsUint32() 22 | case UserCSGInformation: 23 | if len(i.Payload) < 7 { 24 | return 0, io.ErrUnexpectedEOF 25 | } 26 | return binary.BigEndian.Uint32(i.Payload[3:7]) & 0x7ffffff, nil 27 | default: 28 | return 0, &InvalidTypeError{Type: i.Type} 29 | } 30 | } 31 | 32 | // MustCSGID returns CSGID in uint32, ignoring errors. 33 | // This should only be used if it is assured to have the value. 34 | func (i *IE) MustCSGID() uint32 { 35 | v, _ := i.CSGID() 36 | return v 37 | } 38 | -------------------------------------------------------------------------------- /gtpv2/ie/delay-value.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "time" 10 | ) 11 | 12 | // NewDelayValue creates a new DelayValue IE. 13 | func NewDelayValue(delay time.Duration) *IE { 14 | return NewUint8IE(DelayValue, uint8(delay.Seconds()*1000/50)) 15 | } 16 | 17 | // NewDelayValueRaw creates a new DelayValue IE from a uint8 value. 18 | // 19 | // The value should be in multiples of 50ms or zero. 20 | func NewDelayValueRaw(delay uint8) *IE { 21 | return NewUint8IE(DelayValue, delay) 22 | } 23 | 24 | // DelayValue returns DelayValue in time.Duration if the type of IE matches. 25 | // 26 | // The returned value is in time.Duration. To get the value in multiples of 50ms, 27 | // use ValueAsUint8 or access Payload field directly instead. 28 | func (i *IE) DelayValue() (time.Duration, error) { 29 | if i.Type != DelayValue { 30 | return 0, &InvalidTypeError{Type: i.Type} 31 | } 32 | if len(i.Payload) < 1 { 33 | return 0, io.ErrUnexpectedEOF 34 | } 35 | 36 | return time.Duration(i.Payload[0]/50) * time.Millisecond, nil 37 | } 38 | 39 | // MustDelayValue returns DelayValue in time.Duration, ignoring errors. 40 | // This should only be used if it is assured to have the value. 41 | func (i *IE) MustDelayValue() time.Duration { 42 | v, _ := i.DelayValue() 43 | return v 44 | } 45 | -------------------------------------------------------------------------------- /gtpv2/ie/detach-type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewDetachType creates a new DetachType IE. 8 | func NewDetachType(dtype uint8) *IE { 9 | return NewUint8IE(DetachType, dtype) 10 | } 11 | 12 | // DetachType returns DetachType in uint8 if the type of IE matches. 13 | func (i *IE) DetachType() (uint8, error) { 14 | if i.Type != DetachType { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint8() 18 | } 19 | 20 | // MustDetachType returns DetachType in uint8, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustDetachType() uint8 { 23 | v, _ := i.DetachType() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/ebi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewEPSBearerID creates a new EPSBearerID IE. 8 | func NewEPSBearerID(ebi uint8) *IE { 9 | return NewUint8IE(EPSBearerID, ebi&0x0f) 10 | } 11 | 12 | // EPSBearerID returns EPSBearerID if the type of IE matches. 13 | func (i *IE) EPSBearerID() (uint8, error) { 14 | switch i.Type { 15 | case EPSBearerID: 16 | return i.ValueAsUint8() 17 | case BearerContext: 18 | ies, err := i.BearerContext() 19 | if err != nil { 20 | return 0, err 21 | } 22 | 23 | for _, child := range ies { 24 | if child.Type == EPSBearerID { 25 | return child.EPSBearerID() 26 | } 27 | } 28 | return 0, ErrIENotFound 29 | default: 30 | return 0, &InvalidTypeError{Type: i.Type} 31 | } 32 | } 33 | 34 | // MustEPSBearerID returns EPSBearerID in uint8, ignoring errors. 35 | // This should only be used if it is assured to have the value. 36 | func (i *IE) MustEPSBearerID() uint8 { 37 | v, _ := i.EPSBearerID() 38 | return v 39 | } 40 | -------------------------------------------------------------------------------- /gtpv2/ie/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | ) 11 | 12 | // Error definitions. 13 | var ( 14 | ErrTooShortToParse = errors.New("too short to decode as GTP") 15 | ErrInvalidLength = errors.New("length value is invalid") 16 | 17 | ErrInvalidType = errors.New("invalid type") 18 | ErrIENotFound = errors.New("could not find the specified IE in a grouped IE") 19 | ErrIEValueNotFound = errors.New("could not find the specified value in an IE") 20 | 21 | ErrMalformed = errors.New("malformed IE") 22 | ) 23 | 24 | // InvalidTypeError indicates the type of IE is invalid. 25 | type InvalidTypeError struct { 26 | Type uint8 27 | } 28 | 29 | // Error returns message with the invalid type given. 30 | func (e *InvalidTypeError) Error() string { 31 | return fmt.Sprintf("got invalid type: %v", e.Type) 32 | } 33 | -------------------------------------------------------------------------------- /gtpv2/ie/fqdn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewFullyQualifiedDomainName creates a new FullyQualifiedDomainName IE. 8 | func NewFullyQualifiedDomainName(fqdn string) *IE { 9 | return NewFQDNIE(FullyQualifiedDomainName, fqdn) 10 | } 11 | 12 | // FullyQualifiedDomainName returns FullyQualifiedDomainName in string if the type of IE matches. 13 | func (i *IE) FullyQualifiedDomainName() (string, error) { 14 | if i.Type != FullyQualifiedDomainName { 15 | return "", &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsFQDN() 18 | } 19 | 20 | // MustFullyQualifiedDomainName returns FullyQualifiedDomainName in string, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustFullyQualifiedDomainName() string { 23 | v, _ := i.FullyQualifiedDomainName() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/global-cn-id.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | 11 | "github.com/wmnsk/go-gtp/utils" 12 | ) 13 | 14 | // NewGlobalCNID creates a new GlobalCNID IE. 15 | func NewGlobalCNID(mcc, mnc string, cnid uint16) *IE { 16 | i := New(GlobalCNID, 0x00, make([]byte, 5)) 17 | plmn, err := utils.EncodePLMN(mcc, mnc) 18 | if err != nil { 19 | return nil 20 | } 21 | copy(i.Payload[0:3], plmn) 22 | 23 | cnid &= 0xfff 24 | binary.BigEndian.PutUint16(i.Payload[3:5], cnid) 25 | return i 26 | } 27 | 28 | // CNID returns CNID in uinte16 if the type of IE matches. 29 | func (i *IE) CNID() (uint16, error) { 30 | if len(i.Payload) < 5 { 31 | return 0, io.ErrUnexpectedEOF 32 | } 33 | switch i.Type { 34 | case GlobalCNID: 35 | return binary.BigEndian.Uint16(i.Payload[3:5]), nil 36 | default: 37 | return 0, &InvalidTypeError{Type: i.Type} 38 | } 39 | } 40 | 41 | // MustCNID returns CNID in uint16, ignoring errors. 42 | // This should only be used if it is assured to have the value. 43 | func (i *IE) MustCNID() uint16 { 44 | v, _ := i.CNID() 45 | return v 46 | } 47 | -------------------------------------------------------------------------------- /gtpv2/ie/hop-counter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewHopCounter creates a new HopCounter IE. 8 | func NewHopCounter(hop uint8) *IE { 9 | return NewUint8IE(HopCounter, hop) 10 | } 11 | 12 | // HopCounter returns HopCounter in uint8 if the type of IE matches. 13 | func (i *IE) HopCounter() (uint8, error) { 14 | if i.Type != HopCounter { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint8() 18 | } 19 | 20 | // MustHopCounter returns HopCounter in uint8, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustHopCounter() uint8 { 23 | v, _ := i.HopCounter() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/ie_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import "log" 8 | 9 | // Serialize serializes IE into bytes. 10 | // 11 | // Deprecated: use IE.Marshal instead. 12 | func (i *IE) Serialize() ([]byte, error) { 13 | log.Println("IE.Serialize is deprecated. use IE.Marshal instead") 14 | return i.Marshal() 15 | } 16 | 17 | // SerializeTo serializes IE into bytes given as b. 18 | // 19 | // Deprecated: use IE.MarshalTo instead. 20 | func (i *IE) SerializeTo(b []byte) error { 21 | log.Println("IE.SerializeTo is deprecated. use IE.MarshalTo instead") 22 | return i.MarshalTo(b) 23 | } 24 | 25 | // Decode decodes bytes as IE. 26 | // 27 | // Deprecated: use Parse instead. 28 | func Decode(b []byte) (*IE, error) { 29 | log.Println("Decode is deprecated. use Parse instead") 30 | return Parse(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as IE. 34 | // 35 | // Deprecated: use IE.UnmarshalBinary instead. 36 | func (i *IE) DecodeFromBytes(b []byte) error { 37 | log.Println("IE.DecodeFromBytes is deprecated. use IE.UnmarshalBinary instead") 38 | return i.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of IE. 42 | // 43 | // Deprecated: use IE.MarshalLen instead. 44 | func (i *IE) Len() int { 45 | log.Println("IE.Len is deprecated. use IE.MarshalLen instead") 46 | return i.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/ie/imsi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewIMSI creates a new IMSI IE. 14 | func NewIMSI(imsi string) *IE { 15 | i, err := utils.StrToSwappedBytes(imsi, "f") 16 | if err != nil { 17 | return nil 18 | } 19 | 20 | return New(IMSI, 0x00, i) 21 | } 22 | 23 | // IMSI returns IMSI in string if the type of IE matches. 24 | func (i *IE) IMSI() (string, error) { 25 | if i.Type != IMSI { 26 | return "", &InvalidTypeError{Type: i.Type} 27 | } 28 | if len(i.Payload) < 1 { 29 | return "", io.ErrUnexpectedEOF 30 | } 31 | 32 | return utils.SwappedBytesToStr(i.Payload, true), nil 33 | } 34 | 35 | // MustIMSI returns IMSI in string, ignoring errors. 36 | // This should only be used if it is assured to have the value. 37 | func (i *IE) MustIMSI() string { 38 | v, _ := i.IMSI() 39 | return v 40 | } 41 | -------------------------------------------------------------------------------- /gtpv2/ie/integer-number.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewIntegerNumber creates a new IntegerNumber IE. 8 | func NewIntegerNumber(num uint16) *IE { 9 | return NewUint16IE(IntegerNumber, num) 10 | } 11 | 12 | // IntegerNumber returns IntegerNumber in uint16 if the type of IE matches. 13 | func (i *IE) IntegerNumber() (uint16, error) { 14 | switch i.Type { 15 | case IntegerNumber: 16 | return i.ValueAsUint16() 17 | default: 18 | return 0, &InvalidTypeError{Type: i.Type} 19 | } 20 | } 21 | 22 | // MustIntegerNumber returns IntegerNumber in uint16, ignoring errors. 23 | // This should only be used if it is assured to have the value. 24 | func (i *IE) MustIntegerNumber() uint16 { 25 | v, _ := i.IntegerNumber() 26 | return v 27 | } 28 | -------------------------------------------------------------------------------- /gtpv2/ie/ldn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewLocalDistinguishedName creates a new LocalDistinguishedName IE. 8 | func NewLocalDistinguishedName(name string) *IE { 9 | return NewStringIE(LocalDistinguishedName, name) 10 | } 11 | 12 | // LocalDistinguishedName returns LocalDistinguishedName in string if the type of IE matches. 13 | func (i *IE) LocalDistinguishedName() (string, error) { 14 | if i.Type != LocalDistinguishedName { 15 | return "", &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsString() 18 | } 19 | 20 | // MustLocalDistinguishedName returns LocalDistinguishedName in string, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustLocalDistinguishedName() string { 23 | v, _ := i.LocalDistinguishedName() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/mei.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | 11 | "github.com/wmnsk/go-gtp/utils" 12 | ) 13 | 14 | // NewMobileEquipmentIdentity creates a new MobileEquipmentIdentity IE. 15 | func NewMobileEquipmentIdentity(mei string) *IE { 16 | m, err := utils.StrToSwappedBytes(mei, "f") 17 | if err != nil { 18 | return nil 19 | } 20 | return New(MobileEquipmentIdentity, 0x00, m) 21 | } 22 | 23 | // MobileEquipmentIdentity returns MobileEquipmentIdentity in string if the 24 | // type of IE matches. 25 | func (i *IE) MobileEquipmentIdentity() (string, error) { 26 | if i.Type != MobileEquipmentIdentity { 27 | return "", &InvalidTypeError{Type: i.Type} 28 | } 29 | if len(i.Payload) < 1 { 30 | return "", io.ErrUnexpectedEOF 31 | } 32 | 33 | str := utils.SwappedBytesToStr(i.Payload, false) 34 | return strings.TrimSuffix(str, "f"), nil 35 | } 36 | 37 | // MustMobileEquipmentIdentity returns MobileEquipmentIdentity in string, ignoring errors. 38 | // This should only be used if it is assured to have the value. 39 | func (i *IE) MustMobileEquipmentIdentity() string { 40 | v, _ := i.MobileEquipmentIdentity() 41 | return v 42 | } 43 | -------------------------------------------------------------------------------- /gtpv2/ie/msisdn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | 11 | "github.com/wmnsk/go-gtp/utils" 12 | ) 13 | 14 | // NewMSISDN creates a new MSISDN IE. 15 | func NewMSISDN(msisdn string) *IE { 16 | m, err := utils.StrToSwappedBytes(msisdn, "f") 17 | if err != nil { 18 | return nil 19 | } 20 | return New(MSISDN, 0x00, m) 21 | } 22 | 23 | // MSISDN returns MSISDN in string if the type of IE matches. 24 | func (i *IE) MSISDN() (string, error) { 25 | if i.Type != MSISDN { 26 | return "", &InvalidTypeError{Type: i.Type} 27 | } 28 | if len(i.Payload) < 1 { 29 | return "", io.ErrUnexpectedEOF 30 | } 31 | 32 | str := utils.SwappedBytesToStr(i.Payload, false) 33 | return strings.TrimSuffix(str, "f"), nil 34 | } 35 | 36 | // MustMSISDN returns MSISDN in string, ignoring errors. 37 | // This should only be used if it is assured to have the value. 38 | func (i *IE) MustMSISDN() string { 39 | v, _ := i.MSISDN() 40 | return v 41 | } 42 | -------------------------------------------------------------------------------- /gtpv2/ie/node-type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewNodeType creates a new NodeType IE. 8 | func NewNodeType(nodeType uint8) *IE { 9 | return NewUint8IE(NodeType, nodeType) 10 | } 11 | 12 | // NodeType returns NodeType in uint8 if the type of IE matches. 13 | func (i *IE) NodeType() (uint8, error) { 14 | if i.Type != NodeType { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint8() 18 | } 19 | 20 | // MustNodeType returns NodeType in uint8, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustNodeType() uint8 { 23 | v, _ := i.NodeType() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/p-tmsi-signature.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewPTMSISignature creates a new PTMSISignature IE. 14 | func NewPTMSISignature(sig uint32) *IE { 15 | return New(PTMSISignature, 0x00, utils.Uint32To24(sig)) 16 | } 17 | 18 | // PTMSISignature returns PTMSISignature value in uint32 if type matches. 19 | func (i *IE) PTMSISignature() (uint32, error) { 20 | if i.Type != PTMSISignature { 21 | return 0, &InvalidTypeError{Type: i.Type} 22 | } 23 | if len(i.Payload) < 1 { 24 | return 0, io.ErrUnexpectedEOF 25 | } 26 | 27 | return utils.Uint24To32(i.Payload), nil 28 | } 29 | 30 | // MustPTMSISignature returns PTMSISignature in uint32, ignoring errors. 31 | // This should only be used if it is assured to have the value. 32 | func (i *IE) MustPTMSISignature() uint32 { 33 | v, _ := i.PTMSISignature() 34 | return v 35 | } 36 | -------------------------------------------------------------------------------- /gtpv2/ie/p-tmsi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewPacketTMSI creates a new PacketTMSI IE. 8 | func NewPacketTMSI(ptmsi uint32) *IE { 9 | return NewUint32IE(PacketTMSI, ptmsi) 10 | } 11 | 12 | // PacketTMSI returns PacketTMSI value in uint32 if type matches. 13 | func (i *IE) PacketTMSI() (uint32, error) { 14 | if i.Type != PacketTMSI { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint32() 18 | } 19 | 20 | // MustPacketTMSI returns PacketTMSI in uint32, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustPacketTMSI() uint32 { 23 | v, _ := i.PacketTMSI() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/pdn-type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewPDNType creates a new PDNType IE. 8 | func NewPDNType(pdn uint8) *IE { 9 | return NewUint8IE(PDNType, pdn) 10 | } 11 | 12 | // PDNType returns the PDNType value in uint8 if the type of IE matches. 13 | func (i *IE) PDNType() (uint8, error) { 14 | switch i.Type { 15 | case PDNType, PDNAddressAllocation: 16 | return i.ValueAsUint8() 17 | default: 18 | return 0, &InvalidTypeError{Type: i.Type} 19 | } 20 | } 21 | 22 | // MustPDNType returns PDNType in uint8, ignoring errors. 23 | // This should only be used if it is assured to have the value. 24 | func (i *IE) MustPDNType() uint8 { 25 | v, _ := i.PDNType() 26 | return v 27 | } 28 | -------------------------------------------------------------------------------- /gtpv2/ie/plmn-id.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewPLMNID creates a PLMNID IE. 14 | func NewPLMNID(mcc, mnc string) *IE { 15 | encoded, err := utils.EncodePLMN(mcc, mnc) 16 | if err != nil { 17 | return nil 18 | } 19 | 20 | return New(PLMNID, 0x00, encoded) 21 | } 22 | 23 | // PLMNID returns PLMNID(MCC and MNC) in string if the type of IE matches. 24 | func (i *IE) PLMNID() (string, error) { 25 | if i.Type != PLMNID { 26 | return "", &InvalidTypeError{Type: i.Type} 27 | } 28 | if len(i.Payload) < 3 { 29 | return "", io.ErrUnexpectedEOF 30 | } 31 | 32 | mcc, mnc, err := utils.DecodePLMN(i.Payload) 33 | if err != nil { 34 | return "", err 35 | } 36 | 37 | return mcc + mnc, nil 38 | } 39 | 40 | // MustPLMNID returns PLMNID in string, ignoring errors. 41 | // This should only be used if it is assured to have the value. 42 | func (i *IE) MustPLMNID() string { 43 | v, _ := i.PLMNID() 44 | return v 45 | } 46 | -------------------------------------------------------------------------------- /gtpv2/ie/port-number.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewPortNumber creates a new PortNumber IE. 8 | func NewPortNumber(port uint16) *IE { 9 | return NewUint16IE(PortNumber, port) 10 | } 11 | 12 | // PortNumber returns PortNumber in uint16 if the type of IE matches. 13 | func (i *IE) PortNumber() (uint16, error) { 14 | switch i.Type { 15 | case PortNumber: 16 | return i.ValueAsUint16() 17 | default: 18 | return 0, &InvalidTypeError{Type: i.Type} 19 | } 20 | } 21 | 22 | // MustPortNumber returns PortNumber in uint16, ignoring errors. 23 | // This should only be used if it is assured to have the value. 24 | func (i *IE) MustPortNumber() uint16 { 25 | v, _ := i.PortNumber() 26 | return v 27 | } 28 | -------------------------------------------------------------------------------- /gtpv2/ie/private-extension.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | // NewPrivateExtension creates a new PrivateExtension IE. 13 | func NewPrivateExtension(id uint16, value []byte) *IE { 14 | i := New(PrivateExtension, 0x00, make([]byte, 2+len(value))) 15 | binary.BigEndian.PutUint16(i.Payload[0:2], id) 16 | copy(i.Payload[2:], value) 17 | return i 18 | } 19 | 20 | // EnterpriseID returns EnterpriseID in uint16 if the type of IE matches. 21 | func (i *IE) EnterpriseID() (uint16, error) { 22 | if i.Type != PrivateExtension { 23 | return 0, &InvalidTypeError{Type: i.Type} 24 | } 25 | if len(i.Payload) < 2 { 26 | return 0, io.ErrUnexpectedEOF 27 | } 28 | 29 | return binary.BigEndian.Uint16(i.Payload[0:2]), nil 30 | 31 | } 32 | 33 | // MustEnterpriseID returns EnterpriseID in uint16, ignoring errors. 34 | // This should only be used if it is assured to have the value. 35 | func (i *IE) MustEnterpriseID() uint16 { 36 | v, _ := i.EnterpriseID() 37 | return v 38 | } 39 | 40 | // PrivateExtension returns PrivateExtension value in []byte if the type of IE matches. 41 | func (i *IE) PrivateExtension() ([]byte, error) { 42 | if i.Type != PrivateExtension { 43 | return nil, &InvalidTypeError{Type: i.Type} 44 | } 45 | if len(i.Payload) < 3 { 46 | return nil, io.ErrUnexpectedEOF 47 | } 48 | 49 | return i.Payload[2:], nil 50 | } 51 | 52 | // MustPrivateExtension returns PrivateExtension in []byte, ignoring errors. 53 | // This should only be used if it is assured to have the value. 54 | func (i *IE) MustPrivateExtension() []byte { 55 | v, _ := i.PrivateExtension() 56 | return v 57 | } 58 | -------------------------------------------------------------------------------- /gtpv2/ie/pti.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewProcedureTransactionID creates a new ProcedureTransactionID IE. 8 | func NewProcedureTransactionID(pti uint8) *IE { 9 | return NewUint8IE(ProcedureTransactionID, pti) 10 | } 11 | 12 | // ProcedureTransactionID returns ProcedureTransactionID in uint8 if the type of IE matches. 13 | func (i *IE) ProcedureTransactionID() (uint8, error) { 14 | if i.Type != ProcedureTransactionID { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint8() 18 | } 19 | 20 | // MustProcedureTransactionID returns ProcedureTransactionID in uint8, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustProcedureTransactionID() uint8 { 23 | v, _ := i.ProcedureTransactionID() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/rat-type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewRATType creates a new RATType IE. 8 | func NewRATType(rat uint8) *IE { 9 | return NewUint8IE(RATType, rat) 10 | } 11 | 12 | // RATType returns RATType in uint8 if the type of IE matches. 13 | func (i *IE) RATType() (uint8, error) { 14 | switch i.Type { 15 | case RATType: 16 | return i.ValueAsUint8() 17 | default: 18 | return 0, &InvalidTypeError{Type: i.Type} 19 | } 20 | } 21 | 22 | // MustRATType returns RATType in uint8, ignoring errors. 23 | // This should only be used if it is assured to have the value. 24 | func (i *IE) MustRATType() uint8 { 25 | v, _ := i.RATType() 26 | return v 27 | } 28 | -------------------------------------------------------------------------------- /gtpv2/ie/recovery.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewRecovery creates a new Recovery IE. 8 | func NewRecovery(recovery uint8) *IE { 9 | return NewUint8IE(Recovery, recovery) 10 | } 11 | 12 | // Recovery returns Recovery value if the type of IE matches. 13 | func (i *IE) Recovery() (uint8, error) { 14 | if i.Type != Recovery { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint8() 18 | } 19 | 20 | // MustRecovery returns Recovery in uint8, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustRecovery() uint8 { 23 | v, _ := i.Recovery() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/rfsp-index.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewRFSPIndex creates a new RFSPIndex IE. 8 | func NewRFSPIndex(idx uint8) *IE { 9 | return NewUint8IE(RFSPIndex, idx) 10 | } 11 | 12 | // RFSPIndex returns RFSPIndex in uint8 if the type of IE matches. 13 | func (i *IE) RFSPIndex() (uint8, error) { 14 | if i.Type != RFSPIndex { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint8() 18 | } 19 | 20 | // MustRFSPIndex returns RFSPIndex in uint8, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustRFSPIndex() uint8 { 23 | v, _ := i.RFSPIndex() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/selection-mode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewSelectionMode creates a new SelectionMode IE. 8 | func NewSelectionMode(mode uint8) *IE { 9 | return NewUint8IE(SelectionMode, mode) 10 | } 11 | 12 | // SelectionMode returns SelectionMode value if the type of IE matches. 13 | func (i *IE) SelectionMode() (uint8, error) { 14 | if i.Type != SelectionMode { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint8() 18 | } 19 | 20 | // MustSelectionMode returns SelectionMode in uint8, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustSelectionMode() uint8 { 23 | v, _ := i.SelectionMode() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/service-indicator.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewServiceIndicator creates a new ServiceIndicator IE. 8 | func NewServiceIndicator(ind uint8) *IE { 9 | return NewUint8IE(ServiceIndicator, ind) 10 | } 11 | 12 | // ServiceIndicator returns ServiceIndicator in uint8 if the type of IE matches. 13 | func (i *IE) ServiceIndicator() (uint8, error) { 14 | if i.Type != ServiceIndicator { 15 | return 0, &InvalidTypeError{Type: i.Type} 16 | } 17 | return i.ValueAsUint8() 18 | } 19 | 20 | // MustServiceIndicator returns ServiceIndicator in uint8, ignoring errors. 21 | // This should only be used if it is assured to have the value. 22 | func (i *IE) MustServiceIndicator() uint8 { 23 | v, _ := i.ServiceIndicator() 24 | return v 25 | } 26 | -------------------------------------------------------------------------------- /gtpv2/ie/serving-nw.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "io" 9 | 10 | "github.com/wmnsk/go-gtp/utils" 11 | ) 12 | 13 | // NewServingNetwork creates a ServingNetwork IE. 14 | func NewServingNetwork(mcc, mnc string) *IE { 15 | encoded, err := utils.EncodePLMN(mcc, mnc) 16 | if err != nil { 17 | return nil 18 | } 19 | 20 | return New(ServingNetwork, 0x00, encoded) 21 | } 22 | 23 | // ServingNetwork returns ServingNetwork(MCC and MNC) in string if the type of IE matches. 24 | func (i *IE) ServingNetwork() (string, error) { 25 | if i.Type != ServingNetwork { 26 | return "", &InvalidTypeError{Type: i.Type} 27 | } 28 | if len(i.Payload) < 3 { 29 | return "", io.ErrUnexpectedEOF 30 | } 31 | 32 | mcc, mnc, err := utils.DecodePLMN(i.Payload) 33 | if err != nil { 34 | return "", err 35 | } 36 | 37 | return mcc + mnc, nil 38 | } 39 | 40 | // MustServingNetwork returns ServingNetwork in string, ignoring errors. 41 | // This should only be used if it is assured to have the value. 42 | func (i *IE) MustServingNetwork() string { 43 | v, _ := i.ServingNetwork() 44 | return v 45 | } 46 | -------------------------------------------------------------------------------- /gtpv2/ie/tmsi.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | // NewTMSI creates a new TMSI IE. 8 | func NewTMSI(tmsi uint32) *IE { 9 | return NewUint32IE(TMSI, tmsi) 10 | } 11 | 12 | // TMSI returns TMSI in uint32 if the type of IE matches. 13 | func (i *IE) TMSI() (uint32, error) { 14 | switch i.Type { 15 | case TMSI: 16 | return i.ValueAsUint32() 17 | default: 18 | return 0, &InvalidTypeError{Type: i.Type} 19 | } 20 | } 21 | 22 | // MustTMSI returns TMSI in uint32, ignoring errors. 23 | // This should only be used if it is assured to have the value. 24 | func (i *IE) MustTMSI() uint32 { 25 | v, _ := i.TMSI() 26 | return v 27 | } 28 | -------------------------------------------------------------------------------- /gtpv2/ie/uli-timestamp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | "time" 11 | ) 12 | 13 | // NewULITimestamp creates a new ULITimestamp IE. 14 | func NewULITimestamp(ts time.Time) *IE { 15 | u64sec := uint64(ts.Sub(time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC))) / 1000000000 16 | return NewUint32IE(ULITimestamp, uint32(u64sec)) 17 | } 18 | 19 | // Timestamp returns Timestamp in time.Time if the type of IE matches. 20 | func (i *IE) Timestamp() (time.Time, error) { 21 | if len(i.Payload) < 4 { 22 | return time.Time{}, io.ErrUnexpectedEOF 23 | } 24 | 25 | switch i.Type { 26 | case ULITimestamp, TWANIdentifierTimestamp: 27 | return time.Unix(int64(binary.BigEndian.Uint32(i.Payload)-2208988800), 0), nil 28 | default: 29 | return time.Time{}, &InvalidTypeError{Type: i.Type} 30 | } 31 | } 32 | 33 | // MustTimestamp returns Timestamp in time.Time, ignoring errors. 34 | // This should only be used if it is assured to have the value. 35 | func (i *IE) MustTimestamp() time.Time { 36 | v, _ := i.Timestamp() 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /gtpv2/ie/utils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package ie 6 | 7 | func has8thBit(f uint8) bool { 8 | return (f&0x80)>>7 == 1 9 | } 10 | 11 | func has7thBit(f uint8) bool { 12 | return (f&0x40)>>6 == 1 13 | } 14 | 15 | func has6thBit(f uint8) bool { 16 | return (f&0x20)>>5 == 1 17 | } 18 | 19 | func has5thBit(f uint8) bool { 20 | return (f&0x010)>>4 == 1 21 | } 22 | 23 | func has4thBit(f uint8) bool { 24 | return (f&0x08)>>3 == 1 25 | } 26 | 27 | func has3rdBit(f uint8) bool { 28 | return (f&0x04)>>2 == 1 29 | } 30 | 31 | func has2ndBit(f uint8) bool { 32 | return (f&0x02)>>1 == 1 33 | } 34 | 35 | func has1stBit(f uint8) bool { 36 | return (f & 0x01) == 1 37 | } 38 | -------------------------------------------------------------------------------- /gtpv2/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package gtpv2 6 | 7 | import ( 8 | "io" 9 | "log" 10 | "os" 11 | "sync" 12 | ) 13 | 14 | var ( 15 | logger = log.New(os.Stderr, "", log.LstdFlags) 16 | logMu sync.Mutex 17 | ) 18 | 19 | // SetLogger replaces the standard logger with arbitrary *log.Logger. 20 | // 21 | // This package prints just informational logs from goroutines working background 22 | // that might help developers test the program but can be ignored safely. More 23 | // important ones that needs any action by caller would be returned as errors. 24 | func SetLogger(l *log.Logger) { 25 | if l == nil { 26 | log.Println("Don't pass nil to SetLogger: use DisableLogging instead.") 27 | } 28 | 29 | setLogger(l) 30 | } 31 | 32 | // EnableLogging enables the logging from the package. 33 | // If l is nil, it uses default logger provided by the package. 34 | // Logging is enabled by default. 35 | // 36 | // See also: SetLogger. 37 | func EnableLogging(l *log.Logger) { 38 | logMu.Lock() 39 | defer logMu.Unlock() 40 | 41 | setLogger(l) 42 | } 43 | 44 | // DisableLogging disables the logging from the package. 45 | // Logging is enabled by default. 46 | func DisableLogging() { 47 | logMu.Lock() 48 | defer logMu.Unlock() 49 | 50 | logger.SetOutput(io.Discard) 51 | } 52 | 53 | func setLogger(l *log.Logger) { 54 | if l == nil { 55 | l = log.New(os.Stderr, "", log.LstdFlags) 56 | } 57 | 58 | logMu.Lock() 59 | defer logMu.Unlock() 60 | 61 | logger = l 62 | } 63 | func logf(format string, v ...interface{}) { 64 | logMu.Lock() 65 | defer logMu.Unlock() 66 | 67 | logger.Printf(format, v...) 68 | } 69 | -------------------------------------------------------------------------------- /gtpv2/message/change-notification-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestChangeNotificationResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewChangeNotificationResponse( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewIMSI("123451234567890"), 23 | ie.NewMobileEquipmentIdentity("123450123456789"), 24 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 25 | ie.NewPrivateExtension(10415, []byte{0xde, 0xad, 0xbe, 0xef}), 26 | ), 27 | Serialized: []byte{ 28 | // Header 29 | 0x48, 0x27, 0x00, 0x30, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 30 | // IMSI 31 | 0x01, 0x00, 0x08, 0x00, 0x21, 0x43, 0x15, 0x32, 0x54, 0x76, 0x98, 0xf0, 32 | // MAI 33 | 0x4b, 0x00, 0x08, 0x00, 0x21, 0x43, 0x05, 0x21, 0x43, 0x65, 0x87, 0xf9, 34 | // Cause 35 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 36 | // PrivateExtension 37 | 0xff, 0x00, 0x06, 0x00, 0x28, 0xaf, 0xde, 0xad, 0xbe, 0xef, 38 | }, 39 | }, 40 | } 41 | 42 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 43 | v, err := message.ParseChangeNotificationResponse(b) 44 | if err != nil { 45 | return nil, err 46 | } 47 | v.Payload = nil 48 | return v, nil 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /gtpv2/message/context-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/ie" 11 | "github.com/wmnsk/go-gtp/gtpv2/message" 12 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 13 | ) 14 | 15 | func TestContextRequest(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewContextRequest( 20 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 21 | ie.NewIMSI("123451234567890"), 22 | ie.NewPacketTMSI(0xdeadbeef), 23 | ie.NewPTMSISignature(0xbeebee), 24 | ), 25 | Serialized: []byte{ 26 | // Header 27 | 0x48, 0x82, 0x00, 0x23, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 28 | // IMSI 29 | 0x01, 0x00, 0x08, 0x00, 0x21, 0x43, 0x15, 0x32, 0x54, 0x76, 0x98, 0xf0, 30 | // P-TMSI 31 | 0x6f, 0x00, 0x04, 0x00, 0xde, 0xad, 0xbe, 0xef, 32 | // P-TMSI Signature 33 | 0x70, 0x00, 0x03, 0x00, 0xbe, 0xeb, 0xee, 34 | }, 35 | }, 36 | } 37 | 38 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 39 | v, err := message.ParseContextRequest(b) 40 | if err != nil { 41 | return nil, err 42 | } 43 | v.Payload = nil 44 | return v, nil 45 | }) 46 | } 47 | -------------------------------------------------------------------------------- /gtpv2/message/context-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestContextResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewContextResponse( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ie.NewIMSI("123451234567890"), 24 | // ie.NewMMContext(), TODO: implement! 25 | ie.NewFullyQualifiedTEID(gtpv2.IFTypeS10MMEGTPC, 0xffffffff, "1.1.1.1", ""), 26 | ), 27 | Serialized: []byte{ 28 | // Header 29 | 0x48, 0x83, 0x00, 0x27, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 30 | // Cause 31 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 32 | // IMSI 33 | 0x01, 0x00, 0x08, 0x00, 0x21, 0x43, 0x15, 0x32, 0x54, 0x76, 0x98, 0xf0, 34 | // F-TEID 35 | 0x57, 0x00, 0x09, 0x00, 0x8c, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 36 | }, 37 | }, 38 | } 39 | 40 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 41 | v, err := message.ParseContextResponse(b) 42 | if err != nil { 43 | return nil, err 44 | } 45 | v.Payload = nil 46 | return v, nil 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /gtpv2/message/delete-bearer-command_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestDeleteBearerCommand(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewDeleteBearerCommand( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewBearerContext(ie.NewEPSBearerID(5), ie.NewDelayValue(500*time.Millisecond), ie.NewDelayValue(100*time.Millisecond)), 23 | ie.NewBearerContext(ie.NewEPSBearerID(6), ie.NewDelayValue(500*time.Millisecond), ie.NewDelayValue(100*time.Millisecond)), 24 | ), 25 | Serialized: []byte{ 26 | // Header 27 | 0x48, 0x42, 0x00, 0x2e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 28 | // BearerContexts 1 29 | 0x5d, 0x00, 0x0f, 0x00, 30 | 0x49, 0x00, 0x01, 0x00, 0x05, 31 | 0x5c, 0x00, 0x01, 0x00, 0x0a, 32 | 0x5c, 0x00, 0x01, 0x00, 0x02, 33 | // BearerContexts 2 34 | 0x5d, 0x00, 0x0f, 0x00, 35 | 0x49, 0x00, 0x01, 0x00, 0x06, 36 | 0x5c, 0x00, 0x01, 0x00, 0x0a, 37 | 0x5c, 0x00, 0x01, 0x00, 0x02, 38 | }, 39 | }, 40 | } 41 | 42 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 43 | v, err := message.ParseDeleteBearerCommand(b) 44 | if err != nil { 45 | return nil, err 46 | } 47 | v.Payload = nil 48 | return v, nil 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /gtpv2/message/delete-pdn-connection-set-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/ie" 11 | "github.com/wmnsk/go-gtp/gtpv2/message" 12 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 13 | ) 14 | 15 | func TestDeletePDNConnectionSetRequest(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewDeletePDNConnectionSetRequest( 20 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 21 | ie.NewFullyQualifiedCSID("1.1.1.1", 1), 22 | ie.NewFullyQualifiedCSID("1.1.1.1", 1).WithInstance(4), 23 | ), 24 | Serialized: []byte{ 25 | // Header 26 | 0x48, 0x65, 0x00, 0x1e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 27 | // MME-FQ-CSID 28 | 0x84, 0x00, 0x07, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 29 | // TWAN-FQ-CSID 30 | 0x84, 0x00, 0x07, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 31 | }, 32 | }, 33 | } 34 | 35 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 36 | v, err := message.ParseDeletePDNConnectionSetRequest(b) 37 | if err != nil { 38 | return nil, err 39 | } 40 | v.Payload = nil 41 | return v, nil 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /gtpv2/message/delete-pdn-connection-set-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestDeletePDNConnectionSetResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewDeletePDNConnectionSetResponse( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ie.NewRecovery(0xff), 24 | ), 25 | Serialized: []byte{ 26 | // Header 27 | 0x48, 0x66, 0x00, 0x13, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 28 | // Cause 29 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 30 | // Recovery 31 | 0x03, 0x00, 0x01, 0x00, 0xff, 32 | }, 33 | }, 34 | } 35 | 36 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 37 | v, err := message.ParseDeletePDNConnectionSetResponse(b) 38 | if err != nil { 39 | return nil, err 40 | } 41 | v.Payload = nil 42 | return v, nil 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /gtpv2/message/delete-session-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestDeleteSessionResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal/CauseOnly", 20 | Structured: message.NewDeleteSessionResponse( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ), 24 | Serialized: []byte{ 25 | // Header 26 | 0x48, 0x25, 0x00, 0x0e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 27 | // Cause 28 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 29 | }, 30 | }, 31 | } 32 | 33 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 34 | v, err := message.ParseDeleteSessionResponse(b) 35 | if err != nil { 36 | return nil, err 37 | } 38 | v.Payload = nil 39 | return v, nil 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /gtpv2/message/detach-acknowledge_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestDetachAcknowledge(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewDetachAcknowledge( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ie.NewRecovery(0xff), 24 | ), 25 | Serialized: []byte{ 26 | // Header 27 | 0x48, 0x96, 0x00, 0x13, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 28 | // Cause 29 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 30 | // Recovery 31 | 0x03, 0x00, 0x01, 0x00, 0xff, 32 | }, 33 | }, 34 | } 35 | 36 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 37 | v, err := message.ParseDetachAcknowledge(b) 38 | if err != nil { 39 | return nil, err 40 | } 41 | v.Payload = nil 42 | return v, nil 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /gtpv2/message/detach-notification_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestDetachNotification(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewDetachNotification( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ie.NewDetachType(gtpv2.DetachTypePS), 24 | ), 25 | Serialized: []byte{ 26 | // Header 27 | 0x48, 0x95, 0x00, 0x13, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 28 | // Cause 29 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 30 | // Detach Type 31 | 0x96, 0x00, 0x01, 0x00, 0x01, 32 | }, 33 | }, 34 | } 35 | 36 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 37 | v, err := message.ParseDetachNotification(b) 38 | if err != nil { 39 | return nil, err 40 | } 41 | v.Payload = nil 42 | return v, nil 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /gtpv2/message/downlink-data-notification-failure-indication_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestDownlinkDataNotificationFailureIndication(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewDownlinkDataNotificationFailureIndication( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ie.NewNodeType(gtpv2.NodeTypeMME), 24 | ie.NewIMSI("123451234567890"), 25 | ), 26 | Serialized: []byte{ 27 | // Header 28 | 0x48, 0x46, 0x00, 0x1f, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 29 | // Cause 30 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 31 | // NodeType 32 | 0x87, 0x00, 0x01, 0x00, 0x01, 33 | // IMSI 34 | 0x01, 0x00, 0x08, 0x00, 0x21, 0x43, 0x15, 0x32, 0x54, 0x76, 0x98, 0xf0, 35 | }, 36 | }, 37 | } 38 | 39 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 40 | v, err := message.ParseDownlinkDataNotificationFailureIndication(b) 41 | if err != nil { 42 | return nil, err 43 | } 44 | v.Payload = nil 45 | return v, nil 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/message/echo-req_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes EchoRequest into bytes. 10 | // 11 | // Deprecated: use EchoRequest.Marshal instead. 12 | func (e *EchoRequest) Serialize() ([]byte, error) { 13 | log.Println("EchoRequest.Serialize is deprecated. use EchoRequest.Marshal instead") 14 | return e.Marshal() 15 | } 16 | 17 | // SerializeTo serializes EchoRequest into bytes given as b. 18 | // 19 | // Deprecated: use EchoRequest.MarshalTo instead. 20 | func (e *EchoRequest) SerializeTo(b []byte) error { 21 | log.Println("EchoRequest.SerializeTo is deprecated. use EchoRequest.MarshalTo instead") 22 | return e.MarshalTo(b) 23 | } 24 | 25 | // DecodeEchoRequest decodes bytes as EchoRequest. 26 | // 27 | // Deprecated: use ParseEchoRequest instead. 28 | func DecodeEchoRequest(b []byte) (*EchoRequest, error) { 29 | log.Println("DecodeEchoRequest is deprecated. use ParseEchoRequest instead") 30 | return ParseEchoRequest(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as EchoRequest. 34 | // 35 | // Deprecated: use EchoRequest.UnmarshalBinary instead. 36 | func (e *EchoRequest) DecodeFromBytes(b []byte) error { 37 | log.Println("EchoRequest.DecodeFromBytes is deprecated. use EchoRequest.UnmarshalBinary instead") 38 | return e.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of EchoRequest. 42 | // 43 | // Deprecated: use EchoRequest.MarshalLen instead. 44 | func (e *EchoRequest) Len() int { 45 | log.Println("EchoRequest.Len is deprecated. use EchoRequest.MarshalLen instead") 46 | return e.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/message/echo-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/ie" 11 | "github.com/wmnsk/go-gtp/gtpv2/message" 12 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 13 | ) 14 | 15 | func TestEchoRequest(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewEchoRequest( 20 | 0, 21 | ie.NewRecovery(0x80), 22 | ie.NewNodeFeatures(0x01), 23 | ), 24 | Serialized: []byte{ 25 | 0x40, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 26 | // Recovery 27 | 0x03, 0x00, 0x01, 0x00, 0x80, 28 | // Node Features 29 | 0x98, 0x00, 0x01, 0x00, 0x01, 30 | }, 31 | }, 32 | } 33 | 34 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 35 | v, err := message.ParseEchoRequest(b) 36 | if err != nil { 37 | return nil, err 38 | } 39 | v.Payload = nil 40 | return v, nil 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /gtpv2/message/echo-res_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes EchoResponse into bytes. 10 | // 11 | // Deprecated: use EchoResponse.Marshal instead. 12 | func (e *EchoResponse) Serialize() ([]byte, error) { 13 | log.Println("EchoResponse.Serialize is deprecated. use EchoResponse.Marshal instead") 14 | return e.Marshal() 15 | } 16 | 17 | // SerializeTo serializes EchoResponse into bytes given as b. 18 | // 19 | // Deprecated: use EchoResponse.MarshalTo instead. 20 | func (e *EchoResponse) SerializeTo(b []byte) error { 21 | log.Println("EchoResponse.SerializeTo is deprecated. use EchoResponse.MarshalTo instead") 22 | return e.MarshalTo(b) 23 | } 24 | 25 | // DecodeEchoResponse decodes bytes as EchoResponse. 26 | // 27 | // Deprecated: use ParseEchoResponse instead. 28 | func DecodeEchoResponse(b []byte) (*EchoResponse, error) { 29 | log.Println("DecodeEchoResponse is deprecated. use ParseEchoResponse instead") 30 | return ParseEchoResponse(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as EchoResponse. 34 | // 35 | // Deprecated: use EchoResponse.UnmarshalBinary instead. 36 | func (e *EchoResponse) DecodeFromBytes(b []byte) error { 37 | log.Println("EchoResponse.DecodeFromBytes is deprecated. use EchoResponse.UnmarshalBinary instead") 38 | return e.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of EchoResponse. 42 | // 43 | // Deprecated: use EchoResponse.MarshalLen instead. 44 | func (e *EchoResponse) Len() int { 45 | log.Println("EchoResponse.Len is deprecated. use EchoResponse.MarshalLen instead") 46 | return e.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/message/echo-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/ie" 11 | "github.com/wmnsk/go-gtp/gtpv2/message" 12 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 13 | ) 14 | 15 | func TestEchoResponse(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewEchoResponse( 20 | 0, 21 | ie.NewRecovery(0x80), 22 | ie.NewNodeFeatures(0x01), 23 | ), 24 | Serialized: []byte{ 25 | 0x40, 0x02, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 26 | // Recovery 27 | 0x03, 0x00, 0x01, 0x00, 0x80, 28 | // Node Features 29 | 0x98, 0x00, 0x01, 0x00, 0x01, 30 | }, 31 | }, 32 | } 33 | 34 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 35 | v, err := message.ParseEchoResponse(b) 36 | if err != nil { 37 | return nil, err 38 | } 39 | v.Payload = nil 40 | return v, nil 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /gtpv2/message/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "errors" 8 | 9 | // Error definitions. 10 | var ( 11 | ErrInvalidLength = errors.New("length value is invalid") 12 | ErrTooShortToParse = errors.New("too short to decode as GTP") 13 | ) 14 | -------------------------------------------------------------------------------- /gtpv2/message/generic_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Generic into bytes. 10 | // 11 | // Deprecated: use Generic.Marshal instead. 12 | func (g *Generic) Serialize() ([]byte, error) { 13 | log.Println("Generic.Serialize is deprecated. use Generic.Marshal instead") 14 | return g.Marshal() 15 | } 16 | 17 | // SerializeTo serializes Generic into bytes given as b. 18 | // 19 | // Deprecated: use Generic.MarshalTo instead. 20 | func (g *Generic) SerializeTo(b []byte) error { 21 | log.Println("Generic.SerializeTo is deprecated. use Generic.MarshalTo instead") 22 | return g.MarshalTo(b) 23 | } 24 | 25 | // DecodeGeneric decodes bytes as Generic. 26 | // 27 | // Deprecated: use ParseGeneric instead. 28 | func DecodeGeneric(b []byte) (*Generic, error) { 29 | log.Println("DecodeGeneric is deprecated. use ParseGeneric instead") 30 | return ParseGeneric(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as Generic. 34 | // 35 | // Deprecated: use Generic.UnmarshalBinary instead. 36 | func (g *Generic) DecodeFromBytes(b []byte) error { 37 | log.Println("Generic.DecodeFromBytes is deprecated. use Generic.UnmarshalBinary instead") 38 | return g.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of Generic. 42 | // 43 | // Deprecated: use Generic.MarshalLen instead. 44 | func (g *Generic) Len() int { 45 | log.Println("Generic.Len is deprecated. use Generic.MarshalLen instead") 46 | return g.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/message/generic_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/ie" 11 | "github.com/wmnsk/go-gtp/gtpv2/message" 12 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 13 | ) 14 | 15 | func TestGeneric(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewGeneric( 20 | message.MsgTypeEchoRequest, 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewRecovery(0x80), 23 | ), 24 | Serialized: []byte{ 25 | 0x48, 0x01, 0x00, 0x0d, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 26 | 0x80, 27 | }, 28 | }, { 29 | Description: "No-TEID", 30 | Structured: message.NewGeneric( 31 | message.MsgTypeEchoRequest, 32 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 33 | ie.NewRecovery(0x80), 34 | ), 35 | Serialized: []byte{ 36 | 0x48, 0x01, 0x00, 0x0d, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 37 | 0x80, 38 | }, 39 | }, 40 | } 41 | 42 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 43 | v, err := message.ParseGeneric(b) 44 | if err != nil { 45 | return nil, err 46 | } 47 | v.Payload = nil 48 | return v, nil 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /gtpv2/message/header_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Header into bytes. 10 | // 11 | // Deprecated: use Header.Marshal instead. 12 | func (h *Header) Serialize() ([]byte, error) { 13 | log.Println("Header.Serialize is deprecated. use Header.Marshal instead") 14 | return h.Marshal() 15 | } 16 | 17 | // SerializeTo serializes Header into bytes given as b. 18 | // 19 | // Deprecated: use Header.MarshalTo instead. 20 | func (h *Header) SerializeTo(b []byte) error { 21 | log.Println("Header.SerializeTo is deprecated. use Header.MarshalTo instead") 22 | return h.MarshalTo(b) 23 | } 24 | 25 | // DecodeHeader decodes bytes as Header. 26 | // 27 | // Deprecated: use ParseHeader instead. 28 | func DecodeHeader(b []byte) (*Header, error) { 29 | log.Println("DecodeHeader is deprecated. use ParseHeader instead") 30 | return ParseHeader(b) 31 | } 32 | 33 | // DecodeFromBytes decodes bytes as Header. 34 | // 35 | // Deprecated: use Header.UnmarshalBinary instead. 36 | func (h *Header) DecodeFromBytes(b []byte) error { 37 | log.Println("Header.DecodeFromBytes is deprecated. use Header.UnmarshalBinary instead") 38 | return h.UnmarshalBinary(b) 39 | } 40 | 41 | // Len returns the actual length of Header. 42 | // 43 | // Deprecated: use Header.MarshalLen instead. 44 | func (h *Header) Len() int { 45 | log.Println("Header.Len is deprecated. use Header.MarshalLen instead") 46 | return h.MarshalLen() 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/message/header_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/message" 11 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 12 | ) 13 | 14 | func TestHeader(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "Normal", 18 | Structured: message.NewHeader( 19 | message.NewHeaderFlags(2, 0, 1), 20 | 32, // Message type 21 | 0xffffffff, // TEID 22 | 0xdadada, // Sequence Number 23 | []byte{ // Payload: IMSI IE 24 | 0x01, 0x00, 0x08, 0x00, 0x21, 0x43, 0x15, 0x32, 0x54, 0x76, 0x98, 0xf0, 25 | }, 26 | ), 27 | Serialized: []byte{ 28 | 0x48, 0x20, 0x00, 0x14, 0xff, 0xff, 0xff, 0xff, 29 | 0xda, 0xda, 0xda, 0x00, 30 | 0x01, 0x00, 0x08, 0x00, 0x21, 0x43, 0x15, 0x32, 0x54, 0x76, 0x98, 0xf0, 31 | }, 32 | }, 33 | } 34 | 35 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 36 | v, err := message.ParseHeader(b) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return v, nil 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /gtpv2/message/message_deprecated.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message 6 | 7 | import "log" 8 | 9 | // Serialize serializes Message into bytes. 10 | // 11 | // Deprecated: use Marshal instead. 12 | func Serialize(m Message) ([]byte, error) { 13 | log.Println("Serialize is deprecated. use Marshal instead") 14 | return Marshal(m) 15 | } 16 | 17 | // Decode decodes bytes as Message. 18 | // 19 | // Deprecated: use Parse instead. 20 | func Decode(b []byte) (Message, error) { 21 | log.Println("Decode is deprecated. use Parse instead") 22 | return Parse(b) 23 | } 24 | -------------------------------------------------------------------------------- /gtpv2/message/message_fuzz_test.go: -------------------------------------------------------------------------------- 1 | //go:build go1.18 2 | 3 | package message_test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/wmnsk/go-gtp/gtpv2/message" 9 | ) 10 | 11 | func FuzzParse(f *testing.F) { 12 | testcases := [][]byte{ 13 | {0x10, 0x20, 0x30}, 14 | {0x48, 0x20, 0x00, 0x14, 0xff, 0xff, 0xff, 0xff, 0xda, 0xda, 0xda}, 15 | } 16 | for _, tc := range testcases { 17 | f.Add(tc) 18 | } 19 | 20 | f.Fuzz(func(t *testing.T, data []byte) { 21 | if v, err := message.Parse(data); err == nil && v == nil { 22 | t.Errorf("nil without error") 23 | } 24 | }) 25 | } 26 | 27 | func FuzzHeaderParse(f *testing.F) { 28 | f.Fuzz(func(t *testing.T, b []byte) { 29 | if _, err := message.ParseHeader(b); err != nil { 30 | t.Skip() 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /gtpv2/message/message_test.go: -------------------------------------------------------------------------------- 1 | package message_test 2 | 3 | import ( 4 | "net" 5 | ) 6 | 7 | var ( 8 | mac1, _ = net.ParseMAC("12:34:56:78:90:01") 9 | mac2, _ = net.ParseMAC("12:34:56:78:90:02") 10 | ) 11 | -------------------------------------------------------------------------------- /gtpv2/message/modify-bearer-command_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestModifyBearerCommand(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewModifyBearerCommand( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewAggregateMaximumBitRate(0x11111111, 0x22222222), 23 | ie.NewBearerContext(ie.NewDelayValue(500*time.Millisecond), ie.NewDelayValue(100*time.Millisecond)), 24 | ), 25 | Serialized: []byte{ 26 | // Header 27 | 0x48, 0x40, 0x00, 0x22, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 28 | // APN-AMBR 29 | 0x48, 0x00, 0x08, 0x00, 0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 30 | // BearerContext 31 | 0x5d, 0x00, 0x0a, 0x00, 0x5c, 0x00, 0x01, 0x00, 0x0a, 0x5c, 0x00, 0x01, 0x00, 0x02, 32 | }, 33 | }, 34 | } 35 | 36 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 37 | v, err := message.ParseModifyBearerCommand(b) 38 | if err != nil { 39 | return nil, err 40 | } 41 | v.Payload = nil 42 | return v, nil 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /gtpv2/message/modify-bearer-failure-indication_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestModifyBearerFailureIndication(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewModifyBearerFailureIndication( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ), 24 | Serialized: []byte{ 25 | // Header 26 | 0x48, 0x41, 0x00, 0x0e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 27 | // Cause 28 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 29 | }, 30 | }, 31 | } 32 | 33 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 34 | v, err := message.ParseModifyBearerFailureIndication(b) 35 | if err != nil { 36 | return nil, err 37 | } 38 | v.Payload = nil 39 | return v, nil 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /gtpv2/message/pgw-restart-notification-acknowledge_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestPGWRestartNotificationAcknowledge(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewPGWRestartNotificationAcknowledge( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CausePGWNotResponding, 0, 0, 0, nil), 23 | ), 24 | Serialized: []byte{ 25 | // Header 26 | 0x48, 0xb4, 0x00, 0x0e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 27 | // Cause 28 | 0x02, 0x00, 0x02, 0x00, 0x0c, 0x00, 29 | }, 30 | }, 31 | } 32 | 33 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 34 | v, err := message.ParsePGWRestartNotificationAcknowledge(b) 35 | if err != nil { 36 | return nil, err 37 | } 38 | v.Payload = nil 39 | return v, nil 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /gtpv2/message/pgw-restart-notification_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestPGWRestartNotification(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewPGWRestartNotification( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewIPAddress("1.1.1.1"), 23 | ie.NewIPAddress("1.1.1.1").WithInstance(1), 24 | ie.NewCause(gtpv2.CausePGWNotResponding, 0, 0, 0, nil), 25 | ), 26 | Serialized: []byte{ 27 | // Header 28 | 0x48, 0xb3, 0x00, 0x1e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 29 | // P-GW IP 30 | 0x4a, 0x00, 0x04, 0x00, 0x01, 0x01, 0x01, 0x01, 31 | // S-GW IP 32 | 0x4a, 0x00, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 33 | // Cause 34 | 0x02, 0x00, 0x02, 0x00, 0x0c, 0x00, 35 | }, 36 | }, 37 | } 38 | 39 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 40 | v, err := message.ParsePGWRestartNotification(b) 41 | if err != nil { 42 | return nil, err 43 | } 44 | v.Payload = nil 45 | return v, nil 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/message/release-access-bearers-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestReleaseAccessBearersResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal/CauseOnly", 20 | Structured: message.NewReleaseAccessBearersResponse( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ), 24 | Serialized: []byte{ 25 | // Header 26 | 0x48, 0xab, 0x00, 0x0e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 27 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 28 | }, 29 | }, 30 | } 31 | 32 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 33 | v, err := message.ParseReleaseAccessBearersResponse(b) 34 | if err != nil { 35 | return nil, err 36 | } 37 | v.Payload = nil 38 | return v, nil 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /gtpv2/message/resume-notification_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestResumeNotification(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewResumeNotification( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewIMSI("123451234567890"), 23 | ie.NewEPSBearerID(5), 24 | ie.NewNodeType(gtpv2.NodeTypeMME), 25 | ie.NewFullyQualifiedTEID(gtpv2.IFTypeS10MMEGTPC, 0xffffffff, "1.1.1.1", ""), 26 | ie.NewPrivateExtension(256, []byte{4, 5, 6, 7}), 27 | ), 28 | Serialized: []byte{ 29 | // Header 30 | 0x48, 164, 0x00, 53, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 31 | // IMSI 32 | 0x01, 0x00, 0x08, 0x00, 0x21, 0x43, 0x15, 0x32, 0x54, 0x76, 0x98, 0xf0, 33 | // EPSBearerID 34 | 0x49, 0x00, 0x01, 0x00, 0x05, 35 | // NodeType 36 | 0x87, 0x00, 0x01, 0x00, 0x01, 37 | // FullyQualifiedTEID 38 | 0x57, 0x00, 0x09, 0x00, 0x8c, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 39 | // PrivateExtension 40 | 0xff, 0x00, 0x06, 0x00, 1, 0, 4, 5, 6, 7, 41 | }, 42 | }, 43 | } 44 | 45 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 46 | v, err := message.ParseResumeNotification(b) 47 | if err != nil { 48 | return nil, err 49 | } 50 | v.Payload = nil 51 | return v, nil 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /gtpv2/message/stop-paging-indication_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/ie" 11 | "github.com/wmnsk/go-gtp/gtpv2/message" 12 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 13 | ) 14 | 15 | func TestStopPagingIndication(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal/CauseOnly", 19 | Structured: message.NewStopPagingIndication( 20 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 21 | ie.NewIMSI("123451234567890"), 22 | ), 23 | Serialized: []byte{ 24 | // Header 25 | 0x48, 0x49, 0x00, 0x14, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 26 | // IMSI 27 | 0x01, 0x00, 0x08, 0x00, 0x21, 0x43, 0x15, 0x32, 0x54, 0x76, 0x98, 0xf0, 28 | }, 29 | }, 30 | } 31 | 32 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 33 | v, err := message.ParseStopPagingIndication(b) 34 | if err != nil { 35 | return nil, err 36 | } 37 | v.Payload = nil 38 | return v, nil 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /gtpv2/message/update-pdn-connection-set-req_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/ie" 11 | "github.com/wmnsk/go-gtp/gtpv2/message" 12 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 13 | ) 14 | 15 | func TestUpdatePDNConnectionSetRequest(t *testing.T) { 16 | cases := []testutils.TestCase{ 17 | { 18 | Description: "Normal", 19 | Structured: message.NewUpdatePDNConnectionSetRequest( 20 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 21 | ie.NewFullyQualifiedCSID("1.1.1.1", 1), 22 | ie.NewFullyQualifiedCSID("1.1.1.1", 1).WithInstance(1), 23 | ), 24 | Serialized: []byte{ 25 | // Header 26 | 0x48, 0xc8, 0x00, 0x1e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 27 | // MME-FQ-CSID 28 | 0x84, 0x00, 0x07, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 29 | // SGW-FQ-CSID 30 | 0x84, 0x00, 0x07, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 31 | }, 32 | }, 33 | } 34 | 35 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 36 | v, err := message.ParseUpdatePDNConnectionSetRequest(b) 37 | if err != nil { 38 | return nil, err 39 | } 40 | v.Payload = nil 41 | return v, nil 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /gtpv2/message/update-pdn-connection-set-res_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2" 11 | "github.com/wmnsk/go-gtp/gtpv2/ie" 12 | "github.com/wmnsk/go-gtp/gtpv2/message" 13 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 14 | ) 15 | 16 | func TestUpdatePDNConnectionSetResponse(t *testing.T) { 17 | cases := []testutils.TestCase{ 18 | { 19 | Description: "Normal", 20 | Structured: message.NewUpdatePDNConnectionSetResponse( 21 | testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq, 22 | ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil), 23 | ie.NewFullyQualifiedCSID("1.1.1.1", 1), 24 | ie.NewRecovery(0xff), 25 | ), 26 | Serialized: []byte{ 27 | // Header 28 | 0x48, 0xc9, 0x00, 0x1e, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 29 | // Cause 30 | 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 31 | // PGW-FQ-CSID 32 | 0x84, 0x00, 0x07, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 33 | // Recovery 34 | 0x03, 0x00, 0x01, 0x00, 0xff, 35 | }, 36 | }, 37 | } 38 | 39 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 40 | v, err := message.ParseUpdatePDNConnectionSetResponse(b) 41 | if err != nil { 42 | return nil, err 43 | } 44 | v.Payload = nil 45 | return v, nil 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /gtpv2/message/version-not-supported_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 go-gtp authors. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package message_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/wmnsk/go-gtp/gtpv2/message" 11 | "github.com/wmnsk/go-gtp/gtpv2/testutils" 12 | ) 13 | 14 | func TestVersionNotSupportedIndication(t *testing.T) { 15 | cases := []testutils.TestCase{ 16 | { 17 | Description: "Normal/CauseOnly", 18 | Structured: message.NewVersionNotSupportedIndication(testutils.TestBearerInfo.TEID, testutils.TestBearerInfo.Seq), 19 | Serialized: []byte{ 20 | // Header 21 | 0x48, 0x03, 0x00, 0x08, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x01, 0x00, 22 | }, 23 | }, 24 | } 25 | 26 | testutils.Run(t, cases, func(b []byte) (testutils.Serializable, error) { 27 | v, err := message.ParseVersionNotSupportedIndication(b) 28 | if err != nil { 29 | return nil, err 30 | } 31 | v.Payload = nil 32 | return v, nil 33 | }) 34 | } 35 | --------------------------------------------------------------------------------