Full Code of wmnsk/go-gtp for AI

main ecfdc3370199 cached
435 files
1.5 MB
483.9k tokens
3940 symbols
1 requests
Download .txt
Showing preview only (1,609K chars total). Download the full file or copy to clipboard to get everything.
Repository: wmnsk/go-gtp
Branch: main
Commit: ecfdc3370199
Files: 435
Total size: 1.5 MB

Directory structure:
gitextract_o6tx7vdp/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── go.yml
│       └── golangci-lint.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── README.md
├── doc.go
├── errors.go
├── examples/
│   ├── gw-tester/
│   │   ├── README.md
│   │   ├── 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

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: gomod
  directory: "/"
  schedule:
    interval: daily
    time: "20:00"
  open-pull-requests-limit: 10


================================================
FILE: .github/workflows/go.yml
================================================
on: [push, pull_request]
name: Test
jobs:
  test-linux:
    strategy:
      matrix:
        go-version: [1.25.x, 1.26.x]
    runs-on: ubuntu-latest
    steps:
      - name: Install Go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ matrix.go-version }}
      - name: Checkout code
        uses: actions/checkout@v1
      - name: Run unit tests
        run: go test ./...
      - name: Run benchmark
        run: go test -benchmem -bench . ./...
      - name: Build GW Tester
        run: |
          go build -o sgw examples/gw-tester/sgw/*.go
          go build -o pgw examples/gw-tester/pgw/*.go
          go build -o mme examples/gw-tester/mme/*.go
          go build -o enb examples/gw-tester/enb/*.go
      - name: Run GW Tester
        run: |
          sudo ./sgw -config examples/gw-tester/sgw/sgw.yml &
          sleep 1
          sudo ./pgw -config examples/gw-tester/pgw/pgw.yml &
          sleep 1
          sudo ./mme -config examples/gw-tester/mme/mme.yml &
          sleep 1
          sudo ./enb -config examples/gw-tester/enb/enb.yml &
          sleep 1
      - name: Verify GW Tester is working
        run: |
          ENB=$(curl -sS http://127.0.10.1:58080/metrics)
          [ "$(echo "$ENB" | grep "enb_active_sessions [0-9]" | awk '{print $NF}' )" == 5 ] || exit 101
          MME=$(curl -sS http://127.0.10.2:58080/metrics)
          [ "$(echo "$MME" | grep "mme_active_sessions [0-9]" | awk '{print $NF}' )" == 5 ] || exit 101
          SGW=$(curl -sS http://127.0.10.3:58080/metrics)
          [ "$(echo "$SGW" | grep "sgw_active_sessions [0-9]" | awk '{print $NF}' )" == 5 ] || exit 101
          PGW=$(curl -sS http://127.0.10.4:58080/metrics)
          [ "$(echo "$PGW" | grep "pgw_active_sessions [0-9]" | awk '{print $NF}' )" == 5 ] || exit 101
  test-macos:
    strategy:
      matrix:
        go-version: [1.25.x, 1.26.x]
    runs-on: macos-latest
    steps:
      - name: Install Go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ matrix.go-version }}
      - name: Checkout code
        uses: actions/checkout@v1
      - name: Setup loopback interface for tests
        run: |
          sudo ifconfig lo0 alias 127.0.0.2
          sudo ifconfig lo0 alias 127.0.0.11
          sudo ifconfig lo0 alias 127.0.0.12
      - name: Test
        run: go test $(go list ./... | grep -v '/examples')
      - name: Bench
        run: go test -benchmem -bench . $(go list ./... | grep -v '/examples')
  # test-windows:
  #   strategy:
  #     matrix:
  #       go-version: [1.25.x, 1.26.x]
  #   runs-on: windows-latest
  #   steps:
  #   - name: Install Go
  #     uses: actions/setup-go@v5
  #     with:
  #       go-version: ${{ matrix.go-version }}
  #   - name: Checkout code
  #     uses: actions/checkout@v1
  #   - name: Test
  #     run: go test ./...
  #   - name: Bench
  #     run: go test -benchmem -bench . ./...


================================================
FILE: .github/workflows/golangci-lint.yml
================================================
name: golangci-lint
on:
  push:
    tags:
      - v*
    branches:
      - main
  pull_request:
jobs:
  golangci:
    name: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-go@v6
        with:
          go-version-file: 'go.mod'
          cache: true
      - name: golangci-lint
        uses: golangci/golangci-lint-action@v9
        with:
          version: latest


================================================
FILE: .gitignore
================================================
examples/mme/mme
examples/pgw/pgw
examples/sgw/sgw
examples/gw-tester/enb/enb
examples/gw-tester/pgw/pgw
examples/gw-tester/sgw/sgw
examples/gw-tester/mme/mme

**/testdata/


================================================
FILE: .golangci.yml
================================================
version: "2"
run:
  issues-exit-code: 1
  tests: false
linters:
  default: none
  enable:
    - asciicheck
    - bodyclose
    - dogsled
    - errcheck
    - errorlint
    - goconst
    - gocritic
    - gomodguard
    - goprintffuncname
    - gosec
    - govet
    - ineffassign
    - misspell
    - nakedret
    - prealloc
    - rowserrcheck
    - staticcheck
    - unconvert
    - unparam
    - unused
  settings:
    gosec:
      excludes:
        - G115
  exclusions:
    generated: lax
    presets:
      - comments
      - common-false-positives
      - legacy
      - std-error-handling
    paths:
      - third_party$
      - builtin$
      - examples$
issues:
  max-issues-per-linter: 4095
  max-same-issues: 1023
  new: true
formatters:
  enable:
    - gofmt
    - goimports
  exclusions:
    generated: lax
    paths:
      - third_party$
      - builtin$
      - examples$


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019-2025 Yoshiyuki Kurauchi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# go-gtp: GTP in Go

Package gtp provides simple and painless handling of GTP (GPRS Tunneling Protocol) in the Go programming language.

![CI status](https://github.com/wmnsk/go-gtp/actions/workflows/go.yml/badge.svg)
[![golangci-lint](https://github.com/wmnsk/go-gtp/actions/workflows/golangci-lint.yml/badge.svg)](https://github.com/wmnsk/go-gtp/actions/workflows/golangci-lint.yml)
[![Go Reference](https://pkg.go.dev/badge/github.com/wmnsk/go-gtp.svg)](https://pkg.go.dev/github.com/wmnsk/go-gtp)
[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/wmnsk/go-gtp/blob/main/LICENSE)

## Project Status

This project is still EXPERIMENTAL.  
Any part of the implementations (including exported APIs) may be changed before released as v1.0.0.

## Features

* Flexible enough to control everything in the GTP protocol, making it suitable for developing mobile core network nodes or testing tools for them.
* Provides many helpers that are kind to developers, such as session, bearer, and TEID management.
* Makes it easy to handle multiple connections with fixed IP and Port with UDP (or other `net.PacketConn`).
* Currently works only on Linux and macOS since netlink support is introduced. However, the plan is to make it work on Windows in the future.

## Getting Started

### Prerequisites

go-gtp supports Go Modules. Run `go mod tidy` in your project's directory to collect the required packages automatically.

```
go mod tidy
```

_This project follows [the Release Policy of Go](https://golang.org/doc/devel/release.html#policy)._

### Running examples

#### End-to-end

We have a set of tools called GW Tester at [`examples/gw-tester`](./examples/gw-tester). See the [document](./examples/gw-tester/README.md) for how it works and how to run it. It is also used for the integration test of this project. [Workflow setting](./.github/workflows/go.yml) may help you understand it as well.

#### Individual node

[The examples](examples/) work as it is by `go build` and executing commands in the following way.

*Note for macOS users*: before running any go service, make sure to execute `./mac_local_host_enabler.sh` you will find at [examples/utils](examples/utils).

1. Open four terminals on a machine and start capturing on the loopback interface.

2. Start P-GW on terminal #1 and #2
```shell-session
// on terminal #1
./pgw

// on terminal #2
./pgw -s5c 127.0.0.53 -s5u 127.0.0.5
```

3. Start S-GW on terminal #3

```shell-session
// on terminal #3
./sgw
```

4. Start MME on terminal #4

```shell-session
// on terminal #4
./mme
```

5. You will see the nodes exchanging Create Session and Modify Bearer on C-Plane, and ICMP Echo on U-Plane afterwards.

_The "mme" is not an MME per se. In addition to S11 interface, it also mocks UEs and an eNB to establish sessions and send packets on U-Plane._

## Developing with go-gtp

This section briefly describes how to develop your own GTP node with go-gtp.
For the detailed usage of a specific version, see README.md under each version's directory.

| Version | Details                      |
| ------- | ---------------------------- |
| GTPv0   | [README.md](gtpv0/README.md) |
| GTPv1   | [README.md](gtpv1/README.md) |
| GTPv2   | [README.md](gtpv2/README.md) |

### Establishing a connection between nodes

Each version has `net.PacketConn`-like APIs and GTP-specific ones, which are often version-specific.
The basic idea behind the current implementation is;

* `Dial` or `ListenAndServe` to create a connection (`Conn`) between nodes.
* Register handlers to the `Conn` for specific messages with `AddHandler`, allowing users to handle the messages coming from the remote endpoint as flexible as possible, with less pain.
* `CreateXXX` to create session or PDP context with arbitrary IEs given. Session/PDP context is structured, and they also have some helpers like `AddTEID` to handle known TEID properly.

### Handling messages and IEs

#### Messages

All the messages implement the same interface: `message.Message`, and have their own structs named `<MessageName>`, which can be created by `New<MessageName>` with given `ie.IE`s. `message.Message` can be sent on top of `Conn` with `SendMessageTo`, or can be serialized into `[]byte` with `Marshal`.

To parse the message from `[]byte`, use `message.Parse`. The parsed message will be one of the structs that implement `message.Message`, and you can type-assert it to the corresponding struct to access the fields which are a set of `ie.IE`s.

#### IEs

All the IEs are of the same type: `ie.IE` (not an interface). An IE can be created either with `New<IEName>`, with `ie.New`, or with `ie.New<TypeIE>`. The latter two are useful when you want to create an IE with an unsupported type or our constructor does not work well for you.

To parse the IE from `[]byte`, use `ie.Parse` (note that `message.Parse` parses all the IEs on a message - you don't need to call `ie.Parse` when you're handling IEs on a message). The value of the parsed `ie.IE` can be retrieved with `<IEName>`, `ValueAs<IEType>`. Some of the complicated IEs have their own struct named `<IEName>Fields` to get the values by accessing the fields.

For grouped IEs, accesing the `ChildIEs` field and iterating over the list of IEs contained is the most efficient way in most cases. Though there are the methods to get the specific IE value from the list (e.g., `BearerFlags` can be called upon `BearerContext` IE), they are not recommended since they always parse the whole list of IEs again.

## Supported Features

Note that "supported" means that the package provides helpers that make it easier to handle.
In other words, even if a message/IE is not marked as "Yes", you can make it work with some additional effort.

Your contribution is welcome to implement helpers for all the types, of course!

| Version           | Messages | IEs  | Networking (state machine)                  | Details                                                  |
| ----------------- | -------- | ---- | ------------------------------------------- | -------------------------------------------------------- |
| GTPv0             | ~35%     | ~80% | not implemented yet                         | [gtpv0/README](gtpv0/README.md#supported-features) |
| GTPv1             | ~25%     | ~30% | v1-U: functional <br> v1-C: not implemented | [gtpv1/README](gtpv1/README.md#supported-features) |
| GTPv2             | ~40.0%   | ~45% | functional                                  | [gtpv2/README](gtpv2/README.md#supported-features) |
| GTP' <br> (Prime) | N/A      | N/A  | N/A                                         | _not planned_                                            |

_You may also be interested in the sibling project [go-pfcp](https://github.com/wmnsk/go-pfcp) which is a PFCP implementation in Go._

## Contributing

With the design goal of being flexible and easy to use, go-gtp is still in the early stage of development. Any contribution is welcome! Please feel free to open an issue or a pull request.

Please don't forget to run tests once you are done with your changes. Additionally, running the fuzz test is recommended to make sure that the implementation is robust enough.

```shell-session
go test ./...
go test -fuzz .
```

*Note for macOS users*: the first time you run any test, make sure to execute `./mac_local_host_enabler.sh` you will find at [examples/utils](examples/utils). You will have to run the script again after each reboot.

## Authors

[Yoshiyuki Kurauchi](https://wmnsk.com/) and [contributors](https://github.com/wmnsk/go-gtp/graphs/contributors).

## LICENSE

[MIT](https://github.com/wmnsk/go-gtp/blob/main/LICENSE)


================================================
FILE: doc.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Package gtp provides simple and painless handling of GTP (GPRS Tunneling Protocol).
//
// This package is the wrapper for all versions of GTP.  Please see the godocs of each version instead.
//
// GTPv0: https://pkg.go.dev/github.com/wmnsk/go-gtp/v0
//
// GTPv1: https://pkg.go.dev/github.com/wmnsk/go-gtp/v1
//
// GTPv2: https://pkg.go.dev/github.com/wmnsk/go-gtp/v2
//
// Please also see README.md for detailed usage of the APIs provided by this package,
// as well as how to run the examples.
//
// https://github.com/wmnsk/go-gtp/blob/main/README.md
//
// https://github.com/wmnsk/go-gtp/tree/main/examples/gw-tester
package gtp


================================================
FILE: errors.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package gtp

import "errors"

// Common error definitions.
var (
	ErrInvalidVersion    = errors.New("got invalid version")
	ErrInvalidLength     = errors.New("length value is invalid")
	ErrTooShortToParse   = errors.New("too short to decode as GTP")
	ErrTooShortToMarshal = errors.New("too short to serialize")
)


================================================
FILE: examples/gw-tester/README.md
================================================
# GW Tester

A pseudo eNB and MME as a tester for S/P-GW.

## What's this?

![diagram](./docs/diagram.png)

It is a burden to use actual UE/eNB/MME just to test S/P-GW, isn't it?  
GW Tester emulates the minimal required behavior of surrounding nodes to perform quick and simple testing on S/P-GW.

A blog post by the author is available [here](https://wmnsk.com/posts/20200116_gw-tester/) for those who are interested in :)  
_NOTE: Some of the blog post's configurations or codes might be no longer relevant in the current version._

## How it works

### Authentication

Nothing!  
Subscribers defined in the `enb.yml` file can immediately attach and use the created sessions. MME accepts any subscribers without an authentication procedure.
Communication over the S1-MME interface is done with protobuf/gRPC instead of the S1AP protocol.

```
=== AD ===
Looking for a Go package for LTE authentication?
MILENAGE algorithm implementation is available :)

https://github.com/wmnsk/milenage
```

### Gateway Selection

No DNS lookup by TAI/APN is implemented.
MME just chooses gateways according to the mapping of source IP ranges and GW's IPs defined in `mme.yml`. This behavior might be changed in the future.

### Session Establishment

MME exchanges the real GTPv2 session establishment messages like Create/Modify/Delete Session with S-GW.

* IP address assignment  
Currently, we use the IP address that is defined in `enb.yml`, and the one passed by P-GW is ignored. This behavior might be changed in the future to be more practical.

* TEID allocation  
It can be both static and dynamic. Random TEID will be allocated by enb if `i_tei` in `enb.yml` is set to `0`. For outgoing TEID, the one that S-GW allocates will be used.

### U-Plane Data Injection

eNB forwards incoming traffic from UE or generates traffic by itself depending on the `type` in `enb.yml`.
GTP-U feature is based on [Linux Kernel GTP-U](https://www.kernel.org/doc/Documentation/networking/gtp.txt) with netlink.

| type     | behavior                                                                                                        |
| -------- | --------------------------------------------------------------------------------------------------------------- |
| external | eNB encapsulates and forwards the incoming packets from `src_ip` toward the specified interface(`euu_if_name`). |
| http_get | eNB starts sending HTTP GET to the specified URL.                                                               |
| ...      | _(other types might be implemented in the future!)_                                                             |

## Getting Started

### Prerequisites

* Linux (kernel >= 4.12) with root privilege
* `net.ip_forward` enabled
* ports opened: 36412/TCP, 2123/UDP, 2152/UDP

### Run testers

Just `go get` eNB and MME.
Functional S-GW and P-GW are also available in the same directory if you need them.

```shell-session
go get github.com/wmnsk/go-gtp/examples/gw-tester/enb
go get github.com/wmnsk/go-gtp/examples/gw-tester/mme
```

And run them with YAML configuration. See [Configuration](#configurations) section for details.

```shell-session
./mme
```

```shell-session
./enb
```

Then you'll see;

* MME starts sending GTPv2 Create Session Request to S-GW after it receives subscriber information from eNB.
* When sessions are successfully created on S/P-GW, eNB sets up GTP-U tunnels with S-GW.

After the successful creation of the sessions, you can inject packets externally or generate them on eNB.

## Configurations

Each node has a YAML file as a configuration.  
In general, config consists of the network information of local/remote nodes and some node-specific parameters.

### eNB

#### Global

These values are used to identify eNB. Some of them are just to be set inside the packets and not validated.

| config           | type of value | description                                                       |
| ---------------- | ------------- | ----------------------------------------------------------------- |
| `mcc`            | string        | MCC of eNB                                                        |
| `mnc`            | string        | MNC of eNB                                                        |
| `rat_type`       | uint8         | RAT Type (`6` for E-UTRAN)                                        |
| `tai`            | uint16        | TAI of eNB                                                        |
| `eci`            | uint32        | ECI of eNB                                                        |
| `mme_addr`       | string        | IP/Port of MME to dial, for S1-MME interface                      |
| `use_kernel_gtp` | bool          | Use Kernel GTP or not. U-Plane does not work when set to `false`. |
| `prom_addr`      | string        | IP/Port of MME to serve Prometheus                                |

#### Local Addresses

`local_addresses` are the IP addresses/ports to be bound on the local machine.

| config   | type of value | description                   |
| -------- | ------------- | ----------------------------- |
| `s1c_ip` | string        | local IP for S1-MME interface |
| `s1u_ip` | string        | local IP for S1-U interface   |

#### Subscribers

`subscribers` are the list of subscribers to attach.

| config               | type of value | description                                                                                                                                                                     |
| -------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `imsi`               | string        | IMSI of the subscriber                                                                                                                                                          |
| `msisdn`             | string        | MSISDN of the subscriber                                                                                                                                                        |
| `imeisv`             | string        | IMEISV of the subscriber                                                                                                                                                        |
| `src_ip`             | string        | source IP of the subscriber (not assigned by P-GW)                                                                                                                              |
| `i_tei`              | uint32        | incoming TEID that S-GW should specify the subscriber                                                                                                                           |
| `type`               | string        | `external` or `http_get`. see [U-Plane Data Injection](#u-plane-data-injection)                                                                                                 |
| `euu_if_name`        | string        | name of the network interface on eUu side.</br>type=`external`: Used to receive traffic from external UE</br>type=`http_get`: Used as a source interface that `src_ip` is added |
| `http_url`           | string        | URL to HTTP GET by built-in traffic generator                                                                                                                                   |
| `reattach_on_reload` | bool          | whether to perform the attach procedure again on config reload                                                                                                                  |

### MME

#### Global

These values are used to identify MME. Some of them are just to be set inside the packets and not validated.

| config      | type of value | description                        |
| ----------- | ------------- | ---------------------------------- |
| `mcc`       | string        | MCC of MME                         |
| `mnc`       | string        | MNC of MME                         |
| `apn`       | string        | APN assigned to all the subscriber |
| `prom_addr` | string        | IP/Port of MME to serve Prometheus |

#### Local Addresses

`local_addresses` are the IP addresses/ports to be bound on the local machine.

| config     | type of value | description                        |
| ---------- | ------------- | ---------------------------------- |
| `s1c_addr` | string        | local IP/Port for S1-MME interface |
| `s11_ip`   | string        | local IP for S11 interface         |

#### Gateway IPs

IP addresses required to know/tell S-GW. This is typically done by DNS lookup with APN, but it's static for now.

| config       | type of value | description                  |
| ------------ | ------------- | ---------------------------- |
| `sgw_s11_ip` | string        | S-GW's IP for S11 interface  |
| `pgw_s5c_ip` | string        | P-GW's IP for S5-C interface |

### S-GW

#### Local Addresses

`local_addresses` are the IP addresses/ports to be bound on the local machine.

| config           | type of value | description                         |
| ---------------- | ------------- | ----------------------------------- |
| `s11_ip`         | string        | local IP for S11 interface          |
| `s1u_ip`         | string        | local IP for S1-U interface         |
| `s5c_ip`         | string        | local IP for S5-C interface         |
| `s5u_ip`         | string        | local IP for S5-U interface         |
| `use_kernel_gtp` | bool          | Use Kernel GTP or not.              |
| `prom_addr`      | string        | IP/Port of S-GW to serve Prometheus |

### P-GW

#### Global

| config           | type of value | description                                                                |
| ---------------- | ------------- | -------------------------------------------------------------------------- |
| `sgi_if_name`    | string        | name of the network interface on SGi side. Used to downlink route traffic. |
| `route_subnet`   | string        | IP subnet of UEs that should be routed properly.                           |
| `use_kernel_gtp` | bool          | Use Kernel GTP or not. U-Plane does not work when set to `false`.          |
| `prom_addr`      | string        | IP/Port of P-GW to serve Prometheus                                        |

#### Local Addresses

`local_addresses` are the IP addresses/ports to be bound on the local machine.

| config   | type of value | description                 |
| -------- | ------------- | --------------------------- |
| `s5c_ip` | string        | local IP for S5-C interface |
| `s5u_ip` | string        | local IP for S5-U interface |
| `sgi_ip` | string        | local IP for SGi interface  |

## Other Features

### Reloading config

The programs can handle `SIGHUP` to reload config without deleting sessions. Update YAML file and send `SIGHUP` to the process.

### Instrumentation

GW Tester nodes expose some metrics for Prometheus if `prom_addr` is given in each config. You can see the sample response from each node in [this Gist](https://gist.github.com/wmnsk/72f6d2d2450452090cd6351ffe63f660).  
I'm planning to add some more metrics like "success rate of HTTP probe", etc.

| Metrics           | Name                                  | Description                                   |
| ----------------- | ------------------------------------- | --------------------------------------------- |
| Active sessions   | `<node-name>_active_sessions`         | number of session established currently       |
| Active bearers    | `<node-name>_active_bearers`          | number of GTP-U tunnels established currently |
| Messages sent     | `<node-name>_messages_sent_total`     | number of messages sent by messagge type      |
| Messages received | `<node-name>_messages_received_total` | number of messages received by messagge type  |


================================================
FILE: examples/gw-tester/enb/config.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"fmt"
	"io/ioutil"

	"gopkg.in/yaml.v2"
)

// Config is a configurations loaded from yaml.
type Config struct {
	LocalAddrs struct {
		S1CIP string `yaml:"s1c_ip"`
		S1UIP string `yaml:"s1u_ip"`
	} `yaml:"local_addresses"`

	MMEAddr  string `yaml:"mme_addr"`
	PromAddr string `yaml:"prom_addr"`

	MCC          string        `yaml:"mcc"`
	MNC          string        `yaml:"mnc"`
	RATType      uint8         `yaml:"rat_type"`
	TAI          uint16        `yaml:"tai"`
	ECI          uint32        `yaml:"eci"`
	Subscribers  []*Subscriber `yaml:"subscribers"`
	UseKernelGTP bool          `yaml:"use_kernel_gtp"`
}

// Subscriber represents a subscriber.
type Subscriber struct {
	IMSI   string `yaml:"imsi"`
	MSISDN string `yaml:"msisdn"`
	IMEISV string `yaml:"imeisv"`
	SrcIP  string `yaml:"src_ip"`
	ITEI   uint32 `yaml:"i_tei"`

	TrafficType string `yaml:"type"`
	EUuIFName   string `yaml:"euu_if_name"`
	HTTPURL     string `yaml:"http_url"`

	Reattach bool `yaml:"reattach_on_reload"`

	// values for these fields are given from MME.
	sgwAddr string
	otei    uint32
}

// String returns the information of s in string.
func (s *Subscriber) String() string {
	return fmt.Sprintf(
		"IMSI: %s, MSISDN: %s, IMEISV: %s, SrcIP: %s, S-GW: %s, I_TEI: %#08x, O_TEI: %#08x",
		s.IMSI, s.MSISDN, s.IMEISV, s.SrcIP, s.sgwAddr, s.ITEI, s.otei,
	)
}

func loadConfig(path string) (*Config, error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	c := &Config{}
	if err := yaml.Unmarshal(buf, c); err != nil {
		return nil, err
	}

	return c, nil
}


================================================
FILE: examples/gw-tester/enb/enb.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"context"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"log"
	"net"
	"net/http"
	"sync"
	"time"

	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/vishvananda/netlink"
	"google.golang.org/grpc"

	"github.com/wmnsk/go-gtp/examples/gw-tester/s1mme"
	"github.com/wmnsk/go-gtp/gtpv1"
)

type enb struct {
	mu sync.Mutex

	// S1-MME
	mmeAddr     net.Addr
	cConn       *grpc.ClientConn
	s1mmeClient s1mme.AttacherClient

	// S1-U
	uAddr net.Addr
	uConn *gtpv1.UPlaneConn

	location *s1mme.Location

	candidateSubs []*Subscriber
	sessions      []*Subscriber
	attachCh      chan *Subscriber

	useKernelGTP bool

	addedAddrs  map[netlink.Link]*netlink.Addr
	addedRoutes []*netlink.Route
	addedRules  []*netlink.Rule

	promAddr string
	mc       *metricsCollector

	errCh chan error
}

func newENB(cfg *Config) (*enb, error) {
	e := &enb{
		mu: sync.Mutex{},
		location: &s1mme.Location{
			Mcc:     cfg.MCC,
			Mnc:     cfg.MNC,
			RatType: s1mme.Location_RATType(cfg.RATType),
			Tai:     uint32(cfg.TAI),
			Eci:     cfg.ECI,
		},
		candidateSubs: cfg.Subscribers,
		useKernelGTP:  cfg.UseKernelGTP,
		addedAddrs:    make(map[netlink.Link]*netlink.Addr),

		errCh: make(chan error, 1),
	}

	var err error
	e.uAddr, err = net.ResolveUDPAddr("udp", cfg.LocalAddrs.S1UIP+gtpv1.GTPUPort)
	if err != nil {
		return nil, err
	}

	e.mmeAddr, err = net.ResolveTCPAddr("tcp", cfg.MMEAddr)
	if err != nil {
		return nil, err
	}

	if cfg.PromAddr != "" {
		// validate if the address is valid or not.
		if _, err = net.ResolveTCPAddr("tcp", cfg.PromAddr); err != nil {
			return nil, err
		}
		e.promAddr = cfg.PromAddr
	}

	if !e.useKernelGTP {
		log.Println("WARN: U-Plane does not work without GTP kernel module")
	}

	return e, nil
}

func (e *enb) run(ctx context.Context) error {
	// TODO: bind local address(cfg.LocalAddrs.S1CIP) with WithDialer option?
	conn, err := grpc.Dial(e.mmeAddr.String(), grpc.WithInsecure())
	if err != nil {
		return err
	}
	e.s1mmeClient = s1mme.NewAttacherClient(conn)
	log.Printf("Established S1-MME connection with %s", e.mmeAddr)

	e.uConn = gtpv1.NewUPlaneConn(e.uAddr)
	if e.useKernelGTP {
		if err := e.uConn.EnableKernelGTP("gtp-enb", gtpv1.RoleSGSN); err != nil {
			return err
		}
	}
	go func() {
		if err := e.uConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
		log.Println("uConn.ListenAndServe exitted")
	}()
	log.Printf("Started serving S1-U on %s", e.uAddr)

	// start serving Prometheus, if address is given
	if e.promAddr != "" {
		if err := e.runMetricsCollector(); err != nil {
			return err
		}

		http.Handle("/metrics", promhttp.Handler())
		go func() {
			if err := http.ListenAndServe(e.promAddr, nil); err != nil {
				log.Println(err)
			}
		}()
		log.Printf("Started serving Prometheus on %s", e.promAddr)
	}

	for _, sub := range e.candidateSubs {
		select {
		case <-ctx.Done():
			return nil
		case <-time.After(10 * time.Millisecond):
			// not to load too much in case of many subscribers
		}

		if err := e.attach(ctx, sub); err != nil {
			return err
		}
	}

	// wait for new subscribers to be attached
	e.attachCh = make(chan *Subscriber)
	defer close(e.attachCh)
	for {
		select {
		case <-ctx.Done():
			return nil
		case sub := <-e.attachCh:
			go func() {
				if err := e.attach(ctx, sub); err != nil {
					log.Printf("Failed to attach: %s: %s", sub, err)
				}
			}()
			// wait 10ms after dispatching
			time.Sleep(10 * time.Millisecond)
		}
	}
}

func (e *enb) reload(cfg *Config) error {
	e.location = &s1mme.Location{
		Mcc:     cfg.MCC,
		Mnc:     cfg.MNC,
		RatType: s1mme.Location_RATType(cfg.RATType),
		Tai:     uint32(cfg.TAI),
		Eci:     cfg.ECI,
	}

	// TODO: consider more efficient way
	var attachSubs []*Subscriber
	for _, sub := range cfg.Subscribers {
		var existing bool
		for _, attached := range e.sessions {
			if sub.IMSI == attached.IMSI {
				existing = true
			}
		}

		if existing {
			if !sub.Reattach {
				continue
			}

			if err := e.uConn.DelTunnelByITEI(sub.ITEI); err != nil {
				continue
			}
		}
		attachSubs = append(attachSubs, sub)
	}

	for _, sub := range attachSubs {
		e.attachCh <- sub
	}
	return nil
}

func (e *enb) close() error {
	var errs []error
	e.mu.Lock()
	defer e.mu.Unlock()

	for l, a := range e.addedAddrs {
		if err := netlink.AddrDel(l, a); err != nil {
			errs = append(errs, err)
		}
	}

	for _, r := range e.addedRoutes {
		if err := netlink.RouteDel(r); err != nil {
			errs = append(errs, err)
		}
	}

	for _, r := range e.addedRules {
		if err := netlink.RuleDel(r); err != nil {
			errs = append(errs, err)
		}
	}

	if c := e.uConn; c != nil {
		if err := c.Close(); err != nil {
			errs = append(errs, err)
		}
	}
	if c := e.cConn; c != nil {
		if err := c.Close(); err != nil {
			errs = append(errs, err)
		}
	}

	return fmt.Errorf("errors while closing eNB: %v", errs)
}

func (e *enb) attach(ctx context.Context, sub *Subscriber) error {
	// allocate random TEID if 0 is specified in config.
	if sub.ITEI == 0 {
		sub.ITEI = e.newTEID()
	}

	req := &s1mme.AttachRequest{
		Imsi:     sub.IMSI,
		Msisdn:   sub.MSISDN,
		Imeisv:   sub.IMEISV,
		S1UAddr:  e.uConn.LocalAddr().String(),
		SrcIp:    sub.SrcIP,
		ITei:     sub.ITEI,
		Location: e.location,
	}

	rsp, err := e.s1mmeClient.Attach(ctx, req)
	if err != nil {
		return err
	}
	if e.mc != nil {
		e.mc.messagesSent.WithLabelValues(e.mmeAddr.String(), "Attach Request").Inc()
		e.mc.messagesReceived.WithLabelValues(e.mmeAddr.String(), "Attach Response").Inc()
	}

	switch rsp.Cause {
	case s1mme.Cause_SUCCESS:
		sgwIP, _, err := net.SplitHostPort(rsp.SgwAddr)
		if err != nil {
			return err
		}

		if e.useKernelGTP {
			if err := e.uConn.AddTunnelOverride(
				net.ParseIP(sgwIP), net.ParseIP(req.SrcIp), rsp.OTei, req.ITei,
			); err != nil {
				log.Println(net.ParseIP(sgwIP), net.ParseIP(req.SrcIp), rsp.OTei, req.ITei)
				e.errCh <- fmt.Errorf("failed to create tunnel for %s: %w", sub.IMSI, err)
				return nil
			}
			if err := e.addRoute(); err != nil {
				e.errCh <- fmt.Errorf("failed to add route for %s: %w", sub.IMSI, err)
				return nil
			}
		}

		sub.sgwAddr = rsp.SgwAddr
		sub.otei = rsp.OTei

		e.sessions = append(e.sessions, sub)
		if e.useKernelGTP {
			if err := e.setupUPlane(ctx, sub); err != nil {
				e.errCh <- fmt.Errorf("failed to setup U-Plane for %s: %w", sub.IMSI, err)
				return nil
			}
			log.Printf("Successfully established tunnel for %s", sub.IMSI)
		}
	default:
		e.errCh <- fmt.Errorf("got unexpected Cause for %s: %s", rsp.Cause, sub.IMSI)
		return nil
	}

	return nil
}

func (e *enb) newTEID() uint32 {
	b := make([]byte, 4)
	if _, err := rand.Read(b); err != nil {
		return 0
	}

	generated := binary.BigEndian.Uint32(b)
	for _, s := range e.sessions {
		if generated == s.ITEI {
			return e.newTEID()
		}
	}

	return generated
}

func (e *enb) setupUPlane(ctx context.Context, sub *Subscriber) error {
	switch sub.TrafficType {
	case "http_get":
		if err := e.addIP(sub); err != nil {
			return err
		}
		if err := e.addRuleLocal(sub); err != nil {
			return err
		}
		go func() {
			if err := e.runHTTPProbe(ctx, sub); err != nil {
				e.errCh <- err
			}
		}()
	case "external":
		if err := e.addRuleExternal(sub); err != nil {
			return err
		}
	default:
		return fmt.Errorf("unknown/unimplemented type: %s specified for 'type' in subscriber", sub.TrafficType)
	}

	return nil
}

func (e *enb) addRoute() error {
	route := &netlink.Route{
		Dst:       &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}, // default
		LinkIndex: e.uConn.KernelGTP.Link.Attrs().Index,                    // dev gtp-<ECI>
		Scope:     netlink.SCOPE_LINK,                                      // scope link
		Protocol:  4,                                                       // proto static
		Priority:  1,                                                       // metric 1
		Table:     1001,                                                    // table <ECI>
	}

	e.addedRoutes = append(e.addedRoutes, route)
	return netlink.RouteReplace(route)
}

func (e *enb) addRuleExternal(sub *Subscriber) error {
	rules, err := netlink.RuleList(0)
	if err != nil {
		return err
	}

	mask32 := &net.IPNet{IP: net.ParseIP(sub.SrcIP), Mask: net.CIDRMask(32, 32)}
	for _, r := range rules {
		if r.IifName == sub.EUuIFName && r.Src == mask32 && r.Table == 1001 {
			return nil
		}
	}

	rule := netlink.NewRule()
	rule.IifName = sub.EUuIFName
	rule.Src = mask32
	rule.Table = 1001

	e.addedRules = append(e.addedRules, rule)
	return netlink.RuleAdd(rule)
}

func (e *enb) addRuleLocal(sub *Subscriber) error {
	rules, err := netlink.RuleList(0)
	if err != nil {
		return err
	}

	mask32 := &net.IPNet{IP: net.ParseIP(sub.SrcIP), Mask: net.CIDRMask(32, 32)}
	for _, r := range rules {
		if r.Src == mask32 && r.Table == 1001 {
			return nil
		}
	}

	rule := netlink.NewRule()
	rule.Src = mask32
	rule.Table = 1001

	e.addedRules = append(e.addedRules, rule)
	return netlink.RuleAdd(rule)
}

func (e *enb) runHTTPProbe(ctx context.Context, sub *Subscriber) error {
	laddr, err := net.ResolveTCPAddr("tcp", sub.SrcIP+":0")
	if err != nil {
		return err
	}
	dialer := net.Dialer{LocalAddr: laddr}
	client := http.Client{
		Transport: &http.Transport{Dial: dialer.Dial},
		Timeout:   3 * time.Second,
	}

	for {
		select {
		case <-ctx.Done():
			return nil
		case <-time.After(5 * time.Second):
			// do nothing here and go forward
		}

		rsp, err := client.Get(sub.HTTPURL)
		if err != nil {
			e.errCh <- fmt.Errorf("failed to GET %s: %w", sub.HTTPURL, err)
			continue
		}

		if rsp.StatusCode == http.StatusOK {
			log.Printf("[HTTP Probe;%s] Successfully GET %s: Status: %s", sub.IMSI, sub.HTTPURL, rsp.Status)
			rsp.Body.Close()
			continue
		}
		rsp.Body.Close()
		e.errCh <- fmt.Errorf("got invalid response on HTTP probe: %v", rsp.StatusCode)
	}
}

func (e *enb) addIP(sub *Subscriber) error {
	link, err := netlink.LinkByName(sub.EUuIFName)
	if err != nil {
		return err
	}
	addrs, err := netlink.AddrList(link, netlink.FAMILY_ALL)
	if err != nil {
		return err
	}

	netToAdd := &net.IPNet{IP: net.ParseIP(sub.SrcIP), Mask: net.CIDRMask(24, 32)}
	var addr netlink.Addr
	var found bool
	for _, a := range addrs {
		if a.Label == sub.EUuIFName {
			if a.IPNet.String() == netToAdd.String() {
				return nil
			}
			addr = a
			found = true
		}
	}
	if !found {
		return fmt.Errorf("cannot find the interface to add address: %s", sub.EUuIFName)
	}

	addr.IPNet = netToAdd
	if err := netlink.AddrAdd(link, &addr); err != nil {
		return err
	}

	e.mu.Lock()
	defer e.mu.Unlock()

	e.addedAddrs[link] = &addr

	return nil
}


================================================
FILE: examples/gw-tester/enb/enb.yml
================================================
mcc: "001"
mnc: "01"
rat_type: 6 # E-UTRAN
tai: 0x0001
eci: 0x00000001
local_addresses:
  s1c_ip: "127.0.1.11"
  s1u_ip: "127.0.0.11"
mme_addr: "127.0.1.12:36412"
use_kernel_gtp: false
prom_addr: "127.0.10.1:58080"
subscribers:
  - imsi: "001010000000001"
    msisdn: "814000000001"
    imeisv: "1234500000001"
    src_ip: "192.168.101.201"
    i_tei: 1
    type: "http_get"
    euu_if_name: "lo"
    http_url: "http://172.16.0.102/"
    reattach_on_reload: false
  - imsi: "001010000000002"
    msisdn: "814000000002"
    imeisv: "1234500000002"
    src_ip: "192.168.101.202"
    i_tei: 0
    type: "http_get"
    euu_if_name: "lo"
    http_url: "http://172.16.0.102/"
    reattach_on_reload: true
  - imsi: "001010000000003"
    msisdn: "814000000003"
    imeisv: "1234500000003"
    src_ip: "192.168.101.203"
    i_tei: 0
    type: "http_get"
    euu_if_name: "lo"
    http_url: "http://172.16.0.102/"
    reattach_on_reload: false
  - imsi: "001010000000004"
    msisdn: "814000000004"
    imeisv: "1234500000004"
    src_ip: "192.168.101.204"
    i_tei: 0
    type: "http_get"
    euu_if_name: "lo"
    http_url: "http://172.16.0.102/"
    reattach_on_reload: true
  - imsi: "001010000000005"
    msisdn: "814000000005"
    imeisv: "1234500000005"
    src_ip: "192.168.101.205"
    i_tei: 0
    type: "http_get"
    euu_if_name: "lo"
    http_url: "http://172.16.0.102/"
    reattach_on_reload: false
  # example for external client
  #- imsi: "001010000000006"
  #  msisdn: "814000000006"
  #  imeisv: "1234500000006"
  #  src_ip: "192.168.101.101"
  #  i_tei: 1
  #  type: "external"
  #  euu_if_name: "eth0"
  #  http_url: ""
  #  reattach_on_reload: true


================================================
FILE: examples/gw-tester/enb/main.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Command enb works as pseudo eNB that forwards packets through GTPv1 tunnel.
package main

import (
	"context"
	"flag"
	"log"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	var configPath = flag.String("config", "./enb.yml", "Path to the configuration file.")
	flag.Parse()
	log.SetPrefix("[eNB] ")

	cfg, err := loadConfig(*configPath)
	if err != nil {
		log.Fatal(err)
	}

	enb, err := newENB(cfg)
	if err != nil {
		log.Printf("failed to initialize eNB: %s", err)
	}
	defer enb.close()

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGHUP)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	fatalCh := make(chan error, 1)
	go func() {
		if err := enb.run(ctx); err != nil {
			fatalCh <- err
		}
	}()

	for {
		select {
		case sig := <-sigCh:
			switch sig {
			case syscall.SIGINT:
				return
			case syscall.SIGHUP:
				// reload config and attach/detach subscribers again
				newCfg, err := loadConfig(*configPath)
				if err != nil {
					log.Printf("Error reloading config %s", err)
				}

				if err := enb.reload(newCfg); err != nil {
					log.Printf("Error applying reloaded config %s", err)
				}
			}
		case err := <-enb.errCh:
			log.Printf("WARN: %s", err)
		case err := <-fatalCh:
			log.Printf("FATAL: %s", err)
			return
		}
	}
}


================================================
FILE: examples/gw-tester/enb/metrics.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"log"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/vishvananda/netlink"
)

type metricsCollector struct {
	activeSessions   prometheus.GaugeFunc
	activeBearers    prometheus.GaugeFunc
	messagesSent     *prometheus.CounterVec
	messagesReceived *prometheus.CounterVec
}

func (e *enb) runMetricsCollector() error {
	mc := &metricsCollector{}
	mc.activeSessions = promauto.NewGaugeFunc(
		prometheus.GaugeOpts{
			Name: "enb_active_sessions",
			Help: "number of session established currently",
		},
		func() float64 {
			return float64(len(e.sessions))
		},
	)

	mc.activeBearers = promauto.NewGaugeFunc(
		prometheus.GaugeOpts{
			Name: "enb_active_bearers",
			Help: "number of GTP-U tunnels established currently",
		},
		func() float64 {
			tunnels, err := netlink.GTPPDPList()
			if err != nil {
				log.Printf("metrics: could not get tunnels: %s", err)
				return 0
			}
			return float64(len(tunnels))
		},
	)

	mc.messagesSent = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "enb_messages_sent_total",
			Help: "number of message sent by messagge type",
		},
		[]string{"dst", "type"},
	)

	mc.messagesReceived = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "enb_messages_received_total",
			Help: "number of message received by messagge type",
		},
		[]string{"src", "type"},
	)

	e.mc = mc
	return nil
}


================================================
FILE: examples/gw-tester/mme/config.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"io/ioutil"

	"gopkg.in/yaml.v2"
)

// Config is a configurations loaded from yaml.
type Config struct {
	LocalAddrs struct {
		S1CAddr string `yaml:"s1c_addr"`
		S11IP   string `yaml:"s11_ip"`
	} `yaml:"local_addresses"`

	PromAddr string `yaml:"prom_addr"`

	MCC string `yaml:"mcc"`
	MNC string `yaml:"mnc"`

	APN string `yaml:"apn"`

	SgwS11 string `yaml:"sgw_s11_ip"`
	PgwS5C string `yaml:"pgw_s5c_ip"`
}

func loadConfig(path string) (*Config, error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	c := &Config{}
	if err := yaml.Unmarshal(buf, c); err != nil {
		return nil, err
	}

	return c, nil
}


================================================
FILE: examples/gw-tester/mme/handlers.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"net"

	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

func (m *mme) handleCreateSessionResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), sgwAddr)
	if m.mc != nil {
		m.mc.messagesReceived.WithLabelValues(sgwAddr.String(), msg.MessageTypeName()).Inc()
	}

	// find the session associated with TEID
	session, err := c.GetSessionByTEID(msg.TEID(), sgwAddr)
	if err != nil {
		c.RemoveSession(session)
		return err
	}
	bearer := session.GetDefaultBearer()

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	csRspFromSGW := msg.(*message.CreateSessionResponse)

	// check Cause value first.
	if causeIE := csRspFromSGW.Cause; causeIE != nil {
		cause, err := causeIE.Cause()
		if err != nil {
			return err
		}
		if cause != gtpv2.CauseRequestAccepted {
			c.RemoveSession(session)
			return &gtpv2.CauseNotOKError{
				MsgType: csRspFromSGW.MessageTypeName(),
				Cause:   cause,
				Msg:     fmt.Sprintf("subscriber: %s", session.IMSI),
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: msg.MessageType()}
	}

	if paaIE := csRspFromSGW.PAA; paaIE != nil {
		bearer.SubscriberIP, err = paaIE.IPAddress()
		if err != nil {
			return err
		}
	}
	if fteidcIE := csRspFromSGW.SenderFTEIDC; fteidcIE != nil {
		teid, err := fteidcIE.TEID()
		if err != nil {
			return err
		}
		session.AddTEID(gtpv2.IFTypeS11S4SGWGTPC, teid)
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	s11sgwTEID, err := session.GetTEID(gtpv2.IFTypeS11S4SGWGTPC)
	if err != nil {
		c.RemoveSession(session)
		return err
	}
	s11mmeTEID, err := session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		c.RemoveSession(session)
		return err
	}

	if brCtxIE := csRspFromSGW.BearerContextsCreated; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.EPSBearerID:
				bearer.EBI, err = childIE.EPSBearerID()
				if err != nil {
					return err
				}
			case ie.FullyQualifiedTEID:
				if childIE.Instance() != 0 {
					continue
				}
				it, err := childIE.InterfaceType()
				if err != nil {
					return err
				}
				teid, err := childIE.TEID()
				if err != nil {
					return err
				}
				session.AddTEID(it, teid)
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	if err := session.Activate(); err != nil {
		c.RemoveSession(session)
		return err
	}

	log.Printf(
		"Session created with S-GW for Subscriber: %s;\n\tS11 S-GW: %s, TEID->: %#x, TEID<-: %#x",
		session.Subscriber.IMSI, sgwAddr, s11sgwTEID, s11mmeTEID,
	)
	m.created <- struct{}{}
	return nil
}

func (m *mme) handleModifyBearerResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), sgwAddr)
	if m.mc != nil {
		m.mc.messagesReceived.WithLabelValues(sgwAddr.String(), msg.MessageTypeName()).Inc()
	}

	session, err := c.GetSessionByTEID(msg.TEID(), sgwAddr)
	if err != nil {
		return err
	}

	mbRspFromSGW := msg.(*message.ModifyBearerResponse)
	if causeIE := mbRspFromSGW.Cause; causeIE != nil {
		cause, err := causeIE.Cause()
		if err != nil {
			return err
		}
		if cause != gtpv2.CauseRequestAccepted {
			return &gtpv2.CauseNotOKError{
				MsgType: msg.MessageTypeName(),
				Cause:   cause,
				Msg:     fmt.Sprintf("subscriber: %s", session.IMSI),
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.Cause}
	}

	if brCtxIE := mbRspFromSGW.BearerContextsModified; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.FullyQualifiedTEID:
				if childIE.Instance() != 0 {
					continue
				}
				it, err := childIE.InterfaceType()
				if err != nil {
					return err
				}
				teid, err := childIE.TEID()
				if err != nil {
					return err
				}
				session.AddTEID(it, teid)

				m.sgw.s1uIP, err = childIE.IPAddress()
				if err != nil {
					return err
				}
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	log.Printf("Bearer modified with S-GW for Subscriber: %s", session.IMSI)
	m.modified <- struct{}{}
	return nil
}

func (m *mme) handleDeleteSessionResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), sgwAddr)
	if m.mc != nil {
		m.mc.messagesReceived.WithLabelValues(sgwAddr.String(), msg.MessageTypeName()).Inc()
	}

	session, err := c.GetSessionByTEID(msg.TEID(), sgwAddr)
	if err != nil {
		return err
	}

	c.RemoveSession(session)
	log.Printf("Session deleted with S-GW for Subscriber: %s", session.IMSI)
	return nil
}


================================================
FILE: examples/gw-tester/mme/main.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Command mme works as pseudo MME/HSS communicates S/P-GW with GTPv2 signaling.
package main

import (
	"context"
	"flag"
	"log"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	var configPath = flag.String("config", "./mme.yml", "Path to the configuration file.")
	flag.Parse()
	log.SetPrefix("[MME] ")

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGHUP)

	cfg, err := loadConfig(*configPath)
	if err != nil {
		log.Fatal(err)
	}

	mme, err := newMME(cfg)
	if err != nil {
		log.Printf("failed to initialize MME: %s", err)
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	fatalCh := make(chan error)
	go func() {
		if err := mme.run(ctx); err != nil {
			fatalCh <- err
		}
	}()

	for {
		select {
		case sig := <-sigCh:
			switch sig {
			case syscall.SIGINT:
				cancel()
				return
			case syscall.SIGHUP:
				// reload config and attach/detach subscribers
				newCfg, err := loadConfig(*configPath)
				if err != nil {
					log.Printf("Error reloading config %s", err)
				}

				if err := mme.reload(newCfg); err != nil {
					log.Printf("Error applying reloaded config %s", err)
				}
			}
		case err := <-mme.errCh:
			log.Printf("WARN: %s", err)
		case err := <-fatalCh:
			log.Printf("FATAL: %s", err)
			return
		}
	}
}


================================================
FILE: examples/gw-tester/mme/metrics.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

type metricsCollector struct {
	activeSessions   prometheus.GaugeFunc
	messagesSent     *prometheus.CounterVec
	messagesReceived *prometheus.CounterVec
}

func (m *mme) runMetricsCollector() error {
	mc := &metricsCollector{}
	mc.activeSessions = promauto.NewGaugeFunc(
		prometheus.GaugeOpts{
			Name: "mme_active_sessions",
			Help: "number of session established currently",
		},
		func() float64 {
			return float64(m.s11Conn.SessionCount())
		},
	)

	mc.messagesSent = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "mme_messages_sent_total",
			Help: "number of message sent by messagge type",
		},
		[]string{"dst", "type"},
	)

	mc.messagesReceived = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "mme_messages_received_total",
			Help: "number of message received by messagge type",
		},
		[]string{"src", "type"},
	)

	m.mc = mc
	return nil
}


================================================
FILE: examples/gw-tester/mme/mme.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/prometheus/client_golang/prometheus/promhttp"
	"google.golang.org/grpc"

	"github.com/wmnsk/go-gtp/examples/gw-tester/s1mme"
	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

// Session represents a subscriber.
type Session struct {
	IMSI   string
	MSISDN string
	IMEISV string

	SrcIP string

	itei uint32
}

type mme struct {
	s1mmeListener net.Listener
	s11Addr       net.Addr
	s11IP         string
	s11Conn       *gtpv2.Conn

	created  chan struct{}
	modified chan struct{}

	apn      string
	mcc, mnc string

	enb struct {
		mcc   string
		mnc   string
		tai   uint16
		eci   uint32
		s1uIP string
	}

	sgw struct {
		s11IP string
		s1uIP string
	}

	pgw struct {
		s5cIP string
	}

	promAddr string
	mc       *metricsCollector

	errCh chan error
}

func newMME(cfg *Config) (*mme, error) {
	m := &mme{
		mcc: cfg.MCC,
		mnc: cfg.MNC,
		apn: cfg.APN,

		created:  make(chan struct{}, 1),
		modified: make(chan struct{}, 1),

		errCh: make(chan error, 1),
	}
	m.sgw.s11IP = cfg.SgwS11
	m.pgw.s5cIP = cfg.PgwS5C

	// setup S11 conn
	var err error
	m.s11Addr, err = net.ResolveUDPAddr("udp", cfg.LocalAddrs.S11IP+gtpv2.GTPCPort)
	if err != nil {
		return nil, err
	}
	m.s11IP = cfg.LocalAddrs.S11IP

	// setup gRPC server
	m.s1mmeListener, err = net.Listen("tcp", cfg.LocalAddrs.S1CAddr)
	if err != nil {
		return nil, err
	}

	if cfg.PromAddr != "" {
		// validate if the address is valid or not.
		if _, err = net.ResolveTCPAddr("tcp", cfg.PromAddr); err != nil {
			return nil, err
		}
		m.promAddr = cfg.PromAddr
	}

	return m, nil
}

func (m *mme) run(ctx context.Context) error {
	fatalCh := make(chan error, 1)

	srv := grpc.NewServer()
	s1mme.RegisterAttacherServer(srv, m)
	go func() {
		if err := srv.Serve(m.s1mmeListener); err != nil {
			fatalCh <- fmt.Errorf("error on serving gRPC: %w", err)
			return
		}
	}()
	log.Printf("Started serving S1-MME on: %s", m.s1mmeListener.Addr())

	m.s11Conn = gtpv2.NewConn(m.s11Addr, gtpv2.IFTypeS11MMEGTPC, 0)
	go func() {
		if err := m.s11Conn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started serving S11 on: %s", m.s11Addr)

	m.s11Conn.AddHandlers(map[uint8]gtpv2.HandlerFunc{
		message.MsgTypeCreateSessionResponse: m.handleCreateSessionResponse,
		message.MsgTypeModifyBearerResponse:  m.handleModifyBearerResponse,
		message.MsgTypeDeleteSessionResponse: m.handleDeleteSessionResponse,
	})

	// start serving Prometheus, if address is given
	if m.promAddr != "" {
		if err := m.runMetricsCollector(); err != nil {
			return err
		}

		http.Handle("/metrics", promhttp.Handler())
		go func() {
			if err := http.ListenAndServe(m.promAddr, nil); err != nil {
				log.Println(err)
			}
		}()
		log.Printf("Started serving Prometheus on %s", m.promAddr)
	}

	for {
		select {
		case <-ctx.Done():
			// srv.Serve returns when lis is closed
			if err := m.s1mmeListener.Close(); err != nil {
				return err
			}
			return nil
		case err := <-fatalCh:
			return err
		}
	}
}

func (m *mme) reload(cfg *Config) error {
	// TODO: implement
	return nil
}

// Attach is called by eNB by gRPC.
func (m *mme) Attach(ctx context.Context, req *s1mme.AttachRequest) (*s1mme.AttachResponse, error) {
	sess := &Session{
		IMSI:   req.Imsi,
		MSISDN: req.Msisdn,
		IMEISV: req.Imeisv,
		SrcIP:  req.SrcIp,
		itei:   req.ITei,
	}

	var err error
	m.enb.s1uIP, _, err = net.SplitHostPort(req.S1UAddr)
	if err != nil {
		return nil, err
	}

	errCh := make(chan error, 1)
	rspCh := make(chan *s1mme.AttachResponse)
	go func() {
		m.enb.mcc = req.Location.Mcc
		m.enb.mnc = req.Location.Mnc
		m.enb.tai = uint16(req.Location.Tai)
		m.enb.eci = req.Location.Eci

		session, err := m.CreateSession(sess)
		if err != nil {
			errCh <- err
			return
		}
		log.Printf("Sent Create Session Request for %s", session.IMSI)

		select {
		case <-m.created:
			// go forward
		case <-time.After(5 * time.Second):
			errCh <- fmt.Errorf("timed out: %s", session.IMSI)
		}

		if _, err = m.ModifyBearer(session, sess); err != nil {
			errCh <- err
			return
		}
		log.Printf("Sent Modify Bearer Request for %s", session.IMSI)

		select {
		case <-m.modified:
			// go forward
		case <-time.After(5 * time.Second):
			errCh <- fmt.Errorf("timed out: %s", session.IMSI)
		}

		s1teid, err := session.GetTEID(gtpv2.IFTypeS1USGWGTPU)
		if err != nil {
			errCh <- err
			return
		}

		rspCh <- &s1mme.AttachResponse{
			Cause:   s1mme.Cause_SUCCESS,
			SgwAddr: m.sgw.s1uIP + gtpv2.GTPUPort,
			OTei:    s1teid,
		}
	}()

	select {
	case err := <-errCh:
		return nil, err
	case rsp := <-rspCh:
		return rsp, nil
	}
}

// Detach is called by eNB by gRPC.
func (m *mme) Detach(ctx context.Context, req *s1mme.DetachRequest) (*s1mme.DetachResponse, error) {
	// TODO: implement
	return nil, nil
}

func (m *mme) CreateSession(sess *Session) (*gtpv2.Session, error) {
	br := gtpv2.NewBearer(5, "", &gtpv2.QoSProfile{
		PL: 2, QCI: 255, MBRUL: 0xffffffff, MBRDL: 0xffffffff, GBRUL: 0xffffffff, GBRDL: 0xffffffff,
	})
	var pci, pvi uint8
	if br.PCI {
		pci = 1
	}
	if br.PVI {
		pvi = 1
	}

	raddr, err := net.ResolveUDPAddr("udp", m.sgw.s11IP+gtpv2.GTPCPort)
	if err != nil {
		return nil, err
	}

	session, _, err := m.s11Conn.CreateSession(
		raddr,
		ie.NewIMSI(sess.IMSI),
		ie.NewMSISDN(sess.MSISDN),
		ie.NewMobileEquipmentIdentity(sess.IMEISV),
		ie.NewUserLocationInformationStruct(
			ie.NewCGI(m.enb.mcc, m.enb.mnc, 0x1111, 0x2222),
			ie.NewSAI(m.enb.mcc, m.enb.mnc, 0x1111, 0x3333),
			ie.NewRAI(m.enb.mcc, m.enb.mnc, 0x1111, 0x4444),
			ie.NewTAI(m.enb.mcc, m.enb.mnc, 0x5555),
			ie.NewECGI(m.enb.mcc, m.enb.mnc, 0x66666666),
			ie.NewLAI(m.enb.mcc, m.enb.mnc, 0x1111),
			ie.NewMENBI(m.enb.mcc, m.enb.mnc, 0x11111111),
			ie.NewEMENBI(m.enb.mcc, m.enb.mnc, 0x22222222),
		),
		ie.NewRATType(gtpv2.RATTypeEUTRAN),
		ie.NewIndicationFromOctets(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
		m.s11Conn.NewSenderFTEID(m.s11IP, ""),
		ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPC, 0, m.pgw.s5cIP, "").WithInstance(1),
		ie.NewAccessPointName(m.apn),
		ie.NewSelectionMode(gtpv2.SelectionModeMSorNetworkProvidedAPNSubscribedVerified),
		ie.NewPDNType(gtpv2.PDNTypeIPv4),
		ie.NewPDNAddressAllocation(sess.SrcIP),
		ie.NewAPNRestriction(gtpv2.APNRestrictionNoExistingContextsorRestriction),
		ie.NewAggregateMaximumBitRate(0, 0),
		ie.NewBearerContext(
			ie.NewEPSBearerID(br.EBI),
			ie.NewBearerQoS(pci, br.PL, pvi, br.QCI, br.MBRUL, br.MBRDL, br.GBRUL, br.GBRDL),
		),
		ie.NewFullyQualifiedCSID(m.s11IP, 1),
		ie.NewServingNetwork(m.mcc, m.mnc),
		ie.NewUETimeZone(9*time.Hour, 0),
	)
	if err != nil {
		return nil, err
	}
	if m.mc != nil {
		m.mc.messagesSent.WithLabelValues(raddr.String(), "Create Session Request").Inc()
	}

	return session, nil
}

func (m *mme) ModifyBearer(sess *gtpv2.Session, sub *Session) (*gtpv2.Bearer, error) {
	teid, err := sess.GetTEID(gtpv2.IFTypeS11S4SGWGTPC)
	if err != nil {
		return nil, err
	}

	fteid := ie.NewFullyQualifiedTEID(gtpv2.IFTypeS1UeNodeBGTPU, sub.itei, m.enb.s1uIP, "")
	if _, err = m.s11Conn.ModifyBearer(
		teid, sess, ie.NewIndicationFromOctets(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
		ie.NewBearerContext(ie.NewEPSBearerID(sess.GetDefaultBearer().EBI), fteid, ie.NewPortNumber(2125)),
	); err != nil {
		return nil, err
	}
	if m.mc != nil {
		m.mc.messagesSent.WithLabelValues(sess.PeerAddr().String(), "Modify Bearer Request").Inc()
	}

	return nil, nil
}


================================================
FILE: examples/gw-tester/mme/mme.yml
================================================
mcc: "001"
mnc: "01"
apn: "gw-tester.go-gtp.example"
local_addresses:
  s1c_addr: "127.0.1.12:36412"
  s11_ip: "127.0.1.12"
sgw_s11_ip: "127.0.1.13"
pgw_s5c_ip: "127.0.1.15"
prom_addr: "127.0.10.2:58080"


================================================
FILE: examples/gw-tester/pgw/config.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"io/ioutil"

	"gopkg.in/yaml.v2"
)

// Config is a configurations loaded from yaml.
type Config struct {
	LocalAddrs struct {
		S5CIP string `yaml:"s5c_ip"`
		S5UIP string `yaml:"s5u_ip"`
		SGiIP string `yaml:"sgi_ip"`
	} `yaml:"local_addresses"`

	UseKernelGTP bool `yaml:"use_kernel_gtp"`

	SGiIFName   string `yaml:"sgi_if_name"`
	RouteSubnet string `yaml:"route_subnet"`

	PromAddr string `yaml:"prom_addr"`
}

func loadConfig(path string) (*Config, error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	c := &Config{}
	if err := yaml.Unmarshal(buf, c); err != nil {
		return nil, err
	}

	return c, nil
}


================================================
FILE: examples/gw-tester/pgw/handlers.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"net"
	"strings"

	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

func (p *pgw) handleCreateSessionRequest(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), sgwAddr)
	if p.mc != nil {
		p.mc.messagesReceived.WithLabelValues(sgwAddr.String(), msg.MessageTypeName()).Inc()
	}

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	csReqFromSGW := msg.(*message.CreateSessionRequest)

	// keep session information retrieved from the message.
	session := gtpv2.NewSession(sgwAddr, &gtpv2.Subscriber{Location: &gtpv2.Location{}})
	bearer := session.GetDefaultBearer()
	var err error
	if imsiIE := csReqFromSGW.IMSI; imsiIE != nil {
		imsi, err := imsiIE.IMSI()
		if err != nil {
			return err
		}
		session.IMSI = imsi

		// remove previous session for the same subscriber if exists.
		sess, err := c.GetSessionByIMSI(imsi)
		if err != nil {
			switch err.(type) {
			case *gtpv2.UnknownIMSIError:
				// whole new session. just ignore.
			default:
				return fmt.Errorf("got something unexpected: %w", err)
			}
		} else {
			c.RemoveSession(sess)
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.IMSI}
	}
	if msisdnIE := csReqFromSGW.MSISDN; msisdnIE != nil {
		session.MSISDN, err = msisdnIE.MSISDN()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.MSISDN}
	}
	if meiIE := csReqFromSGW.MEI; meiIE != nil {
		session.IMEI, err = meiIE.MobileEquipmentIdentity()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.MobileEquipmentIdentity}
	}
	if apnIE := csReqFromSGW.APN; apnIE != nil {
		bearer.APN, err = apnIE.AccessPointName()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.AccessPointName}
	}
	if netIE := csReqFromSGW.ServingNetwork; netIE != nil {
		session.MCC, err = netIE.MCC()
		if err != nil {
			return err
		}
		session.MNC, err = netIE.MNC()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.ServingNetwork}
	}
	if ratIE := csReqFromSGW.RATType; ratIE != nil {
		session.RATType, err = ratIE.RATType()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.RATType}
	}
	if fteidcIE := csReqFromSGW.SenderFTEIDC; fteidcIE != nil {
		teid, err := fteidcIE.TEID()
		if err != nil {
			return err
		}
		session.AddTEID(gtpv2.IFTypeS5S8SGWGTPC, teid)
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	var s5sgwuIP string
	var oteiU uint32
	if brCtxIE := csReqFromSGW.BearerContextsToBeCreated; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.EPSBearerID:
				bearer.EBI, err = childIE.EPSBearerID()
				if err != nil {
					return err
				}
			case ie.FullyQualifiedTEID:
				it, err := childIE.InterfaceType()
				if err != nil {
					return err
				}
				oteiU, err = childIE.TEID()
				if err != nil {
					return err
				}
				session.AddTEID(it, oteiU)

				s5sgwuIP, err = childIE.IPAddress()
				if err != nil {
					return err
				}
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	if paaIE := csReqFromSGW.PAA; paaIE != nil {
		bearer.SubscriberIP, err = paaIE.IPAddress()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.PDNAddressAllocation}
	}

	cIP := strings.Split(c.LocalAddr().String(), ":")[0]
	uIP := strings.Split(p.s5u, ":")[0]
	s5cFTEID := c.NewSenderFTEID(cIP, "").WithInstance(1)
	s5uFTEID := p.uConn.NewFTEID(gtpv2.IFTypeS5S8PGWGTPU, uIP, "").WithInstance(2)
	s5sgwTEID, err := session.GetTEID(gtpv2.IFTypeS5S8SGWGTPC)
	if err != nil {
		return err
	}
	csRspFromPGW := message.NewCreateSessionResponse(
		s5sgwTEID, 0,
		ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
		s5cFTEID,
		ie.NewPDNAddressAllocation(bearer.SubscriberIP),
		ie.NewAPNRestriction(gtpv2.APNRestrictionPublic2),
		ie.NewBearerContext(
			ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
			ie.NewEPSBearerID(bearer.EBI),
			s5uFTEID,
			ie.NewChargingID(bearer.ChargingID),
		),
	)
	if csReqFromSGW.SGWFQCSID != nil {
		csRspFromPGW.PGWFQCSID = ie.NewFullyQualifiedCSID(cIP, 1)
	}
	session.AddTEID(gtpv2.IFTypeS5S8PGWGTPC, s5cFTEID.MustTEID())
	session.AddTEID(gtpv2.IFTypeS5S8PGWGTPU, s5uFTEID.MustTEID())

	if err := c.RespondTo(sgwAddr, csReqFromSGW, csRspFromPGW); err != nil {
		return err
	}
	if p.mc != nil {
		p.mc.messagesSent.WithLabelValues(sgwAddr.String(), csRspFromPGW.MessageTypeName()).Inc()
	}

	s5pgwTEID, err := session.GetTEID(gtpv2.IFTypeS5S8PGWGTPC)
	if err != nil {
		return err
	}

	// don't forget to activate and add session created to the session list
	if err := session.Activate(); err != nil {
		return err
	}
	c.RegisterSession(s5pgwTEID, session)

	if p.useKernelGTP {
		if err := p.setupUPlane(net.ParseIP(s5sgwuIP), net.ParseIP(bearer.SubscriberIP), oteiU, s5uFTEID.MustTEID()); err != nil {
			return err
		}
	}

	log.Printf("Session created with S-GW for subscriber: %s;\n\tS5C S-GW: %s, TEID->: %#x, TEID<-: %#x",
		session.Subscriber.IMSI, sgwAddr, s5sgwTEID, s5pgwTEID,
	)
	return nil
}

func (p *pgw) handleDeleteSessionRequest(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), sgwAddr)
	if p.mc != nil {
		p.mc.messagesReceived.WithLabelValues(sgwAddr.String(), msg.MessageTypeName()).Inc()
	}

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	session, err := c.GetSessionByTEID(msg.TEID(), sgwAddr)
	if err != nil {
		dsr := message.NewDeleteSessionResponse(
			0, 0,
			ie.NewCause(gtpv2.CauseIMSIIMEINotKnown, 0, 0, 0, nil),
		)
		if err := c.RespondTo(sgwAddr, msg, dsr); err != nil {
			return err
		}

		return err
	}

	// respond to S-GW with DeleteSessionResponse.
	teid, err := session.GetTEID(gtpv2.IFTypeS5S8SGWGTPC)
	if err != nil {
		log.Println(err)
		return nil
	}
	dsr := message.NewDeleteSessionResponse(
		teid, 0,
		ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
	)
	if err := c.RespondTo(sgwAddr, msg, dsr); err != nil {
		return err
	}
	if p.mc != nil {
		p.mc.messagesSent.WithLabelValues(sgwAddr.String(), dsr.MessageTypeName()).Inc()
	}

	log.Printf("Session deleted for Subscriber: %s", session.IMSI)
	c.RemoveSession(session)
	return nil
}


================================================
FILE: examples/gw-tester/pgw/main.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Command pgw is a dead simple implementation of P-GW only with GTP-related features.
package main

import (
	"context"
	"flag"
	"log"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	var configPath = flag.String("config", "./pgw.yml", "Path to the configuration file.")
	flag.Parse()
	log.SetPrefix("[P-GW] ")

	cfg, err := loadConfig(*configPath)
	if err != nil {
		log.Println(err)
		return
	}

	pgw, err := newPGW(cfg)
	if err != nil {
		log.Printf("failed to initialize P-GW: %s", err)
		return
	}
	defer pgw.close()

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGHUP)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	fatalCh := make(chan error)
	go func() {
		if err := pgw.run(ctx); err != nil {
			fatalCh <- err
		}
	}()

	for {
		select {
		case sig := <-sigCh:
			// TODO: reload config on receiving SIGHUP
			log.Println(sig)
			return
		case err := <-pgw.errCh:
			log.Printf("WARN: %s", err)
		case err := <-fatalCh:
			log.Printf("FATAL: %s", err)
			return
		}
	}
}


================================================
FILE: examples/gw-tester/pgw/metrics.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"log"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/vishvananda/netlink"
)

type metricsCollector struct {
	activeSessions   prometheus.GaugeFunc
	activeBearers    prometheus.GaugeFunc
	messagesSent     *prometheus.CounterVec
	messagesReceived *prometheus.CounterVec
}

func (p *pgw) runMetricsCollector() error {
	mc := &metricsCollector{}
	mc.activeSessions = promauto.NewGaugeFunc(
		prometheus.GaugeOpts{
			Name: "pgw_active_sessions",
			Help: "number of session established currently",
		},
		func() float64 {
			return float64(p.cConn.SessionCount())
		},
	)

	mc.activeBearers = promauto.NewGaugeFunc(
		prometheus.GaugeOpts{
			Name: "pgw_active_bearers",
			Help: "number of GTP-U tunnels established currently",
		},
		func() float64 {
			tunnels, err := netlink.GTPPDPList()
			if err != nil {
				log.Printf("metrics: could not get tunnels: %s", err)
				return 0
			}
			return float64(len(tunnels))
		},
	)

	mc.messagesSent = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "pgw_messages_sent_total",
			Help: "number of message sent by messagge type",
		},
		[]string{"dst", "type"},
	)

	mc.messagesReceived = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "pgw_messages_received_total",
			Help: "number of message received by messagge type",
		},
		[]string{"src", "type"},
	)

	p.mc = mc
	return nil
}


================================================
FILE: examples/gw-tester/pgw/pgw.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"

	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/vishvananda/netlink"

	"github.com/wmnsk/go-gtp/gtpv1"
	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

type pgw struct {
	cConn *gtpv2.Conn
	uConn *gtpv1.UPlaneConn

	s5c, s5u string
	sgiIF    string

	useKernelGTP bool

	routeSubnet *net.IPNet
	addedRoutes []*netlink.Route
	addedRules  []*netlink.Rule

	promAddr string
	mc       *metricsCollector

	errCh chan error
}

func newPGW(cfg *Config) (*pgw, error) {
	p := &pgw{
		s5c:          cfg.LocalAddrs.S5CIP + gtpv2.GTPCPort,
		s5u:          cfg.LocalAddrs.S5UIP + gtpv2.GTPUPort,
		useKernelGTP: cfg.UseKernelGTP,
		sgiIF:        cfg.SGiIFName,

		errCh: make(chan error, 1),
	}

	var err error
	_, p.routeSubnet, err = net.ParseCIDR(cfg.RouteSubnet)
	if err != nil {
		return nil, err
	}

	if cfg.PromAddr != "" {
		// validate if the address is valid or not.
		if _, err = net.ResolveTCPAddr("tcp", cfg.PromAddr); err != nil {
			return nil, err
		}
		p.promAddr = cfg.PromAddr
	}

	if !p.useKernelGTP {
		log.Println("WARN: U-Plane does not work without GTP kernel module")
	}

	return p, nil
}

func (p *pgw) run(ctx context.Context) error {
	cAddr, err := net.ResolveUDPAddr("udp", p.s5c)
	if err != nil {
		return err
	}
	p.cConn = gtpv2.NewConn(cAddr, gtpv2.IFTypeS5S8PGWGTPC, 0)
	go func() {
		if err := p.cConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started serving S5-C on %s", cAddr)

	// register handlers for ALL the message you expect remote endpoint to send.
	p.cConn.AddHandlers(map[uint8]gtpv2.HandlerFunc{
		message.MsgTypeCreateSessionRequest: p.handleCreateSessionRequest,
		message.MsgTypeDeleteSessionRequest: p.handleDeleteSessionRequest,
	})

	uAddr, err := net.ResolveUDPAddr("udp", p.s5u)
	if err != nil {
		return err
	}
	p.uConn = gtpv1.NewUPlaneConn(uAddr)
	if p.useKernelGTP {
		if err := p.uConn.EnableKernelGTP("gtp-pgw", gtpv1.RoleGGSN); err != nil {
			return err
		}
	}
	go func() {
		if err = p.uConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
		log.Println("uConn.ListenAndServe exitted")
	}()
	log.Printf("Started serving S5-U on %s", uAddr)

	// start serving Prometheus, if address is given
	if p.promAddr != "" {
		if err := p.runMetricsCollector(); err != nil {
			return err
		}

		http.Handle("/metrics", promhttp.Handler())
		go func() {
			if err := http.ListenAndServe(p.promAddr, nil); err != nil {
				log.Println(err)
			}
		}()
		log.Printf("Started serving Prometheus on %s", p.promAddr)
	}

	for {
		select {
		case <-ctx.Done():
			return nil
		case err := <-p.errCh:
			log.Printf("Warning: %s", err)
		}
	}
}

func (p *pgw) close() error {
	var errs []error
	for _, r := range p.addedRoutes {
		if err := netlink.RouteDel(r); err != nil {
			errs = append(errs, err)
		}
	}
	for _, r := range p.addedRules {
		if err := netlink.RuleDel(r); err != nil {
			errs = append(errs, err)
		}
	}

	if p.uConn != nil {
		if err := p.uConn.Close(); err != nil {
			errs = append(errs, err)
		}
	}

	if err := p.cConn.Close(); err != nil {
		errs = append(errs, err)
	}

	close(p.errCh)

	if len(errs) > 0 {
		return fmt.Errorf("errors while closing S-GW: %+v", errs)
	}
	return nil
}

func (p *pgw) setupUPlane(peerIP, msIP net.IP, otei, itei uint32) error {
	if err := p.uConn.AddTunnelOverride(peerIP, msIP, otei, itei); err != nil {
		return err
	}

	ms32 := &net.IPNet{IP: msIP, Mask: net.CIDRMask(32, 32)}
	dlroute := &netlink.Route{ // ip route replace
		Dst:       ms32,                                 // UE's IP
		LinkIndex: p.uConn.KernelGTP.Link.Attrs().Index, // dev gtp-pgw
		Scope:     netlink.SCOPE_LINK,                   // scope link
		Protocol:  4,                                    // proto static
		Priority:  1,                                    // metric 1
		Table:     3001,                                 // table 3001
	}
	if err := netlink.RouteReplace(dlroute); err != nil {
		return err
	}
	p.addedRoutes = append(p.addedRoutes, dlroute)

	link, err := netlink.LinkByName(p.sgiIF)
	if err != nil {
		return err
	}

	ulroute := &netlink.Route{ // ip route replace
		Dst:       p.routeSubnet,      // dst network via SGi
		LinkIndex: link.Attrs().Index, // SGi I/F name
		Scope:     netlink.SCOPE_LINK, // scope link
		Protocol:  4,                  // proto static
		Priority:  1,                  // metric 1
	}
	if err := netlink.RouteReplace(ulroute); err != nil {
		return err
	}
	p.addedRoutes = append(p.addedRoutes, ulroute)

	rules, err := netlink.RuleList(0)
	if err != nil {
		return err
	}
	for _, r := range rules {
		if r.IifName == link.Attrs().Name && r.Dst == ms32 {
			return nil
		}
	}

	rule := netlink.NewRule()
	rule.IifName = link.Attrs().Name
	rule.Dst = ms32
	rule.Table = 3001
	if err := netlink.RuleAdd(rule); err != nil {
		return err
	}
	p.addedRules = append(p.addedRules, rule)

	return nil
}


================================================
FILE: examples/gw-tester/pgw/pgw.yml
================================================
local_addresses:
  s5c_ip: "127.0.1.15"
  s5u_ip: "127.0.0.15"
  sgi_ip: "127.0.1.254"
sgi_if_name: "lo"
route_subnet: "192.168.101.0/24"
use_kernel_gtp: false
prom_addr: "127.0.10.4:58080"


================================================
FILE: examples/gw-tester/s1mme/s1mme.pb.go
================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: s1mme.proto

package s1mme

import (
	context "context"
	fmt "fmt"
	proto "github.com/golang/protobuf/proto"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
	math "math"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

// Cause represents a result of attach / detach.
type Cause int32

const (
	Cause_INVALID        Cause = 0
	Cause_SUCCESS        Cause = 1
	Cause_GW_UNAVAILABLE Cause = 2
)

var Cause_name = map[int32]string{
	0: "INVALID",
	1: "SUCCESS",
	2: "GW_UNAVAILABLE",
}

var Cause_value = map[string]int32{
	"INVALID":        0,
	"SUCCESS":        1,
	"GW_UNAVAILABLE": 2,
}

func (x Cause) String() string {
	return proto.EnumName(Cause_name, int32(x))
}

func (Cause) EnumDescriptor() ([]byte, []int) {
	return fileDescriptor_24365dc18e89382c, []int{0}
}

type Location_RATType int32

const (
	Location_INVALID        Location_RATType = 0
	Location_UTRAN          Location_RATType = 1
	Location_GERAN          Location_RATType = 2
	Location_WLAN           Location_RATType = 3
	Location_GAN            Location_RATType = 4
	Location_HSPA_EVOLUTION Location_RATType = 5
	Location_EUTRAN         Location_RATType = 6
	Location_VIRTUAL        Location_RATType = 7
	Location_EUTRAN_NB_IOT  Location_RATType = 8
	Location_LTEM           Location_RATType = 9
	Location_NR             Location_RATType = 10
)

var Location_RATType_name = map[int32]string{
	0:  "INVALID",
	1:  "UTRAN",
	2:  "GERAN",
	3:  "WLAN",
	4:  "GAN",
	5:  "HSPA_EVOLUTION",
	6:  "EUTRAN",
	7:  "VIRTUAL",
	8:  "EUTRAN_NB_IOT",
	9:  "LTEM",
	10: "NR",
}

var Location_RATType_value = map[string]int32{
	"INVALID":        0,
	"UTRAN":          1,
	"GERAN":          2,
	"WLAN":           3,
	"GAN":            4,
	"HSPA_EVOLUTION": 5,
	"EUTRAN":         6,
	"VIRTUAL":        7,
	"EUTRAN_NB_IOT":  8,
	"LTEM":           9,
	"NR":             10,
}

func (x Location_RATType) String() string {
	return proto.EnumName(Location_RATType_name, int32(x))
}

func (Location_RATType) EnumDescriptor() ([]byte, []int) {
	return fileDescriptor_24365dc18e89382c, []int{2, 0}
}

// AttachRequest is used to request MME to create a session/bearer.
type AttachRequest struct {
	Imsi                 string    `protobuf:"bytes,1,opt,name=imsi,proto3" json:"imsi,omitempty"`
	Msisdn               string    `protobuf:"bytes,2,opt,name=msisdn,proto3" json:"msisdn,omitempty"`
	Imeisv               string    `protobuf:"bytes,3,opt,name=imeisv,proto3" json:"imeisv,omitempty"`
	S1UAddr              string    `protobuf:"bytes,4,opt,name=s1u_addr,json=s1uAddr,proto3" json:"s1u_addr,omitempty"`
	SrcIp                string    `protobuf:"bytes,5,opt,name=src_ip,json=srcIp,proto3" json:"src_ip,omitempty"`
	ITei                 uint32    `protobuf:"varint,6,opt,name=i_tei,json=iTei,proto3" json:"i_tei,omitempty"`
	Location             *Location `protobuf:"bytes,7,opt,name=location,proto3" json:"location,omitempty"`
	Reattach             bool      `protobuf:"varint,8,opt,name=reattach,proto3" json:"reattach,omitempty"`
	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
	XXX_unrecognized     []byte    `json:"-"`
	XXX_sizecache        int32     `json:"-"`
}

func (m *AttachRequest) Reset()         { *m = AttachRequest{} }
func (m *AttachRequest) String() string { return proto.CompactTextString(m) }
func (*AttachRequest) ProtoMessage()    {}
func (*AttachRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_24365dc18e89382c, []int{0}
}

func (m *AttachRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_AttachRequest.Unmarshal(m, b)
}
func (m *AttachRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_AttachRequest.Marshal(b, m, deterministic)
}
func (m *AttachRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_AttachRequest.Merge(m, src)
}
func (m *AttachRequest) XXX_Size() int {
	return xxx_messageInfo_AttachRequest.Size(m)
}
func (m *AttachRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_AttachRequest.DiscardUnknown(m)
}

var xxx_messageInfo_AttachRequest proto.InternalMessageInfo

func (m *AttachRequest) GetImsi() string {
	if m != nil {
		return m.Imsi
	}
	return ""
}

func (m *AttachRequest) GetMsisdn() string {
	if m != nil {
		return m.Msisdn
	}
	return ""
}

func (m *AttachRequest) GetImeisv() string {
	if m != nil {
		return m.Imeisv
	}
	return ""
}

func (m *AttachRequest) GetS1UAddr() string {
	if m != nil {
		return m.S1UAddr
	}
	return ""
}

func (m *AttachRequest) GetSrcIp() string {
	if m != nil {
		return m.SrcIp
	}
	return ""
}

func (m *AttachRequest) GetITei() uint32 {
	if m != nil {
		return m.ITei
	}
	return 0
}

func (m *AttachRequest) GetLocation() *Location {
	if m != nil {
		return m.Location
	}
	return nil
}

func (m *AttachRequest) GetReattach() bool {
	if m != nil {
		return m.Reattach
	}
	return false
}

// AttachResponse is used to respond to AttachRequest.
type AttachResponse struct {
	Cause                Cause    `protobuf:"varint,1,opt,name=cause,proto3,enum=s1mme.Cause" json:"cause,omitempty"`
	SgwAddr              string   `protobuf:"bytes,2,opt,name=sgw_addr,json=sgwAddr,proto3" json:"sgw_addr,omitempty"`
	OTei                 uint32   `protobuf:"varint,3,opt,name=o_tei,json=oTei,proto3" json:"o_tei,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *AttachResponse) Reset()         { *m = AttachResponse{} }
func (m *AttachResponse) String() string { return proto.CompactTextString(m) }
func (*AttachResponse) ProtoMessage()    {}
func (*AttachResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_24365dc18e89382c, []int{1}
}

func (m *AttachResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_AttachResponse.Unmarshal(m, b)
}
func (m *AttachResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_AttachResponse.Marshal(b, m, deterministic)
}
func (m *AttachResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_AttachResponse.Merge(m, src)
}
func (m *AttachResponse) XXX_Size() int {
	return xxx_messageInfo_AttachResponse.Size(m)
}
func (m *AttachResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_AttachResponse.DiscardUnknown(m)
}

var xxx_messageInfo_AttachResponse proto.InternalMessageInfo

func (m *AttachResponse) GetCause() Cause {
	if m != nil {
		return m.Cause
	}
	return Cause_INVALID
}

func (m *AttachResponse) GetSgwAddr() string {
	if m != nil {
		return m.SgwAddr
	}
	return ""
}

func (m *AttachResponse) GetOTei() uint32 {
	if m != nil {
		return m.OTei
	}
	return 0
}

// Location represents a set of location-related information.
type Location struct {
	Mcc                  string           `protobuf:"bytes,1,opt,name=mcc,proto3" json:"mcc,omitempty"`
	Mnc                  string           `protobuf:"bytes,2,opt,name=mnc,proto3" json:"mnc,omitempty"`
	RatType              Location_RATType `protobuf:"varint,3,opt,name=rat_type,json=ratType,proto3,enum=s1mme.Location_RATType" json:"rat_type,omitempty"`
	Tai                  uint32           `protobuf:"varint,4,opt,name=tai,proto3" json:"tai,omitempty"`
	Eci                  uint32           `protobuf:"varint,5,opt,name=eci,proto3" json:"eci,omitempty"`
	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
	XXX_unrecognized     []byte           `json:"-"`
	XXX_sizecache        int32            `json:"-"`
}

func (m *Location) Reset()         { *m = Location{} }
func (m *Location) String() string { return proto.CompactTextString(m) }
func (*Location) ProtoMessage()    {}
func (*Location) Descriptor() ([]byte, []int) {
	return fileDescriptor_24365dc18e89382c, []int{2}
}

func (m *Location) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Location.Unmarshal(m, b)
}
func (m *Location) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Location.Marshal(b, m, deterministic)
}
func (m *Location) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Location.Merge(m, src)
}
func (m *Location) XXX_Size() int {
	return xxx_messageInfo_Location.Size(m)
}
func (m *Location) XXX_DiscardUnknown() {
	xxx_messageInfo_Location.DiscardUnknown(m)
}

var xxx_messageInfo_Location proto.InternalMessageInfo

func (m *Location) GetMcc() string {
	if m != nil {
		return m.Mcc
	}
	return ""
}

func (m *Location) GetMnc() string {
	if m != nil {
		return m.Mnc
	}
	return ""
}

func (m *Location) GetRatType() Location_RATType {
	if m != nil {
		return m.RatType
	}
	return Location_INVALID
}

func (m *Location) GetTai() uint32 {
	if m != nil {
		return m.Tai
	}
	return 0
}

func (m *Location) GetEci() uint32 {
	if m != nil {
		return m.Eci
	}
	return 0
}

// DetachRequest is used to request MME to delete a session/bearer.
type DetachRequest struct {
	Imsi                 string   `protobuf:"bytes,1,opt,name=imsi,proto3" json:"imsi,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *DetachRequest) Reset()         { *m = DetachRequest{} }
func (m *DetachRequest) String() string { return proto.CompactTextString(m) }
func (*DetachRequest) ProtoMessage()    {}
func (*DetachRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_24365dc18e89382c, []int{3}
}

func (m *DetachRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_DetachRequest.Unmarshal(m, b)
}
func (m *DetachRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_DetachRequest.Marshal(b, m, deterministic)
}
func (m *DetachRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_DetachRequest.Merge(m, src)
}
func (m *DetachRequest) XXX_Size() int {
	return xxx_messageInfo_DetachRequest.Size(m)
}
func (m *DetachRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_DetachRequest.DiscardUnknown(m)
}

var xxx_messageInfo_DetachRequest proto.InternalMessageInfo

func (m *DetachRequest) GetImsi() string {
	if m != nil {
		return m.Imsi
	}
	return ""
}

// DetachResponse is used to respond to DetachRequest.
type DetachResponse struct {
	Cause                Cause    `protobuf:"varint,1,opt,name=cause,proto3,enum=s1mme.Cause" json:"cause,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *DetachResponse) Reset()         { *m = DetachResponse{} }
func (m *DetachResponse) String() string { return proto.CompactTextString(m) }
func (*DetachResponse) ProtoMessage()    {}
func (*DetachResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_24365dc18e89382c, []int{4}
}

func (m *DetachResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_DetachResponse.Unmarshal(m, b)
}
func (m *DetachResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_DetachResponse.Marshal(b, m, deterministic)
}
func (m *DetachResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_DetachResponse.Merge(m, src)
}
func (m *DetachResponse) XXX_Size() int {
	return xxx_messageInfo_DetachResponse.Size(m)
}
func (m *DetachResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_DetachResponse.DiscardUnknown(m)
}

var xxx_messageInfo_DetachResponse proto.InternalMessageInfo

func (m *DetachResponse) GetCause() Cause {
	if m != nil {
		return m.Cause
	}
	return Cause_INVALID
}

func init() {
	proto.RegisterEnum("s1mme.Cause", Cause_name, Cause_value)
	proto.RegisterEnum("s1mme.Location_RATType", Location_RATType_name, Location_RATType_value)
	proto.RegisterType((*AttachRequest)(nil), "s1mme.AttachRequest")
	proto.RegisterType((*AttachResponse)(nil), "s1mme.AttachResponse")
	proto.RegisterType((*Location)(nil), "s1mme.Location")
	proto.RegisterType((*DetachRequest)(nil), "s1mme.DetachRequest")
	proto.RegisterType((*DetachResponse)(nil), "s1mme.DetachResponse")
}

func init() { proto.RegisterFile("s1mme.proto", fileDescriptor_24365dc18e89382c) }

var fileDescriptor_24365dc18e89382c = []byte{
	// 536 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x4f, 0x6f, 0xd3, 0x4c,
	0x10, 0xc6, 0x6b, 0x27, 0xfe, 0xd3, 0xc9, 0xeb, 0xbc, 0xcb, 0x96, 0x82, 0xe9, 0x29, 0x32, 0x97,
	0x08, 0xa4, 0x4a, 0x0d, 0x20, 0xce, 0xdb, 0xd4, 0x0a, 0x96, 0x8c, 0x83, 0x36, 0x4e, 0x7a, 0xb4,
	0x8c, 0xbd, 0x2a, 0x2b, 0xe1, 0xd8, 0x78, 0x1d, 0xaa, 0x4a, 0x7c, 0x09, 0xae, 0x7c, 0x3d, 0xbe,
	0x08, 0xda, 0x5d, 0x27, 0x52, 0x7a, 0x81, 0xdb, 0x33, 0xcf, 0xec, 0x8c, 0xe7, 0x37, 0xde, 0x85,
	0x91, 0xb8, 0xaa, 0x2a, 0x76, 0xd9, 0xb4, 0x75, 0x57, 0x63, 0x4b, 0x05, 0xc1, 0x6f, 0x03, 0x3c,
	0xd2, 0x75, 0x79, 0xf1, 0x85, 0xb2, 0x6f, 0x3b, 0x26, 0x3a, 0x8c, 0x61, 0xc8, 0x2b, 0xc1, 0x7d,
	0x63, 0x62, 0x4c, 0x4f, 0xa9, 0xd2, 0xf8, 0x19, 0xd8, 0x95, 0xe0, 0xa2, 0xdc, 0xfa, 0xa6, 0x72,
	0xfb, 0x48, 0xfa, 0xbc, 0x62, 0x5c, 0x7c, 0xf7, 0x07, 0xda, 0xd7, 0x11, 0x7e, 0x01, 0xae, 0xb8,
	0xda, 0x65, 0x79, 0x59, 0xb6, 0xfe, 0x50, 0x65, 0x1c, 0x71, 0xb5, 0x23, 0x65, 0xd9, 0xe2, 0x73,
	0xb0, 0x45, 0x5b, 0x64, 0xbc, 0xf1, 0x2d, 0x95, 0xb0, 0x44, 0x5b, 0x44, 0x0d, 0x3e, 0x03, 0x8b,
	0x67, 0x1d, 0xe3, 0xbe, 0x3d, 0x31, 0xa6, 0x1e, 0x1d, 0xf2, 0x94, 0x71, 0xfc, 0x1a, 0xdc, 0xaf,
	0x75, 0x91, 0x77, 0xbc, 0xde, 0xfa, 0xce, 0xc4, 0x98, 0x8e, 0x66, 0xff, 0x5f, 0x6a, 0x86, 0xb8,
	0xb7, 0xe9, 0xe1, 0x00, 0xbe, 0x00, 0xb7, 0x65, 0xb9, 0x42, 0xf1, 0xdd, 0x89, 0x31, 0x75, 0xe9,
	0x21, 0x0e, 0x4a, 0x18, 0xef, 0x21, 0x45, 0x53, 0x6f, 0x05, 0xc3, 0x01, 0x58, 0x45, 0xbe, 0x13,
	0x4c, 0x61, 0x8e, 0x67, 0xff, 0xf5, 0x7d, 0xe7, 0xd2, 0xa3, 0x3a, 0xa5, 0x28, 0xee, 0xee, 0x35,
	0x85, 0xd9, 0x53, 0xdc, 0xdd, 0x2b, 0x8a, 0x33, 0xb0, 0x6a, 0x35, 0xee, 0x40, 0x8f, 0x5b, 0xa7,
	0x8c, 0x07, 0xbf, 0x4c, 0x70, 0xf7, 0x83, 0x61, 0x04, 0x83, 0xaa, 0x28, 0xfa, 0x2d, 0x4a, 0xa9,
	0x9c, 0x6d, 0xd1, 0x77, 0x92, 0x12, 0xcf, 0xc0, 0x6d, 0xf3, 0x2e, 0xeb, 0x1e, 0x1a, 0xa6, 0x1a,
	0x8d, 0x67, 0xcf, 0x1f, 0xf1, 0x5d, 0x52, 0x92, 0xa6, 0x0f, 0x0d, 0xa3, 0x4e, 0x9b, 0x77, 0x52,
	0xc8, 0x2e, 0x5d, 0xce, 0xd5, 0x56, 0x3d, 0x2a, 0xa5, 0x74, 0x58, 0xc1, 0xd5, 0x3a, 0x3d, 0x2a,
	0x65, 0xf0, 0xd3, 0x00, 0xa7, 0x2f, 0xc4, 0x23, 0x70, 0xa2, 0x64, 0x43, 0xe2, 0xe8, 0x06, 0x9d,
	0xe0, 0x53, 0xb0, 0xd6, 0x29, 0x25, 0x09, 0x32, 0xa4, 0x5c, 0x84, 0x52, 0x9a, 0xd8, 0x85, 0xe1,
	0x6d, 0x4c, 0x12, 0x34, 0xc0, 0x0e, 0x0c, 0x16, 0x24, 0x41, 0x43, 0x8c, 0x61, 0xfc, 0x61, 0xf5,
	0x89, 0x64, 0xe1, 0x66, 0x19, 0xaf, 0xd3, 0x68, 0x99, 0x20, 0x0b, 0x03, 0xd8, 0xa1, 0xae, 0xb6,
	0x65, 0xd7, 0x4d, 0x44, 0xd3, 0x35, 0x89, 0x91, 0x83, 0x9f, 0x80, 0xa7, 0x13, 0x59, 0x72, 0x9d,
	0x45, 0xcb, 0x14, 0xb9, 0xb2, 0x65, 0x9c, 0x86, 0x1f, 0xd1, 0x29, 0xb6, 0xc1, 0x4c, 0x28, 0x82,
	0xe0, 0x25, 0x78, 0x37, 0xec, 0x2f, 0xf7, 0x2c, 0x78, 0x0b, 0xe3, 0xfd, 0xa1, 0x7f, 0xff, 0x4f,
	0xaf, 0xde, 0x81, 0xa5, 0xe2, 0x63, 0xd6, 0x11, 0x38, 0xab, 0xf5, 0x7c, 0x1e, 0xae, 0x56, 0xc8,
	0x90, 0x3c, 0x8b, 0xdb, 0x6c, 0x9d, 0x90, 0x0d, 0x89, 0x62, 0x72, 0x1d, 0x87, 0xc8, 0x9c, 0xfd,
	0x00, 0x57, 0x5f, 0x0a, 0xd6, 0xe2, 0xf7, 0x60, 0x6b, 0x8d, 0x9f, 0xf6, 0x5f, 0x38, 0x7a, 0x14,
	0x17, 0xe7, 0x8f, 0x5c, 0x3d, 0x5d, 0x70, 0x22, 0x0b, 0xf5, 0xc4, 0x87, 0xc2, 0x23, 0xca, 0x43,
	0xe1, 0x31, 0x56, 0x70, 0xf2, 0xd9, 0x56, 0xcf, 0xf0, 0xcd, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff,
	0xf1, 0x17, 0x91, 0x66, 0x95, 0x03, 0x00, 0x00,
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4

// AttacherClient is the client API for Attacher service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type AttacherClient interface {
	Attach(ctx context.Context, in *AttachRequest, opts ...grpc.CallOption) (*AttachResponse, error)
	Detach(ctx context.Context, in *DetachRequest, opts ...grpc.CallOption) (*DetachResponse, error)
}

type attacherClient struct {
	cc *grpc.ClientConn
}

func NewAttacherClient(cc *grpc.ClientConn) AttacherClient {
	return &attacherClient{cc}
}

func (c *attacherClient) Attach(ctx context.Context, in *AttachRequest, opts ...grpc.CallOption) (*AttachResponse, error) {
	out := new(AttachResponse)
	err := c.cc.Invoke(ctx, "/s1mme.Attacher/Attach", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *attacherClient) Detach(ctx context.Context, in *DetachRequest, opts ...grpc.CallOption) (*DetachResponse, error) {
	out := new(DetachResponse)
	err := c.cc.Invoke(ctx, "/s1mme.Attacher/Detach", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// AttacherServer is the server API for Attacher service.
type AttacherServer interface {
	Attach(context.Context, *AttachRequest) (*AttachResponse, error)
	Detach(context.Context, *DetachRequest) (*DetachResponse, error)
}

// UnimplementedAttacherServer can be embedded to have forward compatible implementations.
type UnimplementedAttacherServer struct {
}

func (*UnimplementedAttacherServer) Attach(ctx context.Context, req *AttachRequest) (*AttachResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method Attach not implemented")
}
func (*UnimplementedAttacherServer) Detach(ctx context.Context, req *DetachRequest) (*DetachResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method Detach not implemented")
}

func RegisterAttacherServer(s *grpc.Server, srv AttacherServer) {
	s.RegisterService(&_Attacher_serviceDesc, srv)
}

func _Attacher_Attach_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(AttachRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(AttacherServer).Attach(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/s1mme.Attacher/Attach",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(AttacherServer).Attach(ctx, req.(*AttachRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Attacher_Detach_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(DetachRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(AttacherServer).Detach(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/s1mme.Attacher/Detach",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(AttacherServer).Detach(ctx, req.(*DetachRequest))
	}
	return interceptor(ctx, in, info, handler)
}

var _Attacher_serviceDesc = grpc.ServiceDesc{
	ServiceName: "s1mme.Attacher",
	HandlerType: (*AttacherServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "Attach",
			Handler:    _Attacher_Attach_Handler,
		},
		{
			MethodName: "Detach",
			Handler:    _Attacher_Detach_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "s1mme.proto",
}


================================================
FILE: examples/gw-tester/s1mme/s1mme.proto
================================================
syntax = "proto3";

package s1mme;

// Attacher defines the service to attach UE.
service Attacher {
    rpc Attach (AttachRequest) returns (AttachResponse) {}
    rpc Detach (DetachRequest) returns (DetachResponse) {}
}

// AttachRequest is used to request MME to create a session/bearer.
message AttachRequest {
    string imsi = 1;
    string msisdn = 2;
    string imeisv = 3;
    string s1u_addr = 4;
    string src_ip = 5;
    uint32 i_tei = 6;
    Location location = 7;
    bool reattach = 8;
}

// AttachResponse is used to respond to AttachRequest.
message AttachResponse {
    Cause cause = 1; // result
    string sgw_addr = 2;
    uint32 o_tei = 3;
}

// Cause represents a result of attach / detach.
enum Cause {
    INVALID = 0;
    SUCCESS = 1;
    GW_UNAVAILABLE = 2;
}

// Location represents a set of location-related information.
message Location {
    string mcc = 1;
    string mnc = 2;
    RATType rat_type = 3;
    uint32 tai = 4;
    uint32 eci = 5;

    enum RATType {
        INVALID = 0;
        UTRAN = 1;
        GERAN = 2;
        WLAN = 3;
        GAN = 4;
        HSPA_EVOLUTION = 5;
        EUTRAN = 6;
        VIRTUAL = 7;
        EUTRAN_NB_IOT = 8;
        LTEM = 9;
        NR = 10;
    }
}

// DetachRequest is used to request MME to delete a session/bearer.
message DetachRequest {
    string imsi = 1;
}

// DetachResponse is used to respond to DetachRequest.
message DetachResponse {
    Cause cause = 1;
}


================================================
FILE: examples/gw-tester/sgw/config.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"io/ioutil"

	"gopkg.in/yaml.v2"
)

// Config is a configurations loaded from yaml.
type Config struct {
	LocalAddrs struct {
		S11IP string `yaml:"s11_ip"`
		S1UIP string `yaml:"s1u_ip"`
		S5CIP string `yaml:"s5c_ip"`
		S5UIP string `yaml:"s5u_ip"`
	} `yaml:"local_addresses"`

	UseKernelGTP bool   `yaml:"use_kernel_gtp"`
	PromAddr     string `yaml:"prom_addr"`
}

func loadConfig(path string) (*Config, error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	c := &Config{}
	if err := yaml.Unmarshal(buf, c); err != nil {
		return nil, err
	}

	return c, nil
}


================================================
FILE: examples/gw-tester/sgw/main.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Command sgw is a dead simple implementation of S-GW.
package main

import (
	"context"
	"flag"
	"log"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	var configPath = flag.String("config", "./sgw.yml", "Path to the configuration file.")
	flag.Parse()
	log.SetPrefix("[S-GW] ")

	cfg, err := loadConfig(*configPath)
	if err != nil {
		log.Println(err)
		return
	}

	sgw, err := newSGW(cfg)
	if err != nil {
		log.Printf("failed to initialize SGW: %s", err)
	}
	defer sgw.close()

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGHUP)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	fatalCh := make(chan error)
	go func() {
		if err := sgw.run(ctx); err != nil {
			fatalCh <- err
		}
	}()

	for {
		select {
		case sig := <-sigCh:
			// TODO: reload config on receiving SIGHUP
			log.Println(sig)
			return
		case err := <-sgw.errCh:
			log.Printf("WARN: %s", err)
		case err := <-fatalCh:
			log.Printf("FATAL: %s", err)
			return
		}
	}
}


================================================
FILE: examples/gw-tester/sgw/metrics.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"log"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/vishvananda/netlink"
)

type metricsCollector struct {
	activeSessions   prometheus.GaugeFunc
	activeBearers    prometheus.GaugeFunc
	messagesSent     *prometheus.CounterVec
	messagesReceived *prometheus.CounterVec
}

func (s *sgw) runMetricsCollector() error {
	mc := &metricsCollector{}
	mc.activeSessions = promauto.NewGaugeFunc(
		prometheus.GaugeOpts{
			Name: "sgw_active_sessions",
			Help: "number of session established currently",
		},
		func() float64 {
			return float64(s.s11Conn.SessionCount())
		},
	)

	mc.activeBearers = promauto.NewGaugeFunc(
		prometheus.GaugeOpts{
			Name: "sgw_active_bearers",
			Help: "number of GTP-U tunnels established currently",
		},
		func() float64 {
			tunnels, err := netlink.GTPPDPList()
			if err != nil {
				log.Printf("metrics: could not get tunnels: %s", err)
				return 0
			}
			return float64(len(tunnels))
		},
	)

	mc.messagesSent = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "sgw_messages_sent_total",
			Help: "number of message sent by messagge type",
		},
		[]string{"dst", "type"},
	)

	mc.messagesReceived = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "sgw_messages_received_total",
			Help: "number of message received by messagge type",
		},
		[]string{"src", "type"},
	)

	s.mc = mc
	return nil
}


================================================
FILE: examples/gw-tester/sgw/s11_handlers.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"net"
	"time"

	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

func (s *sgw) handleCreateSessionRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), mmeAddr)
	if s.mc != nil {
		s.mc.messagesReceived.WithLabelValues(mmeAddr.String(), msg.MessageTypeName()).Inc()
	}

	s11Session := gtpv2.NewSession(mmeAddr, &gtpv2.Subscriber{Location: &gtpv2.Location{}})
	s11Bearer := s11Session.GetDefaultBearer()

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	csReqFromMME := msg.(*message.CreateSessionRequest)

	var pgwAddrString string
	if fteidcIE := csReqFromMME.PGWS5S8FTEIDC; fteidcIE != nil {
		ip, err := fteidcIE.IPAddress()
		if err != nil {
			return err
		}
		pgwAddrString = ip + gtpv2.GTPCPort

		teid, err := fteidcIE.TEID()
		if err != nil {
			return err
		}
		s11Session.AddTEID(gtpv2.IFTypeS5S8PGWGTPC, teid)
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	if fteidcIE := csReqFromMME.SenderFTEIDC; fteidcIE != nil {
		teid, err := fteidcIE.TEID()
		if err != nil {
			return err
		}
		s11Session.AddTEID(gtpv2.IFTypeS11MMEGTPC, teid)
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	raddr, err := net.ResolveUDPAddr("udp", pgwAddrString)
	if err != nil {
		return err
	}

	// keep session information retrieved from the message.
	// XXX - should return error if required IE is missing.
	if imsiIE := csReqFromMME.IMSI; imsiIE != nil {
		imsi, err := imsiIE.IMSI()
		if err != nil {
			return err
		}

		// remove previous session for the same subscriber if exists.
		sess, err := s11Conn.GetSessionByIMSI(imsi)
		if err != nil {
			switch err.(type) {
			case *gtpv2.UnknownIMSIError:
				// whole new session. just ignore.
			default:
				return fmt.Errorf("got something unexpected: %w", err)
			}
		} else {
			s11Conn.RemoveSession(sess)
		}

		s11Session.IMSI = imsi
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.IMSI}
	}

	if msisdnIE := csReqFromMME.MSISDN; msisdnIE != nil {
		s11Session.MSISDN, err = msisdnIE.MSISDN()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.MSISDN}
	}

	if meiIE := csReqFromMME.MEI; meiIE != nil {
		s11Session.IMEI, err = meiIE.MobileEquipmentIdentity()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.MobileEquipmentIdentity}
	}

	if apnIE := csReqFromMME.APN; apnIE != nil {
		s11Bearer.APN, err = apnIE.AccessPointName()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.AccessPointName}
	}

	if netIE := csReqFromMME.ServingNetwork; netIE != nil {
		s11Session.MCC, err = netIE.MCC()
		if err != nil {
			return err
		}
		s11Session.MNC, err = netIE.MNC()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.ServingNetwork}
	}

	if ratIE := csReqFromMME.RATType; ratIE != nil {
		s11Session.RATType, err = ratIE.RATType()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.RATType}
	}
	s11sgwFTEID := s11Conn.NewSenderFTEID(s.s11IP, "")
	s11sgwTEID := s11sgwFTEID.MustTEID()
	s11Conn.RegisterSession(s11sgwTEID, s11Session)

	s5cFTEID := s.s5cConn.NewSenderFTEID(s.s5cIP, "")
	s5uFTEID := s.s5uConn.NewFTEID(gtpv2.IFTypeS5S8SGWGTPU, s.s5uIP, "").WithInstance(2)

	s5Session, seq, err := s.s5cConn.CreateSession(
		raddr,
		csReqFromMME.IMSI, csReqFromMME.MSISDN, csReqFromMME.MEI, csReqFromMME.ServingNetwork,
		csReqFromMME.RATType, csReqFromMME.IndicationFlags, s5cFTEID, csReqFromMME.PGWS5S8FTEIDC,
		csReqFromMME.APN, csReqFromMME.SelectionMode, csReqFromMME.PDNType, csReqFromMME.PAA,
		csReqFromMME.APNRestriction, csReqFromMME.AMBR, csReqFromMME.ULI,
		ie.NewBearerContext(
			ie.NewEPSBearerID(5),
			s5uFTEID,
			ie.NewBearerQoS(1, 2, 1, 0xff, 0, 0, 0, 0),
		),
		csReqFromMME.MMEFQCSID,
		ie.NewFullyQualifiedCSID(s.s5uIP, 1).WithInstance(1),
	)
	if err != nil {
		return err
	}
	s5Session.AddTEID(s5uFTEID.MustInterfaceType(), s5uFTEID.MustTEID())

	log.Printf("Sent Create Session Request to %s for %s", pgwAddrString, s5Session.IMSI)
	if s.mc != nil {
		s.mc.messagesSent.WithLabelValues(mmeAddr.String(), "Create Session Request").Inc()
	}

	var csRspFromSGW *message.CreateSessionResponse
	s11mmeTEID, err := s11Session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}

	incomingMsg, err := s11Session.WaitMessage(seq, 5*time.Second)
	if err != nil {
		csRspFromSGW = message.NewCreateSessionResponse(
			s11mmeTEID, 0,
			ie.NewCause(gtpv2.CauseNoResourcesAvailable, 0, 0, 0, nil),
		)

		if err := s11Conn.RespondTo(mmeAddr, csReqFromMME, csRspFromSGW); err != nil {
			s11Conn.RemoveSession(s11Session)
			return err
		}
		log.Printf(
			"Sent %s with failure code: %d, target subscriber: %s",
			csRspFromSGW.MessageTypeName(), gtpv2.CausePGWNotResponding, s11Session.IMSI,
		)
		s11Conn.RemoveSession(s11Session)
		return err
	}

	var csRspFromPGW *message.CreateSessionResponse
	switch m := incomingMsg.(type) {
	case *message.CreateSessionResponse:
		// move forward
		csRspFromPGW = m

		bearer := s11Session.GetDefaultBearer()
		if ie := csRspFromPGW.PAA; ie != nil {
			bearer.SubscriberIP, err = ie.IPAddress()
			if err != nil {
				return err
			}
		}
	default:
		s11Conn.RemoveSession(s11Session)
		return &gtpv2.UnexpectedTypeError{Msg: incomingMsg}
	}

	// if everything in CreateSessionResponse seems OK, relay it to MME.
	s1usgwFTEID := s.s1uConn.NewFTEID(gtpv2.IFTypeS1USGWGTPU, s.s1uIP, "")
	csRspFromSGW = csRspFromPGW
	csRspFromSGW.SenderFTEIDC = s11sgwFTEID
	csRspFromSGW.SGWFQCSID = ie.NewFullyQualifiedCSID(s.s1uIP, 1).WithInstance(1)
	csRspFromSGW.BearerContextsCreated[0].Add(s1usgwFTEID)
	csRspFromSGW.BearerContextsCreated[0].Remove(ie.ChargingID, 0)
	csRspFromSGW.SetTEID(s11mmeTEID)
	csRspFromSGW.SetLength()

	s11Session.AddTEID(s11sgwFTEID.MustInterfaceType(), s11sgwTEID)
	s11Session.AddTEID(s1usgwFTEID.MustInterfaceType(), s1usgwFTEID.MustTEID())

	if err := s11Conn.RespondTo(mmeAddr, csReqFromMME, csRspFromSGW); err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}
	if s.mc != nil {
		s.mc.messagesSent.WithLabelValues(mmeAddr.String(), csRspFromSGW.MessageTypeName()).Inc()
	}

	s5cpgwTEID, err := s5Session.GetTEID(gtpv2.IFTypeS5S8PGWGTPC)
	if err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}
	s5csgwTEID, err := s5Session.GetTEID(gtpv2.IFTypeS5S8SGWGTPC)
	if err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}

	if err := s11Session.Activate(); err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}

	log.Printf(
		"Session created with MME and P-GW for Subscriber: %s;\n\tS11 MME:  %s, TEID->: %#x, TEID<-: %#x\n\tS5C P-GW: %s, TEID->: %#x, TEID<-: %#x",
		s5Session.Subscriber.IMSI, mmeAddr, s11mmeTEID, s11sgwTEID, pgwAddrString, s5cpgwTEID, s5csgwTEID,
	)
	return nil
}

func (s *sgw) handleModifyBearerRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), mmeAddr)
	if s.mc != nil {
		s.mc.messagesReceived.WithLabelValues(mmeAddr.String(), msg.MessageTypeName()).Inc()
	}

	s11Session, err := s11Conn.GetSessionByTEID(msg.TEID(), mmeAddr)
	if err != nil {
		return err
	}
	s5cSession, err := s.s5cConn.GetSessionByIMSI(s11Session.IMSI)
	if err != nil {
		return err
	}
	s1uBearer := s11Session.GetDefaultBearer()
	s5uBearer := s5cSession.GetDefaultBearer()

	var enbIP string
	mbReqFromMME := msg.(*message.ModifyBearerRequest)
	if brCtxIE := mbReqFromMME.BearerContextsToBeModified; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.Indication:
				// do nothing in this implementation.
			case ie.FullyQualifiedTEID:
				if err := s.handleFTEIDU(childIE, s11Session, s1uBearer); err != nil {
					return err
				}
				enbIP, err = childIE.IPAddress()
				if err != nil {
					return err
				}
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	s11mmeTEID, err := s11Session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		return err
	}
	s1usgwTEID, err := s11Session.GetTEID(gtpv2.IFTypeS1USGWGTPU)
	if err != nil {
		return err
	}
	s5usgwTEID, err := s5cSession.GetTEID(gtpv2.IFTypeS5S8SGWGTPU)
	if err != nil {
		return err
	}
	pgwIP, _, err := net.SplitHostPort(s5uBearer.RemoteAddress().String())
	if err != nil {
		return err
	}

	if s.useKernelGTP {
		if err := s.s1uConn.AddTunnelOverride(
			net.ParseIP(enbIP), net.ParseIP(s1uBearer.SubscriberIP), s1uBearer.OutgoingTEID(), s1usgwTEID,
		); err != nil {
			return err
		}
		if err := s.s5uConn.AddTunnelOverride(
			net.ParseIP(pgwIP), net.ParseIP(s5uBearer.SubscriberIP), s5uBearer.OutgoingTEID(), s5usgwTEID,
		); err != nil {
			return err
		}
	} else {
		if err := s.s1uConn.RelayTo(
			s.s5uConn, s1usgwTEID, s5uBearer.OutgoingTEID(), s5uBearer.RemoteAddress(),
		); err != nil {
			return err
		}
		if err := s.s5uConn.RelayTo(
			s.s1uConn, s5usgwTEID, s1uBearer.OutgoingTEID(), s1uBearer.RemoteAddress(),
		); err != nil {
			return err
		}
	}

	mbRspFromSGW := message.NewModifyBearerResponse(
		s11mmeTEID, 0,
		ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
		ie.NewBearerContext(
			ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
			ie.NewEPSBearerID(s1uBearer.EBI),
			ie.NewFullyQualifiedTEID(gtpv2.IFTypeS1USGWGTPU, s1usgwTEID, s.s1uIP, ""),
		),
	)

	if err := s11Conn.RespondTo(mmeAddr, msg, mbRspFromSGW); err != nil {
		return err
	}
	if s.mc != nil {
		s.mc.messagesSent.WithLabelValues(mmeAddr.String(), mbRspFromSGW.MessageTypeName()).Inc()
	}

	log.Printf(
		"Started listening on U-Plane for Subscriber: %s;\n\tS1-U: %s\n\tS5-U: %s",
		s11Session.IMSI, s.s1uConn.LocalAddr(), s.s5uConn.LocalAddr(),
	)
	return nil
}

func (s *sgw) handleDeleteSessionRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), mmeAddr)
	if s.mc != nil {
		s.mc.messagesReceived.WithLabelValues(mmeAddr.String(), msg.MessageTypeName()).Inc()
	}

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	dsReqFromMME := msg.(*message.DeleteSessionRequest)

	s11Session, err := s11Conn.GetSessionByTEID(msg.TEID(), mmeAddr)
	if err != nil {
		return err
	}

	s5Session, err := s.s5cConn.GetSessionByIMSI(s11Session.IMSI)
	if err != nil {
		return err
	}

	s5cpgwTEID, err := s5Session.GetTEID(gtpv2.IFTypeS5S8PGWGTPC)
	if err != nil {
		return err
	}

	seq, err := s.s5cConn.DeleteSession(
		s5cpgwTEID, s5Session,
		ie.NewEPSBearerID(s5Session.GetDefaultBearer().EBI),
	)
	if err != nil {
		return err
	}

	var dsRspFromSGW *message.DeleteSessionResponse
	s11mmeTEID, err := s11Session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		return err
	}

	incomingMessage, err := s11Session.WaitMessage(seq, 5*time.Second)
	if err != nil {
		dsRspFromSGW = message.NewDeleteSessionResponse(
			s11mmeTEID, 0,
			ie.NewCause(gtpv2.CausePGWNotResponding, 0, 0, 0, nil),
		)

		if err := s11Conn.RespondTo(mmeAddr, dsReqFromMME, dsRspFromSGW); err != nil {
			return err
		}
		log.Printf(
			"Sent %s with failure code: %d, target subscriber: %s",
			dsRspFromSGW.MessageTypeName(), gtpv2.CausePGWNotResponding, s11Session.IMSI,
		)
		if s.mc != nil {
			s.mc.messagesSent.WithLabelValues(mmeAddr.String(), dsRspFromSGW.MessageTypeName()).Inc()
		}
		return err
	}

	// use the cause as it is.
	switch m := incomingMessage.(type) {
	case *message.DeleteSessionResponse:
		// move forward
		dsRspFromSGW = m
	default:
		return &gtpv2.UnexpectedTypeError{Msg: incomingMessage}
	}

	dsRspFromSGW.SetTEID(s11mmeTEID)
	if err := s11Conn.RespondTo(mmeAddr, msg, dsRspFromSGW); err != nil {
		return err
	}

	log.Printf("Session deleted for Subscriber: %s", s11Session.IMSI)
	if s.mc != nil {
		s.mc.messagesSent.WithLabelValues(mmeAddr.String(), dsRspFromSGW.MessageTypeName()).Inc()
	}

	s11Conn.RemoveSession(s11Session)
	return nil
}

func (s *sgw) handleDeleteBearerResponse(s11Conn *gtpv2.Conn, mmeAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), mmeAddr)
	if s.mc != nil {
		s.mc.messagesReceived.WithLabelValues(mmeAddr.String(), msg.MessageTypeName()).Inc()
	}

	s11Session, err := s11Conn.GetSessionByTEID(msg.TEID(), mmeAddr)
	if err != nil {
		return err
	}

	s5Session, err := s.s5cConn.GetSessionByIMSI(s11Session.IMSI)
	if err != nil {
		return err
	}

	if err := gtpv2.PassMessageTo(s5Session, msg, 5*time.Second); err != nil {
		return err
	}

	// remove bearer in handleDeleteBearerRequest instead of doing here,
	// as Delete Bearer Request does not necessarily have EBI.
	return nil
}

func (s *sgw) handleFTEIDU(fteiduIE *ie.IE, session *gtpv2.Session, bearer *gtpv2.Bearer) error {
	if fteiduIE.Type != ie.FullyQualifiedTEID {
		return &gtpv2.UnexpectedIEError{IEType: fteiduIE.Type}
	}

	ip, err := fteiduIE.IPAddress()
	if err != nil {
		return err
	}
	addr, err := net.ResolveUDPAddr("udp", ip+gtpv2.GTPUPort)
	if err != nil {
		return err
	}
	bearer.SetRemoteAddress(addr)

	teid, err := fteiduIE.TEID()
	if err != nil {
		return err
	}
	bearer.SetOutgoingTEID(teid)

	it, err := fteiduIE.InterfaceType()
	if err != nil {
		return err
	}
	session.AddTEID(it, teid)
	return nil
}


================================================
FILE: examples/gw-tester/sgw/s5_handlers.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"net"
	"time"

	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

func (s *sgw) handleCreateSessionResponse(s5cConn *gtpv2.Conn, pgwAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), pgwAddr)
	if s.mc != nil {
		s.mc.messagesReceived.WithLabelValues(pgwAddr.String(), msg.MessageTypeName()).Inc()
	}

	s5Session, err := s5cConn.GetSessionByTEID(msg.TEID(), pgwAddr)
	if err != nil {
		return err
	}

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	csRspFromPGW := msg.(*message.CreateSessionResponse)

	// check Cause value first.
	if causeIE := csRspFromPGW.Cause; causeIE != nil {
		cause, err := causeIE.Cause()
		if err != nil {
			return err
		}
		if cause != gtpv2.CauseRequestAccepted {
			s5cConn.RemoveSession(s5Session)
			// this is not such a fatal error worth stopping the whole program.
			// in the real case it is better to take some action based on the Cause, though.
			return &gtpv2.CauseNotOKError{
				MsgType: csRspFromPGW.MessageTypeName(),
				Cause:   cause,
				Msg:     fmt.Sprintf("subscriber: %s", s5Session.IMSI),
			}
		}
	} else {
		s5cConn.RemoveSession(s5Session)
		return &gtpv2.RequiredIEMissingError{
			Type: ie.Cause,
		}
	}

	bearer := s5Session.GetDefaultBearer()
	// retrieve values that P-GW gave.
	if paaIE := csRspFromPGW.PAA; paaIE != nil {
		ip, err := paaIE.IPAddress()
		if err != nil {
			return err
		}
		bearer.SubscriberIP = ip
	} else {
		s5cConn.RemoveSession(s5Session)
		return &gtpv2.RequiredIEMissingError{Type: ie.PDNAddressAllocation}
	}

	if fteidcIE := csRspFromPGW.PGWS5S8FTEIDC; fteidcIE != nil {
		it, err := fteidcIE.InterfaceType()
		if err != nil {
			return err
		}
		teid, err := fteidcIE.TEID()
		if err != nil {
			return err
		}
		s5Session.AddTEID(it, teid)
	} else {
		s5cConn.RemoveSession(s5Session)
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	if brCtxIE := csRspFromPGW.BearerContextsCreated; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.Cause:
				cause, err := childIE.Cause()
				if err != nil {
					return err
				}
				if cause != gtpv2.CauseRequestAccepted {
					s5cConn.RemoveSession(s5Session)
					return &gtpv2.CauseNotOKError{
						MsgType: csRspFromPGW.MessageTypeName(),
						Cause:   cause,
						Msg:     fmt.Sprintf("subscriber: %s", s5Session.IMSI),
					}
				}
			case ie.EPSBearerID:
				ebi, err := childIE.EPSBearerID()
				if err != nil {
					return err
				}
				bearer.EBI = ebi
			case ie.FullyQualifiedTEID:
				if err := s.handleFTEIDU(childIE, s5Session, bearer); err != nil {
					return err
				}
			case ie.ChargingID:
				cid, err := childIE.ChargingID()
				if err != nil {
					return err
				}
				bearer.ChargingID = cid
			}
		}
	} else {
		s5cConn.RemoveSession(s5Session)
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	if err := s5Session.Activate(); err != nil {
		s5cConn.RemoveSession(s5Session)
		return err
	}

	s11Session, err := s.s11Conn.GetSessionByIMSI(s5Session.IMSI)
	if err != nil {
		return err
	}

	if err := gtpv2.PassMessageTo(s11Session, csRspFromPGW, 5*time.Second); err != nil {
		return err
	}

	return nil
}

func (s *sgw) handleDeleteSessionResponse(s5cConn *gtpv2.Conn, pgwAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), pgwAddr)
	if s.mc != nil {
		s.mc.messagesReceived.WithLabelValues(pgwAddr.String(), msg.MessageTypeName()).Inc()
	}

	s5Session, err := s5cConn.GetSessionByTEID(msg.TEID(), pgwAddr)
	if err != nil {
		return err
	}

	s11Session, err := s.s11Conn.GetSessionByIMSI(s5Session.IMSI)
	if err != nil {
		return err
	}

	if err := gtpv2.PassMessageTo(s11Session, msg, 5*time.Second); err != nil {
		return err
	}

	// even the cause indicates failure, session should be removed locally.
	log.Printf("Session deleted for Subscriber: %s", s5Session.IMSI)
	s5cConn.RemoveSession(s5Session)
	return nil
}

func (s *sgw) handleDeleteBearerRequest(s5cConn *gtpv2.Conn, pgwAddr net.Addr, msg message.Message) error {
	log.Printf("Received %s from %s", msg.MessageTypeName(), pgwAddr)
	if s.mc != nil {
		s.mc.messagesReceived.WithLabelValues(pgwAddr.String(), msg.MessageTypeName()).Inc()
	}

	s5Session, err := s5cConn.GetSessionByTEID(msg.TEID(), pgwAddr)
	if err != nil {
		return err
	}

	s11Session, err := s.s11Conn.GetSessionByIMSI(s5Session.IMSI)
	if err != nil {
		return err
	}

	s5cpgwTEID, err := s5Session.GetTEID(gtpv2.IFTypeS5S8PGWGTPC)
	if err != nil {
		return err
	}

	s11mmeTEID, err := s11Session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		return err
	}

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	dbReqFromPGW := msg.(*message.DeleteBearerRequest)

	var dbRspFromSGW *message.DeleteBearerResponse
	var ebi *ie.IE

	if ie := dbReqFromPGW.LinkedEBI; ie != nil {
		ebi = ie
	}

	if e := dbReqFromPGW.EBIs; e != nil {
		ebiIE := e[0]
		// shouldn't be both.
		if ebi != nil {
			dbRspFromSGW = message.NewDeleteBearerResponse(
				s5cpgwTEID, 0,
				ie.NewCause(gtpv2.CauseContextNotFound, 0, 0, 0, ebiIE),
			)
			if err := s5cConn.RespondTo(pgwAddr, dbReqFromPGW, dbRspFromSGW); err != nil {
				return err
			}
			return fmt.Errorf("%T from %s had both Linked EBI and EBIs IE", dbReqFromPGW, pgwAddr)
		}
		ebi = ebiIE
	}

	if ebi == nil {
		dbRspFromSGW = message.NewDeleteBearerResponse(
			s5cpgwTEID, 0, ie.NewCause(gtpv2.CauseMandatoryIEMissing,
				0, 0, 0, ie.NewEPSBearerID(0),
			),
		)
		if err := s5cConn.RespondTo(pgwAddr, dbReqFromPGW, dbRspFromSGW); err != nil {
			return err
		}
		if s.mc != nil {
			s.mc.messagesSent.WithLabelValues(pgwAddr.String(), dbRspFromSGW.MessageTypeName()).Inc()
		}
		return err
	}

	// check if bearer associated with EBI exists or not.
	_, err = s5Session.LookupBearerByEBI(ebi.MustEPSBearerID())
	if err != nil {
		dbRspFromSGW = message.NewDeleteBearerResponse(
			s5cpgwTEID, 0,
			ie.NewCause(gtpv2.CauseContextNotFound, 0, 0, 0, nil),
		)
		if err := s5cConn.RespondTo(pgwAddr, dbReqFromPGW, dbRspFromSGW); err != nil {
			return err
		}
		if s.mc != nil {
			s.mc.messagesSent.WithLabelValues(pgwAddr.String(), dbRspFromSGW.MessageTypeName()).Inc()
		}
		return err
	}

	// forward to MME
	seq, err := s.s11Conn.DeleteBearer(s11mmeTEID, s11Session, ebi)
	if err != nil {
		return err
	}

	// wait for response from MME for 5 seconds
	incomingMessage, err := s5Session.WaitMessage(seq, 5*time.Second)
	if err != nil {
		dbRspFromSGW = message.NewDeleteBearerResponse(
			s5cpgwTEID, 0,
			ie.NewCause(gtpv2.CauseNoResourcesAvailable, 0, 0, 0, nil),
		)

		if err := s5cConn.RespondTo(pgwAddr, dbReqFromPGW, dbRspFromSGW); err != nil {
			return err
		}
		if s.mc != nil {
			s.mc.messagesSent.WithLabelValues(pgwAddr.String(), dbRspFromSGW.MessageTypeName()).Inc()
		}

		// remove anyway, as P-GW no longer keeps bearer locally
		s5Session.RemoveBearerByEBI(ebi.MustEPSBearerID())
		s11Session.RemoveBearerByEBI(ebi.MustEPSBearerID())
		return err
	}

	switch m := incomingMessage.(type) {
	case *message.DeleteBearerResponse:
		// move forward
		dbRspFromSGW = m
	default:
		return &gtpv2.UnexpectedTypeError{Msg: incomingMessage}
	}

	dbRspFromSGW.SetTEID(s5cpgwTEID)
	if err := s5cConn.RespondTo(pgwAddr, msg, dbRspFromSGW); err != nil {
		return err
	}
	if s.mc != nil {
		s.mc.messagesSent.WithLabelValues(pgwAddr.String(), dbRspFromSGW.MessageTypeName()).Inc()
	}

	s5Session.RemoveBearerByEBI(ebi.MustEPSBearerID())
	s11Session.RemoveBearerByEBI(ebi.MustEPSBearerID())

	return nil
}


================================================
FILE: examples/gw-tester/sgw/sgw.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"

	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/vishvananda/netlink"

	"github.com/wmnsk/go-gtp/gtpv1"
	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

type sgw struct {
	// C-Plane
	s11Addr, s5cAddr net.Addr
	s11Conn, s5cConn *gtpv2.Conn

	// U-Plane
	s1uAddr, s5uAddr net.Addr
	s1uConn, s5uConn *gtpv1.UPlaneConn

	s11IP, s5cIP, s1uIP, s5uIP string

	useKernelGTP bool

	addedRoutes []*netlink.Route
	addedRules  []*netlink.Rule

	promAddr string
	mc       *metricsCollector

	errCh chan error
}

func newSGW(cfg *Config) (*sgw, error) {
	s := &sgw{
		errCh: make(chan error, 1),
	}

	var err error
	s.s11Addr, err = net.ResolveUDPAddr("udp", cfg.LocalAddrs.S11IP+gtpv2.GTPCPort)
	if err != nil {
		return nil, err
	}
	s.s11IP, _, err = net.SplitHostPort(s.s11Addr.String())
	if err != nil {
		return nil, err
	}

	s.s5cAddr, err = net.ResolveUDPAddr("udp", cfg.LocalAddrs.S5CIP+gtpv2.GTPCPort)
	if err != nil {
		return nil, err
	}
	s.s5cIP, _, err = net.SplitHostPort(s.s5cAddr.String())
	if err != nil {
		return nil, err
	}

	s.s1uAddr, err = net.ResolveUDPAddr("udp", cfg.LocalAddrs.S1UIP+gtpv2.GTPUPort)
	if err != nil {
		return nil, err
	}
	s.s1uIP, _, err = net.SplitHostPort(s.s1uAddr.String())
	if err != nil {
		return nil, err
	}

	s.s5uAddr, err = net.ResolveUDPAddr("udp", cfg.LocalAddrs.S5UIP+gtpv2.GTPUPort)
	if err != nil {
		return nil, err
	}
	s.s5uIP, _, err = net.SplitHostPort(s.s5uAddr.String())
	if err != nil {
		return nil, err
	}

	s.useKernelGTP = cfg.UseKernelGTP
	if !s.useKernelGTP {
		log.Println("WARN: U-Plane performance would be significantly less without Kernel GTP")
	}

	if cfg.PromAddr != "" {
		// validate if the address is valid or not.
		if _, err = net.ResolveTCPAddr("tcp", cfg.PromAddr); err != nil {
			return nil, err
		}
		s.promAddr = cfg.PromAddr
	}

	return s, nil
}

func (s *sgw) run(ctx context.Context) error {
	s.s11Conn = gtpv2.NewConn(s.s11Addr, gtpv2.IFTypeS11S4SGWGTPC, 0)
	go func() {
		if err := s.s11Conn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started serving S11 on %s", s.s11Addr)

	s.s5cConn = gtpv2.NewConn(s.s5cAddr, gtpv2.IFTypeS5S8SGWGTPC, 0)
	go func() {
		if err := s.s5cConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started serving S5-C on %s", s.s5cAddr)

	// register handlers for ALL the message you expect remote endpoint to send.
	s.s11Conn.AddHandlers(map[uint8]gtpv2.HandlerFunc{
		message.MsgTypeCreateSessionRequest: s.handleCreateSessionRequest,
		message.MsgTypeModifyBearerRequest:  s.handleModifyBearerRequest,
		message.MsgTypeDeleteSessionRequest: s.handleDeleteSessionRequest,
		message.MsgTypeDeleteBearerResponse: s.handleDeleteBearerResponse,
	})
	s.s5cConn.AddHandlers(map[uint8]gtpv2.HandlerFunc{
		message.MsgTypeCreateSessionResponse: s.handleCreateSessionResponse,
		message.MsgTypeDeleteSessionResponse: s.handleDeleteSessionResponse,
		message.MsgTypeDeleteBearerRequest:   s.handleDeleteBearerRequest,
	})

	s.s1uConn = gtpv1.NewUPlaneConn(s.s1uAddr)
	if s.useKernelGTP {
		if err := s.s1uConn.EnableKernelGTP("gtp-sgw-s1", gtpv1.RoleGGSN); err != nil {
			return err
		}
	}
	go func() {
		if err := s.s1uConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
		log.Println("uConn.ListenAndServe exitted")
	}()
	log.Printf("Started serving S1-U on %s", s.s1uAddr)

	s.s5uConn = gtpv1.NewUPlaneConn(s.s5uAddr)
	if s.useKernelGTP {
		if err := s.s5uConn.EnableKernelGTP("gtp-sgw-s5", gtpv1.RoleSGSN); err != nil {
			return err
		}
	}
	go func() {
		if err := s.s5uConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
		log.Println("uConn.ListenAndServe exitted")
	}()
	log.Printf("Started serving S5-U on %s", s.s5uAddr)

	if s.useKernelGTP {
		if err := s.addRoutes(); err != nil {
			return err
		}
	}

	// start serving Prometheus, if address is given
	if s.promAddr != "" {
		if err := s.runMetricsCollector(); err != nil {
			return err
		}

		http.Handle("/metrics", promhttp.Handler())
		go func() {
			if err := http.ListenAndServe(s.promAddr, nil); err != nil {
				log.Println(err)
			}
		}()
		log.Printf("Started serving Prometheus on %s", s.promAddr)
	}

	for {
		select {
		case <-ctx.Done():
			return nil
		case err := <-s.errCh:
			log.Printf("Warning: %+v", err)
		}
	}
}

func (s *sgw) close() error {
	var errs []error
	for _, r := range s.addedRoutes {
		if err := netlink.RouteDel(r); err != nil {
			errs = append(errs, err)
		}
	}
	for _, r := range s.addedRules {
		if err := netlink.RuleDel(r); err != nil {
			errs = append(errs, err)
		}
	}

	if s.s1uConn != nil {
		if err := s.s1uConn.Close(); err != nil {
			errs = append(errs, err)
		}
	}
	if s.s5uConn != nil {
		if err := s.s5uConn.Close(); err != nil {
			errs = append(errs, err)
		}
	}

	if s.s11Conn != nil {
		if err := s.s11Conn.Close(); err != nil {
			errs = append(errs, err)
		}
	}
	if s.s5cConn != nil {
		if err := s.s5cConn.Close(); err != nil {
			errs = append(errs, err)
		}
	}

	close(s.errCh)

	if len(errs) > 0 {
		return fmt.Errorf("errors while closing S-GW: %+v", errs)
	}
	return nil
}

func (s *sgw) addRoutes() error {
	defnet := &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}
	s1route := &netlink.Route{ // ip route replace
		Dst:       defnet,                         // default
		LinkIndex: s.s5uConn.KernelGTP.Link.Index, // dev gtp-s5
		Scope:     netlink.SCOPE_LINK,             // scope link
		Protocol:  4,                              // proto static
		Priority:  1,                              // metric 1
		Table:     2001,                           // table 2001
	}

	if err := netlink.RouteReplace(s1route); err != nil {
		return err
	}
	s.addedRoutes = append(s.addedRoutes, s1route)

	s5route := &netlink.Route{ // ip route replace
		Dst:       defnet,                                 // default
		LinkIndex: s.s1uConn.KernelGTP.Link.Attrs().Index, // dev gtp-s1
		Scope:     netlink.SCOPE_LINK,                     // scope link
		Protocol:  4,                                      // proto static
		Priority:  1,                                      // metric 1
		Table:     2005,                                   // table 2005
	}

	if err := netlink.RouteReplace(s5route); err != nil {
		return err
	}
	s.addedRoutes = append(s.addedRoutes, s1route)

	rules, err := netlink.RuleList(0)
	if err != nil {
		return err
	}

	var s1found, s5found bool
	for _, r := range rules {
		if s1found && s5found {
			break
		}

		if r.IifName == s.s1uConn.KernelGTP.Link.Name && r.Table == 2001 {
			s1found = true
		}
		if r.IifName == s.s5uConn.KernelGTP.Link.Name && r.Table == 2005 {
			s5found = true
		}
	}

	if !s1found {
		rule := netlink.NewRule()
		rule.IifName = s.s1uConn.KernelGTP.Link.Name
		rule.Table = 2001

		if err := netlink.RuleAdd(rule); err != nil {
			return err
		}
		s.addedRules = append(s.addedRules, rule)
	}

	if !s5found {
		rule := netlink.NewRule()
		rule.IifName = s.s5uConn.KernelGTP.Link.Name
		rule.Table = 2005

		if err := netlink.RuleAdd(rule); err != nil {
			return err
		}
		s.addedRules = append(s.addedRules, rule)
	}

	return nil
}


================================================
FILE: examples/gw-tester/sgw/sgw.yml
================================================
local_addresses:
  s11_ip: "127.0.1.13"
  s1u_ip: "127.0.0.13"
  s5c_ip: "127.0.1.14"
  s5u_ip: "127.0.0.14"
use_kernel_gtp: false
prom_addr: "127.0.10.3:58080"


================================================
FILE: examples/mme/main.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Command mme is a reference implementation of MME with go-gtp.
//
// MME follows the steps below if there's no unexpected events in the middle.
// Note that the  S1 and DNS procedures is just mocked to make it work in
// standalone manner.
//
// 1. Exchange Echo to S-GW address specified in command-line argument.
//
// 2. Start dispatching subscribers by sending Create Session Request to S-GW.
// APN is handled with getPGWIP(), which is hard-coded.
//
// 3. Wait for Create Session Response coming from S-GW with Cause="request accepted".
//
// 4. Create mocked UE and eNB with the required values set as told by S-GW, start
// listening on the interface specified with s1enb flag,  and send Modify Bearer Request
// to S-GW.
//
// 5. Wait for Modify Bearer Response coming from S-GW with Cause="request accepted".
//
// 6. Start sending payload(ICMP Echo Request) encapsulated with GTPv1-U Header, and printing
// the payload of encapsulated packets received.
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"strings"
	"sync"
	"time"

	"github.com/wmnsk/go-gtp/gtpv1"
	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

// command-line flags.
var (
	s11mme = flag.String("s11mme", "127.0.0.111", "local IP on S11 interface.")
	s11sgw = flag.String("s11sgw", "127.0.0.112", "S-GW's IP on S11 interface.")
	s1enb  = flag.String("s1enb", "127.0.0.1", "local IP on S1-U of pseudo eNB.")
)

// variables globally shared.
var (
	attachCh  = make(chan *gtpv2.Subscriber)
	createdCh = make(chan string)
	loggerCh  = make(chan string)
	errCh     = make(chan error)

	once  = sync.Once{}
	delWG = sync.WaitGroup{}
)

func main() {
	flag.Parse()
	log.SetPrefix("[MME] ")

	laddr, err := net.ResolveUDPAddr("udp", *s11mme+gtpv2.GTPCPort)
	if err != nil {
		log.Println(err)
		return
	}
	raddr, err := net.ResolveUDPAddr("udp", *s11sgw+gtpv2.GTPCPort)
	if err != nil {
		log.Println(err)
		return
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// setup *Conn first to check if the remote endpoint is awaken.
	s11Conn, err := gtpv2.Dial(ctx, laddr, raddr, gtpv2.IFTypeS11MMEGTPC, 0)
	if err != nil {
		log.Println(err)
		return
	}
	defer s11Conn.Close()
	log.Printf("Connection established with %s", raddr.String())

	// register handlers for ALL the message you expect remote endpoint to send.
	// by default, Echo and VersionNotsupported is handled without explicit declaration.
	s11Conn.AddHandlers(map[uint8]gtpv2.HandlerFunc{
		message.MsgTypeCreateSessionResponse: handleCreateSessionResponse,
		message.MsgTypeModifyBearerResponse:  handleModifyBearerResponse,
		message.MsgTypeDeleteSessionResponse: handleDeleteSessionResponse,
	})

	// Listen on eNB S1-U interface.
	enbUPlaneAddr, err := net.ResolveUDPAddr("udp", *s1enb+gtpv2.GTPUPort)
	if err != nil {
		log.Println(err)
		return
	}

	uConn = gtpv1.NewUPlaneConn(enbUPlaneAddr)
	defer uConn.Close()

	go func() {
		if err = uConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started listening on %s", enbUPlaneAddr)

	// here you should wait for UEs to come attaching to your network.
	// in this example, the following five subscribers are to be attached.
	// working as worker-dispatcher is preferable in the real case
	go dispatch([]*gtpv2.Subscriber{{
		IMSI: "123451234567891", MSISDN: "8130900000001", IMEI: "123456780000011",
		Location: &gtpv2.Location{MCC: "123", MNC: "45", RATType: gtpv2.RATTypeEUTRAN, TAI: 0x0001, ECI: 0x00000101},
	}, {
		IMSI: "123451234567892", MSISDN: "8130900000002", IMEI: "123456780000012",
		Location: &gtpv2.Location{MCC: "123", MNC: "45", RATType: gtpv2.RATTypeEUTRAN, TAI: 0x0002, ECI: 0x00000202},
	}, {
		IMSI: "123451234567893", MSISDN: "8130900000003", IMEI: "123456780000013",
		Location: &gtpv2.Location{MCC: "123", MNC: "45", RATType: gtpv2.RATTypeEUTRAN, TAI: 0x0003, ECI: 0x00000303},
	}, {
		IMSI: "123451234567894", MSISDN: "8130900000004", IMEI: "123456780000014",
		Location: &gtpv2.Location{MCC: "123", MNC: "45", RATType: gtpv2.RATTypeEUTRAN, TAI: 0x0004, ECI: 0x00000404},
	}, {
		IMSI: "123451234567895", MSISDN: "8130900000005", IMEI: "123456780000015",
		Location: &gtpv2.Location{MCC: "123", MNC: "45", RATType: gtpv2.RATTypeEUTRAN, TAI: 0x0005, ECI: 0x00000505},
	}})

	bearer := gtpv2.NewBearer(5, "", &gtpv2.QoSProfile{
		PL: 2, QCI: 255, MBRUL: 0xffffffff, MBRDL: 0xffffffff, GBRUL: 0xffffffff, GBRDL: 0xffffffff,
	})
	for {
		select {
		// print logs coming from handlers working background
		case str := <-loggerCh:
			log.Println(str)
		// print errors coming from handlers working background
		// it's better to switch over the error to distinguish fatal ones to others.
		case err := <-errCh:
			log.Printf("Warning: %s", err)
		// handle attach requests
		case sub := <-attachCh:
			log.Printf("Started creating session for subscriber: %s", sub.IMSI)
			go func() {
				bearer.APN = "some-apn-1.example"
				if sub.TAI%2 == 0 {
					bearer.APN = "some-apn-2.example"
				}
				if err := handleAttach(raddr, s11Conn, sub, bearer); err != nil {
					errCh <- err
					return
				}
			}()
		case imsi := <-createdCh:
			go func() {
				sess, err := s11Conn.GetSessionByIMSI(imsi)
				if err != nil {
					errCh <- err
					return
				}

				enbIP := strings.Split(*s1enb, ":")[0]
				enbFTEID := uConn.NewFTEID(gtpv2.IFTypeS1UeNodeBGTPU, enbIP, "")
				teid, err := sess.GetTEID(gtpv2.IFTypeS11S4SGWGTPC)
				if err != nil {
					errCh <- err
				}

				if _, err := s11Conn.ModifyBearer(
					teid, sess,
					ie.NewIndicationFromOctets(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
					ie.NewBearerContext(ie.NewEPSBearerID(sess.GetDefaultBearer().EBI), enbFTEID),
				); err != nil {
					errCh <- err
					return
				}
				it, err := enbFTEID.InterfaceType()
				if err != nil {
					errCh <- err
					return
				}
				enbTEID, err := enbFTEID.TEID()
				if err != nil {
					errCh <- err
					return
				}
				sess.AddTEID(it, enbTEID)

				loggerCh <- fmt.Sprintf("Sent Modify Bearer Request for %s", imsi)
			}()
		// delete all the sessions after 30 seconds
		case <-time.After(30 * time.Second):
			for _, sess := range s11Conn.Sessions() {
				teid, err := sess.GetTEID(gtpv2.IFTypeS11S4SGWGTPC)
				if err != nil {
					errCh <- gtpv2.ErrTEIDNotFound
					return
				}
				if _, err := s11Conn.DeleteSession(teid, sess); err != nil {
					log.Printf("Warning: %s", err)
				}
				delWG.Add(1)
				log.Printf("Sent Delete Session Request for %s", sess.IMSI)
			}

			// invoke goroutine to let the logger work
			go func() {
				delWG.Wait()
				log.Fatal("Inactivity timer expired, exitting...")
			}()
		}
	}
}


================================================
FILE: examples/mme/mme.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"fmt"
	"net"

	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

func handleCreateSessionResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), sgwAddr)

	// find the session associated with TEID
	session, err := c.GetSessionByTEID(msg.TEID(), sgwAddr)
	if err != nil {
		c.RemoveSession(session)
		return err
	}
	bearer := session.GetDefaultBearer()

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	csRspFromSGW := msg.(*message.CreateSessionResponse)

	// check Cause value first.
	if ie := csRspFromSGW.Cause; ie != nil {
		cause, err := ie.Cause()
		if err != nil {
			return err
		}
		if cause != gtpv2.CauseRequestAccepted {
			c.RemoveSession(session)
			return &gtpv2.CauseNotOKError{
				MsgType: csRspFromSGW.MessageTypeName(),
				Cause:   cause,
				Msg:     fmt.Sprintf("subscriber: %s", session.IMSI),
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: msg.MessageType()}
	}

	if ie := csRspFromSGW.PAA; ie != nil {
		bearer.SubscriberIP, err = ie.IPAddress()
		if err != nil {
			return err
		}
	}
	if senderIE := csRspFromSGW.SenderFTEIDC; senderIE != nil {
		teid, err := senderIE.TEID()
		if err != nil {
			return err
		}
		session.AddTEID(gtpv2.IFTypeS11S4SGWGTPC, teid)
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	s11sgwTEID, err := session.GetTEID(gtpv2.IFTypeS11S4SGWGTPC)
	if err != nil {
		c.RemoveSession(session)
		return err
	}
	s11mmeTEID, err := session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		c.RemoveSession(session)
		return err
	}

	if brCtxIE := csRspFromSGW.BearerContextsCreated; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.EPSBearerID:
				bearer.EBI, err = childIE.EPSBearerID()
				if err != nil {
					return err
				}
			case ie.FullyQualifiedTEID:
				if childIE.Instance() != 0 {
					continue
				}
				it, err := childIE.InterfaceType()
				if err != nil {
					return err
				}
				teid, err := childIE.TEID()
				if err != nil {
					return err
				}
				session.AddTEID(it, teid)
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	if err := session.Activate(); err != nil {
		c.RemoveSession(session)
		return err
	}

	createdCh <- session.Subscriber.IMSI
	loggerCh <- fmt.Sprintf(
		"Session created with S-GW for Subscriber: %s;\n\tS11 S-GW: %s, TEID->: %#x, TEID<-: %#x",
		session.Subscriber.IMSI, sgwAddr, s11sgwTEID, s11mmeTEID,
	)
	return nil
}

func handleModifyBearerResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), sgwAddr)

	session, err := c.GetSessionByTEID(msg.TEID(), sgwAddr)
	if err != nil {
		return err
	}

	mbRspFromSGW := msg.(*message.ModifyBearerResponse)
	if causeIE := mbRspFromSGW.Cause; causeIE != nil {
		cause, err := causeIE.Cause()
		if err != nil {
			return err
		}
		if cause != gtpv2.CauseRequestAccepted {
			return &gtpv2.CauseNotOKError{
				MsgType: msg.MessageTypeName(),
				Cause:   cause,
				Msg:     fmt.Sprintf("subscriber: %s", session.IMSI),
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.Cause}
	}

	mock := &mockUEeNB{
		subscriberIP: session.GetDefaultBearer().SubscriberIP,
		payload:      payload,
	}
	if brCtxIE := mbRspFromSGW.BearerContextsModified; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.FullyQualifiedTEID:
				if childIE.Instance() != 0 {
					continue
				}
				it, err := childIE.InterfaceType()
				if err != nil {
					return err
				}
				teid, err := childIE.TEID()
				if err != nil {
					return err
				}
				session.AddTEID(it, teid)

				ip, err := childIE.IPAddress()
				if err != nil {
					return err
				}
				sgwUAddr, err := net.ResolveUDPAddr("udp", ip+gtpv2.GTPUPort)
				if err != nil {
					return err
				}
				mock.raddr = sgwUAddr
				mock.teidOut = teid
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	go mock.run(errCh)

	loggerCh <- fmt.Sprintf("Bearer modified with S-GW for Subscriber: %s", session.IMSI)
	return nil
}

func handleDeleteSessionResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), sgwAddr)

	session, err := c.GetSessionByTEID(msg.TEID(), sgwAddr)
	if err != nil {
		return err
	}

	c.RemoveSession(session)
	delWG.Done()
	loggerCh <- fmt.Sprintf("Session deleted with S-GW for Subscriber: %s", session.IMSI)
	return nil
}


================================================
FILE: examples/mme/mock.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"errors"
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/wmnsk/go-gtp/gtpv1"
	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
)

// getPGWIP is to get P-GW's IP address according to APN.
//
// DNS should be used in the real case, but here, to keep the example simple,
// this function just returns IP address hard-coded in apnIPMap.
func getPGWIP(apn string) (string, error) {
	apnIPMap := map[string]string{
		"some-apn-1.example": "127.0.0.52",
		"some-apn-2.example": "127.0.0.53",
	}

	if ip, ok := apnIPMap[apn]; ok {
		return ip, nil
	}
	return "", fmt.Errorf("got unknown APN: %s", apn)
}

// dispatch sends subscribers to attachCh, which will be handled in handleAttach().
func dispatch(subs []*gtpv2.Subscriber) {
	for _, sub := range subs {
		// wait for 0-255ms before sending request (just for a little bit of reality)
		/*
			u8buf := make([]byte, 1)
			rand.Read(u8buf)
			time.Sleep(time.Duration(u8buf[0]) * time.Millisecond)
		*/
		time.Sleep(100 * time.Millisecond)

		attachCh <- sub
	}
}

// handleAttach is to start the session creation on S11.
// in the real case this should be called after the procedure on S1AP/NAS has been done.
func handleAttach(raddr net.Addr, c *gtpv2.Conn, sub *gtpv2.Subscriber, br *gtpv2.Bearer) error {
	// remove previous session for the same subscriber if exists.
	sess, err := c.GetSessionByIMSI(sub.IMSI)
	if err != nil {
		switch err.(type) {
		case *gtpv2.UnknownIMSIError:
			// whole new session. just ignore.
		default:
			return fmt.Errorf("got something unexpected: %w", err)
		}
	} else {
		teid, err := sess.GetTEID(gtpv2.IFTypeS11S4SGWGTPC)
		if err != nil {
			return gtpv2.ErrTEIDNotFound
		}
		// send Delete Session Request to cleanup sessions in S/P-GW.
		if _, err := c.DeleteSession(teid, sess); err != nil {
			return fmt.Errorf("got something unexpected: %w", err)
		}
		c.RemoveSession(sess)
	}

	pgwAddr, err := getPGWIP(br.APN)
	if err != nil {
		return err
	}

	var pci, pvi uint8
	if br.PCI {
		pci = 1
	}
	if br.PVI {
		pvi = 1
	}
	localIP := strings.Split(c.LocalAddr().String(), ":")[0]
	_, _, err = c.CreateSession(
		raddr,
		ie.NewIMSI(sub.IMSI),
		ie.NewMSISDN(sub.MSISDN),
		ie.NewMobileEquipmentIdentity(sub.IMEI),
		ie.NewUserLocationInformationStruct(
			ie.NewCGI(sub.MCC, sub.MNC, sub.LAC, sub.CI),
			ie.NewSAI(sub.MCC, sub.MNC, sub.LAC, sub.SAI),
			ie.NewRAI(sub.MCC, sub.MNC, sub.LAC, sub.RAI),
			ie.NewTAI(sub.MCC, sub.MNC, sub.TAI),
			ie.NewECGI(sub.MCC, sub.MNC, sub.ECI),
			ie.NewLAI(sub.MCC, sub.MNC, sub.LAC),
			ie.NewMENBI(sub.MCC, sub.MNC, sub.MeNBI),
			ie.NewEMENBI(sub.MCC, sub.MNC, sub.EMeNBI),
		),
		ie.NewRATType(sub.RATType),
		ie.NewIndicationFromOctets(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
		c.NewSenderFTEID(localIP, ""),
		ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8PGWGTPC, 0, pgwAddr, "").WithInstance(1),
		ie.NewAccessPointName(br.APN),
		ie.NewSelectionMode(gtpv2.SelectionModeMSorNetworkProvidedAPNSubscribedVerified),
		ie.NewPDNType(gtpv2.PDNTypeIPv4),
		ie.NewPDNAddressAllocation("0.0.0.0"),
		ie.NewAPNRestriction(gtpv2.APNRestrictionNoExistingContextsorRestriction),
		ie.NewAggregateMaximumBitRate(0, 0),
		ie.NewBearerContext(
			ie.NewEPSBearerID(br.EBI),
			ie.NewBearerQoS(pci, br.PL, pvi, br.QCI, br.MBRUL, br.MBRDL, br.GBRUL, br.GBRDL),
		),
		ie.NewFullyQualifiedCSID(localIP, 1),
		ie.NewServingNetwork(sub.MCC, sub.MNC),
		ie.NewUETimeZone(9*time.Hour, 0),
	)
	if err != nil {
		return err
	}

	return nil
}

var (
	uConn   *gtpv1.UPlaneConn
	payload = []byte{ // ICMP Echo to 8.8.8.8 over IP(src will be replaced), checksum is invalid.
		// IP
		0x45, 0x00, 0x00, 0x54, 0x00, 0x01, 0x40, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
		0x08, 0x08, 0x08, 0x08,
		// ICMP
		0x08, 0x00, 0x93, 0x6a, 0x00, 0x01, 0x00, 0x01, 0xdf, 0xd5, 0x2c, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x99, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13,
		0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
		0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
		0x34, 0x35, 0x36, 0x37,
	}
)

type mockUEeNB struct {
	raddr net.Addr

	subscriberIP string
	teidOut      uint32
	payload      []byte
}

func (m mockUEeNB) run(errCh chan error) {
	go func(teid uint32, payload []byte, raddr net.Addr) {
		for {
			copy(payload[12:16], net.ParseIP(m.subscriberIP).To4())
			if _, err := uConn.WriteToGTP(teid, m.payload, raddr); err != nil {
				errCh <- err
				return
			}
			time.Sleep(3 * time.Second)
		}
	}(m.teidOut, m.payload, m.raddr)

	go once.Do(func() {
		buf := make([]byte, 1500)
		for {
			if uConn == nil {
				errCh <- errors.New("uConn conn is not open")
				return
			}

			n, raddr, _, err := uConn.ReadFromGTP(buf)
			if err != nil {
				errCh <- err
				return
			}
			loggerCh <- fmt.Sprintf("Received from %s: %x", raddr, buf[:n])
		}
	})
}


================================================
FILE: examples/pgw/main.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Command pgw is a dead simple implementation of P-GW only with GTP-related features.
//
// This example is not maintained well. Please see example/gw-tester/pgw for better implementation.
//
// P-GW follows the steps below if there's no unexpected events in the middle. Note
// that the Gx procedure is just mocked to make it work in standalone manner.
//
// 1. Wait for Create Session Request from S-GW.
//
// 2. Send Create Session Response to S-GW if the required IEs are not missing, and
// start listening on the interface specified with s5u flag.
//
// 3. If Modify Bearer Request comes from S-GW, update bearer information.
//
// 4. If T-PDU comes from S-GW, print the payload of encapsulated packets received,
// and respond to it with payload(ICMP Echo Reply).
package main

import (
	"context"
	"flag"
	"log"
	"net"
	"time"

	"github.com/wmnsk/go-gtp/gtpv1"
	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

// command-line arguments
var (
	s5c = flag.String("s5c", "127.0.0.52", "IP for S5-C interface.")
	s5u = flag.String("s5u", "127.0.0.4", "IP for S5-U interface.")
)

func main() {
	flag.Parse()
	log.SetPrefix("[P-GW] ")

	s5cAddr, err := net.ResolveUDPAddr("udp", *s5c+gtpv2.GTPCPort)
	if err != nil {
		log.Println(err)
		return
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// start listening on the specified IP:Port.
	s5cConn := gtpv2.NewConn(s5cAddr, gtpv2.IFTypeS5S8PGWGTPC, 0)
	go func() {
		if err := s5cConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started serving C-Plane on %s", s5cAddr)

	// register handlers for ALL the message you expect remote endpoint to send.
	s5cConn.AddHandlers(map[uint8]gtpv2.HandlerFunc{
		message.MsgTypeCreateSessionRequest: handleCreateSessionRequest,
		message.MsgTypeDeleteSessionRequest: handleDeleteSessionRequest,
	})

	s5uAddr, err := net.ResolveUDPAddr("udp", *s5u+gtpv2.GTPUPort)
	if err != nil {
		log.Println(err)
		return
	}

	uConn = gtpv1.NewUPlaneConn(s5uAddr)
	defer uConn.Close()

	go func() {
		if err = uConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started serving U-Plane on %s", s5uAddr)

	for {
		select {
		case str := <-loggerCh:
			log.Printf("%s", str)
		case err := <-errCh:
			log.Printf("Warning: %s", err)
		case <-time.After(10 * time.Second):
			var activeIMSIs []string
			for _, sess := range s5cConn.Sessions() {
				if !sess.IsActive() {
					continue
				}
				activeIMSIs = append(activeIMSIs, sess.IMSI)
			}
			if len(activeIMSIs) == 0 {
				continue
			}

			log.Println("Active Subscribers:")
			for _, imsi := range activeIMSIs {
				log.Printf("\t%s", imsi)
			}
			activeIMSIs = nil
		}
	}
}


================================================
FILE: examples/pgw/pgw.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package main

import (
	"fmt"
	"net"
	"strings"

	"github.com/wmnsk/go-gtp/gtpv1"
	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

// getSubscriberIP is to get IP address to be assigned to the subscriber.
//
// In the real case, P-GW may ask AAA and PCRF retrieve required information for subscriber,
// but here, to keep the example simple, this just returns subscriber's IP address defined in
// the map "subIPMap".
func getSubscriberIP(sub *gtpv2.Subscriber) (string, error) {
	subIPMap := map[string]string{
		"123451234567891": "10.10.10.1",
		"123451234567892": "10.10.10.2",
		"123451234567893": "10.10.10.3",
		"123451234567894": "10.10.10.4",
		"123451234567895": "10.10.10.5",
	}

	if ip, ok := subIPMap[sub.IMSI]; ok {
		return ip, nil
	}
	return "", fmt.Errorf("subscriber %s not found", sub.IMSI)
}

var (
	loggerCh = make(chan string)
	errCh    = make(chan error)

	uConn *gtpv1.UPlaneConn
)

func handleCreateSessionRequest(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), sgwAddr)

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	csReqFromSGW := msg.(*message.CreateSessionRequest)

	// keep session information retrieved from the message.
	session := gtpv2.NewSession(sgwAddr, &gtpv2.Subscriber{Location: &gtpv2.Location{}})
	bearer := session.GetDefaultBearer()
	var err error
	if imsiIE := csReqFromSGW.IMSI; imsiIE != nil {
		imsi, err := imsiIE.IMSI()
		if err != nil {
			return err
		}
		session.IMSI = imsi

		// remove previous session for the same subscriber if exists.
		sess, err := c.GetSessionByIMSI(imsi)
		if err != nil {
			switch err.(type) {
			case *gtpv2.UnknownIMSIError:
				// whole new session. just ignore.
			default:
				return fmt.Errorf("got something unexpected: %w", err)
			}
		} else {
			c.RemoveSession(sess)
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.IMSI}
	}
	if msisdnIE := csReqFromSGW.MSISDN; msisdnIE != nil {
		session.MSISDN, err = msisdnIE.MSISDN()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.MSISDN}
	}
	if meiIE := csReqFromSGW.MEI; meiIE != nil {
		session.IMEI, err = meiIE.MobileEquipmentIdentity()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.MobileEquipmentIdentity}
	}
	if apnIE := csReqFromSGW.APN; apnIE != nil {
		bearer.APN, err = apnIE.AccessPointName()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.AccessPointName}
	}
	if netIE := csReqFromSGW.ServingNetwork; netIE != nil {
		session.MNC, err = netIE.MNC()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.ServingNetwork}
	}
	if ratIE := csReqFromSGW.RATType; ratIE != nil {
		session.RATType, err = ratIE.RATType()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.RATType}
	}
	if fteidcIE := csReqFromSGW.SenderFTEIDC; fteidcIE != nil {
		teid, err := fteidcIE.TEID()
		if err != nil {
			return err
		}
		session.AddTEID(gtpv2.IFTypeS5S8SGWGTPC, teid)
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	var teidOut uint32
	if brCtxIE := csReqFromSGW.BearerContextsToBeCreated; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.EPSBearerID:
				bearer.EBI, err = childIE.EPSBearerID()
				if err != nil {
					return err
				}
			case ie.FullyQualifiedTEID:
				it, err := childIE.InterfaceType()
				if err != nil {
					return err
				}
				teidOut, err := childIE.TEID()
				if err != nil {
					return err
				}
				session.AddTEID(it, teidOut)
			}
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	bearer.SubscriberIP, err = getSubscriberIP(session.Subscriber)
	if err != nil {
		return err
	}

	cIP := strings.Split(c.LocalAddr().String(), ":")[0]
	uIP := strings.Split(*s5u, ":")[0]
	s5cFTEID := c.NewSenderFTEID(cIP, "").WithInstance(1)
	s5uFTEID := uConn.NewFTEID(gtpv2.IFTypeS5S8PGWGTPU, uIP, "").WithInstance(2)
	s5sgwTEID, err := session.GetTEID(gtpv2.IFTypeS5S8SGWGTPC)
	if err != nil {
		return err
	}
	csRspFromPGW := message.NewCreateSessionResponse(
		s5sgwTEID, 0,
		ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
		s5cFTEID,
		ie.NewPDNAddressAllocation(bearer.SubscriberIP),
		ie.NewAPNRestriction(gtpv2.APNRestrictionPublic2),
		ie.NewBearerContext(
			ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
			ie.NewEPSBearerID(bearer.EBI),
			s5uFTEID,
			ie.NewChargingID(bearer.ChargingID),
		),
	)
	if csReqFromSGW.SGWFQCSID != nil {
		csRspFromPGW.PGWFQCSID = ie.NewFullyQualifiedCSID(cIP, 1)
	}
	session.AddTEID(gtpv2.IFTypeS5S8PGWGTPC, s5cFTEID.MustTEID())
	session.AddTEID(gtpv2.IFTypeS5S8PGWGTPU, s5uFTEID.MustTEID())

	if err := c.RespondTo(sgwAddr, csReqFromSGW, csRspFromPGW); err != nil {
		return err
	}

	s5pgwTEID, err := session.GetTEID(gtpv2.IFTypeS5S8PGWGTPC)
	if err != nil {
		return err
	}
	c.RegisterSession(s5pgwTEID, session)

	// don't forget to activate and add session created to the session list
	if err := session.Activate(); err != nil {
		return err
	}

	go func() {
		buf := make([]byte, 1500)
		for {
			n, raddr, _, err := uConn.ReadFromGTP(buf)
			if err != nil {
				return
			}

			rsp := make([]byte, n)
			// update message type and checksum
			copy(rsp, buf[:n])
			rsp[20] = 0
			rsp[22] = 0x9b
			// swap IP
			copy(rsp[12:16], buf[16:20])
			copy(rsp[16:20], buf[12:16])

			if _, err := uConn.WriteToGTP(teidOut, rsp, raddr); err != nil {
				return
			}
		}
	}()

	loggerCh <- fmt.Sprintf("Session created with S-GW for subscriber: %s;\n\tS5C S-GW: %s, TEID->: %#x, TEID<-: %#x",
		session.Subscriber.IMSI, sgwAddr, s5sgwTEID, s5pgwTEID,
	)
	return nil
}

func handleDeleteSessionRequest(c *gtpv2.Conn, sgwAddr net.Addr, msg message.Message) error {
	loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), sgwAddr)

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	session, err := c.GetSessionByTEID(msg.TEID(), sgwAddr)
	if err != nil {
		dsr := message.NewDeleteSessionResponse(
			0, 0,
			ie.NewCause(gtpv2.CauseIMSIIMEINotKnown, 0, 0, 0, nil),
		)
		if err := c.RespondTo(sgwAddr, msg, dsr); err != nil {
			return err
		}

		return err
	}

	// respond to S-GW with DeleteSessionResponse.
	teid, err := session.GetTEID(gtpv2.IFTypeS5S8SGWGTPC)
	if err != nil {
		loggerCh <- fmt.Sprintf("Error: %v", err)
		return nil
	}
	dsr := message.NewDeleteSessionResponse(
		teid, 0,
		ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
	)
	if err := c.RespondTo(sgwAddr, msg, dsr); err != nil {
		return err
	}

	loggerCh <- fmt.Sprintf("Session deleted for Subscriber: %s", session.IMSI)
	c.RemoveSession(session)
	return nil
}


================================================
FILE: examples/sgw/main.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Command sgw is a dead simple implementation of S-GW only with GTP-related features.
//
// S-GW follows the steps below if there's no unexpected events in the middle.
//
// 1. Start listening on S11 interface.
//
// 2. If MME connects to S-GW with Create Session Request, S-GW sends Create Session Request
// to P-GW whose IP is specified by MME with F-TEID IE.
//
// 3. Wait for Create Session Response coming from P-GW with Cause="request accepted", and
// other IEs required are properly set.
//
// 4. Respond to MME with Create Session Response. Here the C-Plane Session is considered to
// be created properly.
//
// 5. If MME sends Modify Bearer Request with eNB information inside, set incoming TEID to
// Bearer and start listening on U-Plane.
//
// 6. If some U-Plane message comes from eNB/P-GW, relay it to P-GW/eNB with TEID and IP
// properly set as told while exchanging the C-Plane signals.
package main

import (
	"context"
	"flag"
	"log"
	"net"
	"time"

	"github.com/wmnsk/go-gtp/gtpv1"
	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

// command-line arguments and global variables
var (
	s11 = flag.String("s11", "127.0.0.112", "local IP on S11 interface.")
	s5c = flag.String("s5c", "127.0.0.51", "local IP on S5-C interface.")
	s1u = flag.String("s1u", "127.0.0.2", "local IP on S1-U interface.")
	s5u = flag.String("s5u", "127.0.0.3", "local IP on S5-U interface.")

	sgw *sGateway
)

type sGateway struct {
	s11Conn, s5cConn *gtpv2.Conn
	s1uConn, s5uConn *gtpv1.UPlaneConn

	loggerCh chan string
	errCh    chan error
}

func newSGW(s11, s5c, s1u, s5u net.Addr) (*sGateway, error) {
	s := &sGateway{
		loggerCh: make(chan string),
		errCh:    make(chan error),
	}

	ctx := context.Background()

	var err error
	s.s11Conn = gtpv2.NewConn(s11, gtpv2.IFTypeS11S4SGWGTPC, 0)
	go func() {
		if err = s.s11Conn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started serving on %s", s11)

	s.s5cConn = gtpv2.NewConn(s5c, gtpv2.IFTypeS5S8SGWGTPC, 0)
	go func() {
		if err = s.s5cConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()
	log.Printf("Started serving on %s", s5c)

	s.s1uConn = gtpv1.NewUPlaneConn(s1u)
	go func() {
		if err = s.s1uConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()

	go func() {
		s.s5uConn = gtpv1.NewUPlaneConn(s5u)
		if err = s.s5uConn.ListenAndServe(ctx); err != nil {
			log.Println(err)
			return
		}
	}()

	return s, nil
}

func (s *sGateway) run() error {
	defer func() {
		s.s11Conn.Close()
		s.s5cConn.Close()
	}()

	// wait for events(logs, errors, timers).
	for {
		select {
		case str := <-s.loggerCh:
			log.Println(str)
		case err := <-s.errCh:
			log.Printf("Warning: %v", err)
		case <-time.After(10 * time.Second):
			var activeIMSIs []string
			for _, sess := range s.s11Conn.Sessions() {
				if !sess.IsActive() {
					continue
				}
				activeIMSIs = append(activeIMSIs, sess.IMSI)
			}
			if len(activeIMSIs) == 0 {
				continue
			}

			log.Println("Active Subscribers:")
			for _, imsi := range activeIMSIs {
				log.Printf("\t%s", imsi)
			}
			activeIMSIs = nil
		}
	}
}

func main() {
	flag.Parse()
	log.SetPrefix("[S-GW] ")

	// resolve specified IP:Port as net.UDPAddr.
	s11, err := net.ResolveUDPAddr("udp", *s11+gtpv2.GTPCPort)
	if err != nil {
		log.Println(err)
		return
	}
	s5c, err := net.ResolveUDPAddr("udp", *s5c+gtpv2.GTPCPort)
	if err != nil {
		log.Println(err)
		return
	}
	s1u, err := net.ResolveUDPAddr("udp", *s1u+gtpv2.GTPUPort)
	if err != nil {
		log.Println(err)
		return
	}
	s5u, err := net.ResolveUDPAddr("udp", *s5u+gtpv2.GTPUPort)
	if err != nil {
		log.Println(err)
		return
	}

	sgw, err = newSGW(s11, s5c, s1u, s5u)
	if err != nil {
		log.Println(err)
		return
	}

	// register handlers for ALL the message you expect remote endpoint to send.
	sgw.s11Conn.AddHandlers(map[uint8]gtpv2.HandlerFunc{
		message.MsgTypeCreateSessionRequest: handleCreateSessionRequest,
		message.MsgTypeModifyBearerRequest:  handleModifyBearerRequest,
		message.MsgTypeDeleteSessionRequest: handleDeleteSessionRequest,
		message.MsgTypeDeleteBearerResponse: handleDeleteBearerResponse,
	})
	sgw.s5cConn.AddHandlers(map[uint8]gtpv2.HandlerFunc{
		message.MsgTypeCreateSessionResponse: handleCreateSessionResponse,
		message.MsgTypeDeleteSessionResponse: handleDeleteSessionResponse,
		message.MsgTypeDeleteBearerRequest:   handleDeleteBearerRequest,
	})

	log.Fatal(sgw.run())
}


================================================
FILE: examples/sgw/s11.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Command sgw is a dead simple implementation of S-GW only with GTP-related features.
package main

import (
	"fmt"
	"net"
	"time"

	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

func handleCreateSessionRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, msg message.Message) error {
	sgw.loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), mmeAddr)

	s11Session := gtpv2.NewSession(mmeAddr, &gtpv2.Subscriber{Location: &gtpv2.Location{}})
	s11Bearer := s11Session.GetDefaultBearer()

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	csReqFromMME := msg.(*message.CreateSessionRequest)

	var pgwAddrString string
	if teidIE := csReqFromMME.PGWS5S8FTEIDC; teidIE != nil {
		ip, err := teidIE.IPAddress()
		if err != nil {
			return err
		}
		pgwAddrString = ip + gtpv2.GTPCPort

		teid, err := teidIE.TEID()
		if err != nil {
			return err
		}
		s11Session.AddTEID(gtpv2.IFTypeS5S8PGWGTPC, teid)
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}
	if senderIE := csReqFromMME.SenderFTEIDC; senderIE != nil {
		teid, err := senderIE.TEID()
		if err != nil {
			return err
		}
		s11Session.AddTEID(gtpv2.IFTypeS11MMEGTPC, teid)
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	laddr, err := net.ResolveUDPAddr("udp", *s5c+gtpv2.GTPCPort)
	if err != nil {
		return err
	}
	raddr, err := net.ResolveUDPAddr("udp", pgwAddrString)
	if err != nil {
		return err
	}

	// keep session information retrieved from the message.
	// XXX - should return error if required IE is missing.
	if imsiIE := csReqFromMME.IMSI; imsiIE != nil {
		imsi, err := imsiIE.IMSI()
		if err != nil {
			return err
		}

		// remove previous session for the same subscriber if exists.
		sess, err := s11Conn.GetSessionByIMSI(imsi)
		if err != nil {
			switch err.(type) {
			case *gtpv2.UnknownIMSIError:
				// whole new session. just ignore.
			default:
				return fmt.Errorf("got something unexpected: %w", err)
			}
		} else {
			s11Conn.RemoveSession(sess)
		}

		s11Session.IMSI = imsi
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.IMSI}
	}
	if msisdnIE := csReqFromMME.MSISDN; msisdnIE != nil {
		s11Session.MSISDN, err = msisdnIE.MSISDN()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.MSISDN}
	}
	if meiIE := csReqFromMME.MEI; meiIE != nil {
		s11Session.IMEI, err = meiIE.MobileEquipmentIdentity()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.MobileEquipmentIdentity}
	}
	if apnIE := csReqFromMME.APN; apnIE != nil {
		s11Bearer.APN, err = apnIE.AccessPointName()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.AccessPointName}
	}
	if netIE := csReqFromMME.ServingNetwork; netIE != nil {
		s11Session.MCC, err = netIE.MCC()
		if err != nil {
			return err
		}
		s11Session.MNC, err = netIE.MNC()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.ServingNetwork}
	}
	if ratIE := csReqFromMME.RATType; ratIE != nil {
		s11Session.RATType, err = ratIE.RATType()
		if err != nil {
			return err
		}
	} else {
		return &gtpv2.RequiredIEMissingError{Type: ie.RATType}
	}

	s11IP, _, err := net.SplitHostPort(*s11 + gtpv2.GTPCPort)
	if err != nil {
		return fmt.Errorf("failed to get IP for S11: %w", err)
	}
	senderFTEID := s11Conn.NewSenderFTEID(s11IP, "")
	s11sgwTEID := senderFTEID.MustTEID()
	s11Conn.RegisterSession(s11sgwTEID, s11Session)

	s5cIP := laddr.IP.String()
	s5uIP, _, err := net.SplitHostPort(*s5u + gtpv2.GTPCPort)
	if err != nil {
		return err
	}
	s5cFTEID := sgw.s5cConn.NewSenderFTEID(s5cIP, "")
	s5uFTEID := sgw.s5uConn.NewFTEID(gtpv2.IFTypeS5S8SGWGTPU, s5uIP, "").WithInstance(2)

	s5Session, seq, err := sgw.s5cConn.CreateSession(
		raddr,
		csReqFromMME.IMSI, csReqFromMME.MSISDN, csReqFromMME.MEI, csReqFromMME.ServingNetwork,
		csReqFromMME.RATType, csReqFromMME.IndicationFlags, s5cFTEID, csReqFromMME.PGWS5S8FTEIDC,
		csReqFromMME.APN, csReqFromMME.SelectionMode, csReqFromMME.PDNType, csReqFromMME.PAA,
		csReqFromMME.APNRestriction, csReqFromMME.AMBR, csReqFromMME.ULI,
		ie.NewBearerContext(
			ie.NewEPSBearerID(5),
			s5uFTEID,
			ie.NewBearerQoS(1, 2, 1, 0xff, 0, 0, 0, 0),
		),
		csReqFromMME.MMEFQCSID,
		ie.NewFullyQualifiedCSID(s5uIP, 1).WithInstance(1),
	)
	if err != nil {
		return err
	}
	s5Session.AddTEID(s5uFTEID.MustInterfaceType(), s5uFTEID.MustTEID())
	sgw.s5cConn.RegisterSession(s5cFTEID.MustTEID(), s5Session)

	sgw.loggerCh <- fmt.Sprintf("Sent Create Session Request to %s for %s", pgwAddrString, s5Session.IMSI)

	var csRspFromSGW *message.CreateSessionResponse
	s11mmeTEID, err := s11Session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}
	incomingMsg, err := s11Session.WaitMessage(seq, 5*time.Second)
	if err != nil {
		csRspFromSGW = message.NewCreateSessionResponse(
			s11mmeTEID, 0,
			ie.NewCause(gtpv2.CauseNoResourcesAvailable, 0, 0, 0, nil),
		)

		if err := s11Conn.RespondTo(mmeAddr, csReqFromMME, csRspFromSGW); err != nil {
			s11Conn.RemoveSession(s11Session)
			return err
		}
		sgw.loggerCh <- fmt.Sprintf(
			"Sent %s with failure code: %d, target subscriber: %s",
			csRspFromSGW.MessageTypeName(), gtpv2.CausePGWNotResponding, s11Session.IMSI,
		)
		s11Conn.RemoveSession(s11Session)
		return err
	}

	var csRspFromPGW *message.CreateSessionResponse
	switch m := incomingMsg.(type) {
	case *message.CreateSessionResponse:
		// move forward
		csRspFromPGW = m
	default:
		s11Conn.RemoveSession(s11Session)
		return &gtpv2.UnexpectedTypeError{Msg: incomingMsg}
	}
	// if everything in CreateSessionResponse seems OK, relay it to MME.
	s1uIP, _, err := net.SplitHostPort(*s1u + gtpv2.GTPCPort)
	if err != nil {
		return fmt.Errorf("failed to get IP for S1-U: %w", err)
	}
	s1usgwFTEID := sgw.s1uConn.NewFTEID(gtpv2.IFTypeS1USGWGTPU, s1uIP, "")
	csRspFromSGW = csRspFromPGW
	csRspFromSGW.SenderFTEIDC = senderFTEID
	csRspFromSGW.SGWFQCSID = ie.NewFullyQualifiedCSID(s1uIP, 1).WithInstance(1)
	csRspFromSGW.BearerContextsCreated[0].Add(s1usgwFTEID)
	csRspFromSGW.BearerContextsCreated[0].Remove(ie.ChargingID, 0)
	csRspFromSGW.SetTEID(s11mmeTEID)
	csRspFromSGW.SetLength()

	if err := s11Conn.RespondTo(mmeAddr, csReqFromMME, csRspFromSGW); err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}
	s11Session.AddTEID(senderFTEID.MustInterfaceType(), s11sgwTEID)
	s11Session.AddTEID(s1usgwFTEID.MustInterfaceType(), s1usgwFTEID.MustTEID())

	s5cpgwTEID, err := s5Session.GetTEID(gtpv2.IFTypeS5S8PGWGTPC)
	if err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}
	s5csgwTEID, err := s5Session.GetTEID(gtpv2.IFTypeS5S8SGWGTPC)
	if err != nil {
		s11Conn.RemoveSession(s11Session)
		return err
	}

	if err := s11Session.Activate(); err != nil {
		sgw.loggerCh <- fmt.Sprintf("Error: %v", err)
		s11Conn.RemoveSession(s11Session)
		return err
	}

	sgw.loggerCh <- fmt.Sprintf(
		"Session created with MME and P-GW for Subscriber: %s;\n\tS11 MME:  %s, TEID->: %#x, TEID<-: %#x\n\tS5C P-GW: %s, TEID->: %#x, TEID<-: %#x",
		s5Session.Subscriber.IMSI, mmeAddr, s11mmeTEID, s11sgwTEID, pgwAddrString, s5cpgwTEID, s5csgwTEID,
	)
	return nil
}

func handleModifyBearerRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, msg message.Message) error {
	sgw.loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), mmeAddr)

	s11Session, err := s11Conn.GetSessionByTEID(msg.TEID(), mmeAddr)
	if err != nil {
		return err
	}
	s5cSession, err := sgw.s5cConn.GetSessionByIMSI(s11Session.IMSI)
	if err != nil {
		return err
	}
	s1uBearer := s11Session.GetDefaultBearer()
	s5uBearer := s5cSession.GetDefaultBearer()

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	mbReqFromMME := msg.(*message.ModifyBearerRequest)
	if brCtxIE := mbReqFromMME.BearerContextsToBeModified; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.Indication:
				// do nothing in this example.
				// S-GW should change its beahavior based on indication flags like;
				//  - pass Modify Bearer Request to P-GW if handover is indicated.
				//  - XXX...
			case ie.FullyQualifiedTEID:
				if err := handleFTEIDU(childIE, s11Session, s1uBearer); err != nil {
					return err
				}
			}
		}
	}

	s11mmeTEID, err := s11Session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		return err
	}
	s1usgwTEID, err := s11Session.GetTEID(gtpv2.IFTypeS1USGWGTPU)
	if err != nil {
		return err
	}
	s5usgwTEID, err := s5cSession.GetTEID(gtpv2.IFTypeS5S8SGWGTPU)
	if err != nil {
		return err
	}
	if err := sgw.s1uConn.RelayTo(
		sgw.s5uConn, s1usgwTEID, s5uBearer.OutgoingTEID(), s5uBearer.RemoteAddress(),
	); err != nil {
		return err
	}
	if err := sgw.s5uConn.RelayTo(
		sgw.s1uConn, s5usgwTEID, s1uBearer.OutgoingTEID(), s1uBearer.RemoteAddress(),
	); err != nil {
		return err
	}

	s1uIP, _, err := net.SplitHostPort(*s1u + gtpv2.GTPCPort)
	if err != nil {
		return err
	}
	mbRspFromSGW := message.NewModifyBearerResponse(
		s11mmeTEID, 0,
		ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
		ie.NewBearerContext(
			ie.NewCause(gtpv2.CauseRequestAccepted, 0, 0, 0, nil),
			ie.NewEPSBearerID(s1uBearer.EBI),
			ie.NewFullyQualifiedTEID(gtpv2.IFTypeS1USGWGTPU, s1usgwTEID, s1uIP, ""),
		),
	)

	if err := s11Conn.RespondTo(mmeAddr, msg, mbRspFromSGW); err != nil {
		return err
	}

	sgw.loggerCh <- fmt.Sprintf(
		"Started listening on U-Plane for Subscriber: %s;\n\tS1-U: %s\n\tS5-U: %s",
		s11Session.IMSI, *s1u, *s5u,
	)
	return nil
}

func handleDeleteSessionRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, msg message.Message) error {
	sgw.loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), mmeAddr)

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	dsReqFromMME := msg.(*message.DeleteSessionRequest)

	s11Session, err := s11Conn.GetSessionByTEID(msg.TEID(), mmeAddr)
	if err != nil {
		return err
	}

	s5Session, err := sgw.s5cConn.GetSessionByIMSI(s11Session.IMSI)
	if err != nil {
		return err
	}

	s5cpgwTEID, err := s5Session.GetTEID(gtpv2.IFTypeS5S8PGWGTPC)
	if err != nil {
		return err
	}

	seq, err := sgw.s5cConn.DeleteSession(
		s5cpgwTEID, s5Session,
		ie.NewEPSBearerID(s5Session.GetDefaultBearer().EBI),
	)
	if err != nil {
		return err
	}

	var dsRspFromSGW *message.DeleteSessionResponse
	s11mmeTEID, err := s11Session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		return err
	}

	incomingMsg, err := s11Session.WaitMessage(seq, 5*time.Second)
	if err != nil {
		dsRspFromSGW = message.NewDeleteSessionResponse(
			s11mmeTEID, 0,
			ie.NewCause(gtpv2.CausePGWNotResponding, 0, 0, 0, nil),
		)

		if err := s11Conn.RespondTo(mmeAddr, dsReqFromMME, dsRspFromSGW); err != nil {
			return err
		}
		sgw.loggerCh <- fmt.Sprintf(
			"Sent %s with failure code: %d, target subscriber: %s",
			dsRspFromSGW.MessageTypeName(), gtpv2.CausePGWNotResponding, s11Session.IMSI,
		)
		return err
	}

	// use the cause as it is.
	switch m := incomingMsg.(type) {
	case *message.DeleteSessionResponse:
		// move forward
		dsRspFromSGW = m
	default:
		return &gtpv2.UnexpectedTypeError{Msg: incomingMsg}
	}

	dsRspFromSGW.SetTEID(s11mmeTEID)
	if err := s11Conn.RespondTo(mmeAddr, msg, dsRspFromSGW); err != nil {
		return err
	}

	sgw.loggerCh <- fmt.Sprintf("Session deleted for Subscriber: %s", s11Session.IMSI)
	s11Conn.RemoveSession(s11Session)

	return nil
}

func handleDeleteBearerResponse(s11Conn *gtpv2.Conn, mmeAddr net.Addr, msg message.Message) error {
	sgw.loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), mmeAddr)

	s11Session, err := s11Conn.GetSessionByTEID(msg.TEID(), mmeAddr)
	if err != nil {
		return err
	}

	s5Session, err := sgw.s5cConn.GetSessionByIMSI(s11Session.IMSI)
	if err != nil {
		return err
	}

	if err := gtpv2.PassMessageTo(s5Session, msg, 5*time.Second); err != nil {
		return err
	}

	// remove bearer in handleDeleteBearerRequest instead of doing here,
	// as Delete Bearer Request does not necessarily have EBI.
	return nil
}

func handleFTEIDU(fteiduIE *ie.IE, session *gtpv2.Session, bearer *gtpv2.Bearer) error {
	if fteiduIE.Type != ie.FullyQualifiedTEID {
		return &gtpv2.UnexpectedIEError{IEType: fteiduIE.Type}
	}

	ip, err := fteiduIE.IPAddress()
	if err != nil {
		return err
	}
	addr, err := net.ResolveUDPAddr("udp", ip+gtpv2.GTPUPort)
	if err != nil {
		return err
	}
	bearer.SetRemoteAddress(addr)

	teid, err := fteiduIE.TEID()
	if err != nil {
		return err
	}
	bearer.SetOutgoingTEID(teid)

	it, err := fteiduIE.InterfaceType()
	if err != nil {
		return err
	}
	session.AddTEID(it, teid)
	return nil
}


================================================
FILE: examples/sgw/s5.go
================================================
package main

import (
	"fmt"
	"net"
	"time"

	"github.com/wmnsk/go-gtp/gtpv2"
	"github.com/wmnsk/go-gtp/gtpv2/ie"
	"github.com/wmnsk/go-gtp/gtpv2/message"
)

func handleCreateSessionResponse(s5cConn *gtpv2.Conn, pgwAddr net.Addr, msg message.Message) error {
	sgw.loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), pgwAddr)

	s5Session, err := s5cConn.GetSessionByTEID(msg.TEID(), pgwAddr)
	if err != nil {
		return err
	}

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	csRspFromPGW := msg.(*message.CreateSessionResponse)

	// check Cause value first.
	if causeIE := csRspFromPGW.Cause; causeIE != nil {
		cause, err := causeIE.Cause()
		if err != nil {
			return err
		}
		if cause != gtpv2.CauseRequestAccepted {
			s5cConn.RemoveSession(s5Session)
			// this is not such a fatal error worth stopping the whole program.
			// in the real case it is better to take some action based on the Cause, though.
			return &gtpv2.CauseNotOKError{
				MsgType: csRspFromPGW.MessageTypeName(),
				Cause:   cause,
				Msg:     fmt.Sprintf("subscriber: %s", s5Session.IMSI),
			}
		}
	} else {
		s5cConn.RemoveSession(s5Session)
		return &gtpv2.RequiredIEMissingError{
			Type: ie.Cause,
		}
	}

	bearer := s5Session.GetDefaultBearer()
	// retrieve values that P-GW gave.
	if paaIE := csRspFromPGW.PAA; paaIE != nil {
		ip, err := paaIE.IPAddress()
		if err != nil {
			return err
		}
		bearer.SubscriberIP = ip
	} else {
		s5cConn.RemoveSession(s5Session)
		return &gtpv2.RequiredIEMissingError{Type: ie.PDNAddressAllocation}
	}
	if fteidcIE := csRspFromPGW.PGWS5S8FTEIDC; fteidcIE != nil {
		it, err := fteidcIE.InterfaceType()
		if err != nil {
			return err
		}
		teid, err := fteidcIE.TEID()
		if err != nil {
			return err
		}
		s5Session.AddTEID(it, teid)
	} else {
		s5cConn.RemoveSession(s5Session)
		return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
	}

	if brCtxIE := csRspFromPGW.BearerContextsCreated; brCtxIE != nil {
		for _, childIE := range brCtxIE[0].ChildIEs {
			switch childIE.Type {
			case ie.Cause:
				cause, err := childIE.Cause()
				if err != nil {
					return err
				}
				if cause != gtpv2.CauseRequestAccepted {
					s5cConn.RemoveSession(s5Session)
					return &gtpv2.CauseNotOKError{
						MsgType: csRspFromPGW.MessageTypeName(),
						Cause:   cause,
						Msg:     fmt.Sprintf("subscriber: %s", s5Session.IMSI),
					}
				}
			case ie.EPSBearerID:
				ebi, err := childIE.EPSBearerID()
				if err != nil {
					return err
				}
				bearer.EBI = ebi
			case ie.FullyQualifiedTEID:
				if err := handleFTEIDU(childIE, s5Session, bearer); err != nil {
					return err
				}
			case ie.ChargingID:
				cid, err := childIE.ChargingID()
				if err != nil {
					return err
				}
				bearer.ChargingID = cid
			}
		}
	} else {
		s5cConn.RemoveSession(s5Session)
		return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
	}

	if err := s5Session.Activate(); err != nil {
		s5cConn.RemoveSession(s5Session)
		return err
	}

	s11Session, err := sgw.s11Conn.GetSessionByIMSI(s5Session.IMSI)
	if err != nil {
		return err
	}

	if err := gtpv2.PassMessageTo(s11Session, csRspFromPGW, 5*time.Second); err != nil {
		return err
	}

	return nil
}

func handleDeleteSessionResponse(s5cConn *gtpv2.Conn, pgwAddr net.Addr, msg message.Message) error {
	sgw.loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), pgwAddr)

	s5Session, err := s5cConn.GetSessionByTEID(msg.TEID(), pgwAddr)
	if err != nil {
		return err
	}

	s11Session, err := sgw.s11Conn.GetSessionByIMSI(s5Session.IMSI)
	if err != nil {
		return err
	}

	if err := gtpv2.PassMessageTo(s11Session, msg, 5*time.Second); err != nil {
		return err
	}

	// even the cause indicates failure, session should be removed locally.
	sgw.loggerCh <- fmt.Sprintf("Session deleted for Subscriber: %s", s5Session.IMSI)
	s5cConn.RemoveSession(s5Session)
	return nil
}

func handleDeleteBearerRequest(s5cConn *gtpv2.Conn, pgwAddr net.Addr, msg message.Message) error {
	sgw.loggerCh <- fmt.Sprintf("Received %s from %s", msg.MessageTypeName(), pgwAddr)

	s5Session, err := s5cConn.GetSessionByTEID(msg.TEID(), pgwAddr)
	if err != nil {
		return err
	}

	s11Session, err := sgw.s11Conn.GetSessionByIMSI(s5Session.IMSI)
	if err != nil {
		return err
	}

	s5cpgwTEID, err := s5Session.GetTEID(gtpv2.IFTypeS5S8PGWGTPC)
	if err != nil {
		return err
	}

	s11mmeTEID, err := s11Session.GetTEID(gtpv2.IFTypeS11MMEGTPC)
	if err != nil {
		return err
	}

	// assert type to refer to the struct field specific to the message.
	// in general, no need to check if it can be type-asserted, as long as the MessageType is
	// specified correctly in AddHandler().
	dbReqFromPGW := msg.(*message.DeleteBearerRequest)

	var dbRspFromSGW *message.DeleteBearerResponse
	var ebi *ie.IE
	if ie := dbReqFromPGW.LinkedEBI; ie != nil {
		ebi = ie
	}
	if e := dbReqFromPGW.EBIs; e != nil {
		ebiIE := e[0]
		// shouldn't be both.
		if ebi != nil {
			dbRspFromSGW = message.NewDeleteBearerResponse(
				s5cpgwTEID, 0,
				ie.NewCause(gtpv2.CauseContextNotFound, 0, 0, 0, ebiIE),
			)
			if err := s5cConn.RespondTo(pgwAddr, dbReqFromPGW, dbRspFromSGW); err != nil {
				return err
			}
			return fmt.Errorf(
				"%T from %s had both Linked EBI and EBIs IE",
				dbReqFromPGW, pgwAddr,
			)
		}
		ebi = ebiIE
	}

	if ebi == nil {
		dbRspFromSGW = message.NewDeleteBearerResponse(
			s5cpgwTEID, 0, ie.NewCause(gtpv2.CauseMandatoryIEMissing,
				0, 0, 0, ie.NewEPSBearerID(0),
			),
		)
		if err := s5cConn.RespondTo(pgwAddr, dbReqFromPGW, dbRspFromSGW); err != nil {
			return err
		}
		return err
	}

	// check if bearer associated with EBI exists or not.
	_, err = s5Session.LookupBearerByEBI(ebi.MustEPSBearerID())
	if err != nil {
		dbRspFromSGW = message.NewDeleteBearerResponse(
			s5cpgwTEID, 0,
			ie.NewCause(gtpv2.CauseContextNotFound, 0, 0, 0, nil),
		)
		if err := s5cConn.RespondTo(pgwAddr, dbReqFromPGW, dbRspFromSGW); err != nil {
			return err
		}
		return err
	}

	// forward to MME
	seq, err := sgw.s11Conn.DeleteBearer(s11mmeTEID, s11Session, ebi)
	if err != nil {
		return err
	}

	// wait for response from MME for 5 seconds
	incomingMsg, err := s5Session.WaitMessage(seq, 5*time.Second)
	if err != nil {
		dbRspFromSGW = message.NewDeleteBearerResponse(
			s5cpgwTEID, 0,
			ie.NewCause(gtpv2.CauseNoResourcesAvailable, 0, 0, 0, nil),
		)

		if err := s5cConn.RespondTo(pgwAddr, dbReqFromPGW, dbRspFromSGW); err != nil {
			return err
		}
		// remove anyway, as P-GW no longer keeps bearer locally
		s5Session.RemoveBearerByEBI(ebi.MustEPSBearerID())
		s11Session.RemoveBearerByEBI(ebi.MustEPSBearerID())
		return err
	}

	switch m := incomingMsg.(type) {
	case *message.DeleteBearerResponse:
		// move forward
		dbRspFromSGW = m
	default:
		return &gtpv2.UnexpectedTypeError{Msg: incomingMsg}
	}

	dbRspFromSGW.SetTEID(s5cpgwTEID)
	if err := s5cConn.RespondTo(pgwAddr, msg, dbRspFromSGW); err != nil {
		return err
	}

	s5Session.RemoveBearerByEBI(ebi.MustEPSBearerID())
	s11Session.RemoveBearerByEBI(ebi.MustEPSBearerID())

	return nil
}


================================================
FILE: examples/utils/mac_local_host_enabler.sh
================================================
# This script will enable 127.0.0.1 up to 127.0.0.256 interfaces
for ((i=2;i<256;i++)) do 
  sudo ifconfig lo0 alias 127.0.0.$i up
done 


================================================
FILE: go.mod
================================================
module github.com/wmnsk/go-gtp

go 1.25.0

require (
	github.com/golang/protobuf v1.5.4
	github.com/google/go-cmp v0.7.0
	github.com/pascaldekloe/goe v0.1.1
	github.com/prometheus/client_golang v1.23.2
	github.com/vishvananda/netlink v1.3.1
	golang.org/x/net v0.51.0
	google.golang.org/grpc v1.79.2
	gopkg.in/yaml.v2 v2.4.0
)

require (
	github.com/beorn7/perks v1.0.1 // indirect
	github.com/cespare/xxhash/v2 v2.3.0 // indirect
	github.com/kr/text v0.2.0 // indirect
	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
	github.com/prometheus/client_model v0.6.2 // indirect
	github.com/prometheus/common v0.67.5 // indirect
	github.com/prometheus/procfs v0.20.1 // indirect
	github.com/vishvananda/netns v0.0.5 // indirect
	go.yaml.in/yaml/v2 v2.4.3 // indirect
	golang.org/x/sys v0.41.0 // indirect
	golang.org/x/text v0.34.0 // indirect
	google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
	google.golang.org/protobuf v1.36.11 // indirect
)


================================================
FILE: go.sum
================================================
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pascaldekloe/goe v0.1.1 h1:Ah6WQ56rZONR3RW3qWa2NCZ6JAVvSpUcoLBaOmYFt9Q=
github.com/pascaldekloe/goe v0.1.1/go.mod h1:KSyfaxQOh0HZPjDP1FL/kFtbqYqrALJTaMafFUIccqU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


================================================
FILE: gtp.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package gtp

import (
	v0msg "github.com/wmnsk/go-gtp/gtpv0/message"
	v1msg "github.com/wmnsk/go-gtp/gtpv1/message"
	v2msg "github.com/wmnsk/go-gtp/gtpv2/message"
)

// Message is an interface that defines all versions of GTP message.
type Message interface {
	MarshalTo([]byte) error
	UnmarshalBinary(b []byte) error
	MarshalLen() int
	Version() int
	MessageType() uint8
	MessageTypeName() string

	// deprecated
	SerializeTo([]byte) error
	DecodeFromBytes(b []byte) error
}

// Marshal returns the byte sequence generated from a Message instance.
// Better to use (*MessageName).Marshal instead if you know the name of message to be serialized.
func Marshal(m Message) ([]byte, error) {
	b := make([]byte, m.MarshalLen())
	if err := m.MarshalTo(b); err != nil {
		return nil, err
	}

	return b, nil
}

// Parse decodes given bytes as Message.
func Parse(b []byte) (Message, error) {
	if len(b) < 8 {
		return nil, ErrTooShortToParse
	}

	switch b[0] >> 5 {
	case 0:
		return v0msg.Parse(b)
	case 1:
		return v1msg.Parse(b)
	case 2:
		return v2msg.Parse(b)
	default:
		return nil, ErrInvalidVersion
	}
}


================================================
FILE: gtp_fuzz_test.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package gtp_test

import (
	"testing"

	"github.com/wmnsk/go-gtp"
)

func FuzzParse(f *testing.F) {
	f.Fuzz(func(t *testing.T, b []byte) {
		if _, err := gtp.Parse(b); err != nil {
			t.Skip()
		}
	})
}


================================================
FILE: gtp_test.go
================================================
// Copyright 2019-2024 go-gtp authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

package gtp

import (
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/pascaldekloe/goe/verify"

	v0
Download .txt
gitextract_o6tx7vdp/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── go.yml
│       └── golangci-lint.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── README.md
├── doc.go
├── errors.go
├── examples/
│   ├── gw-tester/
│   │   ├── README.md
│   │   ├── 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
Download .txt
Showing preview only (350K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3940 symbols across 408 files)

FILE: examples/gw-tester/enb/config.go
  type Config (line 15) | type Config struct
  type Subscriber (line 34) | type Subscriber struct
    method String (line 53) | func (s *Subscriber) String() string {
  function loadConfig (line 60) | func loadConfig(path string) (*Config, error) {

FILE: examples/gw-tester/enb/enb.go
  type enb (line 26) | type enb struct
    method run (line 99) | func (e *enb) run(ctx context.Context) error {
    method reload (line 170) | func (e *enb) reload(cfg *Config) error {
    method close (line 207) | func (e *enb) close() error {
    method attach (line 244) | func (e *enb) attach(ctx context.Context, sub *Subscriber) error {
    method newTEID (line 309) | func (e *enb) newTEID() uint32 {
    method setupUPlane (line 325) | func (e *enb) setupUPlane(ctx context.Context, sub *Subscriber) error {
    method addRoute (line 350) | func (e *enb) addRoute() error {
    method addRuleExternal (line 364) | func (e *enb) addRuleExternal(sub *Subscriber) error {
    method addRuleLocal (line 386) | func (e *enb) addRuleLocal(sub *Subscriber) error {
    method runHTTPProbe (line 407) | func (e *enb) runHTTPProbe(ctx context.Context, sub *Subscriber) error {
    method addIP (line 442) | func (e *enb) addIP(sub *Subscriber) error {
  function newENB (line 56) | func newENB(cfg *Config) (*enb, error) {

FILE: examples/gw-tester/enb/main.go
  function main (line 17) | func main() {

FILE: examples/gw-tester/enb/metrics.go
  type metricsCollector (line 15) | type metricsCollector struct
  method runMetricsCollector (line 22) | func (e *enb) runMetricsCollector() error {

FILE: examples/gw-tester/mme/config.go
  type Config (line 14) | type Config struct
  function loadConfig (line 31) | func loadConfig(path string) (*Config, error) {

FILE: examples/gw-tester/mme/handlers.go
  method handleCreateSessionResponse (line 17) | func (m *mme) handleCreateSessionResponse(c *gtpv2.Conn, sgwAddr net.Add...
  method handleModifyBearerResponse (line 121) | func (m *mme) handleModifyBearerResponse(c *gtpv2.Conn, sgwAddr net.Addr...
  method handleDeleteSessionResponse (line 181) | func (m *mme) handleDeleteSessionResponse(c *gtpv2.Conn, sgwAddr net.Add...

FILE: examples/gw-tester/mme/main.go
  function main (line 17) | func main() {

FILE: examples/gw-tester/mme/metrics.go
  type metricsCollector (line 12) | type metricsCollector struct
  method runMetricsCollector (line 18) | func (m *mme) runMetricsCollector() error {

FILE: examples/gw-tester/mme/mme.go
  type Session (line 25) | type Session struct
  type mme (line 35) | type mme struct
    method run (line 109) | func (m *mme) run(ctx context.Context) error {
    method reload (line 166) | func (m *mme) reload(cfg *Config) error {
    method Attach (line 172) | func (m *mme) Attach(ctx context.Context, req *s1mme.AttachRequest) (*...
    method Detach (line 244) | func (m *mme) Detach(ctx context.Context, req *s1mme.DetachRequest) (*...
    method CreateSession (line 249) | func (m *mme) CreateSession(sess *Session) (*gtpv2.Session, error) {
    method ModifyBearer (line 309) | func (m *mme) ModifyBearer(sess *gtpv2.Session, sub *Session) (*gtpv2....
  function newMME (line 70) | func newMME(cfg *Config) (*mme, error) {

FILE: examples/gw-tester/pgw/config.go
  type Config (line 14) | type Config struct
  function loadConfig (line 29) | func loadConfig(path string) (*Config, error) {

FILE: examples/gw-tester/pgw/handlers.go
  method handleCreateSessionRequest (line 18) | func (p *pgw) handleCreateSessionRequest(c *gtpv2.Conn, sgwAddr net.Addr...
  method handleDeleteSessionRequest (line 206) | func (p *pgw) handleDeleteSessionRequest(c *gtpv2.Conn, sgwAddr net.Addr...

FILE: examples/gw-tester/pgw/main.go
  function main (line 17) | func main() {

FILE: examples/gw-tester/pgw/metrics.go
  type metricsCollector (line 15) | type metricsCollector struct
  method runMetricsCollector (line 22) | func (p *pgw) runMetricsCollector() error {

FILE: examples/gw-tester/pgw/pgw.go
  type pgw (line 22) | type pgw struct
    method run (line 72) | func (p *pgw) run(ctx context.Context) error {
    method close (line 136) | func (p *pgw) close() error {
    method setupUPlane (line 167) | func (p *pgw) setupUPlane(peerIP, msIP net.IP, otei, itei uint32) error {
  function newPGW (line 41) | func newPGW(cfg *Config) (*pgw, error) {

FILE: examples/gw-tester/s1mme/s1mme.pb.go
  constant _ (line 25) | _ = proto.ProtoPackageIsVersion3
  type Cause (line 28) | type Cause
    method String (line 48) | func (x Cause) String() string {
    method EnumDescriptor (line 52) | func (Cause) EnumDescriptor() ([]byte, []int) {
  constant Cause_INVALID (line 31) | Cause_INVALID        Cause = 0
  constant Cause_SUCCESS (line 32) | Cause_SUCCESS        Cause = 1
  constant Cause_GW_UNAVAILABLE (line 33) | Cause_GW_UNAVAILABLE Cause = 2
  type Location_RATType (line 56) | type Location_RATType
    method String (line 100) | func (x Location_RATType) String() string {
    method EnumDescriptor (line 104) | func (Location_RATType) EnumDescriptor() ([]byte, []int) {
  constant Location_INVALID (line 59) | Location_INVALID        Location_RATType = 0
  constant Location_UTRAN (line 60) | Location_UTRAN          Location_RATType = 1
  constant Location_GERAN (line 61) | Location_GERAN          Location_RATType = 2
  constant Location_WLAN (line 62) | Location_WLAN           Location_RATType = 3
  constant Location_GAN (line 63) | Location_GAN            Location_RATType = 4
  constant Location_HSPA_EVOLUTION (line 64) | Location_HSPA_EVOLUTION Location_RATType = 5
  constant Location_EUTRAN (line 65) | Location_EUTRAN         Location_RATType = 6
  constant Location_VIRTUAL (line 66) | Location_VIRTUAL        Location_RATType = 7
  constant Location_EUTRAN_NB_IOT (line 67) | Location_EUTRAN_NB_IOT  Location_RATType = 8
  constant Location_LTEM (line 68) | Location_LTEM           Location_RATType = 9
  constant Location_NR (line 69) | Location_NR             Location_RATType = 10
  type AttachRequest (line 109) | type AttachRequest struct
    method Reset (line 123) | func (m *AttachRequest) Reset()         { *m = AttachRequest{} }
    method String (line 124) | func (m *AttachRequest) String() string { return proto.CompactTextStri...
    method ProtoMessage (line 125) | func (*AttachRequest) ProtoMessage()    {}
    method Descriptor (line 126) | func (*AttachRequest) Descriptor() ([]byte, []int) {
    method XXX_Unmarshal (line 130) | func (m *AttachRequest) XXX_Unmarshal(b []byte) error {
    method XXX_Marshal (line 133) | func (m *AttachRequest) XXX_Marshal(b []byte, deterministic bool) ([]b...
    method XXX_Merge (line 136) | func (m *AttachRequest) XXX_Merge(src proto.Message) {
    method XXX_Size (line 139) | func (m *AttachRequest) XXX_Size() int {
    method XXX_DiscardUnknown (line 142) | func (m *AttachRequest) XXX_DiscardUnknown() {
    method GetImsi (line 148) | func (m *AttachRequest) GetImsi() string {
    method GetMsisdn (line 155) | func (m *AttachRequest) GetMsisdn() string {
    method GetImeisv (line 162) | func (m *AttachRequest) GetImeisv() string {
    method GetS1UAddr (line 169) | func (m *AttachRequest) GetS1UAddr() string {
    method GetSrcIp (line 176) | func (m *AttachRequest) GetSrcIp() string {
    method GetITei (line 183) | func (m *AttachRequest) GetITei() uint32 {
    method GetLocation (line 190) | func (m *AttachRequest) GetLocation() *Location {
    method GetReattach (line 197) | func (m *AttachRequest) GetReattach() bool {
  type AttachResponse (line 205) | type AttachResponse struct
    method Reset (line 214) | func (m *AttachResponse) Reset()         { *m = AttachResponse{} }
    method String (line 215) | func (m *AttachResponse) String() string { return proto.CompactTextStr...
    method ProtoMessage (line 216) | func (*AttachResponse) ProtoMessage()    {}
    method Descriptor (line 217) | func (*AttachResponse) Descriptor() ([]byte, []int) {
    method XXX_Unmarshal (line 221) | func (m *AttachResponse) XXX_Unmarshal(b []byte) error {
    method XXX_Marshal (line 224) | func (m *AttachResponse) XXX_Marshal(b []byte, deterministic bool) ([]...
    method XXX_Merge (line 227) | func (m *AttachResponse) XXX_Merge(src proto.Message) {
    method XXX_Size (line 230) | func (m *AttachResponse) XXX_Size() int {
    method XXX_DiscardUnknown (line 233) | func (m *AttachResponse) XXX_DiscardUnknown() {
    method GetCause (line 239) | func (m *AttachResponse) GetCause() Cause {
    method GetSgwAddr (line 246) | func (m *AttachResponse) GetSgwAddr() string {
    method GetOTei (line 253) | func (m *AttachResponse) GetOTei() uint32 {
  type Location (line 261) | type Location struct
    method Reset (line 272) | func (m *Location) Reset()         { *m = Location{} }
    method String (line 273) | func (m *Location) String() string { return proto.CompactTextString(m) }
    method ProtoMessage (line 274) | func (*Location) ProtoMessage()    {}
    method Descriptor (line 275) | func (*Location) Descriptor() ([]byte, []int) {
    method XXX_Unmarshal (line 279) | func (m *Location) XXX_Unmarshal(b []byte) error {
    method XXX_Marshal (line 282) | func (m *Location) XXX_Marshal(b []byte, deterministic bool) ([]byte, ...
    method XXX_Merge (line 285) | func (m *Location) XXX_Merge(src proto.Message) {
    method XXX_Size (line 288) | func (m *Location) XXX_Size() int {
    method XXX_DiscardUnknown (line 291) | func (m *Location) XXX_DiscardUnknown() {
    method GetMcc (line 297) | func (m *Location) GetMcc() string {
    method GetMnc (line 304) | func (m *Location) GetMnc() string {
    method GetRatType (line 311) | func (m *Location) GetRatType() Location_RATType {
    method GetTai (line 318) | func (m *Location) GetTai() uint32 {
    method GetEci (line 325) | func (m *Location) GetEci() uint32 {
  type DetachRequest (line 333) | type DetachRequest struct
    method Reset (line 340) | func (m *DetachRequest) Reset()         { *m = DetachRequest{} }
    method String (line 341) | func (m *DetachRequest) String() string { return proto.CompactTextStri...
    method ProtoMessage (line 342) | func (*DetachRequest) ProtoMessage()    {}
    method Descriptor (line 343) | func (*DetachRequest) Descriptor() ([]byte, []int) {
    method XXX_Unmarshal (line 347) | func (m *DetachRequest) XXX_Unmarshal(b []byte) error {
    method XXX_Marshal (line 350) | func (m *DetachRequest) XXX_Marshal(b []byte, deterministic bool) ([]b...
    method XXX_Merge (line 353) | func (m *DetachRequest) XXX_Merge(src proto.Message) {
    method XXX_Size (line 356) | func (m *DetachRequest) XXX_Size() int {
    method XXX_DiscardUnknown (line 359) | func (m *DetachRequest) XXX_DiscardUnknown() {
    method GetImsi (line 365) | func (m *DetachRequest) GetImsi() string {
  type DetachResponse (line 373) | type DetachResponse struct
    method Reset (line 380) | func (m *DetachResponse) Reset()         { *m = DetachResponse{} }
    method String (line 381) | func (m *DetachResponse) String() string { return proto.CompactTextStr...
    method ProtoMessage (line 382) | func (*DetachResponse) ProtoMessage()    {}
    method Descriptor (line 383) | func (*DetachResponse) Descriptor() ([]byte, []int) {
    method XXX_Unmarshal (line 387) | func (m *DetachResponse) XXX_Unmarshal(b []byte) error {
    method XXX_Marshal (line 390) | func (m *DetachResponse) XXX_Marshal(b []byte, deterministic bool) ([]...
    method XXX_Merge (line 393) | func (m *DetachResponse) XXX_Merge(src proto.Message) {
    method XXX_Size (line 396) | func (m *DetachResponse) XXX_Size() int {
    method XXX_DiscardUnknown (line 399) | func (m *DetachResponse) XXX_DiscardUnknown() {
    method GetCause (line 405) | func (m *DetachResponse) GetCause() Cause {
  function init (line 412) | func init() {
  function init (line 422) | func init() { proto.RegisterFile("s1mme.proto", fileDescriptor_24365dc18...
  constant _ (line 468) | _ = grpc.SupportPackageIsVersion4
  type AttacherClient (line 473) | type AttacherClient interface
  type attacherClient (line 478) | type attacherClient struct
    method Attach (line 486) | func (c *attacherClient) Attach(ctx context.Context, in *AttachRequest...
    method Detach (line 495) | func (c *attacherClient) Detach(ctx context.Context, in *DetachRequest...
  function NewAttacherClient (line 482) | func NewAttacherClient(cc *grpc.ClientConn) AttacherClient {
  type AttacherServer (line 505) | type AttacherServer interface
  type UnimplementedAttacherServer (line 511) | type UnimplementedAttacherServer struct
    method Attach (line 514) | func (*UnimplementedAttacherServer) Attach(ctx context.Context, req *A...
    method Detach (line 517) | func (*UnimplementedAttacherServer) Detach(ctx context.Context, req *D...
  function RegisterAttacherServer (line 521) | func RegisterAttacherServer(s *grpc.Server, srv AttacherServer) {
  function _Attacher_Attach_Handler (line 525) | func _Attacher_Attach_Handler(srv interface{}, ctx context.Context, dec ...
  function _Attacher_Detach_Handler (line 543) | func _Attacher_Detach_Handler(srv interface{}, ctx context.Context, dec ...

FILE: examples/gw-tester/sgw/config.go
  type Config (line 14) | type Config struct
  function loadConfig (line 26) | func loadConfig(path string) (*Config, error) {

FILE: examples/gw-tester/sgw/main.go
  function main (line 17) | func main() {

FILE: examples/gw-tester/sgw/metrics.go
  type metricsCollector (line 15) | type metricsCollector struct
  method runMetricsCollector (line 22) | func (s *sgw) runMetricsCollector() error {

FILE: examples/gw-tester/sgw/s11_handlers.go
  method handleCreateSessionRequest (line 18) | func (s *sgw) handleCreateSessionRequest(s11Conn *gtpv2.Conn, mmeAddr ne...
  method handleModifyBearerRequest (line 257) | func (s *sgw) handleModifyBearerRequest(s11Conn *gtpv2.Conn, mmeAddr net...
  method handleDeleteSessionRequest (line 360) | func (s *sgw) handleDeleteSessionRequest(s11Conn *gtpv2.Conn, mmeAddr ne...
  method handleDeleteBearerResponse (line 443) | func (s *sgw) handleDeleteBearerResponse(s11Conn *gtpv2.Conn, mmeAddr ne...
  method handleFTEIDU (line 468) | func (s *sgw) handleFTEIDU(fteiduIE *ie.IE, session *gtpv2.Session, bear...

FILE: examples/gw-tester/sgw/s5_handlers.go
  method handleCreateSessionResponse (line 18) | func (s *sgw) handleCreateSessionResponse(s5cConn *gtpv2.Conn, pgwAddr n...
  method handleDeleteSessionResponse (line 141) | func (s *sgw) handleDeleteSessionResponse(s5cConn *gtpv2.Conn, pgwAddr n...
  method handleDeleteBearerRequest (line 167) | func (s *sgw) handleDeleteBearerRequest(s5cConn *gtpv2.Conn, pgwAddr net...

FILE: examples/gw-tester/sgw/sgw.go
  type sgw (line 22) | type sgw struct
    method run (line 102) | func (s *sgw) run(ctx context.Context) error {
    method close (line 195) | func (s *sgw) close() error {
    method addRoutes (line 238) | func (s *sgw) addRoutes() error {
  function newSGW (line 44) | func newSGW(cfg *Config) (*sgw, error) {

FILE: examples/mme/main.go
  function main (line 62) | func main() {

FILE: examples/mme/mme.go
  function handleCreateSessionResponse (line 16) | func handleCreateSessionResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg me...
  function handleModifyBearerResponse (line 117) | func handleModifyBearerResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg mes...
  function handleDeleteSessionResponse (line 185) | func handleDeleteSessionResponse(c *gtpv2.Conn, sgwAddr net.Addr, msg me...

FILE: examples/mme/mock.go
  function getPGWIP (line 23) | func getPGWIP(apn string) (string, error) {
  function dispatch (line 36) | func dispatch(subs []*gtpv2.Subscriber) {
  function handleAttach (line 52) | func handleAttach(raddr net.Addr, c *gtpv2.Conn, sub *gtpv2.Subscriber, ...
  type mockUEeNB (line 142) | type mockUEeNB struct
    method run (line 150) | func (m mockUEeNB) run(errCh chan error) {

FILE: examples/pgw/main.go
  function main (line 41) | func main() {

FILE: examples/pgw/pgw.go
  function getSubscriberIP (line 23) | func getSubscriberIP(sub *gtpv2.Subscriber) (string, error) {
  function handleCreateSessionRequest (line 45) | func handleCreateSessionRequest(c *gtpv2.Conn, sgwAddr net.Addr, msg mes...
  function handleDeleteSessionRequest (line 230) | func handleDeleteSessionRequest(c *gtpv2.Conn, sgwAddr net.Addr, msg mes...

FILE: examples/sgw/main.go
  type sGateway (line 49) | type sGateway struct
    method run (line 103) | func (s *sGateway) run() error {
  function newSGW (line 57) | func newSGW(s11, s5c, s1u, s5u net.Addr) (*sGateway, error) {
  function main (line 137) | func main() {

FILE: examples/sgw/s11.go
  function handleCreateSessionRequest (line 18) | func handleCreateSessionRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, m...
  function handleModifyBearerRequest (line 251) | func handleModifyBearerRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, ms...
  function handleDeleteSessionRequest (line 333) | func handleDeleteSessionRequest(s11Conn *gtpv2.Conn, mmeAddr net.Addr, m...
  function handleDeleteBearerResponse (line 407) | func handleDeleteBearerResponse(s11Conn *gtpv2.Conn, mmeAddr net.Addr, m...
  function handleFTEIDU (line 429) | func handleFTEIDU(fteiduIE *ie.IE, session *gtpv2.Session, bearer *gtpv2...

FILE: examples/sgw/s5.go
  function handleCreateSessionResponse (line 13) | func handleCreateSessionResponse(s5cConn *gtpv2.Conn, pgwAddr net.Addr, ...
  function handleDeleteSessionResponse (line 132) | func handleDeleteSessionResponse(s5cConn *gtpv2.Conn, pgwAddr net.Addr, ...
  function handleDeleteBearerRequest (line 155) | func handleDeleteBearerRequest(s5cConn *gtpv2.Conn, pgwAddr net.Addr, ms...

FILE: gtp.go
  type Message (line 14) | type Message interface
  function Marshal (line 29) | func Marshal(m Message) ([]byte, error) {
  function Parse (line 39) | func Parse(b []byte) (Message, error) {

FILE: gtp_fuzz_test.go
  function FuzzParse (line 13) | func FuzzParse(f *testing.F) {

FILE: gtp_test.go
  function TestMessage (line 25) | func TestMessage(t *testing.T) {

FILE: gtpv0/constants.go
  constant CauseRequestIMSI (line 9) | CauseRequestIMSI              uint8 = 0
  constant CauseRequestIMEI (line 10) | CauseRequestIMEI              uint8 = 1
  constant CauseRequestIMSIandIMEI (line 11) | CauseRequestIMSIandIMEI       uint8 = 2
  constant CauseNoIdentityNeeded (line 12) | CauseNoIdentityNeeded         uint8 = 3
  constant CauseRequestAccepted (line 13) | CauseRequestAccepted          uint8 = 128
  constant CauseNonExistent (line 14) | CauseNonExistent              uint8 = 192
  constant CauseInvalidMessageFormat (line 15) | CauseInvalidMessageFormat     uint8 = 193
  constant CauseIMSINotKnown (line 16) | CauseIMSINotKnown             uint8 = 194
  constant CauseMSIsGPRSDetached (line 17) | CauseMSIsGPRSDetached         uint8 = 195
  constant CauseMSIsNotGPRSResponding (line 18) | CauseMSIsNotGPRSResponding    uint8 = 196
  constant CauseMSRefuses (line 19) | CauseMSRefuses                uint8 = 197
  constant CauseVersionNotSupported (line 20) | CauseVersionNotSupported      uint8 = 198
  constant CauseNoResourcesAvailable (line 21) | CauseNoResourcesAvailable     uint8 = 199
  constant CauseServiceNotSupported (line 22) | CauseServiceNotSupported      uint8 = 200
  constant CauseMandatoryIEIncorrect (line 23) | CauseMandatoryIEIncorrect     uint8 = 201
  constant CauseMandatoryIEMissing (line 24) | CauseMandatoryIEMissing       uint8 = 202
  constant CauseOptionalIEIncorrect (line 25) | CauseOptionalIEIncorrect      uint8 = 203
  constant CauseSystemFailure (line 26) | CauseSystemFailure            uint8 = 204
  constant CauseRoamingRestriction (line 27) | CauseRoamingRestriction       uint8 = 205
  constant CausePTMSISignatureMismatch (line 28) | CausePTMSISignatureMismatch   uint8 = 206
  constant CauseGPRSConnectionSuspended (line 29) | CauseGPRSConnectionSuspended  uint8 = 207
  constant CauseAuthenticationFailure (line 30) | CauseAuthenticationFailure    uint8 = 208
  constant CauseUserAuthenticationFailed (line 31) | CauseUserAuthenticationFailed uint8 = 209
  constant PDPTypeETSI (line 36) | PDPTypeETSI uint8 = iota | 0xf0
  constant PDPTypeIETF (line 37) | PDPTypeIETF
  constant SelectionModeMSorNetworkProvidedAPNSubscribedVerified (line 42) | SelectionModeMSorNetworkProvidedAPNSubscribedVerified uint8 = iota | 0xf0
  constant SelectionModeMSProvidedAPNSubscriptionNotVerified (line 43) | SelectionModeMSProvidedAPNSubscriptionNotVerified
  constant SelectionModeNetworkProvidedAPNSubscriptionNotVerified (line 44) | SelectionModeNetworkProvidedAPNSubscriptionNotVerified

FILE: gtpv0/ie/apn.go
  function NewAccessPointName (line 13) | func NewAccessPointName(apn string) *IE {
  method AccessPointName (line 27) | func (i *IE) AccessPointName() (string, error) {
  method MustAccessPointName (line 58) | func (i *IE) MustAccessPointName() string {

FILE: gtpv0/ie/cause.go
  function NewCause (line 10) | func NewCause(cause uint8) *IE {
  method Cause (line 15) | func (i *IE) Cause() (uint8, error) {
  method MustCause (line 28) | func (i *IE) MustCause() uint8 {

FILE: gtpv0/ie/charging-gateway-address.go
  function NewChargingGatewayAddress (line 13) | func NewChargingGatewayAddress(addr string) *IE {
  method ChargingGatewayAddress (line 26) | func (i *IE) ChargingGatewayAddress() (string, error) {
  method MustChargingGatewayAddress (line 39) | func (i *IE) MustChargingGatewayAddress() string {

FILE: gtpv0/ie/charging-id.go
  function NewChargingID (line 13) | func NewChargingID(id uint32) *IE {
  method ChargingID (line 18) | func (i *IE) ChargingID() (uint32, error) {
  method MustChargingID (line 31) | func (i *IE) MustChargingID() uint32 {

FILE: gtpv0/ie/end-user-address.go
  constant pdpTypeETSI (line 14) | pdpTypeETSI uint8 = iota | 0xf0
  constant pdpTypeIETF (line 15) | pdpTypeIETF
  function NewEndUserAddress (line 22) | func NewEndUserAddress(addr string) *IE {
  function NewEndUserAddressIPv4 (line 38) | func NewEndUserAddressIPv4(addr string) *IE {
  function NewEndUserAddressIPv6 (line 48) | func NewEndUserAddressIPv6(addr string) *IE {
  function newEUAddrV4 (line 57) | func newEUAddrV4(v4 []byte) *IE {
  function newEUAddrV6 (line 69) | func newEUAddrV6(v6 []byte) *IE {
  function NewEndUserAddressPPP (line 83) | func NewEndUserAddressPPP() *IE {
  method EndUserAddress (line 93) | func (i *IE) EndUserAddress() ([]byte, error) {
  method MustEndUserAddress (line 102) | func (i *IE) MustEndUserAddress() []byte {
  method PDPTypeOrganization (line 108) | func (i *IE) PDPTypeOrganization() (uint8, error) {
  method MustPDPTypeOrganization (line 121) | func (i *IE) MustPDPTypeOrganization() uint8 {
  method PDPTypeNumber (line 127) | func (i *IE) PDPTypeNumber() (uint8, error) {
  method MustPDPTypeNumber (line 140) | func (i *IE) MustPDPTypeNumber() uint8 {
  method IPAddress (line 146) | func (i *IE) IPAddress() (string, error) {
  method MustIPAddress (line 169) | func (i *IE) MustIPAddress() string {

FILE: gtpv0/ie/errors.go
  type InvalidTypeError (line 22) | type InvalidTypeError struct
    method Error (line 27) | func (e *InvalidTypeError) Error() string {

FILE: gtpv0/ie/flow-label.go
  function NewFlowLabelDataI (line 13) | func NewFlowLabelDataI(label uint16) *IE {
  method FlowLabelDataI (line 18) | func (i *IE) FlowLabelDataI() (uint16, error) {
  method MustFlowLabelDataI (line 31) | func (i *IE) MustFlowLabelDataI() uint16 {
  function NewFlowLabelSignalling (line 37) | func NewFlowLabelSignalling(label uint16) *IE {
  method FlowLabelSignalling (line 42) | func (i *IE) FlowLabelSignalling() (uint16, error) {
  method MustFlowLabelSignalling (line 55) | func (i *IE) MustFlowLabelSignalling() uint16 {
  function NewFlowLabelDataII (line 61) | func NewFlowLabelDataII(nsapi uint8, label uint16) *IE {
  method FlowLabelDataII (line 69) | func (i *IE) FlowLabelDataII() ([]byte, error) {
  method MustFlowLabelDataII (line 78) | func (i *IE) MustFlowLabelDataII() []byte {
  method NSAPI (line 84) | func (i *IE) NSAPI() (uint8, error) {
  method MustNSAPI (line 99) | func (i *IE) MustNSAPI() uint8 {
  method FlowLabelData (line 105) | func (i *IE) FlowLabelData() (uint16, error) {
  method MustFlowLabelData (line 127) | func (i *IE) MustFlowLabelData() uint16 {

FILE: gtpv0/ie/gsn-address.go
  function NewGSNAddress (line 13) | func NewGSNAddress(addr string) *IE {
  method GSNAddress (line 26) | func (i *IE) GSNAddress() (string, error) {
  method MustGSNAddress (line 39) | func (i *IE) MustGSNAddress() string {

FILE: gtpv0/ie/ie.go
  constant Cause (line 17) | Cause                        uint8 = 1
  constant IMSI (line 18) | IMSI                         uint8 = 2
  constant RouteingAreaIdentity (line 19) | RouteingAreaIdentity         uint8 = 3
  constant TemporaryLogicalLinkIdentity (line 20) | TemporaryLogicalLinkIdentity uint8 = 4
  constant PacketTMSI (line 21) | PacketTMSI                   uint8 = 5
  constant QualityOfServiceProfile (line 22) | QualityOfServiceProfile      uint8 = 6
  constant ReorderingRequired (line 23) | ReorderingRequired           uint8 = 8
  constant AuthenticationTriplet (line 24) | AuthenticationTriplet        uint8 = 9
  constant MAPCause (line 25) | MAPCause                     uint8 = 11
  constant PTMSISignature (line 26) | PTMSISignature               uint8 = 12
  constant MSValidated (line 27) | MSValidated                  uint8 = 13
  constant Recovery (line 28) | Recovery                     uint8 = 14
  constant SelectionMode (line 29) | SelectionMode                uint8 = 15
  constant FlowLabelDataI (line 30) | FlowLabelDataI               uint8 = 16
  constant FlowLabelSignalling (line 31) | FlowLabelSignalling          uint8 = 17
  constant FlowLabelDataII (line 32) | FlowLabelDataII              uint8 = 18
  constant MSNotReachableReason (line 33) | MSNotReachableReason         uint8 = 19
  constant ChargingID (line 34) | ChargingID                   uint8 = 127
  constant EndUserAddress (line 39) | EndUserAddress               uint8 = 128
  constant MMContext (line 40) | MMContext                    uint8 = 129
  constant PDPContext (line 41) | PDPContext                   uint8 = 130
  constant AccessPointName (line 42) | AccessPointName              uint8 = 131
  constant ProtocolConfigurationOptions (line 43) | ProtocolConfigurationOptions uint8 = 132
  constant GSNAddress (line 44) | GSNAddress                   uint8 = 133
  constant MSISDN (line 45) | MSISDN                       uint8 = 134
  constant ChargingGatewayAddress (line 46) | ChargingGatewayAddress       uint8 = 251
  constant PrivateExtension (line 47) | PrivateExtension             uint8 = 255
  type IE (line 51) | type IE struct
    method Marshal (line 65) | func (i *IE) Marshal() ([]byte, error) {
    method MarshalTo (line 74) | func (i *IE) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 99) | func (i *IE) UnmarshalBinary(b []byte) error {
    method IsTV (line 163) | func (i *IE) IsTV() bool {
    method MarshalLen (line 168) | func (i *IE) MarshalLen() int {
    method SetLength (line 179) | func (i *IE) SetLength() {
    method Name (line 189) | func (i *IE) Name() string {
    method String (line 197) | func (i *IE) String() string {
  function New (line 58) | func New(t uint8, p []byte) *IE {
  function Parse (line 90) | func Parse(b []byte) (*IE, error) {
  function parseTVFromBytes (line 111) | func parseTVFromBytes(i *IE, b []byte) error {
  function parseTLVFromBytes (line 125) | func parseTLVFromBytes(i *IE, b []byte) error {
  function ParseMultiIEs (line 210) | func ParseMultiIEs(b []byte) ([]*IE, error) {
  function newUint8ValIE (line 229) | func newUint8ValIE(t, v uint8) *IE {
  function newUint16ValIE (line 233) | func newUint16ValIE(t uint8, v uint16) *IE {
  function newUint32ValIE (line 239) | func newUint32ValIE(t uint8, v uint32) *IE {

FILE: gtpv0/ie/ie_deprecated.go
  method Serialize (line 12) | func (i *IE) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (i *IE) SerializeTo(b []byte) error {
  function Decode (line 28) | func Decode(b []byte) (*IE, error) {
  method DecodeFromBytes (line 36) | func (i *IE) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (i *IE) Len() int {

FILE: gtpv0/ie/ie_fuzz_test.go
  function FuzzParse (line 9) | func FuzzParse(f *testing.F) {

FILE: gtpv0/ie/ie_test.go
  function TestIE (line 15) | func TestIE(t *testing.T) {

FILE: gtpv0/ie/imsi.go
  function NewIMSI (line 14) | func NewIMSI(imsi string) *IE {
  method IMSI (line 23) | func (i *IE) IMSI() (string, error) {
  method MustIMSI (line 36) | func (i *IE) MustIMSI() string {

FILE: gtpv0/ie/ms-not-reachable-reason.go
  function NewMSNotReachableReason (line 10) | func NewMSNotReachableReason(reason uint8) *IE {
  method MSNotReachableReason (line 15) | func (i *IE) MSNotReachableReason() (uint8, error) {
  method MustMSNotReachableReason (line 28) | func (i *IE) MustMSNotReachableReason() uint8 {

FILE: gtpv0/ie/msisdn.go
  function NewMSISDN (line 14) | func NewMSISDN(msisdn string) *IE {
  method MSISDN (line 23) | func (i *IE) MSISDN() (string, error) {
  method MustMSISDN (line 36) | func (i *IE) MustMSISDN() string {

FILE: gtpv0/ie/p-tmsi-signature.go
  function NewPTMSISignature (line 14) | func NewPTMSISignature(sig uint32) *IE {
  method PTMSISignature (line 19) | func (i *IE) PTMSISignature() (uint32, error) {
  method MustPTMSISignature (line 32) | func (i *IE) MustPTMSISignature() uint32 {

FILE: gtpv0/ie/p-tmsi.go
  function NewPacketTMSI (line 13) | func NewPacketTMSI(ptmsi uint32) *IE {
  method PacketTMSI (line 18) | func (i *IE) PacketTMSI() (uint32, error) {
  method MustPacketTMSI (line 31) | func (i *IE) MustPacketTMSI() uint32 {

FILE: gtpv0/ie/private-extension.go
  function NewPrivateExtension (line 13) | func NewPrivateExtension(id uint16, val []byte) *IE {
  method PrivateExtension (line 21) | func (i *IE) PrivateExtension() ([]byte, error) {
  method MustPrivateExtension (line 30) | func (i *IE) MustPrivateExtension() []byte {
  method ExtensionIdentifier (line 36) | func (i *IE) ExtensionIdentifier() (uint16, error) {
  method MustExtensionIdentifier (line 49) | func (i *IE) MustExtensionIdentifier() uint16 {
  method ExtensionValue (line 55) | func (i *IE) ExtensionValue() ([]byte, error) {
  method MustExtensionValue (line 68) | func (i *IE) MustExtensionValue() []byte {

FILE: gtpv0/ie/qos-profile.go
  function NewQualityOfServiceProfile (line 10) | func NewQualityOfServiceProfile(delay, reliability, peak, precedence, me...
  method QualityOfServiceProfile (line 20) | func (i *IE) QualityOfServiceProfile() ([]byte, error) {
  method MustQualityOfServiceProfile (line 29) | func (i *IE) MustQualityOfServiceProfile() []byte {
  method QoSDelay (line 35) | func (i *IE) QoSDelay() (uint8, error) {
  method MustQoSDelay (line 48) | func (i *IE) MustQoSDelay() uint8 {
  method QoSReliability (line 54) | func (i *IE) QoSReliability() (uint8, error) {
  method MustQoSReliability (line 67) | func (i *IE) MustQoSReliability() uint8 {
  method QoSPeak (line 73) | func (i *IE) QoSPeak() (uint8, error) {
  method MustQoSPeak (line 86) | func (i *IE) MustQoSPeak() uint8 {
  method QoSPrecedence (line 92) | func (i *IE) QoSPrecedence() (uint8, error) {
  method MustQoSPrecedence (line 105) | func (i *IE) MustQoSPrecedence() uint8 {
  method QoSMean (line 111) | func (i *IE) QoSMean() (uint8, error) {
  method MustQoSMean (line 124) | func (i *IE) MustQoSMean() uint8 {

FILE: gtpv0/ie/rai.go
  function NewRouteingAreaIdentity (line 15) | func NewRouteingAreaIdentity(mcc, mnc string, lac uint16, rac uint8) *IE {
  method RouteingAreaIdentity (line 33) | func (i *IE) RouteingAreaIdentity() ([]byte, error) {
  method MustRouteingAreaIdentity (line 42) | func (i *IE) MustRouteingAreaIdentity() []byte {
  method MCC (line 48) | func (i *IE) MCC() (string, error) {
  method MustMCC (line 62) | func (i *IE) MustMCC() string {
  method MNC (line 68) | func (i *IE) MNC() (string, error) {
  method MustMNC (line 82) | func (i *IE) MustMNC() string {
  method LAC (line 88) | func (i *IE) LAC() (uint16, error) {
  method MustLAC (line 102) | func (i *IE) MustLAC() uint16 {
  method RAC (line 108) | func (i *IE) RAC() (uint8, error) {
  method MustRAC (line 122) | func (i *IE) MustRAC() uint8 {

FILE: gtpv0/ie/recovery.go
  function NewRecovery (line 10) | func NewRecovery(recovery uint8) *IE {
  method Recovery (line 15) | func (i *IE) Recovery() (uint8, error) {
  method MustRecovery (line 28) | func (i *IE) MustRecovery() uint8 {

FILE: gtpv0/ie/reordering-required.go
  function NewReorderingRequired (line 8) | func NewReorderingRequired(required bool) *IE {
  method ReorderingRequired (line 16) | func (i *IE) ReorderingRequired() bool {

FILE: gtpv0/ie/selection-mode.go
  function NewSelectionMode (line 12) | func NewSelectionMode(mode uint8) *IE {
  method SelectionMode (line 17) | func (i *IE) SelectionMode() (uint8, error) {
  method MustSelectionMode (line 30) | func (i *IE) MustSelectionMode() uint8 {

FILE: gtpv0/ie/tlli.go
  function NewTemporaryLogicalLinkIdentity (line 13) | func NewTemporaryLogicalLinkIdentity(tlli uint32) *IE {
  method TemporaryLogicalLinkIdentity (line 18) | func (i *IE) TemporaryLogicalLinkIdentity() (uint32, error) {
  method MustTemporaryLogicalLinkIdentity (line 31) | func (i *IE) MustTemporaryLogicalLinkIdentity() uint32 {

FILE: gtpv0/message/create-pdp-context-req.go
  type CreatePDPContextRequest (line 12) | type CreatePDPContextRequest struct
    method Marshal (line 82) | func (c *CreatePDPContextRequest) Marshal() ([]byte, error) {
    method MarshalTo (line 92) | func (c *CreatePDPContextRequest) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 202) | func (c *CreatePDPContextRequest) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 259) | func (c *CreatePDPContextRequest) MarshalLen() int {
    method SetLength (line 312) | func (c *CreatePDPContextRequest) SetLength() {
    method MessageTypeName (line 317) | func (c *CreatePDPContextRequest) MessageTypeName() string {
    method TID (line 322) | func (c *CreatePDPContextRequest) TID() string {
  function NewCreatePDPContextRequest (line 31) | func NewCreatePDPContextRequest(seq, label uint16, tid uint64, ies ...*i...
  function ParseCreatePDPContextRequest (line 193) | func ParseCreatePDPContextRequest(b []byte) (*CreatePDPContextRequest, e...

FILE: gtpv0/message/create-pdp-context-req_deprecated.go
  method Serialize (line 12) | func (c *CreatePDPContextRequest) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (c *CreatePDPContextRequest) SerializeTo(b []byte) error {
  function DecodeCreatePDPContextRequest (line 28) | func DecodeCreatePDPContextRequest(b []byte) (*CreatePDPContextRequest, ...
  method DecodeFromBytes (line 36) | func (c *CreatePDPContextRequest) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (c *CreatePDPContextRequest) Len() int {

FILE: gtpv0/message/create-pdp-context-req_test.go
  function TestCreatePDPContextRequest (line 16) | func TestCreatePDPContextRequest(t *testing.T) {

FILE: gtpv0/message/create-pdp-context-res.go
  type CreatePDPContextResponse (line 12) | type CreatePDPContextResponse struct
    method Marshal (line 81) | func (c *CreatePDPContextResponse) Marshal() ([]byte, error) {
    method MarshalTo (line 91) | func (c *CreatePDPContextResponse) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 201) | func (c *CreatePDPContextResponse) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 258) | func (c *CreatePDPContextResponse) MarshalLen() int {
    method SetLength (line 310) | func (c *CreatePDPContextResponse) SetLength() {
    method MessageTypeName (line 315) | func (c *CreatePDPContextResponse) MessageTypeName() string {
    method TID (line 320) | func (c *CreatePDPContextResponse) TID() string {
  function NewCreatePDPContextResponse (line 31) | func NewCreatePDPContextResponse(seq, label uint16, tid uint64, ies ...*...
  function ParseCreatePDPContextResponse (line 192) | func ParseCreatePDPContextResponse(b []byte) (*CreatePDPContextResponse,...

FILE: gtpv0/message/create-pdp-context-res_deprecated.go
  method Serialize (line 12) | func (c *CreatePDPContextResponse) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (c *CreatePDPContextResponse) SerializeTo(b []byte) error {
  function DecodeCreatePDPContextResponse (line 28) | func DecodeCreatePDPContextResponse(b []byte) (*CreatePDPContextResponse...
  method DecodeFromBytes (line 36) | func (c *CreatePDPContextResponse) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (c *CreatePDPContextResponse) Len() int {

FILE: gtpv0/message/create-pdp-context-res_test.go
  function TestCreatePDPContextResponse (line 16) | func TestCreatePDPContextResponse(t *testing.T) {

FILE: gtpv0/message/delete-pdp-context-req.go
  type DeletePDPContextRequest (line 14) | type DeletePDPContextRequest struct
    method Marshal (line 45) | func (d *DeletePDPContextRequest) Marshal() ([]byte, error) {
    method MarshalTo (line 55) | func (d *DeletePDPContextRequest) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 93) | func (d *DeletePDPContextRequest) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 124) | func (d *DeletePDPContextRequest) MarshalLen() int {
    method SetLength (line 141) | func (d *DeletePDPContextRequest) SetLength() {
    method MessageTypeName (line 146) | func (d *DeletePDPContextRequest) MessageTypeName() string {
    method TID (line 151) | func (d *DeletePDPContextRequest) TID() string {
  function NewDeletePDPContextRequest (line 21) | func NewDeletePDPContextRequest(seq, label uint16, tid uint64, ies ...*i...
  function ParseDeletePDPContextRequest (line 84) | func ParseDeletePDPContextRequest(b []byte) (*DeletePDPContextRequest, e...

FILE: gtpv0/message/delete-pdp-context-req_deprecated.go
  method Serialize (line 12) | func (d *DeletePDPContextRequest) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (d *DeletePDPContextRequest) SerializeTo(b []byte) error {
  function DecodeDeletePDPContextRequest (line 28) | func DecodeDeletePDPContextRequest(b []byte) (*DeletePDPContextRequest, ...
  method DecodeFromBytes (line 36) | func (d *DeletePDPContextRequest) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (d *DeletePDPContextRequest) Len() int {

FILE: gtpv0/message/delete-pdp-context-req_test.go
  function TestDeletePDPContextRequest (line 14) | func TestDeletePDPContextRequest(t *testing.T) {

FILE: gtpv0/message/delete-pdp-context-res.go
  type DeletePDPContextResponse (line 12) | type DeletePDPContextResponse struct
    method Marshal (line 46) | func (d *DeletePDPContextResponse) Marshal() ([]byte, error) {
    method MarshalTo (line 56) | func (d *DeletePDPContextResponse) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 99) | func (d *DeletePDPContextResponse) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 132) | func (d *DeletePDPContextResponse) MarshalLen() int {
    method SetLength (line 152) | func (d *DeletePDPContextResponse) SetLength() {
    method MessageTypeName (line 157) | func (d *DeletePDPContextResponse) MessageTypeName() string {
    method TID (line 162) | func (d *DeletePDPContextResponse) TID() string {
  function NewDeletePDPContextResponse (line 20) | func NewDeletePDPContextResponse(seq, label uint16, tid uint64, ies ...*...
  function ParseDeletePDPContextResponse (line 90) | func ParseDeletePDPContextResponse(b []byte) (*DeletePDPContextResponse,...

FILE: gtpv0/message/delete-pdp-context-res_deprecated.go
  method Serialize (line 12) | func (d *DeletePDPContextResponse) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (d *DeletePDPContextResponse) SerializeTo(b []byte) error {
  function DecodeDeletePDPContextResponse (line 28) | func DecodeDeletePDPContextResponse(b []byte) (*DeletePDPContextResponse...
  method DecodeFromBytes (line 36) | func (d *DeletePDPContextResponse) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (d *DeletePDPContextResponse) Len() int {

FILE: gtpv0/message/delete-pdp-context-res_test.go
  function TestDeletePDPContextResponse (line 16) | func TestDeletePDPContextResponse(t *testing.T) {

FILE: gtpv0/message/echo-req.go
  type EchoRequest (line 14) | type EchoRequest struct
    method Marshal (line 45) | func (e *EchoRequest) Marshal() ([]byte, error) {
    method MarshalTo (line 55) | func (e *EchoRequest) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 93) | func (e *EchoRequest) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 124) | func (e *EchoRequest) MarshalLen() int {
    method SetLength (line 142) | func (e *EchoRequest) SetLength() {
    method MessageTypeName (line 147) | func (e *EchoRequest) MessageTypeName() string {
    method TID (line 152) | func (e *EchoRequest) TID() string {
  function NewEchoRequest (line 21) | func NewEchoRequest(seq, label uint16, tid uint64, ies ...*ie.IE) *EchoR...
  function ParseEchoRequest (line 84) | func ParseEchoRequest(b []byte) (*EchoRequest, error) {

FILE: gtpv0/message/echo-req_deprecated.go
  method Serialize (line 12) | func (e *EchoRequest) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (e *EchoRequest) SerializeTo(b []byte) error {
  function DecodeEchoRequest (line 28) | func DecodeEchoRequest(b []byte) (*EchoRequest, error) {
  method DecodeFromBytes (line 36) | func (e *EchoRequest) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (e *EchoRequest) Len() int {

FILE: gtpv0/message/echo-req_test.go
  function TestEchoRequest (line 14) | func TestEchoRequest(t *testing.T) {

FILE: gtpv0/message/echo-res.go
  type EchoResponse (line 12) | type EchoResponse struct
    method Marshal (line 46) | func (e *EchoResponse) Marshal() ([]byte, error) {
    method MarshalTo (line 56) | func (e *EchoResponse) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 100) | func (e *EchoResponse) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 133) | func (e *EchoResponse) MarshalLen() int {
    method SetLength (line 154) | func (e *EchoResponse) SetLength() {
    method MessageTypeName (line 159) | func (e *EchoResponse) MessageTypeName() string {
    method TID (line 164) | func (e *EchoResponse) TID() string {
  function NewEchoResponse (line 20) | func NewEchoResponse(seq, label uint16, tid uint64, ies ...*ie.IE) *Echo...
  function ParseEchoResponse (line 91) | func ParseEchoResponse(b []byte) (*EchoResponse, error) {

FILE: gtpv0/message/echo-res_deprecated.go
  method Serialize (line 12) | func (e *EchoResponse) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (e *EchoResponse) SerializeTo(b []byte) error {
  function DecodeEchoResponse (line 28) | func DecodeEchoResponse(b []byte) (*EchoResponse, error) {
  method DecodeFromBytes (line 36) | func (e *EchoResponse) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (e *EchoResponse) Len() int {

FILE: gtpv0/message/echo-res_test.go
  function TestEchoResponse (line 15) | func TestEchoResponse(t *testing.T) {

FILE: gtpv0/message/generic.go
  type Generic (line 14) | type Generic struct
    method Marshal (line 37) | func (g *Generic) Marshal() ([]byte, error) {
    method MarshalTo (line 47) | func (g *Generic) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 78) | func (g *Generic) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 96) | func (g *Generic) MarshalLen() int {
    method SetLength (line 109) | func (g *Generic) SetLength() {
    method MessageTypeName (line 114) | func (g *Generic) MessageTypeName() string {
    method TID (line 119) | func (g *Generic) TID() string {
    method AddIE (line 124) | func (g *Generic) AddIE(ie ...*ie.IE) {
  function NewGeneric (line 20) | func NewGeneric(msgType uint8, seq, label uint16, tid uint64, ie ...*ie....
  function ParseGeneric (line 69) | func ParseGeneric(b []byte) (*Generic, error) {

FILE: gtpv0/message/generic_deprecated.go
  method Serialize (line 12) | func (g *Generic) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (g *Generic) SerializeTo(b []byte) error {
  function DecodeGeneric (line 28) | func DecodeGeneric(b []byte) (*Generic, error) {
  method DecodeFromBytes (line 36) | func (g *Generic) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (g *Generic) Len() int {

FILE: gtpv0/message/generic_test.go
  function TestGeneric (line 15) | func TestGeneric(t *testing.T) {

FILE: gtpv0/message/header.go
  type Header (line 15) | type Header struct
    method Marshal (line 50) | func (h *Header) Marshal() ([]byte, error) {
    method MarshalTo (line 59) | func (h *Header) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 86) | func (h *Header) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 108) | func (h *Header) MarshalLen() int {
    method SetLength (line 113) | func (h *Header) SetLength() {
    method String (line 118) | func (h *Header) String() string {
    method tid (line 132) | func (h *Header) tid() string {
    method Version (line 140) | func (h *Header) Version() int {
    method MessageType (line 145) | func (h *Header) MessageType() uint8 {
  function NewHeader (line 27) | func NewHeader(flags, mtype uint8, seq, label uint16, tid uint64, payloa...
  function HeaderFlags (line 43) | func HeaderFlags(v, p, s int) uint8 {
  function ParseHeader (line 77) | func ParseHeader(b []byte) (*Header, error) {

FILE: gtpv0/message/header_deprecated.go
  method Serialize (line 12) | func (h *Header) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (h *Header) SerializeTo(b []byte) error {
  function DecodeHeader (line 28) | func DecodeHeader(b []byte) (*Header, error) {
  method DecodeFromBytes (line 36) | func (h *Header) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (h *Header) Len() int {

FILE: gtpv0/message/header_test.go
  function TestHeader (line 14) | func TestHeader(t *testing.T) {

FILE: gtpv0/message/message.go
  constant _ (line 20) | _ uint8 = iota
  constant MsgTypeEchoRequest (line 21) | MsgTypeEchoRequest
  constant MsgTypeEchoResponse (line 22) | MsgTypeEchoResponse
  constant MsgTypeVersionNotSupported (line 23) | MsgTypeVersionNotSupported
  constant MsgTypeNodeAliveRequest (line 24) | MsgTypeNodeAliveRequest
  constant MsgTypeNodeAliveResponse (line 25) | MsgTypeNodeAliveResponse
  constant MsgTypeRedirectionRequest (line 26) | MsgTypeRedirectionRequest
  constant MsgTypeRedirectionResponse (line 27) | MsgTypeRedirectionResponse
  constant _ (line 28) | _
  constant _ (line 29) | _
  constant _ (line 30) | _
  constant _ (line 31) | _
  constant _ (line 32) | _
  constant _ (line 33) | _
  constant _ (line 34) | _
  constant _ (line 35) | _
  constant MsgTypeCreatePDPContextRequest (line 36) | MsgTypeCreatePDPContextRequest
  constant MsgTypeCreatePDPContextResponse (line 37) | MsgTypeCreatePDPContextResponse
  constant MsgTypeUpdatePDPContextRequest (line 38) | MsgTypeUpdatePDPContextRequest
  constant MsgTypeUpdatePDPContextResponse (line 39) | MsgTypeUpdatePDPContextResponse
  constant MsgTypeDeletePDPContextRequest (line 40) | MsgTypeDeletePDPContextRequest
  constant MsgTypeDeletePDPContextResponse (line 41) | MsgTypeDeletePDPContextResponse
  constant MsgTypeCreateAAPDPContextRequest (line 42) | MsgTypeCreateAAPDPContextRequest
  constant MsgTypeCreateAAPDPContextResponse (line 43) | MsgTypeCreateAAPDPContextResponse
  constant MsgTypeDeleteAAPDPContextRequest (line 44) | MsgTypeDeleteAAPDPContextRequest
  constant MsgTypeDeleteAAPDPContextResponse (line 45) | MsgTypeDeleteAAPDPContextResponse
  constant MsgTypeErrorIndication (line 46) | MsgTypeErrorIndication
  constant MsgTypePDUNotificationRequest (line 47) | MsgTypePDUNotificationRequest
  constant MsgTypePDUNotificationResponse (line 48) | MsgTypePDUNotificationResponse
  constant MsgTypePDUNotificationRejectRequest (line 49) | MsgTypePDUNotificationRejectRequest
  constant MsgTypePDUNotificationRejectResponse (line 50) | MsgTypePDUNotificationRejectResponse
  constant _ (line 51) | _
  constant MsgTypeSendRouteingInformationforGPRSRequest (line 52) | MsgTypeSendRouteingInformationforGPRSRequest
  constant MsgTypeSendRouteingInformationforGPRSResponse (line 53) | MsgTypeSendRouteingInformationforGPRSResponse
  constant MsgTypeFailureReportRequest (line 54) | MsgTypeFailureReportRequest
  constant MsgTypeFailureReportResponse (line 55) | MsgTypeFailureReportResponse
  constant MsgTypeNoteMSGPRSPresentRequest (line 56) | MsgTypeNoteMSGPRSPresentRequest
  constant MsgTypeNoteMSGPRSPresentResponse (line 57) | MsgTypeNoteMSGPRSPresentResponse
  constant _ (line 58) | _
  constant _ (line 59) | _
  constant _ (line 60) | _
  constant _ (line 61) | _
  constant _ (line 62) | _
  constant _ (line 63) | _
  constant _ (line 64) | _
  constant _ (line 65) | _
  constant _ (line 66) | _
  constant _ (line 67) | _
  constant MsgTypeIdentificationRequest (line 68) | MsgTypeIdentificationRequest
  constant MsgTypeIdentificationResponse (line 69) | MsgTypeIdentificationResponse
  constant MsgTypeSGSNContextRequest (line 70) | MsgTypeSGSNContextRequest
  constant MsgTypeSGSNContextResponse (line 71) | MsgTypeSGSNContextResponse
  constant MsgTypeSGSNContextAcknowledge (line 72) | MsgTypeSGSNContextAcknowledge
  constant MsgTypeDataRecordTransferRequest (line 73) | MsgTypeDataRecordTransferRequest  = 240
  constant MsgTypeDataRecordTransferResponse (line 74) | MsgTypeDataRecordTransferResponse = 241
  constant MsgTypeTPDU (line 75) | MsgTypeTPDU                       = 255
  type Message (line 79) | type Message interface
  function Marshal (line 96) | func Marshal(g Message) ([]byte, error) {
  function Parse (line 106) | func Parse(b []byte) (Message, error) {
  function Decapsulate (line 201) | func Decapsulate(b []byte) ([]byte, error) {
  function Prettify (line 217) | func Prettify(m Message) string {
  type field (line 231) | type field struct
  function prettifyFields (line 236) | func prettifyFields(fields []*field) []string {
  function prettifyIE (line 264) | func prettifyIE(name string, i *ie.IE) string {

FILE: gtpv0/message/message_deprecated.go
  function Serialize (line 12) | func Serialize(m Message) ([]byte, error) {
  function Decode (line 20) | func Decode(b []byte) (Message, error) {

FILE: gtpv0/message/message_fuzz_test.go
  function FuzzParse (line 9) | func FuzzParse(f *testing.F) {
  function FuzzHeaderParse (line 17) | func FuzzHeaderParse(f *testing.F) {

FILE: gtpv0/message/t-pdu.go
  type TPDU (line 8) | type TPDU struct
    method Marshal (line 24) | func (t *TPDU) Marshal() ([]byte, error) {
    method MarshalTo (line 34) | func (t *TPDU) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 54) | func (t *TPDU) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 66) | func (t *TPDU) MarshalLen() int {
    method SetLength (line 71) | func (t *TPDU) SetLength() {
    method MessageTypeName (line 76) | func (t *TPDU) MessageTypeName() string {
    method TID (line 81) | func (t *TPDU) TID() string {
  function NewTPDU (line 13) | func NewTPDU(seq, label uint16, tid uint64, payload []byte) *TPDU {
  function ParseTPDU (line 45) | func ParseTPDU(b []byte) (*TPDU, error) {

FILE: gtpv0/message/t-pdu_deprecated.go
  method Serialize (line 12) | func (t *TPDU) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (t *TPDU) SerializeTo(b []byte) error {
  function DecodeTPDU (line 28) | func DecodeTPDU(b []byte) (*TPDU, error) {
  method DecodeFromBytes (line 36) | func (t *TPDU) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (t *TPDU) Len() int {

FILE: gtpv0/message/t-pdu_test.go
  function TestTPDU (line 14) | func TestTPDU(t *testing.T) {

FILE: gtpv0/message/update-pdp-context-req.go
  type UpdatePDPContextRequest (line 12) | type UpdatePDPContextRequest struct
    method Marshal (line 69) | func (u *UpdatePDPContextRequest) Marshal() ([]byte, error) {
    method MarshalTo (line 79) | func (u *UpdatePDPContextRequest) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 165) | func (u *UpdatePDPContextRequest) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 214) | func (u *UpdatePDPContextRequest) MarshalLen() int {
    method SetLength (line 255) | func (u *UpdatePDPContextRequest) SetLength() {
    method MessageTypeName (line 260) | func (u *UpdatePDPContextRequest) MessageTypeName() string {
    method TID (line 265) | func (u *UpdatePDPContextRequest) TID() string {
  function NewUpdatePDPContextRequest (line 27) | func NewUpdatePDPContextRequest(seq, label uint16, tid uint64, ies ...*i...
  function ParseUpdatePDPContextRequest (line 156) | func ParseUpdatePDPContextRequest(b []byte) (*UpdatePDPContextRequest, e...

FILE: gtpv0/message/update-pdp-context-req_deprecated.go
  method Serialize (line 12) | func (u *UpdatePDPContextRequest) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (u *UpdatePDPContextRequest) SerializeTo(b []byte) error {
  function DecodeUpdatePDPContextRequest (line 28) | func DecodeUpdatePDPContextRequest(b []byte) (*UpdatePDPContextRequest, ...
  method DecodeFromBytes (line 36) | func (u *UpdatePDPContextRequest) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (u *UpdatePDPContextRequest) Len() int {

FILE: gtpv0/message/update-pdp-context-req_test.go
  function TestUpdatePDPContextRequest (line 15) | func TestUpdatePDPContextRequest(t *testing.T) {

FILE: gtpv0/message/update-pdp-context-res.go
  type UpdatePDPContextResponse (line 12) | type UpdatePDPContextResponse struct
    method Marshal (line 75) | func (u *UpdatePDPContextResponse) Marshal() ([]byte, error) {
    method MarshalTo (line 85) | func (u *UpdatePDPContextResponse) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 183) | func (u *UpdatePDPContextResponse) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 236) | func (u *UpdatePDPContextResponse) MarshalLen() int {
    method SetLength (line 283) | func (u *UpdatePDPContextResponse) SetLength() {
    method MessageTypeName (line 288) | func (u *UpdatePDPContextResponse) MessageTypeName() string {
    method TID (line 293) | func (u *UpdatePDPContextResponse) TID() string {
  function NewUpdatePDPContextResponse (line 29) | func NewUpdatePDPContextResponse(seq, label uint16, tid uint64, ies ...*...
  function ParseUpdatePDPContextResponse (line 174) | func ParseUpdatePDPContextResponse(b []byte) (*UpdatePDPContextResponse,...

FILE: gtpv0/message/update-pdp-context-res_deprecated.go
  method Serialize (line 12) | func (u *UpdatePDPContextResponse) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (u *UpdatePDPContextResponse) SerializeTo(b []byte) error {
  function DecodeUpdatePDPContextResponse (line 28) | func DecodeUpdatePDPContextResponse(b []byte) (*UpdatePDPContextResponse...
  method DecodeFromBytes (line 36) | func (u *UpdatePDPContextResponse) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (u *UpdatePDPContextResponse) Len() int {

FILE: gtpv0/message/update-pdp-context-res_test.go
  function TestUpdatePDPContextResponse (line 16) | func TestUpdatePDPContextResponse(t *testing.T) {

FILE: gtpv0/testutils/testutils.go
  type Serializable (line 16) | type Serializable interface
  type TestCase (line 22) | type TestCase struct
  type ParseFunc (line 29) | type ParseFunc
  function Run (line 40) | func Run(t *testing.T, cases []TestCase, parse ParseFunc) {

FILE: gtpv1/conn.go
  type Conn (line 14) | type Conn interface

FILE: gtpv1/constants.go
  constant GTPCPort (line 9) | GTPCPort = ":2123"
  constant GTPUPort (line 10) | GTPUPort = ":2152"
  constant ReqCauseRequestIMSI (line 15) | ReqCauseRequestIMSI uint8 = iota
  constant ReqCauseRequestIMEI (line 16) | ReqCauseRequestIMEI
  constant ReqCauseRequestIMSIAndIMEI (line 17) | ReqCauseRequestIMSIAndIMEI
  constant ReqCauseNoIdentityNeeded (line 18) | ReqCauseNoIdentityNeeded
  constant ReqCauseMSRefuses (line 19) | ReqCauseMSRefuses
  constant ReqCauseMSIsNotGPRSResponding (line 20) | ReqCauseMSIsNotGPRSResponding
  constant ReqCauseReactivationRequested (line 21) | ReqCauseReactivationRequested
  constant ReqCausePDPAddressInactivityTimerExpires (line 22) | ReqCausePDPAddressInactivityTimerExpires
  constant ReqCauseNetworkFailure (line 23) | ReqCauseNetworkFailure
  constant ReqCauseQoSParameterMismatch (line 24) | ReqCauseQoSParameterMismatch
  constant ResCauseRequestAccepted (line 30) | ResCauseRequestAccepted uint8 = iota + 128
  constant ResCauseNewPDPTypeDueToNetworkPreference (line 31) | ResCauseNewPDPTypeDueToNetworkPreference
  constant ResCauseNewPDPTypeDueToSingleAddressBearerOnly (line 32) | ResCauseNewPDPTypeDueToSingleAddressBearerOnly
  constant ResCauseNonExistent (line 38) | ResCauseNonExistent uint8 = iota + 192
  constant ResCauseInvalidMessageFormat (line 39) | ResCauseInvalidMessageFormat
  constant ResCauseIMSIIMEINotKnown (line 40) | ResCauseIMSIIMEINotKnown
  constant ResCauseMSIsGPRSDetached (line 41) | ResCauseMSIsGPRSDetached
  constant ResCauseMSIsNotGPRSResponding (line 42) | ResCauseMSIsNotGPRSResponding
  constant ResCauseMSRefuses (line 43) | ResCauseMSRefuses
  constant ResCauseVersionNotSupported (line 44) | ResCauseVersionNotSupported
  constant ResCauseNoResourcesAvailable (line 45) | ResCauseNoResourcesAvailable
  constant ResCauseServiceNotSupported (line 46) | ResCauseServiceNotSupported
  constant ResCauseMandatoryIEIncorrect (line 47) | ResCauseMandatoryIEIncorrect
  constant ResCauseMandatoryIEMissing (line 48) | ResCauseMandatoryIEMissing
  constant ResCauseOptionalIEIncorrect (line 49) | ResCauseOptionalIEIncorrect
  constant ResCauseSystemFailure (line 50) | ResCauseSystemFailure
  constant ResCauseRoamingRestriction (line 51) | ResCauseRoamingRestriction
  constant ResCausePTMSISignatureMismatch (line 52) | ResCausePTMSISignatureMismatch
  constant ResCauseGPRSConnectionSuspended (line 53) | ResCauseGPRSConnectionSuspended
  constant ResCauseAuthenticationFailure (line 54) | ResCauseAuthenticationFailure
  constant ResCauseUserAuthenticationFailed (line 55) | ResCauseUserAuthenticationFailed
  constant ResCauseContextNotFound (line 56) | ResCauseContextNotFound
  constant ResCauseAllDynamicPDPAddressesAreOccupied (line 57) | ResCauseAllDynamicPDPAddressesAreOccupied
  constant ResCauseNoMemoryIsAvailable (line 58) | ResCauseNoMemoryIsAvailable
  constant ResCauseRelocationFailure (line 59) | ResCauseRelocationFailure
  constant ResCauseUnknownMandatoryExtensionHeader (line 60) | ResCauseUnknownMandatoryExtensionHeader
  constant ResCauseSemanticErrorInTheTFTOperation (line 61) | ResCauseSemanticErrorInTheTFTOperation
  constant ResCauseSyntacticErrorInTheTFTOperation (line 62) | ResCauseSyntacticErrorInTheTFTOperation
  constant ResCauseSemanticErrorsInPacketFilter (line 63) | ResCauseSemanticErrorsInPacketFilter
  constant ResCauseSyntacticErrorsInPacketFilter (line 64) | ResCauseSyntacticErrorsInPacketFilter
  constant ResCauseMissingOrUnknownAPN (line 65) | ResCauseMissingOrUnknownAPN
  constant ResCauseUnknownPDPAddressOrPDPType (line 66) | ResCauseUnknownPDPAddressOrPDPType
  constant ResCausePDPContextWithoutTFTAlreadyActivated (line 67) | ResCausePDPContextWithoutTFTAlreadyActivated
  constant ResCauseAPNAccessDeniedNoSubscription (line 68) | ResCauseAPNAccessDeniedNoSubscription
  constant ResCauseAPNRestrictionTypeIncompatibilityWithCurrentlyActivePDPContexts (line 69) | ResCauseAPNRestrictionTypeIncompatibilityWithCurrentlyActivePDPContexts
  constant ResCauseMSMBMSCapabilitiesInsufficient (line 70) | ResCauseMSMBMSCapabilitiesInsufficient
  constant ResCauseInvalidCorrelationID (line 71) | ResCauseInvalidCorrelationID
  constant ResCauseMBMSBearerContextSuperseded (line 72) | ResCauseMBMSBearerContextSuperseded
  constant ResCauseBearerControlModeViolation (line 73) | ResCauseBearerControlModeViolation
  constant ResCauseCollisionWithNetworkInitiatedRequest (line 74) | ResCauseCollisionWithNetworkInitiatedRequest
  constant ResCauseAPNCongestion (line 75) | ResCauseAPNCongestion
  constant ResCauseBearerHandlingNotSupported (line 76) | ResCauseBearerHandlingNotSupported
  constant ResCauseTargetAccessRestrictedForTheSubscriber (line 77) | ResCauseTargetAccessRestrictedForTheSubscriber
  constant ResCauseUEIsTemporarilyNotReachableDueToPowerSaving (line 78) | ResCauseUEIsTemporarilyNotReachableDueToPowerSaving
  constant ResCauseRelocationFailureDueToNASMessageRedirection (line 79) | ResCauseRelocationFailureDueToNASMessageRedirection
  constant SelectionModeMSorNetworkProvidedAPNSubscribedVerified (line 85) | SelectionModeMSorNetworkProvidedAPNSubscribedVerified uint8 = iota | 0xf0
  constant SelectionModeMSProvidedAPNSubscriptionNotVerified (line 86) | SelectionModeMSProvidedAPNSubscriptionNotVerified
  constant SelectionModeNetworkProvidedAPNSubscriptionNotVerified (line 87) | SelectionModeNetworkProvidedAPNSubscriptionNotVerified
  constant PDPTypeETSI (line 92) | PDPTypeETSI uint8 = iota | 0xf0
  constant PDPTypeIETF (line 93) | PDPTypeIETF
  constant ProtoIDLCP (line 99) | ProtoIDLCP  uint16 = 0xc021
  constant ProtoIDPAP (line 100) | ProtoIDPAP  uint16 = 0xc023
  constant ProtoIDCHAP (line 101) | ProtoIDCHAP uint16 = 0xc223
  constant ProtoIDIPCP (line 102) | ProtoIDIPCP uint16 = 0x8021
  constant _ (line 107) | _ uint16 = iota
  constant ContIDPCSCFIPv6AddressRequest (line 108) | ContIDPCSCFIPv6AddressRequest
  constant ContIDIMCNSubsystemSignalingFlag (line 109) | ContIDIMCNSubsystemSignalingFlag
  constant ContIDDNSServerIPv6AddressRequest (line 110) | ContIDDNSServerIPv6AddressRequest
  constant ContIDNotSupported (line 111) | ContIDNotSupported
  constant ContIDMSSupportofNetworkRequestedBearerControlIndicator (line 112) | ContIDMSSupportofNetworkRequestedBearerControlIndicator
  constant _ (line 113) | _
  constant ContIDDSMIPv6HomeAgentAddressRequest (line 114) | ContIDDSMIPv6HomeAgentAddressRequest
  constant ContIDDSMIPv6HomeNetworkPrefixRequest (line 115) | ContIDDSMIPv6HomeNetworkPrefixRequest
  constant ContIDDSMIPv6IPv4HomeAgentAddressRequest (line 116) | ContIDDSMIPv6IPv4HomeAgentAddressRequest
  constant ContIDIPaddressAllocationViaNASSignalling (line 117) | ContIDIPaddressAllocationViaNASSignalling
  constant ContIDIPv4addressAllocationViaDHCPv4 (line 118) | ContIDIPv4addressAllocationViaDHCPv4
  constant ContIDPCSCFIPv4AddressRequest (line 119) | ContIDPCSCFIPv4AddressRequest
  constant ContIDDNSServerIPv4AddressRequest (line 120) | ContIDDNSServerIPv4AddressRequest
  constant ContIDMSISDNRequest (line 121) | ContIDMSISDNRequest
  constant ContIDIFOMSupportRequest (line 122) | ContIDIFOMSupportRequest
  constant ContIDIPv4LinkMTURequest (line 123) | ContIDIPv4LinkMTURequest
  constant ContIDMSSupportOfLocalAddressInTFTIndicator (line 124) | ContIDMSSupportOfLocalAddressInTFTIndicator
  constant ContIDPCSCFReselectionSupport (line 125) | ContIDPCSCFReselectionSupport
  constant ContIDNBIFOMRequestIndicator (line 126) | ContIDNBIFOMRequestIndicator
  constant ContIDNBIFOMMode (line 127) | ContIDNBIFOMMode
  constant ContIDNonIPLinkMTURequest (line 128) | ContIDNonIPLinkMTURequest
  constant ContIDAPNRateControlSupportIndicator (line 129) | ContIDAPNRateControlSupportIndicator
  constant ContID3GPPPSDataOffUEStatus (line 130) | ContID3GPPPSDataOffUEStatus
  constant ContIDReliableDataServiceRequestIndicator (line 131) | ContIDReliableDataServiceRequestIndicator
  constant ContIDAdditionalAPNRateControlForExceptionDataSupportIndicator (line 132) | ContIDAdditionalAPNRateControlForExceptionDataSupportIndicator
  constant ContIDPDUSessionID (line 133) | ContIDPDUSessionID
  constant _ (line 134) | _
  constant _ (line 135) | _
  constant _ (line 136) | _
  constant _ (line 137) | _
  constant _ (line 138) | _
  constant ContIDEthernetFramePayloadMTURequest (line 139) | ContIDEthernetFramePayloadMTURequest
  constant ContIDUnstructuredLinkMTURequest (line 140) | ContIDUnstructuredLinkMTURequest
  constant ContID5GSMCauseValue (line 141) | ContID5GSMCauseValue
  constant ConfigProtocolPPPWithIP (line 146) | ConfigProtocolPPPWithIP uint8 = 0
  constant _ (line 151) | _ uint8 = iota
  constant RatTypeUTRAN (line 152) | RatTypeUTRAN
  constant RatTypeGERAN (line 153) | RatTypeGERAN
  constant RatTypeWLAN (line 154) | RatTypeWLAN
  constant RatTypeGAN (line 155) | RatTypeGAN
  constant RatTypeHSPAEvolution (line 156) | RatTypeHSPAEvolution
  constant RatTypeEUTRAN (line 157) | RatTypeEUTRAN
  constant LocTypeCGI (line 162) | LocTypeCGI uint8 = iota
  constant LocTypeSAI (line 163) | LocTypeSAI
  constant LocTypeRAI (line 164) | LocTypeRAI
  constant APNRestrictionNoExistingContextsorRestriction (line 169) | APNRestrictionNoExistingContextsorRestriction uint8 = iota
  constant APNRestrictionPublic1 (line 170) | APNRestrictionPublic1
  constant APNRestrictionPublic2 (line 171) | APNRestrictionPublic2
  constant APNRestrictionPrivate1 (line 172) | APNRestrictionPrivate1
  constant APNRestrictionPrivate2 (line 173) | APNRestrictionPrivate2
  constant _ (line 178) | _ uint8 = iota
  constant MAPCauseUnknownSubscriber (line 179) | MAPCauseUnknownSubscriber
  constant MAPCauseUnknownBaseStation (line 180) | MAPCauseUnknownBaseStation
  constant MAPCauseUnknownMSC (line 181) | MAPCauseUnknownMSC
  constant MAPCauseSecureTransportError (line 182) | MAPCauseSecureTransportError
  constant MAPCauseUnidentifiedSubscriber (line 183) | MAPCauseUnidentifiedSubscriber
  constant MAPCauseAbsentSubscriberSM (line 184) | MAPCauseAbsentSubscriberSM
  constant MAPCauseUnknownEquipment (line 185) | MAPCauseUnknownEquipment
  constant MAPCauseRoamingNotAllowed (line 186) | MAPCauseRoamingNotAllowed
  constant MAPCauseIllegalSubscriber (line 187) | MAPCauseIllegalSubscriber
  constant MAPCauseBearerServiceNotProvisioned (line 188) | MAPCauseBearerServiceNotProvisioned
  constant MAPCauseTeleserviceNotProvisioned (line 189) | MAPCauseTeleserviceNotProvisioned
  constant MAPCauseIllegalEquipment (line 190) | MAPCauseIllegalEquipment
  constant MAPCauseCallBarred (line 191) | MAPCauseCallBarred
  constant MAPCauseForwardingViolation (line 192) | MAPCauseForwardingViolation
  constant MAPCauseCUGReject (line 193) | MAPCauseCUGReject
  constant MAPCauseIllegalSSOperation (line 194) | MAPCauseIllegalSSOperation
  constant MAPCauseSSErrorStatus (line 195) | MAPCauseSSErrorStatus
  constant MAPCauseSSNotAvailable (line 196) | MAPCauseSSNotAvailable
  constant MAPCauseSSSubscriptionViolatio (line 197) | MAPCauseSSSubscriptionViolatio
  constant MAPCauseSSIncompatibility (line 198) | MAPCauseSSIncompatibility
  constant MAPCauseFacilityNotSupported (line 199) | MAPCauseFacilityNotSupported
  constant MAPCauseOngoingGroupCall (line 200) | MAPCauseOngoingGroupCall
  constant MAPCauseInvalidTargetBaseStation (line 201) | MAPCauseInvalidTargetBaseStation
  constant MAPCauseNoRadioResourceAvailable (line 202) | MAPCauseNoRadioResourceAvailable
  constant MAPCauseNoHandoverNumberAvailable (line 203) | MAPCauseNoHandoverNumberAvailable
  constant MAPCauseSubsequentHandoverFailure (line 204) | MAPCauseSubsequentHandoverFailure
  constant MAPCauseAbsentSubscriber (line 205) | MAPCauseAbsentSubscriber
  constant MAPCauseIncompatibleTerminal (line 206) | MAPCauseIncompatibleTerminal
  constant MAPCauseShortTermDenial (line 207) | MAPCauseShortTermDenial
  constant MAPCauseLongTermDenial (line 208) | MAPCauseLongTermDenial
  constant MAPCauseSubscriberBusyForMTSMS (line 209) | MAPCauseSubscriberBusyForMTSMS
  constant MAPCauseSMDeliveryFailure (line 210) | MAPCauseSMDeliveryFailure
  constant MAPCauseMessageWaitingListFull (line 211) | MAPCauseMessageWaitingListFull
  constant MAPCauseSystemFailure (line 212) | MAPCauseSystemFailure
  constant MAPCauseDataMissing (line 213) | MAPCauseDataMissing
  constant MAPCauseUnexpectedDataValue (line 214) | MAPCauseUnexpectedDataValue
  constant MAPCausePWRegistrationFailure (line 215) | MAPCausePWRegistrationFailure
  constant MAPCauseNegativePWCheck (line 216) | MAPCauseNegativePWCheck
  constant MAPCauseNoRoamingNumberAvailable (line 217) | MAPCauseNoRoamingNumberAvailable
  constant MAPCauseTracingBufferFull (line 218) | MAPCauseTracingBufferFull
  constant _ (line 219) | _
  constant MAPCauseTargetCellOutsideGroupCallArea (line 220) | MAPCauseTargetCellOutsideGroupCallArea
  constant MAPCauseNumberOfPWAttemptsViolation (line 221) | MAPCauseNumberOfPWAttemptsViolation
  constant MAPCauseNumberChanged (line 222) | MAPCauseNumberChanged
  constant MAPCauseBusySubscriber (line 223) | MAPCauseBusySubscriber
  constant MAPCauseNoSubscriberReply (line 224) | MAPCauseNoSubscriberReply
  constant MAPCauseForwardingFailed (line 225) | MAPCauseForwardingFailed
  constant MAPCauseORNotAllowed (line 226) | MAPCauseORNotAllowed
  constant MAPCauseATINotAllowed (line 227) | MAPCauseATINotAllowed
  constant MAPCauseNoGroupCallNumberAvailable (line 228) | MAPCauseNoGroupCallNumberAvailable
  constant MAPCauseResourceLimitation (line 229) | MAPCauseResourceLimitation
  constant MAPCauseUnauthorizedRequestingNetwork (line 230) | MAPCauseUnauthorizedRequestingNetwork
  constant MAPCauseUnauthorizedLCSClient (line 231) | MAPCauseUnauthorizedLCSClient
  constant MAPCausePositionMethodFailure (line 232) | MAPCausePositionMethodFailure
  constant _ (line 233) | _
  constant _ (line 234) | _
  constant _ (line 235) | _
  constant MAPCauseUnknownOrUnreachableLCSClient (line 236) | MAPCauseUnknownOrUnreachableLCSClient
  constant MAPCauseMMEventNotSupported (line 237) | MAPCauseMMEventNotSupported
  constant MAPCauseATSINotAllowed (line 238) | MAPCauseATSINotAllowed
  constant MAPCauseATMNotAllowed (line 239) | MAPCauseATMNotAllowed
  constant MAPCauseInformationNotAvailabl (line 240) | MAPCauseInformationNotAvailabl
  constant _ (line 241) | _
  constant _ (line 242) | _
  constant _ (line 243) | _
  constant _ (line 244) | _
  constant _ (line 245) | _
  constant _ (line 246) | _
  constant _ (line 247) | _
  constant _ (line 248) | _
  constant MAPCauseUnknownAlphabe (line 249) | MAPCauseUnknownAlphabe
  constant MAPCauseUSSDBusy (line 250) | MAPCauseUSSDBusy
  constant _ (line 255) | _ uint8 = iota
  constant RABPreempted (line 256) | RABPreempted
  constant RANAPCauseTrelocoverallExpiry (line 257) | RANAPCauseTrelocoverallExpiry
  constant RANAPCauseTrelocprepExpiry (line 258) | RANAPCauseTrelocprepExpiry
  constant RANAPCauseTreloccompleteExpiry (line 259) | RANAPCauseTreloccompleteExpiry
  constant RANAPCauseTqueuingExpiry (line 260) | RANAPCauseTqueuingExpiry
  constant RANAPCauseRelocationTriggered (line 261) | RANAPCauseRelocationTriggered
  constant RANAPCauseTRELOCallocExpiry (line 262) | RANAPCauseTRELOCallocExpiry
  constant RANAPCauseUnableToEstablishDuringRelocation (line 263) | RANAPCauseUnableToEstablishDuringRelocation
  constant RANAPCauseUnknownTargetRNC (line 264) | RANAPCauseUnknownTargetRNC
  constant RANAPCauseRelocationCancelled (line 265) | RANAPCauseRelocationCancelled
  constant RANAPCauseSuccessfulRelocation (line 266) | RANAPCauseSuccessfulRelocation
  constant RANAPCauseRequestedCipheringIntegrityProtectionAlgorithmsNotSupported (line 267) | RANAPCauseRequestedCipheringIntegrityProtectionAlgorithmsNotSupported
  constant RANAPCauseChangeOfCipheringIntegrityProtectionIsNotSupported (line 268) | RANAPCauseChangeOfCipheringIntegrityProtectionIsNotSupported
  constant RANAPCauseFailureInTheRadioInterfaceProcedure (line 269) | RANAPCauseFailureInTheRadioInterfaceProcedure
  constant RANAPCauseReleaseDueToUTRANGeneratedReason (line 270) | RANAPCauseReleaseDueToUTRANGeneratedReason
  constant RANAPCauseUserInactivity (line 271) | RANAPCauseUserInactivity
  constant RANAPCauseTimeCriticalRelocation (line 272) | RANAPCauseTimeCriticalRelocation
  constant RANAPCauseRequestedTrafficClassNotAvailable (line 273) | RANAPCauseRequestedTrafficClassNotAvailable
  constant RANAPCauseInvalidRABParametersValue (line 274) | RANAPCauseInvalidRABParametersValue
  constant RANAPCauseRequestedMaximumBitRateNotAvailable (line 275) | RANAPCauseRequestedMaximumBitRateNotAvailable
  constant RANAPCauseRequestedGuaranteedBitRateNotAvailable (line 276) | RANAPCauseRequestedGuaranteedBitRateNotAvailable
  constant RANAPCauseRequestedTransferDelayNotAchievable (line 277) | RANAPCauseRequestedTransferDelayNotAchievable
  constant RANAPCauseInvalidRABParametersCombination (line 278) | RANAPCauseInvalidRABParametersCombination
  constant RANAPCauseConditionViolationForSDUParameters (line 279) | RANAPCauseConditionViolationForSDUParameters
  constant RANAPCauseConditionViolationForTrafficHandlingPriority (line 280) | RANAPCauseConditionViolationForTrafficHandlingPriority
  constant RANAPCauseConditionViolationForGuaranteedBitRate (line 281) | RANAPCauseConditionViolationForGuaranteedBitRate
  constant RANAPCauseUserPlaneVersionsNotSupported (line 282) | RANAPCauseUserPlaneVersionsNotSupported
  constant RANAPCauseIuUPFailure (line 283) | RANAPCauseIuUPFailure
  constant RANAPCauseRelocationFailureInTargetCNRNCOrTargetSystem (line 284) | RANAPCauseRelocationFailureInTargetCNRNCOrTargetSystem
  constant RANAPCauseInvalidRABID (line 285) | RANAPCauseInvalidRABID
  constant RANAPCauseNoRemainingRAB (line 286) | RANAPCauseNoRemainingRAB
  constant RANAPCauseInteractionWithOtherProcedure (line 287) | RANAPCauseInteractionWithOtherProcedure
  constant RANAPCauseRequestedMaximumBitRateForDLNotAvailable (line 288) | RANAPCauseRequestedMaximumBitRateForDLNotAvailable
  constant RANAPCauseRequestedMaximumBitRateForULNotAvailable (line 289) | RANAPCauseRequestedMaximumBitRateForULNotAvailable
  constant RANAPCauseRequestedGuaranteedBitRateForDLNotAvailable (line 290) | RANAPCauseRequestedGuaranteedBitRateForDLNotAvailable
  constant RANAPCauseRequestedGuaranteedBitRateForULNotAvailable (line 291) | RANAPCauseRequestedGuaranteedBitRateForULNotAvailable
  constant RANAPCauseRepeatedIntegrityCheckingFailure (line 292) | RANAPCauseRepeatedIntegrityCheckingFailure
  constant RANAPCauseRequestedReportTypeNotSupported (line 293) | RANAPCauseRequestedReportTypeNotSupported
  constant RANAPCauseRequestSuperseded (line 294) | RANAPCauseRequestSuperseded
  constant RANAPCauseReleaseDueToUEWenRatedSignallingConnectionRelease (line 295) | RANAPCauseReleaseDueToUEWenRatedSignallingConnectionRelease
  constant RANAPCauseResourceOptimisationRelocation (line 296) | RANAPCauseResourceOptimisationRelocation
  constant RANAPCauseRequestedInformationNotAvailable (line 297) | RANAPCauseRequestedInformationNotAvailable
  constant RANAPCauseRelocationDesirableForRadioReasons (line 298) | RANAPCauseRelocationDesirableForRadioReasons
  constant RANAPCauseRelocationNotSupportedInTargetRNCOrTargetSystem (line 299) | RANAPCauseRelocationNotSupportedInTargetRNCOrTargetSystem
  constant RANAPCauseDirectedRetry (line 300) | RANAPCauseDirectedRetry
  constant RANAPCauseRadioConnectionWithUELost (line 301) | RANAPCauseRadioConnectionWithUELost
  constant RANAPCauseRNCUnableToEstablishAllRFCs (line 302) | RANAPCauseRNCUnableToEstablishAllRFCs
  constant RANAPCauseDecipheringKeysNotAvailable (line 303) | RANAPCauseDecipheringKeysNotAvailable
  constant RANAPCauseDedicatedAssistanceDataNotAvailable (line 304) | RANAPCauseDedicatedAssistanceDataNotAvailable
  constant RANAPCauseRelocationTargetNotAllowed (line 305) | RANAPCauseRelocationTargetNotAllowed
  constant RANAPCauseLocationReportingCongestion (line 306) | RANAPCauseLocationReportingCongestion
  constant RANAPCauseReduceLoadInServingCell (line 307) | RANAPCauseReduceLoadInServingCell
  constant RANAPCauseNoRadioResourcesAvailableInTargetCell (line 308) | RANAPCauseNoRadioResourcesAvailableInTargetCell
  constant RANAPCauseGERANIuModeFailure (line 309) | RANAPCauseGERANIuModeFailure
  constant RANAPCauseAccessRestrictedDueToSharedNetworks (line 310) | RANAPCauseAccessRestrictedDueToSharedNetworks
  constant RANAPCauseIncomingRelocationNotSupportedDueTodPUESBINEFeature (line 311) | RANAPCauseIncomingRelocationNotSupportedDueTodPUESBINEFeature
  constant RANAPCauseTrafficLoadInTheTargetCellHigherThanInTheSourceCell (line 312) | RANAPCauseTrafficLoadInTheTargetCellHigherThanInTheSourceCell
  constant RANAPCauseMBMSNoMulticastServiceForThisUE (line 313) | RANAPCauseMBMSNoMulticastServiceForThisUE
  constant RANAPCauseMBMSUnknownUEID (line 314) | RANAPCauseMBMSUnknownUEID
  constant RANAPCauseSuccessfulMBMSSessionStartNoDataBearerNecessary (line 315) | RANAPCauseSuccessfulMBMSSessionStartNoDataBearerNecessary
  constant RANAPCauseMBMSSupersededDueToNNSF (line 316) | RANAPCauseMBMSSupersededDueToNNSF
  constant RANAPCauseMBMSUELinkingAlreadyDone (line 317) | RANAPCauseMBMSUELinkingAlreadyDone
  constant RANAPCauseMBMSUEDeLinkingFailureNoExistingUELinking (line 318) | RANAPCauseMBMSUEDeLinkingFailureNoExistingUELinking
  constant RANAPCauseTMGIUnknown (line 319) | RANAPCauseTMGIUnknown
  constant RANAPCauseSignallingTransportResourceFailure (line 320) | RANAPCauseSignallingTransportResourceFailure
  constant RANAPCauseIuTransportConnectionFailedToEstablish (line 321) | RANAPCauseIuTransportConnectionFailedToEstablish
  constant _ (line 322) | _
  constant _ (line 323) | _
  constant _ (line 324) | _
  constant _ (line 325) | _
  constant _ (line 326) | _
  constant _ (line 327) | _
  constant _ (line 328) | _
  constant _ (line 329) | _
  constant _ (line 330) | _
  constant _ (line 331) | _
  constant _ (line 332) | _
  constant _ (line 333) | _
  constant _ (line 334) | _
  constant _ (line 335) | _
  constant RANAPCauseUserRestrictionStartIndication (line 336) | RANAPCauseUserRestrictionStartIndication
  constant RANAPCauseUserRestrictionEndIndication (line 337) | RANAPCauseUserRestrictionEndIndication
  constant RANAPCauseNormalRelease (line 338) | RANAPCauseNormalRelease
  constant _ (line 339) | _
  constant _ (line 340) | _
  constant _ (line 341) | _
  constant _ (line 342) | _
  constant _ (line 343) | _
  constant _ (line 344) | _
  constant _ (line 345) | _
  constant _ (line 346) | _
  constant _ (line 347) | _
  constant _ (line 348) | _
  constant _ (line 349) | _
  constant _ (line 350) | _
  constant _ (line 351) | _
  constant RANAPCauseTransferSyntaxError (line 352) | RANAPCauseTransferSyntaxError
  constant RANAPCauseSemanticError (line 353) | RANAPCauseSemanticError
  constant RANAPCauseMessageNotCompatibleWithReceiverState (line 354) | RANAPCauseMessageNotCompatibleWithReceiverState
  constant RANAPCauseAbstractSyntaxErrorReject (line 355) | RANAPCauseAbstractSyntaxErrorReject
  constant RANAPCauseAbstractSyntaxErrorIgnoreAndNotify (line 356) | RANAPCauseAbstractSyntaxErrorIgnoreAndNotify
  constant RANAPCauseAbstractSyntaxErrorFalselyConstructedMessage (line 357) | RANAPCauseAbstractSyntaxErrorFalselyConstructedMessage
  constant _ (line 358) | _
  constant _ (line 359) | _
  constant _ (line 360) | _
  constant _ (line 361) | _
  constant _ (line 362) | _
  constant _ (line 363) | _
  constant _ (line 364) | _
  constant _ (line 365) | _
  constant _ (line 366) | _
  constant _ (line 367) | _
  constant RANAPCauseOAMIntervention (line 368) | RANAPCauseOAMIntervention
  constant RANAPCauseNoResourceAvailable (line 369) | RANAPCauseNoResourceAvailable
  constant RANAPCauseUnspecifiedFailure (line 370) | RANAPCauseUnspecifiedFailure
  constant RANAPCauseNetworkOptimisation (line 371) | RANAPCauseNetworkOptimisation

FILE: gtpv1/errors.go
  type ErrorIndicatedError (line 26) | type ErrorIndicatedError struct
    method Error (line 31) | func (e *ErrorIndicatedError) Error() string {
  type HandlerNotFoundError (line 39) | type HandlerNotFoundError struct
    method Error (line 44) | func (e *HandlerNotFoundError) Error() string {

FILE: gtpv1/gtpv1_fuzz_test.go
  function FuzzDecapsulate (line 9) | func FuzzDecapsulate(f *testing.F) {

FILE: gtpv1/handlers.go
  type HandlerFunc (line 17) | type HandlerFunc
  type msgHandlerMap (line 19) | type msgHandlerMap struct
    method store (line 23) | func (m *msgHandlerMap) store(msgType uint8, handler HandlerFunc) {
    method load (line 27) | func (m *msgHandlerMap) load(msgType uint8) (HandlerFunc, bool) {
  function newMsgHandlerMap (line 36) | func newMsgHandlerMap(m map[uint8]HandlerFunc) *msgHandlerMap {
  function newDefaultMsgHandlerMap (line 45) | func newDefaultMsgHandlerMap() *msgHandlerMap {
  function handleTPDU (line 59) | func handleTPDU(c Conn, senderAddr net.Addr, msg message.Message) error {
  function handleEchoRequest (line 99) | func handleEchoRequest(c Conn, senderAddr net.Addr, msg message.Message)...
  function handleEchoResponse (line 112) | func handleEchoResponse(c Conn, senderAddr net.Addr, msg message.Message...
  function handleErrorIndication (line 123) | func handleErrorIndication(c Conn, senderAddr net.Addr, msg message.Mess...

FILE: gtpv1/ie/apn-restriction.go
  function NewAPNRestriction (line 10) | func NewAPNRestriction(restriction uint8) *IE {
  method APNRestriction (line 15) | func (i *IE) APNRestriction() (uint8, error) {
  method MustAPNRestriction (line 28) | func (i *IE) MustAPNRestriction() uint8 {

FILE: gtpv1/ie/apn.go
  function NewAccessPointName (line 13) | func NewAccessPointName(apn string) *IE {
  method AccessPointName (line 27) | func (i *IE) AccessPointName() (string, error) {
  method MustAccessPointName (line 55) | func (i *IE) MustAccessPointName() string {

FILE: gtpv1/ie/authentication-quintuplet.go
  function NewAuthenticationQuintuplet (line 10) | func NewAuthenticationQuintuplet(rand, xres, ck, ik, autn []byte) *IE {
  method AuthenticationQuintuplet (line 32) | func (i *IE) AuthenticationQuintuplet() ([]byte, error) {
  method MustAuthenticationQuintuplet (line 45) | func (i *IE) MustAuthenticationQuintuplet() []byte {
  method XRES (line 51) | func (i *IE) XRES() ([]byte, error) {
  method MustXRES (line 74) | func (i *IE) MustXRES() []byte {
  method CK (line 80) | func (i *IE) CK() ([]byte, error) {
  method MustCK (line 99) | func (i *IE) MustCK() []byte {
  method IK (line 105) | func (i *IE) IK() ([]byte, error) {
  method MustIK (line 124) | func (i *IE) MustIK() []byte {
  method AUTN (line 130) | func (i *IE) AUTN() ([]byte, error) {
  method MustAUTN (line 149) | func (i *IE) MustAUTN() []byte {

FILE: gtpv1/ie/authentication-triplet.go
  function NewAuthenticationTriplet (line 10) | func NewAuthenticationTriplet(rand, sres, kc []byte) *IE {
  method AuthenticationTriplet (line 20) | func (i *IE) AuthenticationTriplet() ([]byte, error) {
  method MustAuthenticationTriplet (line 29) | func (i *IE) MustAuthenticationTriplet() []byte {
  method RAND (line 35) | func (i *IE) RAND() ([]byte, error) {
  method MustRAND (line 49) | func (i *IE) MustRAND() []byte {
  method SRES (line 55) | func (i *IE) SRES() ([]byte, error) {
  method MustSRES (line 69) | func (i *IE) MustSRES() []byte {
  method Kc (line 75) | func (i *IE) Kc() ([]byte, error) {
  method MustKc (line 89) | func (i *IE) MustKc() []byte {

FILE: gtpv1/ie/cause.go
  function NewCause (line 10) | func NewCause(cause uint8) *IE {
  method Cause (line 15) | func (i *IE) Cause() (uint8, error) {
  method MustCause (line 28) | func (i *IE) MustCause() uint8 {

FILE: gtpv1/ie/charging-id.go
  function NewChargingID (line 13) | func NewChargingID(id uint32) *IE {
  method ChargingID (line 18) | func (i *IE) ChargingID() (uint32, error) {
  method MustChargingID (line 31) | func (i *IE) MustChargingID() uint32 {

FILE: gtpv1/ie/common-flags.go
  function NewCommonFlags (line 12) | func NewCommonFlags(dualAddr, upgradeQoS, nrsn, noQoS, mbmsCount, ranRea...
  method CommonFlags (line 22) | func (i *IE) CommonFlags() (uint8, error) {
  method MustCommonFlags (line 35) | func (i *IE) MustCommonFlags() uint8 {
  method IsDualAddressBearer (line 41) | func (i *IE) IsDualAddressBearer() bool {
  method IsUpgradeQoSSupported (line 46) | func (i *IE) IsUpgradeQoSSupported() bool {
  method IsNRSN (line 51) | func (i *IE) IsNRSN() bool {
  method IsNoQoSNegotiation (line 56) | func (i *IE) IsNoQoSNegotiation() bool {
  method IsMBMSCountingInformation (line 61) | func (i *IE) IsMBMSCountingInformation() bool {
  method IsRANProceduresReady (line 66) | func (i *IE) IsRANProceduresReady() bool {
  method IsMBMSServiceType (line 71) | func (i *IE) IsMBMSServiceType() bool {
  method IsProhibitPayloadCompression (line 76) | func (i *IE) IsProhibitPayloadCompression() bool {

FILE: gtpv1/ie/end-user-address.go
  constant pdpTypeETSI (line 13) | pdpTypeETSI uint8 = iota | 0xf0
  constant pdpTypeIETF (line 14) | pdpTypeIETF
  function NewEndUserAddress (line 21) | func NewEndUserAddress(addr string) *IE {
  function NewEndUserAddressByIP (line 30) | func NewEndUserAddressByIP(ip net.IP) *IE {
  function NewEndUserAddressIPv4 (line 46) | func NewEndUserAddressIPv4(addr string) *IE {
  function NewEndUserAddressIPv6 (line 56) | func NewEndUserAddressIPv6(addr string) *IE {
  function newEUAddrV4 (line 65) | func newEUAddrV4(v4 []byte) *IE {
  function newEUAddrV6 (line 77) | func newEUAddrV6(v6 []byte) *IE {
  function NewEndUserAddressPPP (line 90) | func NewEndUserAddressPPP() *IE {
  method EndUserAddress (line 100) | func (i *IE) EndUserAddress() ([]byte, error) {
  method MustEndUserAddress (line 109) | func (i *IE) MustEndUserAddress() []byte {
  method PDPTypeOrganization (line 115) | func (i *IE) PDPTypeOrganization() (uint8, error) {
  method MustPDPTypeOrganization (line 128) | func (i *IE) MustPDPTypeOrganization() uint8 {
  method PDPTypeNumber (line 134) | func (i *IE) PDPTypeNumber() (uint8, error) {
  method MustPDPTypeNumber (line 147) | func (i *IE) MustPDPTypeNumber() uint8 {

FILE: gtpv1/ie/errors.go
  type InvalidTypeError (line 22) | type InvalidTypeError struct
    method Error (line 27) | func (e *InvalidTypeError) Error() string {

FILE: gtpv1/ie/extended-common-flags-ii.go
  function NewExtendedCommonFlagsII (line 12) | func NewExtendedCommonFlagsII(pmtsmi, dtci, pnsi int) *IE {
  method ExtendedCommonFlagsII (line 22) | func (i *IE) ExtendedCommonFlagsII() (uint8, error) {
  method MustExtendedCommonFlagsII (line 35) | func (i *IE) MustExtendedCommonFlagsII() uint8 {
  method IsPMTSMI (line 41) | func (i *IE) IsPMTSMI() bool {
  method IsDTCI (line 46) | func (i *IE) IsDTCI() bool {
  method IsPNSI (line 51) | func (i *IE) IsPNSI() bool {

FILE: gtpv1/ie/extended-common-flags.go
  function NewExtendedCommonFlags (line 12) | func NewExtendedCommonFlags(uasi, bdwi, pcri, vb, retloc, cpsr, ccrsi, u...
  method ExtendedCommonFlags (line 22) | func (i *IE) ExtendedCommonFlags() (uint8, error) {
  method MustExtendedCommonFlags (line 35) | func (i *IE) MustExtendedCommonFlags() uint8 {
  method IsUASI (line 41) | func (i *IE) IsUASI() bool {
  method IsBDWI (line 46) | func (i *IE) IsBDWI() bool {
  method IsPCRI (line 51) | func (i *IE) IsPCRI() bool {
  method IsVB (line 56) | func (i *IE) IsVB() bool {
  method IsRetLoc (line 61) | func (i *IE) IsRetLoc() bool {
  method IsCPSR (line 66) | func (i *IE) IsCPSR() bool {
  method IsCCRSI (line 71) | func (i *IE) IsCCRSI() bool {
  method IsUnauthenticatedIMSI (line 76) | func (i *IE) IsUnauthenticatedIMSI() bool {

FILE: gtpv1/ie/extension-header-type-list.go
  function NewExtensionHeaderTypeList (line 8) | func NewExtensionHeaderTypeList(types ...uint8) *IE {
  method ExtensionHeaderTypeList (line 13) | func (i *IE) ExtensionHeaderTypeList() ([]uint8, error) {
  method MustExtensionHeaderTypeList (line 23) | func (i *IE) MustExtensionHeaderTypeList() []uint8 {

FILE: gtpv1/ie/gsn-address.go
  function NewGSNAddress (line 13) | func NewGSNAddress(addr string) *IE {
  function NewGSNAddressByIP (line 18) | func NewGSNAddressByIP(ip net.IP) *IE {
  method GSNAddress (line 34) | func (i *IE) GSNAddress() (string, error) {
  method MustGSNAddress (line 47) | func (i *IE) MustGSNAddress() string {

FILE: gtpv1/ie/ie.go
  constant Cause (line 17) | Cause                        uint8 = 1
  constant IMSI (line 18) | IMSI                         uint8 = 2
  constant RouteingAreaIdentity (line 19) | RouteingAreaIdentity         uint8 = 3
  constant TemporaryLogicalLinkIdentity (line 20) | TemporaryLogicalLinkIdentity uint8 = 4
  constant PacketTMSI (line 21) | PacketTMSI                   uint8 = 5
  constant ReorderingRequired (line 22) | ReorderingRequired           uint8 = 8
  constant AuthenticationTriplet (line 23) | AuthenticationTriplet        uint8 = 9
  constant MAPCause (line 24) | MAPCause                     uint8 = 11
  constant PTMSISignature (line 25) | PTMSISignature               uint8 = 12
  constant MSValidated (line 26) | MSValidated                  uint8 = 13
  constant Recovery (line 27) | Recovery                     uint8 = 14
  constant SelectionMode (line 28) | SelectionMode                uint8 = 15
  constant TEIDDataI (line 29) | TEIDDataI                    uint8 = 16
  constant TEIDCPlane (line 30) | TEIDCPlane                   uint8 = 17
  constant TEIDDataII (line 31) | TEIDDataII                   uint8 = 18
  constant TeardownInd (line 32) | TeardownInd                  uint8 = 19
  constant NSAPI (line 33) | NSAPI                        uint8 = 20
  constant RANAPCause (line 34) | RANAPCause                   uint8 = 21
  constant RABContext (line 35) | RABContext                   uint8 = 22
  constant RadioPrioritySMS (line 36) | RadioPrioritySMS             uint8 = 23
  constant RadioPriority (line 37) | RadioPriority                uint8 = 24
  constant PacketFlowID (line 38) | PacketFlowID                 uint8 = 25
  constant ChargingCharacteristics (line 39) | ChargingCharacteristics      uint8 = 26
  constant TraceReference (line 40) | TraceReference               uint8 = 27
  constant TraceType (line 41) | TraceType                    uint8 = 28
  constant MSNotReachableReason (line 42) | MSNotReachableReason         uint8 = 29
  constant ChargingID (line 43) | ChargingID                   uint8 = 127
  constant EndUserAddress (line 48) | EndUserAddress                        uint8 = 128
  constant MMContext (line 49) | MMContext                             uint8 = 129
  constant PDPContext (line 50) | PDPContext                            uint8 = 130
  constant AccessPointName (line 51) | AccessPointName                       uint8 = 131
  constant ProtocolConfigurationOptions (line 52) | ProtocolConfigurationOptions          uint8 = 132
  constant GSNAddress (line 53) | GSNAddress                            uint8 = 133
  constant MSISDN (line 54) | MSISDN                                uint8 = 134
  constant QoSProfile (line 55) | QoSProfile                            uint8 = 135
  constant AuthenticationQuintuplet (line 56) | AuthenticationQuintuplet              uint8 = 136
  constant TrafficFlowTemplate (line 57) | TrafficFlowTemplate                   uint8 = 137
  constant TargetIdentification (line 58) | TargetIdentification                  uint8 = 138
  constant UTRANTransparentContainer (line 59) | UTRANTransparentContainer             uint8 = 139
  constant RABSetupInformation (line 60) | RABSetupInformation                   uint8 = 140
  constant ExtensionHeaderTypeList (line 61) | ExtensionHeaderTypeList               uint8 = 141
  constant TriggerID (line 62) | TriggerID                             uint8 = 142
  constant OMCIdentity (line 63) | OMCIdentity                           uint8 = 143
  constant RANTransparentContainer (line 64) | RANTransparentContainer               uint8 = 144
  constant PDPContextPrioritization (line 65) | PDPContextPrioritization              uint8 = 145
  constant AdditionalRABSetupInformation (line 66) | AdditionalRABSetupInformation         uint8 = 146
  constant SGSNNumber (line 67) | SGSNNumber                            uint8 = 147
  constant CommonFlags (line 68) | CommonFlags                           uint8 = 148
  constant APNRestriction (line 69) | APNRestriction                        uint8 = 149
  constant RadioPriorityLCS (line 70) | RadioPriorityLCS                      uint8 = 150
  constant RATType (line 71) | RATType                               uint8 = 151
  constant UserLocationInformation (line 72) | UserLocationInformation               uint8 = 152
  constant MSTimeZone (line 73) | MSTimeZone                            uint8 = 153
  constant IMEISV (line 74) | IMEISV                                uint8 = 154
  constant CAMELChargingInformationContainer (line 75) | CAMELChargingInformationContainer     uint8 = 155
  constant MBMSUEContext (line 76) | MBMSUEContext                         uint8 = 156
  constant TemporaryMobileGroupIdentity (line 77) | TemporaryMobileGroupIdentity          uint8 = 157
  constant RIMRoutingAddress (line 78) | RIMRoutingAddress                     uint8 = 158
  constant MBMSProtocolConfigurationOptions (line 79) | MBMSProtocolConfigurationOptions      uint8 = 159
  constant MBMSServiceArea (line 80) | MBMSServiceArea                       uint8 = 160
  constant SourceRNCPDCPContextInfo (line 81) | SourceRNCPDCPContextInfo              uint8 = 161
  constant AdditionalTraceInfo (line 82) | AdditionalTraceInfo                   uint8 = 162
  constant HopCounter (line 83) | HopCounter                            uint8 = 163
  constant SelectedPLMNID (line 84) | SelectedPLMNID                        uint8 = 164
  constant MBMSSessionIdentifier (line 85) | MBMSSessionIdentifier                 uint8 = 165
  constant MBMS2G3GIndicator (line 86) | MBMS2G3GIndicator                     uint8 = 166
  constant EnhancedNSAPI (line 87) | EnhancedNSAPI                         uint8 = 167
  constant MBMSSessionDuration (line 88) | MBMSSessionDuration                   uint8 = 168
  constant AdditionalMBMSTraceInfo (line 89) | AdditionalMBMSTraceInfo               uint8 = 169
  constant MBMSSessionRepetitionNumber (line 90) | MBMSSessionRepetitionNumber           uint8 = 170
  constant MBMSTimeToDataTransfer (line 91) | MBMSTimeToDataTransfer                uint8 = 171
  constant BSSContainer (line 92) | BSSContainer                          uint8 = 173
  constant CellIdentification (line 93) | CellIdentification                    uint8 = 174
  constant PDUNumbers (line 94) | PDUNumbers                            uint8 = 175
  constant BSSGPCause (line 95) | BSSGPCause                            uint8 = 176
  constant RequiredMBMSBearerCapabilities (line 96) | RequiredMBMSBearerCapabilities        uint8 = 177
  constant RIMRoutingAddressDiscriminator (line 97) | RIMRoutingAddressDiscriminator        uint8 = 178
  constant ListOfSetupPFCs (line 98) | ListOfSetupPFCs                       uint8 = 179
  constant PSHandoverXIDParameters (line 99) | PSHandoverXIDParameters               uint8 = 180
  constant MSInfoChangeReportingAction (line 100) | MSInfoChangeReportingAction           uint8 = 181
  constant DirectTunnelFlags (line 101) | DirectTunnelFlags                     uint8 = 182
  constant CorrelationID (line 102) | CorrelationID                         uint8 = 183
  constant BearerControlMode (line 103) | BearerControlMode                     uint8 = 184
  constant MBMSFlowIdentifier (line 104) | MBMSFlowIdentifier                    uint8 = 185
  constant MBMSIPMulticastDistribution (line 105) | MBMSIPMulticastDistribution           uint8 = 186
  constant MBMSDistributionAcknowledgement (line 106) | MBMSDistributionAcknowledgement       uint8 = 187
  constant ReliableInterRATHandoverInfo (line 107) | ReliableInterRATHandoverInfo          uint8 = 188
  constant RFSPIndex (line 108) | RFSPIndex                             uint8 = 189
  constant FullyQualifiedDomainName (line 109) | FullyQualifiedDomainName              uint8 = 190
  constant EvolvedAllocationRetentionPriorityI (line 110) | EvolvedAllocationRetentionPriorityI   uint8 = 191
  constant EvolvedAllocationRetentionPriorityII (line 111) | EvolvedAllocationRetentionPriorityII  uint8 = 192
  constant ExtendedCommonFlags (line 112) | ExtendedCommonFlags                   uint8 = 193
  constant UserCSGInformation (line 113) | UserCSGInformation                    uint8 = 194
  constant CSGInformationReportingAction (line 114) | CSGInformationReportingAction         uint8 = 195
  constant CSGID (line 115) | CSGID                                 uint8 = 196
  constant CSGMembershipIndication (line 116) | CSGMembershipIndication               uint8 = 197
  constant AggregateMaximumBitRate (line 117) | AggregateMaximumBitRate               uint8 = 198
  constant UENetworkCapability (line 118) | UENetworkCapability                   uint8 = 199
  constant UEAMBR (line 119) | UEAMBR                                uint8 = 200
  constant APNAMBRWithNSAPI (line 120) | APNAMBRWithNSAPI                      uint8 = 201
  constant GGSNBackOffTime (line 121) | GGSNBackOffTime                       uint8 = 202
  constant SignallingPriorityIndication (line 122) | SignallingPriorityIndication          uint8 = 203
  constant SignallingPriorityIndicationWithNSAPI (line 123) | SignallingPriorityIndicationWithNSAPI uint8 = 204
  constant HigherBitratesThan16MbpsFlag (line 124) | HigherBitratesThan16MbpsFlag          uint8 = 205
  constant AdditionalMMContextForSRVCC (line 125) | AdditionalMMContextForSRVCC           uint8 = 207
  constant AdditionalFlagsForSRVCC (line 126) | AdditionalFlagsForSRVCC               uint8 = 208
  constant STNSR (line 127) | STNSR                                 uint8 = 209
  constant CMSISDN (line 128) | CMSISDN                               uint8 = 210
  constant ExtendedRANAPCause (line 129) | ExtendedRANAPCause                    uint8 = 211
  constant ENodeBID (line 130) | ENodeBID                              uint8 = 212
  constant SelectionModeWithNSAPI (line 131) | SelectionModeWithNSAPI                uint8 = 213
  constant ULITimestamp (line 132) | ULITimestamp                          uint8 = 214
  constant LHNIDWithNSAPI (line 133) | LHNIDWithNSAPI                        uint8 = 215
  constant CNOperatorSelectionEntity (line 134) | CNOperatorSelectionEntity             uint8 = 216
  constant UEUsageType (line 135) | UEUsageType                           uint8 = 217
  constant ExtendedCommonFlagsII (line 136) | ExtendedCommonFlagsII                 uint8 = 218
  constant NodeIdentifier (line 137) | NodeIdentifier                        uint8 = 219
  constant CIoTOptimizationsSupportIndication (line 138) | CIoTOptimizationsSupportIndication    uint8 = 220
  constant SCEFPDNConnection (line 139) | SCEFPDNConnection                     uint8 = 221
  constant IOVUpdatesCounter (line 140) | IOVUpdatesCounter                     uint8 = 222
  constant MappedUEUsageType (line 141) | MappedUEUsageType                     uint8 = 223
  constant UPFunctionSelectionIndicationFlags (line 142) | UPFunctionSelectionIndicationFlags    uint8 = 224
  constant SpecialIETypeForIETypeExtension (line 143) | SpecialIETypeForIETypeExtension       uint8 = 238
  constant ChargingGatewayAddress (line 144) | ChargingGatewayAddress                uint8 = 251
  constant PrivateExtension (line 145) | PrivateExtension                      uint8 = 255
  type IE (line 149) | type IE struct
    method Marshal (line 164) | func (i *IE) Marshal() ([]byte, error) {
    method MarshalTo (line 173) | func (i *IE) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 202) | func (i *IE) UnmarshalBinary(b []byte) error {
    method IsTV (line 301) | func (i *IE) IsTV() bool {
    method MarshalLen (line 306) | func (i *IE) MarshalLen() int {
    method SetLength (line 323) | func (i *IE) SetLength() {
    method Name (line 333) | func (i *IE) Name() string {
    method String (line 341) | func (i *IE) String() string {
  function New (line 156) | func New(t uint8, p []byte) *IE {
  function Parse (line 193) | func Parse(b []byte) (*IE, error) {
  function decodeTVFromBytes (line 219) | func decodeTVFromBytes(i *IE, b []byte) error {
  function decodeTLVFromBytes (line 234) | func decodeTLVFromBytes(i *IE, b []byte) error {
  function decodeExtensionHeaderTypeList (line 249) | func decodeExtensionHeaderTypeList(i *IE, b []byte) error {
  function ParseMultiIEs (line 354) | func ParseMultiIEs(b []byte) ([]*IE, error) {
  function newUint8ValIE (line 373) | func newUint8ValIE(t, v uint8) *IE {
  function newUint32ValIE (line 384) | func newUint32ValIE(t uint8, v uint32) *IE {

FILE: gtpv1/ie/ie_deprecated.go
  method Serialize (line 12) | func (i *IE) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (i *IE) SerializeTo(b []byte) error {
  function Decode (line 28) | func Decode(b []byte) (*IE, error) {
  method DecodeFromBytes (line 36) | func (i *IE) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (i *IE) Len() int {

FILE: gtpv1/ie/ie_fuzz_test.go
  function FuzzParse (line 9) | func FuzzParse(f *testing.F) {

FILE: gtpv1/ie/ie_test.go
  function TestIEs (line 17) | func TestIEs(t *testing.T) {

FILE: gtpv1/ie/imei.go
  function NewIMEISV (line 15) | func NewIMEISV(imei string) *IE {
  method IMEISV (line 24) | func (i *IE) IMEISV() (string, error) {
  method MustIMEISV (line 37) | func (i *IE) MustIMEISV() string {

FILE: gtpv1/ie/imei_test.go
  function TestIE_IMEISV (line 9) | func TestIE_IMEISV(t *testing.T) {

FILE: gtpv1/ie/imsi.go
  function NewIMSI (line 14) | func NewIMSI(imsi string) *IE {
  method IMSI (line 23) | func (i *IE) IMSI() (string, error) {
  method MustIMSI (line 36) | func (i *IE) MustIMSI() string {

FILE: gtpv1/ie/ip.go
  method IP (line 13) | func (i *IE) IP() (net.IP, error) {
  method MustIP (line 31) | func (i *IE) MustIP() net.IP {
  method IPAddress (line 37) | func (i *IE) IPAddress() (string, error) {
  method MustIPAddress (line 48) | func (i *IE) MustIPAddress() string {

FILE: gtpv1/ie/lac.go
  method LAC (line 13) | func (i *IE) LAC() (uint16, error) {
  method MustLAC (line 32) | func (i *IE) MustLAC() uint16 {

FILE: gtpv1/ie/map-cause.go
  function NewMAPCause (line 10) | func NewMAPCause(cause uint8) *IE {
  method MAPCause (line 15) | func (i *IE) MAPCause() (uint8, error) {
  method MustMAPCause (line 28) | func (i *IE) MustMAPCause() uint8 {

FILE: gtpv1/ie/mcc-mnc.go
  method MCC (line 14) | func (i *IE) MCC() (string, error) {
  method MustMCC (line 33) | func (i *IE) MustMCC() string {
  method MNC (line 39) | func (i *IE) MNC() (string, error) {
  method MustMNC (line 58) | func (i *IE) MustMNC() string {

FILE: gtpv1/ie/ms-timezone.go
  constant TimeAdjustNoDaylightSaving (line 15) | TimeAdjustNoDaylightSaving uint8 = iota
  constant TimeAdjustDaylightSavingOneHour (line 16) | TimeAdjustDaylightSavingOneHour
  constant TimeAdjustDaylightSavingTwoHour (line 17) | TimeAdjustDaylightSavingTwoHour
  function NewMSTimeZone (line 21) | func NewMSTimeZone(tz time.Duration, daylightSaving uint8) *IE {
  method TimeZone (line 36) | func (i *IE) TimeZone() (time.Duration, error) {
  method MustTimeZone (line 55) | func (i *IE) MustTimeZone() time.Duration {
  method DaylightSaving (line 61) | func (i *IE) DaylightSaving() (uint8, error) {
  method MustDaylightSaving (line 74) | func (i *IE) MustDaylightSaving() uint8 {

FILE: gtpv1/ie/ms-validated.go
  function NewMSValidated (line 8) | func NewMSValidated(validated bool) *IE {
  method MSValidated (line 16) | func (i *IE) MSValidated() bool {

FILE: gtpv1/ie/msisdn.go
  function NewMSISDN (line 14) | func NewMSISDN(msisdn string) *IE {
  method MSISDN (line 23) | func (i *IE) MSISDN() (string, error) {
  method MustMSISDN (line 36) | func (i *IE) MustMSISDN() string {

FILE: gtpv1/ie/nsapi.go
  function NewNSAPI (line 10) | func NewNSAPI(nsapi uint8) *IE {
  method NSAPI (line 15) | func (i *IE) NSAPI() (uint8, error) {
  method MustNSAPI (line 28) | func (i *IE) MustNSAPI() uint8 {

FILE: gtpv1/ie/p-tmsi-signature.go
  function NewPTMSISignature (line 14) | func NewPTMSISignature(sig uint32) *IE {
  method PTMSISignature (line 19) | func (i *IE) PTMSISignature() (uint32, error) {
  method MustPTMSISignature (line 32) | func (i *IE) MustPTMSISignature() uint32 {

FILE: gtpv1/ie/p-tmsi.go
  function NewPacketTMSI (line 13) | func NewPacketTMSI(ptmsi uint32) *IE {
  method PacketTMSI (line 18) | func (i *IE) PacketTMSI() (uint32, error) {
  method MustPacketTMSI (line 31) | func (i *IE) MustPacketTMSI() uint32 {

FILE: gtpv1/ie/pco.go
  type ConfigurationProtocolOption (line 10) | type ConfigurationProtocolOption struct
    method Marshal (line 27) | func (c *ConfigurationProtocolOption) Marshal() ([]byte, error) {
    method MarshalTo (line 37) | func (c *ConfigurationProtocolOption) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 58) | func (c *ConfigurationProtocolOption) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 74) | func (c *ConfigurationProtocolOption) MarshalLen() int {
  function NewConfigurationProtocolOption (line 17) | func NewConfigurationProtocolOption(pid uint16, contents []byte) *Config...
  function ParseConfigurationProtocolOption (line 48) | func ParseConfigurationProtocolOption(b []byte) (*ConfigurationProtocolO...
  type PCOPayload (line 79) | type PCOPayload struct
    method Marshal (line 93) | func (p *PCOPayload) Marshal() ([]byte, error) {
    method MarshalTo (line 103) | func (p *PCOPayload) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 127) | func (p *PCOPayload) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 149) | func (p *PCOPayload) MarshalLen() int {
  function NewPCOPayload (line 85) | func NewPCOPayload(configProto uint8, opts ...*ConfigurationProtocolOpti...
  function ParsePCOPayload (line 117) | func ParsePCOPayload(b []byte) (*PCOPayload, error) {
  function NewProtocolConfigurationOptions (line 159) | func NewProtocolConfigurationOptions(configProto uint8, options ...*Conf...
  method ProtocolConfigurationOptions (line 172) | func (i *IE) ProtocolConfigurationOptions() (*PCOPayload, error) {
  method MustProtocolConfigurationOptions (line 186) | func (i *IE) MustProtocolConfigurationOptions() *PCOPayload {

FILE: gtpv1/ie/private-extension.go
  function NewPrivateExtension (line 13) | func NewPrivateExtension(id uint16, val []byte) *IE {
  method PrivateExtension (line 21) | func (i *IE) PrivateExtension() ([]byte, error) {
  method MustPrivateExtension (line 30) | func (i *IE) MustPrivateExtension() []byte {
  method ExtensionIdentifier (line 36) | func (i *IE) ExtensionIdentifier() (uint16, error) {
  method MustExtensionIdentifier (line 49) | func (i *IE) MustExtensionIdentifier() uint16 {
  method ExtensionValue (line 55) | func (i *IE) ExtensionValue() ([]byte, error) {
  method MustExtensionValue (line 68) | func (i *IE) MustExtensionValue() []byte {

FILE: gtpv1/ie/qos-profile.go
  function NewQoSProfile (line 10) | func NewQoSProfile(payload []byte) *IE {
  method QoSProfile (line 17) | func (i *IE) QoSProfile() ([]byte, error) {
  method MustQoSProfile (line 26) | func (i *IE) MustQoSProfile() []byte {

FILE: gtpv1/ie/rac.go
  method RAC (line 10) | func (i *IE) RAC() (uint8, error) {
  method MustRAC (line 30) | func (i *IE) MustRAC() uint8 {

FILE: gtpv1/ie/rai.go
  function NewRouteingAreaIdentity (line 14) | func NewRouteingAreaIdentity(mcc, mnc string, lac uint16, rac uint8) *IE {
  method RouteingAreaIdentity (line 37) | func (i *IE) RouteingAreaIdentity() ([]byte, error) {
  method MustRouteingAreaIdentity (line 46) | func (i *IE) MustRouteingAreaIdentity() []byte {

FILE: gtpv1/ie/rai_test.go
  function TestRouteingAreaIdentity (line 11) | func TestRouteingAreaIdentity(t *testing.T) {

FILE: gtpv1/ie/ranap-cause.go
  function NewRANAPCause (line 10) | func NewRANAPCause(cause uint8) *IE {
  method RANAPCause (line 15) | func (i *IE) RANAPCause() (uint8, error) {
  method MustRANAPCause (line 28) | func (i *IE) MustRANAPCause() uint8 {

FILE: gtpv1/ie/rat-type.go
  function NewRATType (line 10) | func NewRATType(ratType uint8) *IE {
  method RATType (line 18) | func (i *IE) RATType() (uint8, error) {
  method MustRATType (line 31) | func (i *IE) MustRATType() uint8 {

FILE: gtpv1/ie/recovery.go
  function NewRecovery (line 10) | func NewRecovery(recovery uint8) *IE {
  method Recovery (line 15) | func (i *IE) Recovery() (uint8, error) {
  method MustRecovery (line 28) | func (i *IE) MustRecovery() uint8 {

FILE: gtpv1/ie/reordering-required.go
  function NewReorderingRequired (line 8) | func NewReorderingRequired(required bool) *IE {
  method ReorderingRequired (line 16) | func (i *IE) ReorderingRequired() bool {

FILE: gtpv1/ie/selection-mode.go
  function NewSelectionMode (line 12) | func NewSelectionMode(mode uint8) *IE {
  method SelectionMode (line 17) | func (i *IE) SelectionMode() (uint8, error) {
  method MustSelectionMode (line 30) | func (i *IE) MustSelectionMode() uint8 {

FILE: gtpv1/ie/teardown-ind.go
  function NewTeardownInd (line 8) | func NewTeardownInd(teardown bool) *IE {
  method TeardownInd (line 16) | func (i *IE) TeardownInd() bool {

FILE: gtpv1/ie/teid.go
  function NewTEIDDataI (line 13) | func NewTEIDDataI(teid uint32) *IE {
  function NewTEIDCPlane (line 18) | func NewTEIDCPlane(teid uint32) *IE {
  function NewTEIDDataII (line 23) | func NewTEIDDataII(teid uint32) *IE {
  method TEID (line 28) | func (i *IE) TEID() (uint32, error) {
  method MustTEID (line 42) | func (i *IE) MustTEID() uint32 {

FILE: gtpv1/ie/uli-timestamp.go
  function NewULITimestamp (line 14) | func NewULITimestamp(ts time.Time) *IE {
  method Timestamp (line 20) | func (i *IE) Timestamp() (time.Time, error) {
  method MustTimestamp (line 35) | func (i *IE) MustTimestamp() time.Time {

FILE: gtpv1/ie/uli.go
  constant locTypeCGI (line 16) | locTypeCGI uint8 = iota
  constant locTypeSAI (line 17) | locTypeSAI
  constant locTypeRAI (line 18) | locTypeRAI
  function NewUserLocationInformationWithCGI (line 22) | func NewUserLocationInformationWithCGI(mcc, mnc string, lac, cgi uint16)...
  function NewUserLocationInformationWithSAI (line 41) | func NewUserLocationInformationWithSAI(mcc, mnc string, lac, sac uint16)...
  function NewUserLocationInformationWithRAI (line 60) | func NewUserLocationInformationWithRAI(mcc, mnc string, lac uint16, rac ...
  method UserLocationInformation (line 79) | func (i *IE) UserLocationInformation() ([]byte, error) {
  method MustUserLocationInformation (line 88) | func (i *IE) MustUserLocationInformation() []byte {
  method CGI (line 94) | func (i *IE) CGI() (uint16, error) {
  method MustCGI (line 113) | func (i *IE) MustCGI() uint16 {
  method SAC (line 119) | func (i *IE) SAC() (uint16, error) {
  method MustSAC (line 138) | func (i *IE) MustSAC() uint16 {

FILE: gtpv1/ie/uli_test.go
  function TestUserLocationInformationWithCGI (line 11) | func TestUserLocationInformationWithCGI(t *testing.T) {
  function TestUserLocationInformationWithRAI (line 61) | func TestUserLocationInformationWithRAI(t *testing.T) {
  function TestUserLocationInformationWithSAI (line 87) | func TestUserLocationInformationWithSAI(t *testing.T) {

FILE: gtpv1/logger.go
  function SetLogger (line 24) | func SetLogger(l *log.Logger) {
  function EnableLogging (line 37) | func EnableLogging(l *log.Logger) {
  function DisableLogging (line 46) | func DisableLogging() {
  function setLogger (line 53) | func setLogger(l *log.Logger) {
  function logf (line 64) | func logf(format string, v ...interface{}) {

FILE: gtpv1/message/create-pdp-context-req.go
  type CreatePDPContextRequest (line 12) | type CreatePDPContextRequest struct
    method Marshal (line 167) | func (c *CreatePDPContextRequest) Marshal() ([]byte, error) {
    method MarshalTo (line 177) | func (c *CreatePDPContextRequest) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 443) | func (c *CreatePDPContextRequest) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 561) | func (c *CreatePDPContextRequest) MarshalLen() int {
    method SetLength (line 692) | func (c *CreatePDPContextRequest) SetLength() {
    method MessageTypeName (line 697) | func (c *CreatePDPContextRequest) MessageTypeName() string {
    method TEID (line 702) | func (c *CreatePDPContextRequest) TEID() uint32 {
  function NewCreatePDPContextRequest (line 57) | func NewCreatePDPContextRequest(teid uint32, seq uint16, ies ...*ie.IE) ...
  function ParseCreatePDPContextRequest (line 434) | func ParseCreatePDPContextRequest(b []byte) (*CreatePDPContextRequest, e...

FILE: gtpv1/message/create-pdp-context-req_deprecated.go
  method Serialize (line 12) | func (c *CreatePDPContextRequest) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (c *CreatePDPContextRequest) SerializeTo(b []byte) error {
  function DecodeCreatePDPContextRequest (line 28) | func DecodeCreatePDPContextRequest(b []byte) (*CreatePDPContextRequest, ...
  method DecodeFromBytes (line 36) | func (c *CreatePDPContextRequest) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (c *CreatePDPContextRequest) Len() int {

FILE: gtpv1/message/create-pdp-context-req_test.go
  function TestCreatePDPContextRequest (line 16) | func TestCreatePDPContextRequest(t *testing.T) {

FILE: gtpv1/message/create-pdp-context-res.go
  type CreatePDPContextResponse (line 12) | type CreatePDPContextResponse struct
    method Marshal (line 127) | func (c *CreatePDPContextResponse) Marshal() ([]byte, error) {
    method MarshalTo (line 137) | func (c *CreatePDPContextResponse) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 331) | func (c *CreatePDPContextResponse) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 422) | func (c *CreatePDPContextResponse) MarshalLen() int {
    method SetLength (line 517) | func (c *CreatePDPContextResponse) SetLength() {
    method MessageTypeName (line 522) | func (c *CreatePDPContextResponse) MessageTypeName() string {
    method TEID (line 527) | func (c *CreatePDPContextResponse) TEID() uint32 {
  function NewCreatePDPContextResponse (line 45) | func NewCreatePDPContextResponse(teid uint32, seq uint16, ies ...*ie.IE)...
  function ParseCreatePDPContextResponse (line 322) | func ParseCreatePDPContextResponse(b []byte) (*CreatePDPContextResponse,...

FILE: gtpv1/message/create-pdp-context-res_deprecated.go
  method Serialize (line 12) | func (c *CreatePDPContextResponse) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (c *CreatePDPContextResponse) SerializeTo(b []byte) error {
  function DecodeCreatePDPContextResponse (line 28) | func DecodeCreatePDPContextResponse(b []byte) (*CreatePDPContextResponse...
  method DecodeFromBytes (line 36) | func (c *CreatePDPContextResponse) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (c *CreatePDPContextResponse) Len() int {

FILE: gtpv1/message/create-pdp-context-res_test.go
  function TestCreatePDPContextResponse (line 16) | func TestCreatePDPContextResponse(t *testing.T) {

FILE: gtpv1/message/delete-pdp-context-req.go
  type DeletePDPContextRequest (line 12) | type DeletePDPContextRequest struct
    method Marshal (line 65) | func (d *DeletePDPContextRequest) Marshal() ([]byte, error) {
    method MarshalTo (line 75) | func (d *DeletePDPContextRequest) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 161) | func (d *DeletePDPContextRequest) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 207) | func (d *DeletePDPContextRequest) MarshalLen() int {
    method SetLength (line 248) | func (d *DeletePDPContextRequest) SetLength() {
    method MessageTypeName (line 253) | func (d *DeletePDPContextRequest) MessageTypeName() string {
    method TEID (line 258) | func (d *DeletePDPContextRequest) TEID() uint32 {
  function NewDeletePDPContextRequest (line 27) | func NewDeletePDPContextRequest(teid uint32, seq uint16, ies ...*ie.IE) ...
  function ParseDeletePDPContextRequest (line 152) | func ParseDeletePDPContextRequest(b []byte) (*DeletePDPContextRequest, e...

FILE: gtpv1/message/delete-pdp-context-req_deprecated.go
  method Serialize (line 12) | func (d *DeletePDPContextRequest) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (d *DeletePDPContextRequest) SerializeTo(b []byte) error {
  function DecodeDeletePDPContextRequest (line 28) | func DecodeDeletePDPContextRequest(b []byte) (*DeletePDPContextRequest, ...
  method DecodeFromBytes (line 36) | func (d *DeletePDPContextRequest) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (d *DeletePDPContextRequest) Len() int {

FILE: gtpv1/message/delete-pdp-context-req_test.go
  function TestDeletePDPContextRequest (line 16) | func TestDeletePDPContextRequest(t *testing.T) {

FILE: gtpv1/message/delete-pdp-context-res.go
  type DeletePDPContextResponse (line 12) | type DeletePDPContextResponse struct
    method Marshal (line 56) | func (d *DeletePDPContextResponse) Marshal() ([]byte, error) {
    method MarshalTo (line 66) | func (d *DeletePDPContextResponse) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 134) | func (d *DeletePDPContextResponse) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 174) | func (d *DeletePDPContextResponse) MarshalLen() int {
    method SetLength (line 206) | func (d *DeletePDPContextResponse) SetLength() {
    method MessageTypeName (line 211) | func (d *DeletePDPContextResponse) MessageTypeName() string {
    method TEID (line 216) | func (d *DeletePDPContextResponse) TEID() uint32 {
  function NewDeletePDPContextResponse (line 24) | func NewDeletePDPContextResponse(teid uint32, seq uint16, ies ...*ie.IE)...
  function ParseDeletePDPContextResponse (line 125) | func ParseDeletePDPContextResponse(b []byte) (*DeletePDPContextResponse,...

FILE: gtpv1/message/delete-pdp-context-res_deprecated.go
  method Serialize (line 12) | func (d *DeletePDPContextResponse) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (d *DeletePDPContextResponse) SerializeTo(b []byte) error {
  function DecodeDeletePDPContextResponse (line 28) | func DecodeDeletePDPContextResponse(b []byte) (*DeletePDPContextResponse...
  method DecodeFromBytes (line 36) | func (d *DeletePDPContextResponse) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (d *DeletePDPContextResponse) Len() int {

FILE: gtpv1/message/delete-pdp-context-res_test.go
  function TestDeletePDPContextResponse (line 16) | func TestDeletePDPContextResponse(t *testing.T) {

FILE: gtpv1/message/echo-req.go
  type EchoRequest (line 12) | type EchoRequest struct
    method Marshal (line 41) | func (e *EchoRequest) Marshal() ([]byte, error) {
    method MarshalTo (line 51) | func (e *EchoRequest) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 89) | func (e *EchoRequest) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 117) | func (e *EchoRequest) MarshalLen() int {
    method SetLength (line 134) | func (e *EchoRequest) SetLength() {
    method MessageTypeName (line 139) | func (e *EchoRequest) MessageTypeName() string {
    method TEID (line 144) | func (e *EchoRequest) TEID() uint32 {
  function NewEchoRequest (line 19) | func NewEchoRequest(seq uint16, ies ...*ie.IE) *EchoRequest {
  function ParseEchoRequest (line 80) | func ParseEchoRequest(b []byte) (*EchoRequest, error) {

FILE: gtpv1/message/echo-req_deprecated.go
  method Serialize (line 12) | func (e *EchoRequest) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (e *EchoRequest) SerializeTo(b []byte) error {
  function DecodeEchoRequest (line 28) | func DecodeEchoRequest(b []byte) (*EchoRequest, error) {
  method DecodeFromBytes (line 36) | func (e *EchoRequest) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (e *EchoRequest) Len() int {

FILE: gtpv1/message/echo-req_test.go
  function TestEchoRequest (line 14) | func TestEchoRequest(t *testing.T) {

FILE: gtpv1/message/echo-res.go
  type EchoResponse (line 12) | type EchoResponse struct
    method Marshal (line 44) | func (e *EchoResponse) Marshal() ([]byte, error) {
    method MarshalTo (line 54) | func (e *EchoResponse) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 98) | func (e *EchoResponse) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 130) | func (e *EchoResponse) MarshalLen() int {
    method SetLength (line 151) | func (e *EchoResponse) SetLength() {
    method MessageTypeName (line 156) | func (e *EchoResponse) MessageTypeName() string {
    method TEID (line 161) | func (e *EchoResponse) TEID() uint32 {
  function NewEchoResponse (line 20) | func NewEchoResponse(seq uint16, ies ...*ie.IE) *EchoResponse {
  function ParseEchoResponse (line 89) | func ParseEchoResponse(b []byte) (*EchoResponse, error) {

FILE: gtpv1/message/echo-res_deprecated.go
  method Serialize (line 12) | func (e *EchoResponse) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (e *EchoResponse) SerializeTo(b []byte) error {
  function DecodeEchoResponse (line 28) | func DecodeEchoResponse(b []byte) (*EchoResponse, error) {
  method DecodeFromBytes (line 36) | func (e *EchoResponse) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (e *EchoResponse) Len() int {

FILE: gtpv1/message/echo-res_test.go
  function TestEchoResponse (line 15) | func TestEchoResponse(t *testing.T) {

FILE: gtpv1/message/end-marker.go
  type EndMarker (line 12) | type EndMarker struct
    method Marshal (line 41) | func (e *EndMarker) Marshal() ([]byte, error) {
    method MarshalTo (line 51) | func (e *EndMarker) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 89) | func (e *EndMarker) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 117) | func (e *EndMarker) MarshalLen() int {
    method SetLength (line 134) | func (e *EndMarker) SetLength() {
    method MessageTypeName (line 139) | func (e *EndMarker) MessageTypeName() string {
    method TEID (line 144) | func (e *EndMarker) TEID() uint32 {
  function NewEndMarker (line 19) | func NewEndMarker(ies ...*ie.IE) *EndMarker {
  function ParseEndMarker (line 80) | func ParseEndMarker(b []byte) (*EndMarker, error) {

FILE: gtpv1/message/end-marker_test.go
  function TestEndMarker (line 14) | func TestEndMarker(t *testing.T) {

FILE: gtpv1/message/error-indication.go
  type ErrorIndication (line 10) | type ErrorIndication struct
    method Marshal (line 45) | func (e *ErrorIndication) Marshal() ([]byte, error) {
    method MarshalTo (line 55) | func (e *ErrorIndication) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 105) | func (e *ErrorIndication) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 139) | func (e *ErrorIndication) MarshalLen() int {
    method SetLength (line 162) | func (e *ErrorIndication) SetLength() {
    method MessageTypeName (line 167) | func (e *ErrorIndication) MessageTypeName() string {
    method TEID (line 172) | func (e *ErrorIndication) TEID() uint32 {
  function NewErrorIndication (line 19) | func NewErrorIndication(teid uint32, seq uint16, ies ...*ie.IE) *ErrorIn...
  function ParseErrorIndication (line 96) | func ParseErrorIndication(b []byte) (*ErrorIndication, error) {

FILE: gtpv1/message/error-indication_deprecated.go
  method Serialize (line 12) | func (e *ErrorIndication) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (e *ErrorIndication) SerializeTo(b []byte) error {
  function DecodeErrorIndication (line 28) | func DecodeErrorIndication(b []byte) (*ErrorIndication, error) {
  method DecodeFromBytes (line 36) | func (e *ErrorIndication) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (e *ErrorIndication) Len() int {

FILE: gtpv1/message/error-indication_test.go
  function TestErrorIndication (line 15) | func TestErrorIndication(t *testing.T) {

FILE: gtpv1/message/errors.go
  type InvalidTypeError (line 21) | type InvalidTypeError struct
    method Error (line 26) | func (e *InvalidTypeError) Error() string {

FILE: gtpv1/message/extension-header.go
  constant ExtHeaderTypeNoMoreExtensionHeaders (line 11) | ExtHeaderTypeNoMoreExtensionHeaders                 uint8 = 0b00000000
  constant ExtHeaderTypeMBMSSupportIndication (line 12) | ExtHeaderTypeMBMSSupportIndication                  uint8 = 0b00000001
  constant ExtHeaderTypeMSInfoChangeReportingSupportIndication (line 13) | ExtHeaderTypeMSInfoChangeReportingSupportIndication uint8 = 0b00000010
  constant ExtHeaderTypeLongPDCPPDUNumber (line 14) | ExtHeaderTypeLongPDCPPDUNumber                      uint8 = 0b00000011
  constant ExtHeaderTypeServiceClassIndicator (line 15) | ExtHeaderTypeServiceClassIndicator                  uint8 = 0b00100000
  constant ExtHeaderTypeUDPPort (line 16) | ExtHeaderTypeUDPPort                                uint8 = 0b01000000
  constant ExtHeaderTypeRANContainer (line 17) | ExtHeaderTypeRANContainer                           uint8 = 0b10000001
  constant ExtHeaderTypeLongPDCPPDUNumberRequired (line 18) | ExtHeaderTypeLongPDCPPDUNumberRequired              uint8 = 0b10000010
  constant ExtHeaderTypeXwRANContainer (line 19) | ExtHeaderTypeXwRANContainer                         uint8 = 0b10000011
  constant ExtHeaderTypeNRRANContainer (line 20) | ExtHeaderTypeNRRANContainer                         uint8 = 0b10000100
  constant ExtHeaderTypePDUSessionContainer (line 21) | ExtHeaderTypePDUSessionContainer                    uint8 = 0b10000101
  constant ExtHeaderTypePDCPPDUNumber (line 22) | ExtHeaderTypePDCPPDUNumber                          uint8 = 0b11000000
  constant ExtHeaderTypeSuspendRequest (line 23) | ExtHeaderTypeSuspendRequest                         uint8 = 0b11000001
  constant ExtHeaderTypeSuspendResponse (line 24) | ExtHeaderTypeSuspendResponse                        uint8 = 0b11000010
  type ExtensionHeader (line 28) | type ExtensionHeader struct
    method Marshal (line 52) | func (e *ExtensionHeader) Marshal() ([]byte, error) {
    method MarshalTo (line 61) | func (e *ExtensionHeader) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 88) | func (e *ExtensionHeader) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 132) | func (e *ExtensionHeader) MarshalLen() int {
    method SetLength (line 137) | func (e *ExtensionHeader) SetLength() {
    method String (line 142) | func (e *ExtensionHeader) String() string {
    method IsComprehensionRequired (line 153) | func (e *ExtensionHeader) IsComprehensionRequired() bool {
  function NewExtensionHeader (line 40) | func NewExtensionHeader(typ uint8, content []byte, nextType uint8) *Exte...
  function ParseExtensionHeader (line 79) | func ParseExtensionHeader(b []byte) (*ExtensionHeader, error) {
  function ParseMultiExtensionHeaders (line 110) | func ParseMultiExtensionHeaders(b []byte) ([]*ExtensionHeader, error) {
  function pad4Len (line 157) | func pad4Len(n int) int {

FILE: gtpv1/message/generic.go
  type Generic (line 15) | type Generic struct
    method Marshal (line 32) | func (g *Generic) Marshal() ([]byte, error) {
    method MarshalTo (line 42) | func (g *Generic) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 73) | func (g *Generic) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 91) | func (g *Generic) MarshalLen() int {
    method SetLength (line 105) | func (g *Generic) SetLength() {
    method MessageTypeName (line 110) | func (g *Generic) MessageTypeName() string {
    method TEID (line 115) | func (g *Generic) TEID() uint32 {
    method AddIE (line 120) | func (g *Generic) AddIE(ie ...*ie.IE) {
  function NewGeneric (line 21) | func NewGeneric(msgType uint8, teid uint32, seq uint16, ie ...*ie.IE) *G...
  function ParseGeneric (line 64) | func ParseGeneric(b []byte) (*Generic, error) {

FILE: gtpv1/message/generic_deprecated.go
  method Serialize (line 12) | func (g *Generic) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (g *Generic) SerializeTo(b []byte) error {
  function DecodeGeneric (line 28) | func DecodeGeneric(b []byte) (*Generic, error) {
  method DecodeFromBytes (line 36) | func (g *Generic) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (g *Generic) Len() int {

FILE: gtpv1/message/generic_test.go
  function TestGeneric (line 14) | func TestGeneric(t *testing.T) {

FILE: gtpv1/message/header.go
  type Header (line 13) | type Header struct
    method Marshal (line 62) | func (h *Header) Marshal() ([]byte, error) {
    method MarshalTo (line 71) | func (h *Header) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 122) | func (h *Header) UnmarshalBinary(b []byte) error {
    method SetTEID (line 181) | func (h *Header) SetTEID(teid uint32) {
    method Sequence (line 187) | func (h *Header) Sequence() uint16 {
    method HasSequence (line 192) | func (h *Header) HasSequence() bool {
    method SetSequenceNumber (line 197) | func (h *Header) SetSequenceNumber(seq uint16) {
    method WithSequenceNumber (line 204) | func (h *Header) WithSequenceNumber(seq uint16) *Header {
    method HasNPDUNumber (line 210) | func (h *Header) HasNPDUNumber() bool {
    method SetNPDUNumber (line 215) | func (h *Header) SetNPDUNumber(npdu uint8) {
    method WithNPDUNumber (line 222) | func (h *Header) WithNPDUNumber(npdu uint8) *Header {
    method HasExtensionHeader (line 228) | func (h *Header) HasExtensionHeader() bool {
    method SetNextExtensionHeaderType (line 233) | func (h *Header) SetNextExtensionHeaderType(exhType uint8) {
    method WithExtensionHeaders (line 239) | func (h *Header) WithExtensionHeaders(extHdrs ...*ExtensionHeader) *He...
    method MarshalLen (line 245) | func (h *Header) MarshalLen() int {
    method SetLength (line 261) | func (h *Header) SetLength() {
    method Version (line 266) | func (h *Header) Version() int {
    method MessageType (line 271) | func (h *Header) MessageType() uint8 {
    method String (line 276) | func (h *Header) String() string {
    method AddExtensionHeaders (line 296) | func (h *Header) AddExtensionHeaders(extHdrs ...*ExtensionHeader) error {
  function NewHeader (line 26) | func NewHeader(flags, mtype uint8, teid uint32, seqnum uint16, payload [...
  function NewHeaderWithNPDUNumber (line 41) | func NewHeaderWithNPDUNumber(flags, mtype uint8, teid uint32, seqnum uin...
  function NewHeaderWithExtensionHeaders (line 48) | func NewHeaderWithExtensionHeaders(flags, mtype uint8, teid uint32, seqn...
  function NewHeaderFlags (line 55) | func NewHeaderFlags(v, p, e, s, n int) uint8 {
  function ParseHeader (line 113) | func ParseHeader(b []byte) (*Header, error) {

FILE: gtpv1/message/header_deprecated.go
  method Serialize (line 12) | func (h *Header) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (h *Header) SerializeTo(b []byte) error {
  function DecodeHeader (line 28) | func DecodeHeader(b []byte) (*Header, error) {
  method DecodeFromBytes (line 36) | func (h *Header) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (h *Header) Len() int {

FILE: gtpv1/message/header_test.go
  function TestHeader (line 14) | func TestHeader(t *testing.T) {
  function TestHeaderErrorDetection (line 211) | func TestHeaderErrorDetection(t *testing.T) {

FILE: gtpv1/message/message.go
  constant _ (line 20) | _ uint8 = iota
  constant MsgTypeEchoRequest (line 21) | MsgTypeEchoRequest
  constant MsgTypeEchoResponse (line 22) | MsgTypeEchoResponse
  constant MsgTypeVersionNotSupported (line 23) | MsgTypeVersionNotSupported
  constant MsgTypeNodeAliveRequest (line 24) | MsgTypeNodeAliveRequest
  constant MsgTypeNodeAliveResponse (line 25) | MsgTypeNodeAliveResponse
  constant MsgTypeRedirectionRequest (line 26) | MsgTypeRedirectionRequest
  constant MsgTypeRedirectionResponse (line 27) | MsgTypeRedirectionResponse
  constant _ (line 28) | _
  constant _ (line 29) | _
  constant _ (line 30) | _
  constant _ (line 31) | _
  constant _ (line 32) | _
  constant _ (line 33) | _
  constant _ (line 34) | _
  constant _ (line 35) | _
  constant MsgTypeCreatePDPContextRequest (line 36) | MsgTypeCreatePDPContextRequest
  constant MsgTypeCreatePDPContextResponse (line 37) | MsgTypeCreatePDPContextResponse
  constant MsgTypeUpdatePDPContextRequest (line 38) | MsgTypeUpdatePDPContextRequest
  constant MsgTypeUpdatePDPContextResponse (line 39) | MsgTypeUpdatePDPContextResponse
  constant MsgTypeDeletePDPContextRequest (line 40) | MsgTypeDeletePDPContextRequest
  constant MsgTypeDeletePDPContextResponse (line 41) | MsgTypeDeletePDPContextResponse
  constant MsgTypeCreateAAPDPContextRequest (line 42) | MsgTypeCreateAAPDPContextRequest
  constant MsgTypeCreateAAPDPContextResponse (line 43) | MsgTypeCreateAAPDPContextResponse
  constant MsgTypeDeleteAAPDPContextRequest (line 44) | MsgTypeDeleteAAPDPContextRequest
  constant MsgTypeDeleteAAPDPContextResponse (line 45) | MsgTypeDeleteAAPDPContextResponse
  constant MsgTypeErrorIndication (line 46) | MsgTypeErrorIndication
  constant MsgTypePDUNotificationRequest (line 47) | MsgTypePDUNotificationRequest
  constant MsgTypePDUNotificationResponse (line 48) | MsgTypePDUNotificationResponse
  constant MsgTypePDUNotificationRejectRequest (line 49) | MsgTypePDUNotificationRejectRequest
  constant MsgTypePDUNotificationRejectResponse (line 50) | MsgTypePDUNotificationRejectResponse
  constant MsgTypeSupportedExtensionHeaderNotification (line 51) | MsgTypeSupportedExtensionHeaderNotification
  constant MsgTypeSendRoutingInfoRequest (line 52) | MsgTypeSendRoutingInfoRequest
  constant MsgTypeSendRoutingInfoResponse (line 53) | MsgTypeSendRoutingInfoResponse
  constant MsgTypeFailureReportRequest (line 54) | MsgTypeFailureReportRequest
  constant MsgTypeFailureReportResponse (line 55) | MsgTypeFailureReportResponse
  constant MsgTypeNoteMSPresentRequest (line 56) | MsgTypeNoteMSPresentRequest
  constant MsgTypeNoteMSPresentResponse (line 57) | MsgTypeNoteMSPresentResponse
  constant _ (line 58) | _
  constant _ (line 59) | _
  constant _ (line 60) | _
  constant _ (line 61) | _
  constant _ (line 62) | _
  constant _ (line 63) | _
  constant _ (line 64) | _
  constant _ (line 65) | _
  constant _ (line 66) | _
  constant _ (line 67) | _
  constant _ (line 68) | _
  constant _ (line 69) | _
  constant _ (line 70) | _
  constant _ (line 71) | _
  constant _ (line 72) | _
  constant _ (line 73) | _
  constant _ (line 74) | _
  constant _ (line 75) | _
  constant MsgTypeIdentificationRequest (line 76) | MsgTypeIdentificationRequest
  constant MsgTypeIdentificationResponse (line 77) | MsgTypeIdentificationResponse
  constant MsgTypeSGSNContextRequest (line 78) | MsgTypeSGSNContextRequest
  constant MsgTypeSGSNContextResponse (line 79) | MsgTypeSGSNContextResponse
  constant MsgTypeSGSNContextAcknowledge (line 80) | MsgTypeSGSNContextAcknowledge
  constant MsgTypeDataRecordTransferRequest (line 81) | MsgTypeDataRecordTransferRequest  uint8 = 240
  constant MsgTypeDataRecordTransferResponse (line 82) | MsgTypeDataRecordTransferResponse uint8 = 241
  constant MsgTypeEndMarker (line 83) | MsgTypeEndMarker                  uint8 = 254
  constant MsgTypeTPDU (line 84) | MsgTypeTPDU                       uint8 = 255
  type Message (line 88) | type Message interface
  function Marshal (line 107) | func Marshal(g Message) ([]byte, error) {
  function Parse (line 117) | func Parse(b []byte) (Message, error) {
  function Prettify (line 221) | func Prettify(m Message) string {
  type field (line 235) | type field struct
  function prettifyFields (line 240) | func prettifyFields(fields []*field) []string {
  function prettifyIE (line 268) | func prettifyIE(name string, i *ie.IE) string {

FILE: gtpv1/message/message_deprecated.go
  function Serialize (line 12) | func Serialize(m Message) ([]byte, error) {
  function Decode (line 20) | func Decode(b []byte) (Message, error) {

FILE: gtpv1/message/message_fuzz_test.go
  function FuzzParse (line 9) | func FuzzParse(f *testing.F) {
  function FuzzHeaderParse (line 17) | func FuzzHeaderParse(f *testing.F) {

FILE: gtpv1/message/supported-extension-header-notification.go
  type SupportedExtensionHeaderNotification (line 12) | type SupportedExtensionHeaderNotification struct
    method Marshal (line 41) | func (e *SupportedExtensionHeaderNotification) Marshal() ([]byte, erro...
    method MarshalTo (line 51) | func (e *SupportedExtensionHeaderNotification) MarshalTo(b []byte) err...
    method UnmarshalBinary (line 89) | func (e *SupportedExtensionHeaderNotification) UnmarshalBinary(b []byt...
    method MarshalLen (line 119) | func (e *SupportedExtensionHeaderNotification) MarshalLen() int {
    method SetLength (line 136) | func (e *SupportedExtensionHeaderNotification) SetLength() {
    method MessageTypeName (line 141) | func (e *SupportedExtensionHeaderNotification) MessageTypeName() string {
    method TEID (line 146) | func (e *SupportedExtensionHeaderNotification) TEID() uint32 {
  function NewSupportedExtensionHeaderNotification (line 19) | func NewSupportedExtensionHeaderNotification(teid uint32, seq uint16, ie...
  function ParseSupportedExtensionHeaderNotification (line 80) | func ParseSupportedExtensionHeaderNotification(b []byte) (*SupportedExte...

FILE: gtpv1/message/supported-extension-header-notification_test.go
  function TestSupportedExtensionHeaderNotification (line 15) | func TestSupportedExtensionHeaderNotification(t *testing.T) {

FILE: gtpv1/message/t-pdu.go
  type TPDU (line 8) | type TPDU struct
    method Marshal (line 37) | func (t *TPDU) Marshal() ([]byte, error) {
    method MarshalTo (line 47) | func (t *TPDU) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 66) | func (t *TPDU) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 77) | func (t *TPDU) MarshalLen() int {
    method SetLength (line 82) | func (t *TPDU) SetLength() {
    method MessageTypeName (line 87) | func (t *TPDU) MessageTypeName() string {
    method TEID (line 92) | func (t *TPDU) TEID() uint32 {
    method Decapsulate (line 97) | func (t *TPDU) Decapsulate() []byte {
  function NewTPDU (line 13) | func NewTPDU(teid uint32, payload []byte) *TPDU {
  function NewTPDUWithSequence (line 21) | func NewTPDUWithSequence(teid uint32, seq uint16, payload []byte) *TPDU {
  function NewTPDUWithExtentionHeader (line 29) | func NewTPDUWithExtentionHeader(teid uint32, payload []byte, extHdrs ......
  function ParseTPDU (line 57) | func ParseTPDU(b []byte) (*TPDU, error) {

FILE: gtpv1/message/t-pdu_deprecated.go
  method Serialize (line 12) | func (t *TPDU) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (t *TPDU) SerializeTo(b []byte) error {
  function DecodeTPDU (line 28) | func DecodeTPDU(b []byte) (*TPDU, error) {
  method DecodeFromBytes (line 36) | func (t *TPDU) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (t *TPDU) Len() int {

FILE: gtpv1/message/t-pdu_test.go
  function TestTPDU (line 14) | func TestTPDU(t *testing.T) {

FILE: gtpv1/message/update-pdp-context-req.go
  type UpdatePDPContextRequest (line 12) | type UpdatePDPContextRequest struct
    method Marshal (line 137) | func (u *UpdatePDPContextRequest) Marshal() ([]byte, error) {
    method MarshalTo (line 147) | func (u *UpdatePDPContextRequest) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 365) | func (u *UpdatePDPContextRequest) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 461) | func (u *UpdatePDPContextRequest) MarshalLen() int {
    method SetLength (line 568) | func (u *UpdatePDPContextRequest) SetLength() {
    method MessageTypeName (line 573) | func (u *UpdatePDPContextRequest) MessageTypeName() string {
    method TEID (line 578) | func (u *UpdatePDPContextRequest) TEID() uint32 {
  function NewUpdatePDPContextRequest (line 49) | func NewUpdatePDPContextRequest(teid uint32, seq uint16, ies ...*ie.IE) ...
  function ParseUpdatePDPContextRequest (line 356) | func ParseUpdatePDPContextRequest(b []byte) (*UpdatePDPContextRequest, e...

FILE: gtpv1/message/update-pdp-context-req_deprecated.go
  method Serialize (line 12) | func (u *UpdatePDPContextRequest) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (u *UpdatePDPContextRequest) SerializeTo(b []byte) error {
  function DecodeUpdatePDPContextRequest (line 28) | func DecodeUpdatePDPContextRequest(b []byte) (*UpdatePDPContextRequest, ...
  method DecodeFromBytes (line 36) | func (u *UpdatePDPContextRequest) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (u *UpdatePDPContextRequest) Len() int {

FILE: gtpv1/message/update-pdp-context-req_test.go
  function TestUpdatePDPContextRequest (line 15) | func TestUpdatePDPContextRequest(t *testing.T) {

FILE: gtpv1/message/update-pdp-context-res.go
  type UpdatePDPContextResponse (line 12) | type UpdatePDPContextResponse struct
    method Marshal (line 109) | func (u *UpdatePDPContextResponse) Marshal() ([]byte, error) {
    method MarshalTo (line 119) | func (u *UpdatePDPContextResponse) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 277) | func (u *UpdatePDPContextResponse) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 355) | func (u *UpdatePDPContextResponse) MarshalLen() int {
    method SetLength (line 432) | func (u *UpdatePDPContextResponse) SetLength() {
    method MessageTypeName (line 437) | func (u *UpdatePDPContextResponse) MessageTypeName() string {
    method TEID (line 442) | func (u *UpdatePDPContextResponse) TEID() uint32 {
  function NewUpdatePDPContextResponse (line 39) | func NewUpdatePDPContextResponse(teid uint32, seq uint16, ies ...*ie.IE)...
  function ParseUpdatePDPContextResponse (line 268) | func ParseUpdatePDPContextResponse(b []byte) (*UpdatePDPContextResponse,...

FILE: gtpv1/message/update-pdp-context-res_deprecated.go
  method Serialize (line 12) | func (u *UpdatePDPContextResponse) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (u *UpdatePDPContextResponse) SerializeTo(b []byte) error {
  function DecodeUpdatePDPContextResponse (line 28) | func DecodeUpdatePDPContextResponse(b []byte) (*UpdatePDPContextResponse...
  method DecodeFromBytes (line 36) | func (u *UpdatePDPContextResponse) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (u *UpdatePDPContextResponse) Len() int {

FILE: gtpv1/message/update-pdp-context-res_test.go
  function TestUpdatePDPContextResponse (line 16) | func TestUpdatePDPContextResponse(t *testing.T) {

FILE: gtpv1/message/version-not-supported.go
  type VersionNotSupported (line 12) | type VersionNotSupported struct
    method Marshal (line 35) | func (v *VersionNotSupported) Marshal() ([]byte, error) {
    method MarshalTo (line 45) | func (v *VersionNotSupported) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 76) | func (v *VersionNotSupported) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 101) | func (v *VersionNotSupported) MarshalLen() int {
    method SetLength (line 114) | func (v *VersionNotSupported) SetLength() {
    method MessageTypeName (line 119) | func (v *VersionNotSupported) MessageTypeName() string {
    method TEID (line 124) | func (v *VersionNotSupported) TEID() uint32 {
  function NewVersionNotSupported (line 18) | func NewVersionNotSupported(teid uint32, seq uint16, ie ...*ie.IE) *Vers...
  function ParseVersionNotSupported (line 67) | func ParseVersionNotSupported(b []byte) (*VersionNotSupported, error) {

FILE: gtpv1/message/version-not-supported_deprecated.go
  method Serialize (line 12) | func (v *VersionNotSupported) Serialize() ([]byte, error) {
  method SerializeTo (line 20) | func (v *VersionNotSupported) SerializeTo(b []byte) error {
  function DecodeVersionNotSupported (line 28) | func DecodeVersionNotSupported(b []byte) (*VersionNotSupported, error) {
  method DecodeFromBytes (line 36) | func (v *VersionNotSupported) DecodeFromBytes(b []byte) error {
  method Len (line 44) | func (v *VersionNotSupported) Len() int {

FILE: gtpv1/message/version-not-supported_test.go
  function TestVersionNotSupported (line 14) | func TestVersionNotSupported(t *testing.T) {

FILE: gtpv1/relay.go
  type Relay (line 17) | type Relay struct
    method Run (line 42) | func (r *Relay) Run() {
    method Close (line 99) | func (r *Relay) Close() error {
    method closed (line 110) | func (r *Relay) closed() <-chan struct{} {
    method AddPeer (line 117) | func (r *Relay) AddPeer(teidIn, teidOut uint32, raddr net.Addr) {
    method getPeer (line 124) | func (r *Relay) getPeer(teid uint32) (*peer, bool) {
  function NewRelay (line 27) | func NewRelay(leftConn, rightConn *UPlaneConn) *Relay {

FILE: gtpv1/relay_test.go
  function TestRelay (line 15) | func TestRelay(t *testing.T) {

FILE: gtpv1/testutils/testutils.go
  type Serializable (line 16) | type Serializable interface
  type TestCase (line 22) | type TestCase struct
  type ParseFunc (line 29) | type ParseFunc
  function Run (line 38) | func Run(t *testing.T, cases []TestCase, decode ParseFunc) {

FILE: gtpv1/tunnel.go
  type peer (line 12) | type peer struct
  method RelayTo (line 21) | func (u *UPlaneConn) RelayTo(c *UPlaneConn, teidIn, teidOut uint32, radd...
  method CloseRelay (line 36) | func (u *UPlaneConn) CloseRelay(teidIn uint32) error {

FILE: gtpv1/tunnel_linux.go
  type Role (line 16) | type Role
  constant RoleGGSN (line 20) | RoleGGSN Role = iota
  constant RoleSGSN (line 21) | RoleSGSN
  method EnableKernelGTP (line 40) | func (u *UPlaneConn) EnableKernelGTP(devname string, role Role) error {
  method AddTunnel (line 88) | func (u *UPlaneConn) AddTunnel(peerIP, msIP net.IP, otei, itei uint32) e...
  method AddTunnelOverride (line 109) | func (u *UPlaneConn) AddTunnelOverride(peerIP, msIP net.IP, otei, itei u...
  method DelTunnelByITEI (line 127) | func (u *UPlaneConn) DelTunnelByITEI(itei uint32) error {
  method DelTunnelByMSAddress (line 146) | func (u *UPlaneConn) DelTunnelByMSAddress(msIP net.IP) error {

FILE: gtpv1/u-conn.go
  type tpduSet (line 28) | type tpduSet struct
  type pktConn (line 35) | type pktConn interface
  type pktConn4 (line 52) | type pktConn4 struct
    method ReadFrom (line 65) | func (pkt pktConn4) ReadFrom(b []byte) (n int, src net.Addr, err error) {
    method WriteTo (line 71) | func (pkt pktConn4) WriteTo(b []byte, dst net.Addr) (n int, err error) {
    method setDSCPECN (line 76) | func (pkt pktConn4) setDSCPECN(dscpecs int) error {
    method DSCPECN (line 82) | func (pkt pktConn4) DSCPECN() (int, error) {
    method WriteToWithDSCPECN (line 88) | func (pkt pktConn4) WriteToWithDSCPECN(p []byte, addr net.Addr, dscpec...
    method File (line 110) | func (pkt pktConn4) File() (f *os.File, err error) {
  type pktConn6 (line 114) | type pktConn6 struct
    method ReadFrom (line 127) | func (pkt pktConn6) ReadFrom(b []byte) (n int, src net.Addr, err error) {
    method WriteTo (line 133) | func (pkt pktConn6) WriteTo(b []byte, dst net.Addr) (n int, err error) {
    method setDSCPECN (line 138) | func (pkt pktConn6) setDSCPECN(dscpecs int) error {
    method DSCPECN (line 144) | func (pkt pktConn6) DSCPECN() (int, error) {
    method WriteToWithDSCPECN (line 150) | func (pkt pktConn6) WriteToWithDSCPECN(p []byte, addr net.Addr, dscpec...
    method File (line 172) | func (pkt pktConn6) File() (f *os.File, err error) {
  function newPktConn (line 177) | func newPktConn(laddr net.Addr) (pktConn, error) {
  type UPlaneConn (line 205) | type UPlaneConn struct
    method ListenAndServe (line 319) | func (u *UPlaneConn) ListenAndServe(ctx context.Context) error {
    method listenAndServe (line 332) | func (u *UPlaneConn) listenAndServe(ctx context.Context) error {
    method serve (line 337) | func (u *UPlaneConn) serve(ctx context.Context) error {
    method ReadFrom (line 448) | func (u *UPlaneConn) ReadFrom(p []byte) (n int, addr net.Addr, err err...
    method ReadFromGTP (line 457) | func (u *UPlaneConn) ReadFromGTP(p []byte) (n int, addr net.Addr, teid...
    method WriteTo (line 478) | func (u *UPlaneConn) WriteTo(p []byte, addr net.Addr) (n int, err erro...
    method WriteToWithDSCPECN (line 489) | func (u *UPlaneConn) WriteToWithDSCPECN(p []byte, addr net.Addr, dscpe...
    method WriteToGTP (line 494) | func (u *UPlaneConn) WriteToGTP(teid uint32, p []byte, addr net.Addr) ...
    method closed (line 508) | func (u *UPlaneConn) closed() <-chan struct{} {
    method Close (line 514) | func (u *UPlaneConn) Close() error {
    method LocalAddr (line 524) | func (u *UPlaneConn) LocalAddr() net.Addr {
    method SetDeadline (line 543) | func (u *UPlaneConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 550) | func (u *UPlaneConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 559) | func (u *UPlaneConn) SetWriteDeadline(t time.Time) error {
    method AddHandler (line 577) | func (u *UPlaneConn) AddHandler(msgType uint8, fn HandlerFunc) {
    method AddHandlers (line 584) | func (u *UPlaneConn) AddHandlers(funcs map[uint8]HandlerFunc) {
    method handleMessage (line 590) | func (u *UPlaneConn) handleMessage(senderAddr net.Addr, msg message.Me...
    method EchoRequest (line 604) | func (u *UPlaneConn) EchoRequest(raddr net.Addr) error {
    method EchoResponse (line 617) | func (u *UPlaneConn) EchoResponse(raddr net.Addr) error {
    method ErrorIndication (line 630) | func (u *UPlaneConn) ErrorIndication(raddr net.Addr, received message....
    method RespondTo (line 655) | func (u *UPlaneConn) RespondTo(raddr net.Addr, received, toBeSent mess...
    method Restarts (line 669) | func (u *UPlaneConn) Restarts() uint8 {
    method NewFTEID (line 682) | func (u *UPlaneConn) NewFTEID(ifType uint8, v4, v6 string) (fteidIE *v...
    method EnableErrorIndication (line 742) | func (u *UPlaneConn) EnableErrorIndication() {
    method DisableErrorIndication (line 754) | func (u *UPlaneConn) DisableErrorIndication() {
  type KernelGTP (line 224) | type KernelGTP struct
  function NewUPlaneConn (line 231) | func NewUPlaneConn(laddr net.Addr) *UPlaneConn {
  function DialUPlane (line 246) | func DialUPlane(ctx context.Context, laddr, raddr net.Addr) (*UPlaneConn...
  function generateRandomUint32 (line 711) | func generateRandomUint32() uint32 {
  type iteiMap (line 720) | type iteiMap struct
    method tryStore (line 728) | func (t *iteiMap) tryStore(itei uint32, ts time.Time) bool {
    method delete (line 733) | func (t *iteiMap) delete(itei uint32) {
  function newiteiMap (line 724) | func newiteiMap() *iteiMap {

FILE: gtpv1/u-conn_test.go
  type testVal (line 18) | type testVal struct
  function setup (line 24) | func setup(ctx context.Context) (cliConn, srvConn *gtpv1.UPlaneConn, err...
  function TestClientWrite (line 53) | func TestClientWrite(t *testing.T) {

FILE: gtpv1/utils.go
  function Encapsulate (line 10) | func Encapsulate(teid uint32, payload []byte) *message.TPDU {
  function EncapsulateWithExtensionHeader (line 17) | func EncapsulateWithExtensionHeader(teid uint32, payload []byte, extHdrs...
  function Decapsulate (line 23) | func Decapsulate(b []byte) (uint32, []byte, error) {
  function DecapsulateWithExtensionHeader (line 38) | func DecapsulateWithExtensionHeader(b []byte) (uint32, []byte, []*messag...

FILE: gtpv2/bearer.go
  type QoSProfile (line 12) | type QoSProfile struct
  type Bearer (line 22) | type Bearer struct
    method RemoteAddress (line 40) | func (b *Bearer) RemoteAddress() net.Addr {
    method SetRemoteAddress (line 45) | func (b *Bearer) SetRemoteAddress(raddr net.Addr) {
    method IncomingTEID (line 50) | func (b *Bearer) IncomingTEID() uint32 {
    method SetIncomingTEID (line 55) | func (b *Bearer) SetIncomingTEID(teid uint32) {
    method OutgoingTEID (line 60) | func (b *Bearer) OutgoingTEID() uint32 {
    method SetOutgoingTEID (line 65) | func (b *Bearer) SetOutgoingTEID(teid uint32) {
  function NewBearer (line 33) | func NewBearer(ebi uint8, apn string, qos *QoSProfile) *Bearer {

FILE: gtpv2/conn.go
  type Conn (line 30) | type Conn struct
    method ListenAndServe (line 137) | func (c *Conn) ListenAndServe(ctx context.Context) error {
    method Listen (line 146) | func (c *Conn) Listen(ctx context.Context) error {
    method listenAndServe (line 157) | func (c *Conn) listenAndServe(ctx context.Context) error {
    method closed (line 162) | func (c *Conn) closed() <-chan struct{} {
    method Serve (line 167) | func (c *Conn) Serve(ctx context.Context) error {
    method ReadFrom (line 218) | func (c *Conn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
    method WriteTo (line 227) | func (c *Conn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
    method Close (line 233) | func (c *Conn) Close() error {
    method LocalAddr (line 243) | func (c *Conn) LocalAddr() net.Addr {
    method SetDeadline (line 262) | func (c *Conn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 269) | func (c *Conn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 278) | func (c *Conn) SetWriteDeadline(t time.Time) error {
    method AddHandler (line 298) | func (c *Conn) AddHandler(msgType uint8, fn HandlerFunc) {
    method AddHandlers (line 307) | func (c *Conn) AddHandlers(funcs map[uint8]HandlerFunc) {
    method handleMessage (line 313) | func (c *Conn) handleMessage(senderAddr net.Addr, msg message.Message)...
    method EnableValidation (line 344) | func (c *Conn) EnableValidation() {
    method DisableValidation (line 354) | func (c *Conn) DisableValidation() {
    method validate (line 360) | func (c *Conn) validate(senderAddr net.Addr, msg message.Message) error {
    method SendMessageTo (line 380) | func (c *Conn) SendMessageTo(msg message.Message, addr net.Addr) (uint...
    method IncSequence (line 398) | func (c *Conn) IncSequence() uint32 {
    method DecSequence (line 412) | func (c *Conn) DecSequence() uint32 {
    method SequenceNumber (line 421) | func (c *Conn) SequenceNumber() uint32 {
    method EchoRequest (line 429) | func (c *Conn) EchoRequest(raddr net.Addr) (uint32, error) {
    method EchoResponse (line 440) | func (c *Conn) EchoResponse(raddr net.Addr, req message.Message) error {
    method VersionNotSupportedIndication (line 451) | func (c *Conn) VersionNotSupportedIndication(raddr net.Addr, req messa...
    method ParseCreateSession (line 461) | func (c *Conn) ParseCreateSession(raddr net.Addr, ies ...*ie.IE) (*Ses...
    method CreateSession (line 595) | func (c *Conn) CreateSession(raddr net.Addr, ie ...*ie.IE) (*Session, ...
    method DeleteSession (line 613) | func (c *Conn) DeleteSession(teid uint32, sess *Session, ie ...*ie.IE)...
    method ModifyBearer (line 624) | func (c *Conn) ModifyBearer(teid uint32, sess *Session, ie ...*ie.IE) ...
    method DeleteBearer (line 635) | func (c *Conn) DeleteBearer(teid uint32, sess *Session, ie ...*ie.IE) ...
    method RespondTo (line 649) | func (c *Conn) RespondTo(raddr net.Addr, received, toBeSent message.Me...
    method GetSessionByTEID (line 664) | func (c *Conn) GetSessionByTEID(teid uint32, peer net.Addr) (*Session,...
    method GetSessionByIMSI (line 676) | func (c *Conn) GetSessionByIMSI(imsi string) (*Session, error) {
    method GetIMSIByTEID (line 684) | func (c *Conn) GetIMSIByTEID(teid uint32, peer net.Addr) (string, erro...
    method RegisterSession (line 699) | func (c *Conn) RegisterSession(itei uint32, session *Session) {
    method RemoveSession (line 707) | func (c *Conn) RemoveSession(session *Session) {
    method RemoveSessionByIMSI (line 730) | func (c *Conn) RemoveSessionByIMSI(imsi string) {
    method NewSenderFTEID (line 748) | func (c *Conn) NewSenderFTEID(v4, v6 string) (fteidIE *ie.IE) {
    method Sessions (line 786) | func (c *Conn) Sessions() []*Session {
    method SessionCount (line 799) | func (c *Conn) SessionCount() int {
    method BearerCount (line 815) | func (c *Conn) BearerCount() int {
  function NewConn (line 56) | func NewConn(laddr net.Addr, localIfType, counter uint8) *Conn {
  function Dial (line 77) | func Dial(ctx context.Context, laddr, raddr net.Addr, localIfType, count...
  function generateRandomUint32 (line 776) | func generateRandomUint32() uint32 {
  type imsiSessionMap (line 828) | type imsiSessionMap struct
    method store (line 836) | func (i *imsiSessionMap) store(imsi string, session *Session) {
    method load (line 840) | func (i *imsiSessionMap) load(imsi string) (*Session, bool) {
    method delete (line 848) | func (i *imsiSessionMap) delete(imsi string) {
    method rangeWithFunc (line 852) | func (i *imsiSessionMap) rangeWithFunc(fn func(imsi, session interface...
  function newimsiSessionMap (line 832) | func newimsiSessionMap() *imsiSessionMap {
  type iteiSessionMap (line 856) | type iteiSessionMap struct
    method store (line 864) | func (t *iteiSessionMap) store(teid uint32, session *Session) {
    method tryStore (line 868) | func (t *iteiSessionMap) tryStore(teid uint32, session *Session) bool {
    method load (line 873) | func (t *iteiSessionMap) load(teid uint32) (*Session, bool) {
    method delete (line 881) | func (t *iteiSessionMap) delete(teid uint32) {
    method rangeWithFunc (line 885) | func (t *iteiSessionMap) rangeWithFunc(fn func(imsi, session interface...
  function newiteiSessionMap (line 860) | func newiteiSessionMap() *iteiSessionMap {

FILE: gtpv2/conn_test.go
  function setup (line 20) | func setup(ctx context.Context, doneCh chan struct{}) (cliConn, srvConn ...
  function TestCreateSession (line 117) | func TestCreateSession(t *testing.T) {

FILE: gtpv2/constants.go
  constant ContIDMSSupportOfNetworkRequestedBearerControlIndicator (line 9) | ContIDMSSupportOfNetworkRequestedBearerControlIndicator uint16 = 5
  constant ContIDIPAddressAllocationViaNASSignalling (line 10) | ContIDIPAddressAllocationViaNASSignalling               uint16 = 10
  constant ContIDIPv4AddressAllocationViaDHCPv4 (line 11) | ContIDIPv4AddressAllocationViaDHCPv4                    uint16 = 11
  constant ContID3GPPPSDataOffUEStatus (line 12) | ContID3GPPPSDataOffUEStatus                             uint16 = 23
  constant SelectionModeMSOrNetworkProvidedAPNSubscribedVerified (line 14) | SelectionModeMSOrNetworkProvidedAPNSubscribedVerified uint8 = 0
  constant GTPCPort (line 19) | GTPCPort = ":2123"
  constant GTPUPort (line 20) | GTPUPort = ":2152"
  constant IFTypeS1UeNodeBGTPU (line 25) | IFTypeS1UeNodeBGTPU uint8 = iota
  constant IFTypeS1USGWGTPU (line 26) | IFTypeS1USGWGTPU
  constant IFTypeS12RNCGTPU (line 27) | IFTypeS12RNCGTPU
  constant IFTypeS12SGWGTPU (line 28) | IFTypeS12SGWGTPU
  constant IFTypeS5S8SGWGTPU (line 29) | IFTypeS5S8SGWGTPU
  constant IFTypeS5S8PGWGTPU (line 30) | IFTypeS5S8PGWGTPU
  constant IFTypeS5S8SGWGTPC (line 31) | IFTypeS5S8SGWGTPC
  constant IFTypeS5S8PGWGTPC (line 32) | IFTypeS5S8PGWGTPC
  constant IFTypeS5S8SGWPMIPv6 (line 33) | IFTypeS5S8SGWPMIPv6
  constant IFTypeS5S8PGWPMIPv6 (line 34) | IFTypeS5S8PGWPMIPv6
  constant IFTypeS11MMEGTPC (line 35) | IFTypeS11MMEGTPC
  constant IFTypeS11S4SGWGTPC (line 36) | IFTypeS11S4SGWGTPC
  constant IFTypeS10MMEGTPC (line 37) | IFTypeS10MMEGTPC
  constant IFTypeS3MMEGTPC (line 38) | IFTypeS3MMEGTPC
  constant IFTypeS3SGSNGTPC (line 39) | IFTypeS3SGSNGTPC
  constant IFTypeS4SGSNGTPU (line 40) | IFTypeS4SGSNGTPU
  constant IFTypeS4SGWGTPU (line 41) | IFTypeS4SGWGTPU
  constant IFTypeS4SGSNGTPC (line 42) | IFTypeS4SGSNGTPC
  constant IFTypeS16SGSNGTPC (line 43) | IFTypeS16SGSNGTPC
  constant IFTypeeNodeBGTPUForDL (line 44) | IFTypeeNodeBGTPUForDL
  constant IFTypeeNodeBGTPUForUL (line 45) | IFTypeeNodeBGTPUForUL
  constant IFTypeRNCGTPUForData (line 46) | IFTypeRNCGTPUForData
  constant IFTypeSGSNGTPUForData (line 47) | IFTypeSGSNGTPUForData
  constant IFTypeSGWUPFGTPUForDL (line 48) | IFTypeSGWUPFGTPUForDL
  constant IFTypeSmMBMSGWGTPC (line 49) | IFTypeSmMBMSGWGTPC
  constant IFTypeSnMBMSGWGTPC (line 50) | IFTypeSnMBMSGWGTPC
  constant IFTypeSmMMEGTPC (line 51) | IFTypeSmMMEGTPC
  constant IFTypeSnSGSNGTPC (line 52) | IFTypeSnSGSNGTPC
  constant IFTypeSGWGTPUForUL (line 53) | IFTypeSGWGTPUForUL
  constant IFTypeSnSGSNGTPU (line 54) | IFTypeSnSGSNGTPU
  constant IFTypeS2bePDGGTPC (line 55) | IFTypeS2bePDGGTPC
  constant IFTypeS2bUePDGGTPU (line 56) | IFTypeS2bUePDGGTPU
  constant IFTypeS2bPGWGTPC (line 57) | IFTypeS2bPGWGTPC
  constant IFTypeS2bUPGWGTPU (line 58) | IFTypeS2bUPGWGTPU
  constant IFTypeS2aTWANGTPU (line 59) | IFTypeS2aTWANGTPU
  constant IFTypeS2aTWANGTPC (line 60) | IFTypeS2aTWANGTPC
  constant IFTypeS2aPGWGTPC (line 61) | IFTypeS2aPGWGTPC
  constant IFTypeS2aPGWGTPU (line 62) | IFTypeS2aPGWGTPU
  constant IFTypeS11MMEGTPU (line 63) | IFTypeS11MMEGTPU
  constant IFTypeS11SGWGTPU (line 64) | IFTypeS11SGWGTPU
  constant APNRestrictionNoExistingContextsorRestriction (line 69) | APNRestrictionNoExistingContextsorRestriction uint8 = iota
  constant APNRestrictionPublic1 (line 70) | APNRestrictionPublic1
  constant APNRestrictionPublic2 (line 71) | APNRestrictionPublic2
  constant APNRestrictionPrivate1 (line 72) | APNRestrictionPrivate1
  constant APNRestrictionPrivate2 (line 73) | APNRestrictionPrivate2
  constant _ (line 78) | _                                                                       ...
  constant _ (line 79) | _                                                                       ...
  constant CauseLocalDetach (line 80) | CauseLocalDetach                                                        ...
  constant CauseCompleteDetach (line 81) | CauseCompleteDetach                                                     ...
  constant CauseRATChangedFrom3GPPToNon3GPP (line 82) | CauseRATChangedFrom3GPPToNon3GPP                                        ...
  constant CauseISRDeactivation (line 83) | CauseISRDeactivation                                                    ...
  constant CauseErrorIndicationReceivedFromRNCeNodeBS4SGSNMME (line 84) | CauseErrorIndicationReceivedFromRNCeNodeBS4SGSNMME                      ...
  constant CauseIMSIDetachOnly (line 85) | CauseIMSIDetachOnly                                                     ...
  constant CauseReactivationRequested (line 86) | CauseReactivationRequested                                              ...
  constant CausePDNReconnectionToThisAPNDisallowed (line 87) | CausePDNReconnectionToThisAPNDisallowed                                 ...
  constant CauseAccessChangedFromNon3GPPTo3GPP (line 88) | CauseAccessChangedFromNon3GPPTo3GPP                                     ...
  constant CausePDNConnectionInactivityTimerExpires (line 89) | CausePDNConnectionInactivityTimerExpires                                ...
  constant CausePGWNotResponding (line 90) | CausePGWNotResponding                                                   ...
  constant CauseNetworkFailure (line 91) | CauseNetworkFailure                                                     ...
  constant CauseQoSParameterMismatch (line 92) | CauseQoSParameterMismatch                                               ...
  constant _ (line 93) | _                                                                       ...
  constant CauseRequestAccepted (line 94) | CauseRequestAccepted                                                    ...
  constant CauseRequestAcceptedPartially (line 95) | CauseRequestAcceptedPartially                                           ...
  constant CauseNewPDNTypeDueToNetworkPreference (line 96) | CauseNewPDNTypeDueToNetworkPreference                                   ...
  constant CauseNewPDNTypeDueToSingleAddressBearerOnly (line 97) | CauseNewPDNTypeDueToSingleAddressBearerOnly                             ...
  constant CauseContextNotFound (line 98) | CauseContextNotFound                                                    ...
  constant CauseInvalidMessageFormat (line 99) | CauseInvalidMessageFormat                                               ...
  constant CauseVersionNotSupportedByNextPeer (line 100) | CauseVersionNotSupportedByNextPeer                                      ...
  constant CauseInvalidLength (line 101) | CauseInvalidLength                                                      ...
  constant CauseServiceNotSupported (line 102) | CauseServiceNotSupported                                                ...
  constant CauseMandatoryIEIncorrect (line 103) | CauseMandatoryIEIncorrect                                               ...
  constant CauseMandatoryIEMissing (line 104) | CauseMandatoryIEMissing                                                 ...
  constant _ (line 105) | _                                                                       ...
  constant CauseSystemFailure (line 106) | CauseSystemFailure                                                      ...
  constant CauseNoResourcesAvailable (line 107) | CauseNoResourcesAvailable                                               ...
  constant CauseSemanticErrorInTheTFTOperation (line 108) | CauseSemanticErrorInTheTFTOperation                                     ...
  constant CauseSyntacticErrorInTheTFTOperation (line 109) | CauseSyntacticErrorInTheTFTOperation                                    ...
  constant CauseSemanticErrorsInPacketFilters (line 110) | CauseSemanticErrorsInPacketFilters                                      ...
  constant CauseSyntacticErrorsInPacketFilters (line 111) | CauseSyntacticErrorsInPacketFilters                                     ...
  constant CauseMissingOrUnknownAPN (line 112) | CauseMissingOrUnknownAPN                                                ...
  constant _ (line 113) | _                                                                       ...
  constant CauseGREKeyNotFound (line 114) | CauseGREKeyNotFound                                                     ...
  constant CauseRelocationFailure (line 115) | CauseRelocationFailure                                                  ...
  constant CauseDeniedInRAT (line 116) | CauseDeniedInRAT                                                        ...
  constant CausePreferredPDNTypeNotSupported (line 117) | CausePreferredPDNTypeNotSupported                                       ...
  constant CauseAllDynamicAddressesAreOccupied (line 118) | CauseAllDynamicAddressesAreOccupied                                     ...
  constant CauseUEContextWithoutTFTAlreadyActivated (line 119) | CauseUEContextWithoutTFTAlreadyActivated                                ...
  constant CauseProtocolTypeNotSupported (line 120) | CauseProtocolTypeNotSupported                                           ...
  constant CauseUENotResponding (line 121) | CauseUENotResponding                                                    ...
  constant CauseUERefuses (line 122) | CauseUERefuses                                                          ...
  constant CauseServiceDenied (line 123) | CauseServiceDenied                                                      ...
  constant CauseUnableToPageUE (line 124) | CauseUnableToPageUE                                                     ...
  constant CauseNoMemoryAvailable (line 125) | CauseNoMemoryAvailable                                                  ...
  constant CauseUserAuthenticationFailed (line 126) | CauseUserAuthenticationFailed                                           ...
  constant CauseAPNAccessDeniedNoSubscription (line 127) | CauseAPNAccessDeniedNoSubscription                                      ...
  constant CauseRequestRejectedReasonNotSpecified (line 128) | CauseRequestRejectedReasonNotSpecified                                  ...
  constant CausePTMSISignatureMismatch (line 129) | CausePTMSISignatureMismatch                                             ...
  constant CauseIMSIIMEINotKnown (line 130) | CauseIMSIIMEINotKnown                                                   ...
  constant CauseSemanticErrorInTheTADOperation (line 131) | CauseSemanticErrorInTheTADOperation                                     ...
  constant CauseSyntacticErrorInTheTADOperation (line 132) | CauseSyntacticErrorInTheTADOperation                                    ...
  constant _ (line 133) | _                                                                       ...
  constant CauseRemotePeerNotResponding (line 134) | CauseRemotePeerNotResponding                                            ...
  constant CauseCollisionWithNetworkInitiatedRequest (line 135) | CauseCollisionWithNetworkInitiatedRequest                               ...
  constant CauseUnableToPageUEDueToSuspension (line 136) | CauseUnableToPageUEDueToSuspension                                      ...
  constant CauseConditionalIEMissing (line 137) | CauseConditionalIEMissing                                               ...
  constant CauseAPNRestrictionTypeIncompatibleWithCurrentlyActivePDNConnection (line 138) | CauseAPNRestrictionTypeIncompatibleWithCurrentlyActivePDNConnection     ...
  constant CauseInvalidOverallLengthOfTheTriggeredResponseMessageAndAPiggybackedInitialMessage (line 139) | CauseInvalidOverallLengthOfTheTriggeredResponseMessageAndAPiggybackedIni...
  constant CauseDataForwardingNotSupported (line 140) | CauseDataForwardingNotSupported                                         ...
  constant CauseInvalidReplyFromRemotePeer (line 141) | CauseInvalidReplyFromRemotePeer                                         ...
  constant CauseFallbackToGTPv1 (line 142) | CauseFallbackToGTPv1                                                    ...
  constant CauseInvalidPeer (line 143) | CauseInvalidPeer                                                        ...
  constant CauseTemporarilyRejectedDueToHandoverTAURAUProcedureInProgress (line 144) | CauseTemporarilyRejectedDueToHandoverTAURAUProcedureInProgress          ...
  constant CauseModificationsNotLimitedToS1UBearers (line 145) | CauseModificationsNotLimitedToS1UBearers                                ...
  constant CauseRequestRejectedForAPMIPv6Reason (line 146) | CauseRequestRejectedForAPMIPv6Reason                                    ...
  constant CauseAPNCongestion (line 147) | CauseAPNCongestion                                                      ...
  constant CauseBearerHandlingNotSupported (line 148) | CauseBearerHandlingNotSupported                                         ...
  constant CauseUEAlreadyReattached (line 149) | CauseUEAlreadyReattached                                                ...
  constant CauseMultiplePDNConnectionsForAGivenAPNNotAllowed (line 150) | CauseMultiplePDNConnectionsForAGivenAPNNotAllowed                       ...
  constant CauseTargetAccessRestrictedForTheSubscriber (line 151) | CauseTargetAccessRestrictedForTheSubscriber                             ...
  constant _ (line 152) | _                                                                       ...
  constant CauseMMESGSNRefusesDueToVPLMNPolicy (line 153) | CauseMMESGSNRefusesDueToVPLMNPolicy                                     ...
  constant CauseGTPCEntityCongestion (line 154) | CauseGTPCEntityCongestion                                               ...
  constant CauseLateOverlappingRequest (line 155) | CauseLateOverlappingRequest                                             ...
  constant CauseTimedOutRequest (line 156) | CauseTimedOutRequest                                                    ...
  constant CauseUEIsTemporarilyNotReachableDueToPowerSaving (line 157) | CauseUEIsTemporarilyNotReachableDueToPowerSaving                        ...
  constant CauseRelocationFailureDueToNASMessageRedirection (line 158) | CauseRelocationFailureDueToNASMessageRedirection                        ...
  constant CauseUENotAuthorisedByOCSOrExternalAAAServer (line 159) | CauseUENotAuthorisedByOCSOrExternalAAAServer                            ...
  constant CauseMultipleAccessesToAPDNConnectionNotAllowed (line 160) | CauseMultipleAccessesToAPDNConnectionNotAllowed                         ...
  constant CauseRequestRejectedDueToUECapability (line 161) | CauseRequestRejectedDueToUECapability                                   ...
  constant CauseS1UPathFailure (line 162) | CauseS1UPathFailure                                                     ...
  constant CMINonCSG (line 167) | CMINonCSG uint8 = iota
  constant CMICSG (line 168) | CMICSG
  constant _ (line 173) | _ uint8 = iota
  constant DetachTypePS (line 174) | DetachTypePS
  constant DetachTypeCombinedPSCS (line 175) | DetachTypeCombinedPSCS
  constant NodeIDIPv4 (line 180) | NodeIDIPv4 uint8 = iota
  constant NodeIDIPv6 (line 181) | NodeIDIPv6
  constant NodeIDOther (line 182) | NodeIDOther
  constant NodeTypeSGSN (line 187) | NodeTypeSGSN uint8 = iota
  constant NodeTypeMME (line 188) | NodeTypeMME
  constant ProtoIDLCP (line 194) | ProtoIDLCP  uint16 = 0xc021
  constant ProtoIDPAP (line 195) | ProtoIDPAP  uint16 = 0xc023
  constant ProtoIDCHAP (line 196) | ProtoIDCHAP uint16 = 0xc223
  constant ProtoIDIPCP (line 197) | ProtoIDIPCP uint16 = 0x8021
  constant _ (line 202) | _ uint16 = iota
  constant ContIDPCSCFIPv6AddressRequest (line 203) | ContIDPCSCFIPv6AddressRequest
  constant ContIDIMCNSubsystemSignalingFlag (line 204) | ContIDIMCNSubsystemSignalingFlag
  constant ContIDDNSServerIPv6AddressRequest (line 205) | ContIDDNSServerIPv6AddressRequest
  constant ContIDNotSupported (line 206) | ContIDNotSupported
  constant ContIDMSSupportofNetworkRequestedBearerControlIndicator (line 207) | ContIDMSSupportofNetworkRequestedBearerControlIndicator
  constant _ (line 208) | _
  constant ContIDDSMIPv6HomeAgentAddressRequest (line 209) | ContIDDSMIPv6HomeAgentAddressRequest
  constant ContIDDSMIPv6HomeNetworkPrefixRequest (line 210) | ContIDDSMIPv6HomeNetworkPrefixRequest
  constant ContIDDSMIPv6IPv4HomeAgentAddressRequest (line 211) | ContIDDSMIPv6IPv4HomeAgentAddressRequest
  constant ContIDIPaddressAllocationViaNASSignalling (line 212) | ContIDIPaddressAllocationViaNASSignalling
  constant ContIDIPv4addressAllocationViaDHCPv4 (line 213) | ContIDIPv4addressAllocationViaDHCPv4
  constant ContIDPCSCFIPv4AddressRequest (line 214) | ContIDPCSCFIPv4AddressRequest
  constant ContIDDNSServerIPv4AddressRequest (line 215) | ContIDDNSServerIPv4AddressRequest
  constant ContIDMSISDNRequest (line 216) | ContIDMSISDNRequest
  constant ContIDIFOMSupportRequest (line 217) | ContIDIFOMSupportRequest
  constant ContIDIPv4LinkMTURequest (line 218) | ContIDIPv4LinkMTURequest
  constant ContIDMSSupportOfLocalAddressInTFTIndicator (line 219) | ContIDMSSupportOfLocalAddressInTFTIndicator
  constant ContIDPCSCFReselectionSupport (line 220) | ContIDPCSCFReselectionSupport
  constant ContIDNBIFOMRequestIndicator (line 221) | ContIDNBIFOMRequestIndicator
  constant ContIDNBIFOMMode (line 222) | ContIDNBIFOMMode
  constant ContIDNonIPLinkMTURequest (line 223) | ContIDNonIPLinkMTURequest
  constant ContIDAPNRateControlSupportIndicator (line 224) | ContIDAPNRateControlSupportIndicator
  constant ContID3GPPPSDataOffUEstatus (line 225) | ContID3GPPPSDataOffUEstatus
  constant ContIDReliableDataServiceRequestIndicator (line 226) | ContIDReliableDataServiceRequestIndicator
  constant ContIDAdditionalAPNRateControlForExceptionDataSupportIndicator (line 227) | ContIDAdditionalAPNRateControlForExceptionDataSupportIndicator
  constant ContIDPDUSessionID (line 228) | ContIDPDUSessionID
  constant _ (line 229) | _
  constant _ (line 230) | _
  constant _ (line 231) | _
  constant _ (line 232) | _
  constant _ (line 233) | _
  constant ContIDEthernetFramePayloadMTURequest (line 234) | ContIDEthernetFramePayloadMTURequest
  constant ContIDUnstructuredLinkMTURequest (line 235) | ContIDUnstructuredLinkMTURequest
  constant ContID5GSMCauseValue (line 236) | ContID5GSMCauseValue
  constant ConfigProtocolPPPWithIP (line 241) | ConfigProtocolPPPWithIP uint8 = 0
  constant _ (line 246) | _ uint8 = iota
  constant PDNTypeIPv4 (line 247) | PDNTypeIPv4
  constant PDNTypeIPv6 (line 248) | PDNTypeIPv6
  constant PDNTypeIPv4v6 (line 249) | PDNTypeIPv4v6
  constant PDNTypeNonIP (line 250) | PDNTypeNonIP
  constant _ (line 255) | _ uint8 = iota
  constant ProtoTypeS1APCause (line 256) | ProtoTypeS1APCause
  constant ProtoTypeEMMCause (line 257) | ProtoTypeEMMCause
  constant ProtoTypeESMCause (line 258) | ProtoTypeESMCause
  constant ProtoTypeDiameterCause (line 259) | ProtoTypeDiameterCause
  constant ProtoTypeIKEv2Cause (line 260) | ProtoTypeIKEv2Cause
  constant CauseTypeRadioNetworkLayer (line 265) | CauseTypeRadioNetworkLayer uint8 = iota
  constant CauseTypeTransportLayer (line 266) | CauseTypeTransportLayer
  constant CauseTypeNAS (line 267) | CauseTypeNAS
  constant CauseTypeProtocol (line 268) | CauseTypeProtocol
  constant CauseTypeMiscellaneous (line 269) | CauseTypeMiscellaneous
  constant _ (line 274) | _ uint8 = iota
  constant RATTypeUTRAN (line 275) | RATTypeUTRAN
  constant RATTypeGERAN (line 276) | RATTypeGERAN
  constant RATTypeWLAN (line 277) | RATTypeWLAN
  constant RATTypeGAN (line 278) | RATTypeGAN
  constant RATTypeHSPAEvolution (line 279) | RATTypeHSPAEvolution
  constant RATTypeEUTRAN (line 280) | RATTypeEUTRAN
  constant RATTypeVirtual (line 281) | RATTypeVirtual
  constant RATTypeEUTRANNBIoT (line 282) | RATTypeEUTRANNBIoT
  constant RATTypeLTEM (line 283) | RATTypeLTEM
  constant RATTypeNR (line 284) | RATTypeNR
  constant SelectionModeMSorNetworkProvidedAPNSubscribedVerified (line 289) | SelectionModeMSorNetworkProvidedAPNSubscribedVerified uint8 = iota
  constant SelectionModeMSProvidedAPNSubscriptionNotVerified (line 290) | SelectionModeMSProvidedAPNSubscriptionNotVerified
  constant SelectionModeNetworkProvidedAPNSubscriptionNotVerified (line 291) | SelectionModeNetworkProvidedAPNSubscriptionNotVerified
  constant _ (line 296) | _ uint8 = iota
  constant ServiceIndCSCall (line 297) | ServiceIndCSCall
  constant ServiceIndSMS (line 298) | ServiceIndSMS
  constant AccessModeClosed (line 303) | AccessModeClosed uint8 = iota
  constant AccessModeHybrid (line 304) | AccessModeHybrid
  constant DaylightSavingNoAdjustment (line 309) | DaylightSavingNoAdjustment uint8 = iota
  constant DaylightSavingPlusOneHour (line 310) | DaylightSavingPlusOneHour
  constant DaylightSavingPlusTwoHours (line 311) | DaylightSavingPlusTwoHours

FILE: gtpv2/errors.go
  type CauseNotOKError (line 24) | type CauseNotOKError struct
    method Error (line 31) | func (e *CauseNotOKError) Error() string {
  type RequiredIEMissingError (line 36) | type RequiredIEMissingError struct
    method Error (line 41) | func (e *RequiredIEMissingError) Error() string {
  type RequiredParameterMissingError (line 46) | type RequiredParameterMissingError struct
    method Error (line 51) | func (e *RequiredParameterMissingError) Error() string {
  type UnexpectedTypeError (line 56) | type UnexpectedTypeError struct
    method Error (line 61) | func (e *UnexpectedTypeError) Error() string {
  type UnexpectedIEError (line 66) | type UnexpectedIEError struct
    method Error (line 71) | func (e *UnexpectedIEError) Error() string {
  type InvalidVersionError (line 77) | type InvalidVersionError struct
    method Error (line 82) | func (e *InvalidVersionError) Error() string {
  type InvalidSequenceError (line 87) | type InvalidSequenceError struct
    method Error (line 92) | func (e *InvalidSequenceError) Error() string {
  type InvalidTEIDError (line 98) | type InvalidTEIDError struct
    method Error (line 103) | func (e *InvalidTEIDError) Error() string {
  type UnknownIMSIError (line 108) | type UnknownIMSIError struct
    method Error (line 113) | func (e *UnknownIMSIError) Error() string {
  type UnknownAPNError (line 118) | type UnknownAPNError struct
    method Error (line 123) | func (e *UnknownAPNError) Error() string {
  type InvalidSessionError (line 128) | type InvalidSessionError struct
    method Error (line 133) | func (e *InvalidSessionError) Error() string {
  type BearerNotFoundError (line 138) | type BearerNotFoundError struct
    method Error (line 143) | func (e *BearerNotFoundError) Error() string {
  type HandlerNotFoundError (line 151) | type HandlerNotFoundError struct
    method Error (line 156) | func (e *HandlerNotFoundError) Error() string {

FILE: gtpv2/handlers.go
  type HandlerFunc (line 16) | type HandlerFunc
  type msgHandlerMap (line 18) | type msgHandlerMap struct
    method store (line 22) | func (m *msgHandlerMap) store(msgType uint8, handler HandlerFunc) {
    method load (line 26) | func (m *msgHandlerMap) load(msgType uint8) (HandlerFunc, bool) {
  function newMsgHandlerMap (line 35) | func newMsgHandlerMap(m map[uint8]HandlerFunc) *msgHandlerMap {
  function newDefaultMsgHandlerMap (line 44) | func newDefaultMsgHandlerMap() *msgHandlerMap {
  function handleEchoRequest (line 54) | func handleEchoRequest(c *Conn, senderAddr net.Addr, msg message.Message...
  function handleEchoResponse (line 67) | func handleEchoResponse(c *Conn, senderAddr net.Addr, msg message.Messag...
  function handleVersionNotSupportedIndication (line 78) | func handleVersionNotSupportedIndication(c *Conn, senderAddr net.Addr, m...

FILE: gtpv2/helpers_test.go
  function init (line 17) | func init() {
  function TestSessionCount (line 33) | func TestSessionCount(t *testing.T) {
  function TestGetSessionByIMSI_GetTEID (line 39) | func TestGetSessionByIMSI_GetTEID(t *testing.T) {
  function BenchmarkAddSession (line 58) | func BenchmarkAddSession(b *testing.B) {
  function TestGetSessionByTEID (line 74) | func TestGetSessionByTEID(t *testing.T) {
  function TestGetIMSIByTEID (line 88) | func TestGetIMSIByTEID(t *testing.T) {
  function TestRemoveSession (line 102) | func TestRemoveSession(t *testing.T) {
  function TestRemoveSessionByIMSI (line 128) | func TestRemoveSessionByIMSI(t *testing.T) {

FILE: gtpv2/ie/ambr.go
  function NewAggregateMaximumBitRate (line 13) | func NewAggregateMaximumBitRate(up, down uint32) *IE {
  method AggregateMaximumBitRate (line 24) | func (i *IE) AggregateMaximumBitRate() (*AggregateMaximumBitRateFields, ...
  type AggregateMaximumBitRateFields (line 34) | type AggregateMaximumBitRateFields struct
    method Marshal (line 48) | func (f *AggregateMaximumBitRateFields) Marshal() ([]byte, error) {
    method MarshalTo (line 58) | func (f *AggregateMaximumBitRateFields) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 80) | func (f *AggregateMaximumBitRateFields) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 92) | func (f *AggregateMaximumBitRateFields) MarshalLen() int {
  function NewAggregateMaximumBitRateFields (line 40) | func NewAggregateMaximumBitRateFields(up, down uint32) *AggregateMaximum...
  function ParseAggregateMaximumBitRateFields (line 70) | func ParseAggregateMaximumBitRateFields(b []byte) (*AggregateMaximumBitR...
  method AggregateMaximumBitRateUp (line 98) | func (i *IE) AggregateMaximumBitRateUp() (uint32, error) {
  method MustAggregateMaximumBitRateUp (line 111) | func (i *IE) MustAggregateMaximumBitRateUp() uint32 {
  method AggregateMaximumBitRateDown (line 118) | func (i *IE) AggregateMaximumBitRateDown() (uint32, error) {
  method MustAggregateMaximumBitRateDown (line 131) | func (i *IE) MustAggregateMaximumBitRateDown() uint32 {

FILE: gtpv2/ie/apn-restriction.go
  function NewAPNRestriction (line 8) | func NewAPNRestriction(restriction uint8) *IE {
  method APNRestriction (line 13) | func (i *IE) APNRestriction() (uint8, error) {
  method MustAPNRestriction (line 23) | func (i *IE) MustAPNRestriction() uint8 {
  method RestrictionType (line 29) | func (i *IE) RestrictionType() (uint8, error) {

FILE: gtpv2/ie/apn.go
  function NewAccessPointName (line 8) | func NewAccessPointName(apn string) *IE {
  method AccessPointName (line 13) | func (i *IE) AccessPointName() (string, error) {
  method MustAccessPointName (line 22) | func (i *IE) MustAccessPointName() string {

FILE: gtpv2/ie/arp.go
  function NewAllocationRetensionPriority (line 8) | func NewAllocationRetensionPriority(pci, pl, pvi uint8) *IE {
  method AllocationRetensionPriority (line 15) | func (i *IE) AllocationRetensionPriority() (uint8, error) {
  method HasPVI (line 23) | func (i *IE) HasPVI() bool {
  method HasPCI (line 33) | func (i *IE) HasPCI() bool {
  method PriorityLevel (line 43) | func (i *IE) PriorityLevel() (uint8, error) {
  method PreemptionVulnerability (line 67) | func (i *IE) PreemptionVulnerability() bool {
  method PreemptionCapability (line 74) | func (i *IE) PreemptionCapability() bool {

FILE: gtpv2/ie/bearer-context.go
  function NewBearerContext (line 10) | func NewBearerContext(ies ...*IE) *IE {
  function NewBearerContextWithinCreateBearerRequest (line 15) | func NewBearerContextWithinCreateBearerRequest(ebi, tft, qos, chargeID, ...
  function NewBearerContextWithinCreateBearerResponse (line 22) | func NewBearerContextWithinCreateBearerResponse(ebi, cause, pco, rannasC...
  function NewBearerContextWithinDeleteBearerRequest (line 29) | func NewBearerContextWithinDeleteBearerRequest(ebi, cause *IE) *IE {
  function NewBearerContextWithinDeleteBearerResponse (line 34) | func NewBearerContextWithinDeleteBearerResponse(ebi, cause, pco, rannasC...
  function NewBearerContextWithinModifyBearerCommand (line 39) | func NewBearerContextWithinModifyBearerCommand(ebi, qos *IE) *IE {
  function NewBearerContextWithinUpdateBearerRequest (line 44) | func NewBearerContextWithinUpdateBearerRequest(ebi, tft, qos, flags, pco...
  function NewBearerContextWithinUpdateBearerResponse (line 49) | func NewBearerContextWithinUpdateBearerResponse(ebi, cause, pco, rannasC...
  function NewBearerContextWithinDeleteBearerCommand (line 56) | func NewBearerContextWithinDeleteBearerCommand(ebi, flags, rannasCause *...
  function NewBearerContextWithinDeleteBearerFailureIndication (line 61) | func NewBearerContextWithinDeleteBearerFailureIndication(ebi, cause *IE)...
  function NewBearerContextWithinCreateIndirectDataForwardingTunnelRequest (line 66) | func NewBearerContextWithinCreateIndirectDataForwardingTunnelRequest(ebi...
  function NewBearerContextWithinCreateIndirectDataForwardingTunnelResponse (line 73) | func NewBearerContextWithinCreateIndirectDataForwardingTunnelResponse(eb...
  function NewBearerContextWithinForwardRelocationRequest (line 80) | func NewBearerContextWithinForwardRelocationRequest(ebi, tft, qos, conta...
  function NewBearerContextWithinContextResponse (line 87) | func NewBearerContextWithinContextResponse(ebi, tft, qos, container, ti ...
  function NewBearerContextWithinContextAcknowledge (line 94) | func NewBearerContextWithinContextAcknowledge(ebi, fwdFTEID *IE) *IE {
  method BearerContext (line 99) | func (i *IE) BearerContext() ([]*IE, error) {

FILE: gtpv2/ie/bearer-flags.go
  function NewBearerFlags (line 8) | func NewBearerFlags(asi, vInd, vb, ppc uint8) *IE {
  method BearerFlags (line 15) | func (i *IE) BearerFlags() (uint8, error) {
  method MustBearerFlags (line 38) | func (i *IE) MustBearerFlags() uint8 {
  method HasPPC (line 44) | func (i *IE) HasPPC() bool {
  method HasVB (line 54) | func (i *IE) HasVB() bool {
  method HasVind (line 64) | func (i *IE) HasVind() bool {
  method HasASI (line 74) | func (i *IE) HasASI() bool {
  method ActivityStatusIndicator (line 85) | func (i *IE) ActivityStatusIndicator() bool {
  method VSRVCC (line 95) | func (i *IE) VSRVCC() bool {
  method VoiceBearer (line 104) | func (i *IE) VoiceBearer() bool {
  method ProhibitPayloadCompression (line 114) | func (i *IE) ProhibitPayloadCompression() bool {

FILE: gtpv2/ie/bearer-qos.go
  function NewBearerQoS (line 15) | func NewBearerQoS(pci, pl, pvi, qci uint8, umbr, dmbr, ugbr, dgbr uint64...
  method BearerQoS (line 26) | func (i *IE) BearerQoS() (*BearerQoSFields, error) {
  type BearerQoSFields (line 48) | type BearerQoSFields struct
    method Marshal (line 70) | func (f *BearerQoSFields) Marshal() ([]byte, error) {
    method MarshalTo (line 80) | func (f *BearerQoSFields) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 107) | func (f *BearerQoSFields) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 124) | func (f *BearerQoSFields) MarshalLen() int {
  function NewBearerQoSFields (line 58) | func NewBearerQoSFields(pci, pl, pvi, qci uint8, umbr, dmbr, ugbr, dgbr ...
  function ParseBearerQoSFields (line 97) | func ParseBearerQoSFields(b []byte) (*BearerQoSFields, error) {
  method QCILabel (line 129) | func (i *IE) QCILabel() (uint8, error) {
  method MBRForUplink (line 144) | func (i *IE) MBRForUplink() (uint64, error) {
  method MustMBRForUplink (line 163) | func (i *IE) MustMBRForUplink() uint64 {
  method MBRForDownlink (line 169) | func (i *IE) MBRForDownlink() (uint64, error) {
  method MustMBRForDownlink (line 188) | func (i *IE) MustMBRForDownlink() uint64 {
  method GBRForUplink (line 194) | func (i *IE) GBRForUplink() (uint64, error) {
  method MustGBRForUplink (line 213) | func (i *IE) MustGBRForUplink() uint64 {
  method GBRForDownlink (line 219) | func (i *IE) GBRForDownlink() (uint64, error) {
  method MustGBRForDownlink (line 238) | func (i *IE) MustGBRForDownlink() uint64 {

FILE: gtpv2/ie/bearer-tft.go
  constant TFTOpIgnoreThisIE (line 9) | TFTOpIgnoreThisIE                       uint8 = 0
  constant TFTOpCreateNewTFT (line 10) | TFTOpCreateNewTFT                       uint8 = 1
  constant TFTOpDeleteExistingTFT (line 11) | TFTOpDeleteExistingTFT                  uint8 = 2
  constant TFTOpAddPacketFiltersToExistingTFT (line 12) | TFTOpAddPacketFiltersToExistingTFT      uint8 = 3
  constant TFTOpReplacePacketFiltersInExistingTFT (line 13) | TFTOpReplacePacketFiltersInExistingTFT  uint8 = 4
  constant TFTOpDeletePacketFiltersFromExistingTFT (line 14) | TFTOpDeletePacketFiltersFromExistingTFT uint8 = 5
  constant TFTOpNoTFTOperation (line 15) | TFTOpNoTFTOperation                     uint8 = 6
  function NewBearerTFT (line 22) | func NewBearerTFT(op uint8, filters []*TFTPacketFilter, ids []uint8, par...
  function NewBearerTFTCreateNewTFT (line 33) | func NewBearerTFTCreateNewTFT(filters []*TFTPacketFilter, params []*TFTP...
  function NewBearerTFTAddPacketFilters (line 38) | func NewBearerTFTAddPacketFilters(filters []*TFTPacketFilter, params []*...
  function NewBearerTFTReplacePacketFilters (line 43) | func NewBearerTFTReplacePacketFilters(filters []*TFTPacketFilter, params...
  function NewBearerTFTDeletePacketFilters (line 48) | func NewBearerTFTDeletePacketFilters(ids []uint8, params ...*TFTParamete...
  function NewBearerTFTDeleteExistingTFT (line 53) | func NewBearerTFTDeleteExistingTFT(params ...*TFTParameter) *IE {
  function NewBearerTFTNoTFTOperation (line 58) | func NewBearerTFTNoTFTOperation(params ...*TFTParameter) *IE {
  method BearerTFT (line 63) | func (i *IE) BearerTFT() (*TrafficFlowTemplate, error) {

FILE: gtpv2/ie/cause.go
  function NewCause (line 13) | func NewCause(cause uint8, pce, bce, cs uint8, offendingIE *IE) *IE {
  method Cause (line 28) | func (i *IE) Cause() (uint8, error) {
  method MustCause (line 51) | func (i *IE) MustCause() uint8 {
  method CauseFlags (line 57) | func (i *IE) CauseFlags() (uint8, error) {
  method MustCauseFlags (line 84) | func (i *IE) MustCauseFlags() uint8 {
  method HasCS (line 90) | func (i *IE) HasCS() bool {
  method HasBCE (line 100) | func (i *IE) HasBCE() bool {
  method HasPCE (line 110) | func (i *IE) HasPCE() bool {
  method IsRemoteCause (line 120) | func (i *IE) IsRemoteCause() bool {
  method IsBearerContextIEError (line 136) | func (i *IE) IsBearerContextIEError() bool {
  method IsPDNConnectionIEError (line 152) | func (i *IE) IsPDNConnectionIEError() bool {
  method OffendingIE (line 170) | func (i *IE) OffendingIE() (*IE, error) {
  method MustOffendingIE (line 184) | func (i *IE) MustOffendingIE() *IE {

FILE: gtpv2/ie/charging-characteristics.go
  function NewChargingCharacteristics (line 8) | func NewChargingCharacteristics(chr uint16) *IE {
  method ChargingCharacteristics (line 13) | func (i *IE) ChargingCharacteristics() (uint16, error) {
  method MustChargingCharacteristics (line 22) | func (i *IE) MustChargingCharacteristics() uint16 {

FILE: gtpv2/ie/charging-id.go
  function NewChargingID (line 8) | func NewChargingID(id uint32) *IE {
  method ChargingID (line 13) | func (i *IE) ChargingID() (uint32, error) {
  method MustChargingID (line 36) | func (i *IE) MustChargingID() uint32 {

FILE: gtpv2/ie/cmi.go
  function NewCSGMembershipIndication (line 10) | func NewCSGMembershipIndication(cmi uint8) *IE {
  method CMI (line 15) | func (i *IE) CMI() (uint8, error) {
  method MustCMI (line 31) | func (i *IE) MustCMI() uint8 {

FILE: gtpv2/ie/csg-id.go
  function NewCSGID (line 13) | func NewCSGID(id uint32) *IE {
  method CSGID (line 18) | func (i *IE) CSGID() (uint32, error) {
  method MustCSGID (line 34) | func (i *IE) MustCSGID() uint32 {

FILE: gtpv2/ie/delay-value.go
  function NewDelayValue (line 13) | func NewDelayValue(delay time.Duration) *IE {
  function NewDelayValueRaw (line 20) | func NewDelayValueRaw(delay uint8) *IE {
  method DelayValue (line 28) | func (i *IE) DelayValue() (time.Duration, error) {
  method MustDelayValue (line 41) | func (i *IE) MustDelayValue() time.Duration {

FILE: gtpv2/ie/detach-type.go
  function NewDetachType (line 8) | func NewDetachType(dtype uint8) *IE {
  method DetachType (line 13) | func (i *IE) DetachType() (uint8, error) {
  method MustDetachType (line 22) | func (i *IE) MustDetachType() uint8 {

FILE: gtpv2/ie/ebi.go
  function NewEPSBearerID (line 8) | func NewEPSBearerID(ebi uint8) *IE {
  method EPSBearerID (line 13) | func (i *IE) EPSBearerID() (uint8, error) {
  method MustEPSBearerID (line 36) | func (i *IE) MustEPSBearerID() uint8 {

FILE: gtpv2/ie/epc-timer.go
  function NewEPCTimer (line 15) | func NewEPCTimer(duration time.Duration) *IE {
  function NewEPCTimerRaw (line 56) | func NewEPCTimerRaw(duration uint8) *IE {
  method EPCTimer (line 64) | func (i *IE) EPCTimer() (time.Duration, error) {
  method MustEPCTimer (line 70) | func (i *IE) MustEPCTimer() time.Duration {
  method Timer (line 76) | func (i *IE) Timer() (time.Duration, error) {

FILE: gtpv2/ie/errors.go
  type InvalidTypeError (line 25) | type InvalidTypeError struct
    method Error (line 30) | func (e *InvalidTypeError) Error() string {

FILE: gtpv2/ie/f-teid.go
  function NewFullyQualifiedTEID (line 14) | func NewFullyQualifiedTEID(ifType uint8, teid uint32, v4, v6 string) *IE {
  function NewFullyQualifiedTEIDNetIP (line 25) | func NewFullyQualifiedTEIDNetIP(ifType uint8, teid uint32, v4, v6 net.IP...
  method FullyQualifiedTEID (line 36) | func (i *IE) FullyQualifiedTEID() (*FullyQualifiedTEIDFields, error) {
  type FullyQualifiedTEIDFields (line 46) | type FullyQualifiedTEIDFields struct
    method Marshal (line 74) | func (f *FullyQualifiedTEIDFields) Marshal() ([]byte, error) {
    method MarshalTo (line 84) | func (f *FullyQualifiedTEIDFields) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 128) | func (f *FullyQualifiedTEIDFields) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 161) | func (f *FullyQualifiedTEIDFields) MarshalLen() int {
  function NewFullyQualifiedTEIDFields (line 55) | func NewFullyQualifiedTEIDFields(ifType uint8, teid uint32, v4, v6 net.I...
  function ParseFullyQualifiedTEIDFields (line 118) | func ParseFullyQualifiedTEIDFields(b []byte) (*FullyQualifiedTEIDFields,...
  method HasIPv4 (line 174) | func (i *IE) HasIPv4() bool {
  method HasIPv6 (line 188) | func (i *IE) HasIPv6() bool {
  method InterfaceType (line 202) | func (i *IE) InterfaceType() (uint8, error) {
  method MustInterfaceType (line 215) | func (i *IE) MustInterfaceType() uint8 {
  method GREKey (line 221) | func (i *IE) GREKey() (uint32, error) {
  method MustGREKey (line 250) | func (i *IE) MustGREKey() uint32 {
  method TEID (line 256) | func (i *IE) TEID() (uint32, error) {
  method MustTEID (line 286) | func (i *IE) MustTEID() uint32 {

FILE: gtpv2/ie/flow-qos.go
  function NewFlowQoS (line 14) | func NewFlowQoS(qci uint8, umbr, dmbr, ugbr, dgbr uint64) *IE {
  method FlowQoS (line 25) | func (i *IE) FlowQoS() (*FlowQoSFields, error) {
  type FlowQoSFields (line 35) | type FlowQoSFields struct
    method Marshal (line 55) | func (f *FlowQoSFields) Marshal() ([]byte, error) {
    method MarshalTo (line 65) | func (f *FlowQoSFields) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 91) | func (f *FlowQoSFields) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 107) | func (f *FlowQoSFields) MarshalLen() int {
  function NewFlowQoSFields (line 44) | func NewFlowQoSFields(qci uint8, umbr, dmbr, ugbr, dgbr uint64) *FlowQoS...
  function ParseFlowQoSFields (line 81) | func ParseFlowQoSFields(b []byte) (*FlowQoSFields, error) {

FILE: gtpv2/ie/fq-csid.go
  constant nodeIDIPv4 (line 16) | nodeIDIPv4 uint8 = iota
  constant nodeIDIPv6 (line 17) | nodeIDIPv6
  constant nodeIDOther (line 18) | nodeIDOther
  function NewFullyQualifiedCSID (line 22) | func NewFullyQualifiedCSID(nodeID string, csIDs ...uint16) *IE {
  method FullyQualifiedCSID (line 33) | func (i *IE) FullyQualifiedCSID() (*FullyQualifiedCSIDFields, error) {
  type FullyQualifiedCSIDFields (line 43) | type FullyQualifiedCSIDFields struct
    method Marshal (line 77) | func (f *FullyQualifiedCSIDFields) Marshal() ([]byte, error) {
    method MarshalTo (line 87) | func (f *FullyQualifiedCSIDFields) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 123) | func (f *FullyQualifiedCSIDFields) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 162) | func (f *FullyQualifiedCSIDFields) MarshalLen() int {
  function NewFullyQualifiedCSIDFields (line 51) | func NewFullyQualifiedCSIDFields(nodeID string, csIDs ...uint16) *FullyQ...
  function ParseFullyQualifiedCSIDFields (line 113) | func ParseFullyQualifiedCSIDFields(b []byte) (*FullyQualifiedCSIDFields,...
  method NodeIDType (line 179) | func (i *IE) NodeIDType() (uint8, error) {
  method MustNodeIDType (line 194) | func (i *IE) MustNodeIDType() uint8 {
  method NodeID (line 200) | func (i *IE) NodeID() ([]byte, error) {
  method MustNodeID (line 228) | func (i *IE) MustNodeID() []byte {
  method CSIDs (line 234) | func (i *IE) CSIDs() ([]uint16, error) {
  method MustCSIDs (line 267) | func (i *IE) MustCSIDs() []uint16 {

FILE: gtpv2/ie/fqdn.go
  function NewFullyQualifiedDomainName (line 8) | func NewFullyQualifiedDomainName(fqdn string) *IE {
  method FullyQualifiedDomainName (line 13) | func (i *IE) FullyQualifiedDomainName() (string, error) {
  method MustFullyQualifiedDomainName (line 22) | func (i *IE) MustFullyQualifiedDomainName() string {

FILE: gtpv2/ie/global-cn-id.go
  function NewGlobalCNID (line 15) | func NewGlobalCNID(mcc, mnc string, cnid uint16) *IE {
  method CNID (line 29) | func (i *IE) CNID() (uint16, error) {
  method MustCNID (line 43) | func (i *IE) MustCNID() uint16 {

FILE: gtpv2/ie/guti.go
  function NewGUTI (line 15) | func NewGUTI(mcc, mnc string, groupID uint16, code uint8, mTMSI uint32) ...
  method GUTI (line 26) | func (i *IE) GUTI() (*GUTIFields, error) {
  type GUTIFields (line 36) | type GUTIFields struct
    method Marshal (line 55) | func (f *GUTIFields) Marshal() ([]byte, error) {
    method MarshalTo (line 65) | func (f *GUTIFields) MarshalTo(b []byte) error {
    method UnmarshalBinary (line 98) | func (f *GUTIFields) UnmarshalBinary(b []byte) error {
    method MarshalLen (line 122) | func (f *GUTIFields) MarshalLen() int {
  function NewGUTIFields (line 44) | func NewGUTIFields(mcc, mnc string, groupID uint16, code uint8, mTMSI ui...
  function ParseGUTIFields (line 88) | func ParseGUTIFields(b []byte) (*GUTIFields, error) {
  method MMEGroupID (line 127) | func (i *IE) MMEGroupID() (uint16, error) {
  method MustMMEGroupID (line 141) | func (i *IE) MustMMEGroupID() uint16 {
  method MMECode (line 147) | func (i *IE) MMECode() (uint8, error) {
  method MustMMECode (line 161) | func (i *IE) MustMMECode() u
Condensed preview — 435 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,693K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 145,
    "preview": "version: 2\nupdates:\n- package-ecosystem: gomod\n  directory: \"/\"\n  schedule:\n    interval: daily\n    time: \"20:00\"\n  open"
  },
  {
    "path": ".github/workflows/go.yml",
    "chars": 2900,
    "preview": "on: [push, pull_request]\nname: Test\njobs:\n  test-linux:\n    strategy:\n      matrix:\n        go-version: [1.25.x, 1.26.x]"
  },
  {
    "path": ".github/workflows/golangci-lint.yml",
    "chars": 422,
    "preview": "name: golangci-lint\non:\n  push:\n    tags:\n      - v*\n    branches:\n      - main\n  pull_request:\njobs:\n  golangci:\n    na"
  },
  {
    "path": ".gitignore",
    "chars": 173,
    "preview": "examples/mme/mme\nexamples/pgw/pgw\nexamples/sgw/sgw\nexamples/gw-tester/enb/enb\nexamples/gw-tester/pgw/pgw\nexamples/gw-tes"
  },
  {
    "path": ".golangci.yml",
    "chars": 885,
    "preview": "version: \"2\"\nrun:\n  issues-exit-code: 1\n  tests: false\nlinters:\n  default: none\n  enable:\n    - asciicheck\n    - bodyclo"
  },
  {
    "path": "LICENSE",
    "chars": 1080,
    "preview": "MIT License\n\nCopyright (c) 2019-2025 Yoshiyuki Kurauchi\n\nPermission is hereby granted, free of charge, to any person obt"
  },
  {
    "path": "README.md",
    "chars": 7671,
    "preview": "# go-gtp: GTP in Go\n\nPackage gtp provides simple and painless handling of GTP (GPRS Tunneling Protocol) in the Go progra"
  },
  {
    "path": "doc.go",
    "chars": 801,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "errors.go",
    "chars": 478,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/README.md",
    "chars": 11995,
    "preview": "# GW Tester\n\nA pseudo eNB and MME as a tester for S/P-GW.\n\n## What's this?\n\n![diagram](./docs/diagram.png)\n\nIt is a burd"
  },
  {
    "path": "examples/gw-tester/enb/config.go",
    "chars": 1751,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/enb/enb.go",
    "chars": 10766,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/enb/enb.yml",
    "chars": 1664,
    "preview": "mcc: \"001\"\nmnc: \"01\"\nrat_type: 6 # E-UTRAN\ntai: 0x0001\neci: 0x00000001\nlocal_addresses:\n  s1c_ip: \"127.0.1.11\"\n  s1u_ip:"
  },
  {
    "path": "examples/gw-tester/enb/main.go",
    "chars": 1476,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/enb/metrics.go",
    "chars": 1606,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/mme/config.go",
    "chars": 824,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/mme/handlers.go",
    "chars": 5055,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/mme/main.go",
    "chars": 1463,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/mme/metrics.go",
    "chars": 1178,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/mme/mme.go",
    "chars": 7706,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/mme/mme.yml",
    "chars": 204,
    "preview": "mcc: \"001\"\nmnc: \"01\"\napn: \"gw-tester.go-gtp.example\"\nlocal_addresses:\n  s1c_addr: \"127.0.1.12:36412\"\n  s11_ip: \"127.0.1."
  },
  {
    "path": "examples/gw-tester/pgw/config.go",
    "chars": 829,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/pgw/handlers.go",
    "chars": 6942,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/pgw/main.go",
    "chars": 1211,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/pgw/metrics.go",
    "chars": 1613,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/pgw/pgw.go",
    "chars": 5160,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/pgw/pgw.yml",
    "chars": 190,
    "preview": "local_addresses:\n  s5c_ip: \"127.0.1.15\"\n  s5u_ip: \"127.0.0.15\"\n  sgi_ip: \"127.0.1.254\"\nsgi_if_name: \"lo\"\nroute_subnet: \""
  },
  {
    "path": "examples/gw-tester/s1mme/s1mme.pb.go",
    "chars": 19625,
    "preview": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// source: s1mme.proto\n\npackage s1mme\n\nimport (\n\tcontext \"context\"\n\tfmt"
  },
  {
    "path": "examples/gw-tester/s1mme/s1mme.proto",
    "chars": 1448,
    "preview": "syntax = \"proto3\";\n\npackage s1mme;\n\n// Attacher defines the service to attach UE.\nservice Attacher {\n    rpc Attach (Att"
  },
  {
    "path": "examples/gw-tester/sgw/config.go",
    "chars": 781,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/sgw/main.go",
    "chars": 1170,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/sgw/metrics.go",
    "chars": 1615,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/sgw/s11_handlers.go",
    "chars": 13942,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/sgw/s5_handlers.go",
    "chars": 8119,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/sgw/sgw.go",
    "chars": 7422,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/gw-tester/sgw/sgw.yml",
    "chars": 161,
    "preview": "local_addresses:\n  s11_ip: \"127.0.1.13\"\n  s1u_ip: \"127.0.0.13\"\n  s5c_ip: \"127.0.1.14\"\n  s5u_ip: \"127.0.0.14\"\nuse_kernel_"
  },
  {
    "path": "examples/mme/main.go",
    "chars": 6860,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/mme/mme.go",
    "chars": 5029,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/mme/mock.go",
    "chars": 5099,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/pgw/main.go",
    "chars": 2915,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/pgw/pgw.go",
    "chars": 7342,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/sgw/main.go",
    "chars": 4639,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/sgw/s11.go",
    "chars": 13301,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "examples/sgw/s5.go",
    "chars": 7207,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/wmnsk/go-gtp/gtpv2\"\n\t\"github.com/wmnsk/go-gtp/gtpv2/ie\"\n\t\"git"
  },
  {
    "path": "examples/utils/mac_local_host_enabler.sh",
    "chars": 137,
    "preview": "# This script will enable 127.0.0.1 up to 127.0.0.256 interfaces\nfor ((i=2;i<256;i++)) do \n  sudo ifconfig lo0 alias 127"
  },
  {
    "path": "go.mod",
    "chars": 1007,
    "preview": "module github.com/wmnsk/go-gtp\n\ngo 1.25.0\n\nrequire (\n\tgithub.com/golang/protobuf v1.5.4\n\tgithub.com/google/go-cmp v0.7.0"
  },
  {
    "path": "go.sum",
    "chars": 7500,
    "preview": "github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:"
  },
  {
    "path": "gtp.go",
    "chars": 1270,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtp_fuzz_test.go",
    "chars": 368,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtp_test.go",
    "chars": 2463,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/README.md",
    "chars": 6323,
    "preview": "# v0: GTPv0 in Golang\n\nPackage v0 provides simple and painless handling of GTPv0 protocol in pure Golang.\n\n## Getting St"
  },
  {
    "path": "gtpv0/constants.go",
    "chars": 1511,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/doc.go",
    "chars": 518,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/apn.go",
    "chars": 1345,
    "preview": "// Copyright 2019-2024 go-gtp. All rights reserved.\n// Use of this source code is governed by a MIT-style license that c"
  },
  {
    "path": "gtpv0/ie/cause.go",
    "chars": 723,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/charging-gateway-address.go",
    "chars": 1076,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/charging-id.go",
    "chars": 837,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/end-user-address.go",
    "chars": 3994,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/errors.go",
    "chars": 721,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/flow-label.go",
    "chars": 3469,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/gsn-address.go",
    "chars": 920,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/ie.go",
    "chars": 6128,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/ie_deprecated.go",
    "chars": 1271,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/ie_fuzz_test.go",
    "chars": 210,
    "preview": "package ie_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/wmnsk/go-gtp/gtpv0/ie\"\n)\n\nfunc FuzzParse(f *testing.F) {\n\tf.Fuzz(func"
  },
  {
    "path": "gtpv0/ie/ie_test.go",
    "chars": 5138,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/imsi.go",
    "chars": 869,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/ms-not-reachable-reason.go",
    "chars": 905,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/msisdn.go",
    "chars": 885,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/p-tmsi-signature.go",
    "chars": 902,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/p-tmsi.go",
    "chars": 843,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/private-extension.go",
    "chars": 2011,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/qos-profile.go",
    "chars": 3537,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/rai.go",
    "chars": 3022,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/recovery.go",
    "chars": 765,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/reordering-required.go",
    "chars": 653,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/selection-mode.go",
    "chars": 931,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/ie/tlli.go",
    "chars": 1057,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/create-pdp-context-req.go",
    "chars": 7712,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/create-pdp-context-req_deprecated.go",
    "chars": 1876,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/create-pdp-context-req_test.go",
    "chars": 2104,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/create-pdp-context-res.go",
    "chars": 7795,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/create-pdp-context-res_deprecated.go",
    "chars": 1904,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/create-pdp-context-res_test.go",
    "chars": 2380,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/delete-pdp-context-req.go",
    "chars": 3518,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/delete-pdp-context-req_deprecated.go",
    "chars": 1876,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/delete-pdp-context-req_test.go",
    "chars": 982,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/delete-pdp-context-res.go",
    "chars": 3746,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/delete-pdp-context-res_deprecated.go",
    "chars": 1904,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/delete-pdp-context-res_test.go",
    "chars": 1139,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/echo-req.go",
    "chars": 3229,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/echo-req_deprecated.go",
    "chars": 1540,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/echo-req_test.go",
    "chars": 946,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/echo-res.go",
    "chars": 3511,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/echo-res_deprecated.go",
    "chars": 1568,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/echo-res_test.go",
    "chars": 1051,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/errors.go",
    "chars": 411,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/generic.go",
    "chars": 2690,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/generic_deprecated.go",
    "chars": 1428,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/generic_test.go",
    "chars": 1367,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/header.go",
    "chars": 3554,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/header_deprecated.go",
    "chars": 1400,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/header_test.go",
    "chars": 1199,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/message.go",
    "chars": 6745,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/message_deprecated.go",
    "chars": 595,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/message_fuzz_test.go",
    "chars": 376,
    "preview": "package message_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/wmnsk/go-gtp/gtpv0/message\"\n)\n\nfunc FuzzParse(f *testing.F) {\n\tf"
  },
  {
    "path": "gtpv0/message/t-pdu.go",
    "chars": 1868,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/t-pdu_deprecated.go",
    "chars": 1344,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/t-pdu_test.go",
    "chars": 986,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/update-pdp-context-req.go",
    "chars": 6370,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/update-pdp-context-req_deprecated.go",
    "chars": 1876,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/update-pdp-context-req_test.go",
    "chars": 1630,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/update-pdp-context-res.go",
    "chars": 7092,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/update-pdp-context-res_deprecated.go",
    "chars": 1904,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/message/update-pdp-context-res_test.go",
    "chars": 2301,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv0/testutils/testutils.go",
    "chars": 2709,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/README.md",
    "chars": 23301,
    "preview": "# v1: GTPv1 in Golang\n\nPackage v1 provides simple and painless handling of GTPv1-C and GTPv1-U protocols in pure Golang."
  },
  {
    "path": "gtpv1/conn.go",
    "chars": 452,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/constants.go",
    "chars": 9659,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/doc.go",
    "chars": 430,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/errors.go",
    "chars": 1514,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/gtpv1_fuzz_test.go",
    "chars": 228,
    "preview": "package gtpv1_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/wmnsk/go-gtp/gtpv1\"\n)\n\nfunc FuzzDecapsulate(f *testing.F) {\n\tf.Fuz"
  },
  {
    "path": "gtpv1/handlers.go",
    "chars": 3540,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/apn-restriction.go",
    "chars": 846,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/apn.go",
    "chars": 1290,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/authentication-quintuplet.go",
    "chars": 3889,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/authentication-triplet.go",
    "chars": 2390,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/cause.go",
    "chars": 727,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/charging-id.go",
    "chars": 852,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/common-flags.go",
    "chars": 2424,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/end-user-address.go",
    "chars": 3399,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/errors.go",
    "chars": 725,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/extended-common-flags-ii.go",
    "chars": 1476,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/extended-common-flags.go",
    "chars": 2340,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/extension-header-type-list.go",
    "chars": 868,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/gsn-address.go",
    "chars": 1066,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/ie.go",
    "chars": 14050,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/ie_deprecated.go",
    "chars": 1271,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/ie_fuzz_test.go",
    "chars": 210,
    "preview": "package ie_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/wmnsk/go-gtp/gtpv1/ie\"\n)\n\nfunc FuzzParse(f *testing.F) {\n\tf.Fuzz(func"
  },
  {
    "path": "gtpv1/ie/ie_test.go",
    "chars": 6797,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/imei.go",
    "chars": 920,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/imei_test.go",
    "chars": 625,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/imsi.go",
    "chars": 848,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/ip.go",
    "chars": 1053,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/lac.go",
    "chars": 838,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/map-cause.go",
    "chars": 762,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/mcc-mnc.go",
    "chars": 1452,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/ms-timezone.go",
    "chars": 1883,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/ms-validated.go",
    "chars": 587,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/msisdn.go",
    "chars": 885,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/nsapi.go",
    "chars": 723,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/p-tmsi-signature.go",
    "chars": 902,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/p-tmsi.go",
    "chars": 843,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/pco.go",
    "chars": 4938,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/private-extension.go",
    "chars": 2011,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/qos-profile.go",
    "chars": 870,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/rac.go",
    "chars": 785,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/rai.go",
    "chars": 1227,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/rai_test.go",
    "chars": 697,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/ranap-cause.go",
    "chars": 786,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/rat-type.go",
    "chars": 757,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/recovery.go",
    "chars": 765,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/reordering-required.go",
    "chars": 650,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/selection-mode.go",
    "chars": 931,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/teardown-ind.go",
    "chars": 585,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/teid.go",
    "chars": 1084,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/uli-timestamp.go",
    "chars": 1045,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/uli.go",
    "chars": 3504,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/ie/uli_test.go",
    "chars": 2285,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/logger.go",
    "chars": 1460,
    "preview": "// Copyright 2019 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style license tha"
  },
  {
    "path": "gtpv1/message/create-pdp-context-req.go",
    "chars": 17555,
    "preview": "// Copyright 2019-2023 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/create-pdp-context-req_deprecated.go",
    "chars": 1876,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/create-pdp-context-req_test.go",
    "chars": 3061,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/create-pdp-context-res.go",
    "chars": 13232,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/create-pdp-context-res_deprecated.go",
    "chars": 1904,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/create-pdp-context-res_test.go",
    "chars": 1709,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/delete-pdp-context-req.go",
    "chars": 6019,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/delete-pdp-context-req_deprecated.go",
    "chars": 1876,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/delete-pdp-context-req_test.go",
    "chars": 1061,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/delete-pdp-context-res.go",
    "chars": 5038,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/delete-pdp-context-res_deprecated.go",
    "chars": 1904,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/delete-pdp-context-res_test.go",
    "chars": 1016,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/echo-req.go",
    "chars": 3086,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/echo-req_deprecated.go",
    "chars": 1540,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/echo-req_test.go",
    "chars": 750,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/echo-res.go",
    "chars": 3503,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/echo-res_deprecated.go",
    "chars": 1568,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/echo-res_test.go",
    "chars": 823,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/end-marker.go",
    "chars": 3026,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/end-marker_test.go",
    "chars": 715,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/error-indication.go",
    "chars": 3897,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/error-indication_deprecated.go",
    "chars": 1652,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/error-indication_test.go",
    "chars": 1058,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/errors.go",
    "chars": 766,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/extension-header.go",
    "chars": 4597,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/generic.go",
    "chars": 2675,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/generic_deprecated.go",
    "chars": 1428,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/generic_test.go",
    "chars": 769,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/header.go",
    "chars": 8144,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/header_deprecated.go",
    "chars": 1400,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  },
  {
    "path": "gtpv1/message/header_test.go",
    "chars": 7643,
    "preview": "// Copyright 2019-2024 go-gtp authors. All rights reserved.\n// Use of this source code is governed by a MIT-style licens"
  }
]

// ... and 235 more files (download for full content)

About this extraction

This page contains the full source code of the wmnsk/go-gtp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 435 files (1.5 MB), approximately 483.9k tokens, and a symbol index with 3940 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!