mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn.git
synced 2025-11-02 21:23:14 +00:00
Compare commits
65 Commits
cccamp2019
...
osmith/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5997357c69 | ||
|
|
de67c001b7 | ||
|
|
ad08d17e07 | ||
|
|
118c411e81 | ||
|
|
fa2656d14e | ||
|
|
6e6347613d | ||
|
|
61557f42c1 | ||
|
|
a868e17c5e | ||
|
|
1fd50d9abe | ||
|
|
4146121cc9 | ||
|
|
85386dcfad | ||
|
|
9203da58e2 | ||
|
|
b71d2c5ddd | ||
|
|
029a70e493 | ||
|
|
de80976d94 | ||
|
|
284314ab0a | ||
|
|
4d1d2e78b1 | ||
|
|
030824e172 | ||
|
|
0e124d3131 | ||
|
|
865bf6f1bf | ||
|
|
10af11dacc | ||
|
|
afadd102bf | ||
|
|
12235310af | ||
|
|
d597ee260a | ||
|
|
743e687496 | ||
|
|
4c7609a508 | ||
|
|
62f6f9aebf | ||
|
|
3bad31bcb4 | ||
|
|
eb5aee580d | ||
|
|
e30f19542b | ||
|
|
a8f782502b | ||
|
|
324bb5a11e | ||
|
|
1cb4be9db0 | ||
|
|
6888021bf2 | ||
|
|
10b3d70fea | ||
|
|
8e3766cd38 | ||
|
|
d7276bde55 | ||
|
|
35f0e664bf | ||
|
|
31c4657c97 | ||
|
|
2e91fee1ad | ||
|
|
33ebedc3d5 | ||
|
|
ab264ebba8 | ||
|
|
a0bcfad99b | ||
|
|
762c39ccc6 | ||
|
|
ea05d5c5f8 | ||
|
|
9d016fd499 | ||
|
|
b8f22bd6c7 | ||
|
|
fd815bba12 | ||
|
|
ccd1252bd7 | ||
|
|
02514bc592 | ||
|
|
9119d50849 | ||
|
|
3b848bdc42 | ||
|
|
8b88f5f7f3 | ||
|
|
a794811416 | ||
|
|
87264e6454 | ||
|
|
0b72240799 | ||
|
|
8333ef10c9 | ||
|
|
6dfb5fef40 | ||
|
|
259e303436 | ||
|
|
6ec5dc26b3 | ||
|
|
4ec21769b2 | ||
|
|
c44af53d1e | ||
|
|
f8d3e7fe05 | ||
|
|
d8037bcedc | ||
|
|
aa89f5dffc |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -2,6 +2,7 @@ debian/*.log
|
||||
*.o
|
||||
*.lo
|
||||
*.a
|
||||
*.la
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -38,9 +39,9 @@ ltmain.sh
|
||||
|
||||
|
||||
# apps and app data
|
||||
src/gprs/osmo-sgsn
|
||||
src/gprs/osmo-gbproxy
|
||||
src/gprs/osmo-gtphub
|
||||
src/sgsn/osmo-sgsn
|
||||
src/gbproxy/osmo-gbproxy
|
||||
src/gtphub/osmo-gtphub
|
||||
src/libcommon/gsup_test_client
|
||||
|
||||
#tests
|
||||
|
||||
4
TODO-RELEASE
Normal file
4
TODO-RELEASE
Normal file
@@ -0,0 +1,4 @@
|
||||
#component what description / commit summary line
|
||||
osmo-sgsn libgtp We dropped libgtp gtp_retranstimeout timer code which became a
|
||||
no-op in osmo-ggsn.git c94837c6a401bf0f80791b619a9b4cfbe9160afd,
|
||||
which means next osmo-sgsn release will require libgtp > 1.4.0.
|
||||
@@ -247,6 +247,9 @@ AC_OUTPUT(
|
||||
include/osmocom/sgsn/Makefile
|
||||
src/Makefile
|
||||
src/gprs/Makefile
|
||||
src/sgsn/Makefile
|
||||
src/gbproxy/Makefile
|
||||
src/gtphub/Makefile
|
||||
tests/Makefile
|
||||
tests/atlocal
|
||||
tests/gprs/Makefile
|
||||
|
||||
62
debian/copyright
vendored
62
debian/copyright
vendored
@@ -81,38 +81,38 @@ Files: include/osmocom/sgsn/a_reset.h
|
||||
include/osmocom/sgsn/gprs_utils.h
|
||||
include/osmocom/sgsn/gtphub.h
|
||||
include/osmocom/sgsn/signal.h
|
||||
src/gprs/crc24.c
|
||||
src/gprs/gb_proxy.c
|
||||
src/gprs/gb_proxy_main.c
|
||||
src/gprs/gb_proxy_patch.c
|
||||
src/gprs/gb_proxy_peer.c
|
||||
src/gprs/gb_proxy_tlli.c
|
||||
src/gprs/gb_proxy_vty.c
|
||||
src/gprs/gprs_gb_parse.c
|
||||
src/gprs/gprs_gmm.c
|
||||
src/gprs/gprs_llc.c
|
||||
src/gprs/gprs_llc_parse.c
|
||||
src/gprs/gprs_llc_vty.c
|
||||
src/gprs/gprs_llc_xid.c
|
||||
src/gprs/gprs_sgsn.c
|
||||
src/gprs/gprs_sndcp.c
|
||||
src/gprs/gprs_sndcp_comp.c
|
||||
src/gprs/gprs_sndcp_dcomp.c
|
||||
src/gprs/gprs_sndcp_pcomp.c
|
||||
src/gprs/gprs_sndcp_vty.c
|
||||
src/gprs/gprs_sndcp_xid.c
|
||||
src/gprs/gprs_subscriber.c
|
||||
src/gprs/crc24.c
|
||||
src/gprs/gprs_gb_parse.c
|
||||
src/gprs/gprs_utils.c
|
||||
src/gprs/gtphub.c
|
||||
src/gprs/gtphub_main.c
|
||||
src/gprs/gtphub_vty.c
|
||||
src/gprs/sgsn_ares.c
|
||||
src/gprs/sgsn_auth.c
|
||||
src/gprs/sgsn_cdr.c
|
||||
src/gprs/sgsn_ctrl.c
|
||||
src/gprs/sgsn_libgtp.c
|
||||
src/gprs/sgsn_main.c
|
||||
src/gprs/sgsn_vty.c
|
||||
src/gbproxy/gb_proxy.c
|
||||
src/gbproxy/gb_proxy_main.c
|
||||
src/gbproxy/gb_proxy_patch.c
|
||||
src/gbproxy/gb_proxy_peer.c
|
||||
src/gbproxy/gb_proxy_tlli.c
|
||||
src/gbproxy/gb_proxy_vty.c
|
||||
src/gtphub/gtphub.c
|
||||
src/gtphub/gtphub_main.c
|
||||
src/gtphub/gtphub_vty.c
|
||||
src/sgsn/gprs_gmm.c
|
||||
src/sgsn/gprs_llc.c
|
||||
src/sgsn/gprs_llc_vty.c
|
||||
src/sgsn/gprs_llc_xid.c
|
||||
src/sgsn/gprs_sgsn.c
|
||||
src/sgsn/gprs_sndcp.c
|
||||
src/sgsn/gprs_sndcp_comp.c
|
||||
src/sgsn/gprs_sndcp_dcomp.c
|
||||
src/sgsn/gprs_sndcp_pcomp.c
|
||||
src/sgsn/gprs_sndcp_vty.c
|
||||
src/sgsn/gprs_sndcp_xid.c
|
||||
src/sgsn/gprs_subscriber.c
|
||||
src/sgsn/sgsn_auth.c
|
||||
src/sgsn/sgsn_cdr.c
|
||||
src/sgsn/sgsn_ctrl.c
|
||||
src/sgsn/sgsn_libgtp.c
|
||||
src/sgsn/sgsn_main.c
|
||||
src/sgsn/sgsn_vty.c
|
||||
tests/gtphub/gtphub_test.c
|
||||
tests/sgsn/sgsn_test.c
|
||||
tests/slhc/slhc_test.c
|
||||
@@ -140,8 +140,8 @@ License: AGPL-3.0+
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Files: src/gprs/gtphub_ares.c
|
||||
src/gprs/gtphub_sock.c
|
||||
Files: src/gtphub/gtphub_ares.c
|
||||
src/gtphub/gtphub_sock.c
|
||||
tests/gbproxy/gbproxy_test.c
|
||||
Copyright: 2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
|
||||
2013 sysmocom s.f.m.c. GmbH
|
||||
|
||||
@@ -59,7 +59,7 @@ The LD_LIBRARY_PATH below may be needed if OpenGGSN installed to /usr/local.
|
||||
2. GTPHub:
|
||||
|
||||
cd <your-test-dir>
|
||||
path/to/openbsc/openbsc/src/gprs/osmo-gtphub -c gtphub.conf #-e 1 #for DEBUG level
|
||||
path/to/openbsc/openbsc/src/gtphub/osmo-gtphub -c gtphub.conf #-e 1 #for DEBUG level
|
||||
|
||||
3. SGSN tests:
|
||||
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
EXTRA_DIST = osmosgsn-usermanual.adoc \
|
||||
osmosgsn-usermanual-docinfo.xml \
|
||||
osmosgsn-vty-reference.xml \
|
||||
osmogbproxy-usermanual.adoc \
|
||||
osmogbproxy-usermanual-docinfo.xml \
|
||||
regen_doc.sh \
|
||||
chapters \
|
||||
vty
|
||||
vty \
|
||||
osmogbproxy-vty-reference.xml \
|
||||
vty-osmogbproxy \
|
||||
$(NULL)
|
||||
|
||||
if BUILD_MANUALS
|
||||
ASCIIDOC = osmosgsn-usermanual.adoc
|
||||
ASCIIDOC = osmosgsn-usermanual.adoc osmogbproxy-usermanual.adoc
|
||||
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
||||
|
||||
VTY_REFERENCE = osmosgsn-vty-reference.xml
|
||||
VTY_REFERENCE = osmosgsn-vty-reference.xml osmogbproxy-vty-reference.xml
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||
|
||||
OSMO_REPOSITORY = osmo-sgsn
|
||||
|
||||
6
doc/manuals/chapters/gbproxy-configuration.adoc
Normal file
6
doc/manuals/chapters/gbproxy-configuration.adoc
Normal file
@@ -0,0 +1,6 @@
|
||||
== Configuring OsmoGbPROXY
|
||||
|
||||
TBD. Unfortunately this chapter of the manual still needs to be written.
|
||||
Osmocom has very limited funding and support resources; Feel free to help
|
||||
us completing this documentation by contributing with code, documentation
|
||||
or by supporting the developers financially.
|
||||
29
doc/manuals/chapters/gbproxy-control.adoc
Normal file
29
doc/manuals/chapters/gbproxy-control.adoc
Normal file
@@ -0,0 +1,29 @@
|
||||
[[control]]
|
||||
== Control interface
|
||||
|
||||
The actual protocol is described in <<common-control-if>>, the variables
|
||||
common to all programs using it are described in <<ctrl_common_vars>>. Here we
|
||||
describe variables specific to OsmoGbPROXY.
|
||||
|
||||
.Variables available over control interface
|
||||
[options="header",width="100%",cols="20%,5%,5%,50%,20%"]
|
||||
|===
|
||||
|Name|Access|Trap|Value|Comment
|
||||
|nsvc-state|RO|No|"<nsei>,<nsvci>,<local-alive>,<local-blocked>,<remote-role>,<remote-alive>,<remote-blocked>"|See <<nsvc_state>> for details.
|
||||
|gbproxy-state|RO|No|"<nsei>,<bvci>,<mcc>,<mnc>,<lac>,<rac>,<blocked>"|See <<gbproxy_state>> for details.
|
||||
|number-of-peers|RO|No|"<num-of-bss>"|Count of concurrent BSS(BTS) peers.
|
||||
|===
|
||||
|
||||
[[nsvc_state]]
|
||||
=== nsvc-state
|
||||
|
||||
Return the list of active NS-VCs (NS Virtual Circuits), including information
|
||||
on the key parameters, such as NSEI, NSVCI and the local + remote ALIVE
|
||||
and BLOCKED state.
|
||||
|
||||
[[gbproxy_state]]
|
||||
=== gbproxy-state
|
||||
|
||||
Return the list of active Peers, including information on the key
|
||||
parameters, such as NSEI, BVCI, and the MCC-MNC-LAC-RAC of the attached
|
||||
BSS, as well as the overall state (BLOCKED or UNBLOCKED).
|
||||
127
doc/manuals/chapters/gbproxy-overview.adoc
Normal file
127
doc/manuals/chapters/gbproxy-overview.adoc
Normal file
@@ -0,0 +1,127 @@
|
||||
[[chapter_overview]]
|
||||
== Overview
|
||||
|
||||
=== About OsmoGbPROXY
|
||||
|
||||
OsmoGbPROXY is the Osmocom proxy for the 3GPP Gb interface. The Gb
|
||||
interface is defined by 3GPP as the protocol between the BSS and the
|
||||
SGSN inside the 2G/2.5G/2.75G packet switched network domain.
|
||||
|
||||
As Osmocom implements a BTS-colocated PCU, there are potentially many
|
||||
Gb interface connections between all those many PCUs in the network
|
||||
and the SGSN. This can be cumbersome to configure/maintain at the
|
||||
SGSN sine.
|
||||
|
||||
OsmoGbPROXY aggregates many PCU-facing Gb connections into one Gb
|
||||
connection to the SGSN. This is achieved by
|
||||
|
||||
* maintaining sepaate NS-VCs on the PCU side and on the SGSN side
|
||||
* more or less transparently routing BSSGP peer-to-peer Virtual Circuits
|
||||
(BVCs) through the proxy
|
||||
* having some special handling for the signaling BVC (BVCI=0) which is
|
||||
shared among all the PCUs connected to the proxy
|
||||
|
||||
=== Data Model
|
||||
|
||||
==== gbproxy_config
|
||||
|
||||
This contains the parsed configuration of the OsmoGbPROXY.
|
||||
|
||||
==== gproxy_peer
|
||||
|
||||
A "peer" is any remote NS-entity that the proxy interacts with. A peer
|
||||
includes information about:
|
||||
|
||||
* the [unique] NSEI of the peer
|
||||
* the [unique] BVCI of the peer
|
||||
* the Routeing Area (RA) of the peer
|
||||
|
||||
==== gbproxy_tlli_state
|
||||
|
||||
One of the (unique) TLLI of any of the subscribers/UEs attached to any of
|
||||
the BTSs/PCUs served by the proxy.
|
||||
|
||||
==== gbproxy_link_info
|
||||
|
||||
One of the [unique] subscribers/connections that are served through this
|
||||
proxy. The information includes
|
||||
|
||||
* the TLLI on BSS side
|
||||
* the TLLI on SGSN side (may be different due to P-TMSI rewriting)
|
||||
* the NSEI of the SGSN for this link
|
||||
* a timestamp when we last conversed with this subscriber
|
||||
* state related to IMSI acquisition
|
||||
** a temporary queue of stored messages (until IMSI acquisition succeeds)
|
||||
** N(U) rewriting state (inserting IDENTTIY REQ changes LLC sequence numbers)
|
||||
|
||||
==== gbproxy_match
|
||||
|
||||
A single matching rule against which IMSIs are matched. The matching rule
|
||||
is expressed as regular expression. There can be one such matching rule for
|
||||
each
|
||||
|
||||
* routing between two different SGSNs, see below
|
||||
* patching of messages (e.g. APN, PLMN)
|
||||
|
||||
|
||||
=== Advanced Features
|
||||
|
||||
==== PLMN patching
|
||||
|
||||
This feature permits to modify the PLMN inside any BSSGP messages
|
||||
containing the Routing Area ID (RAID).
|
||||
|
||||
The configured core-mcc and core-mnc will be used towards the SGSN,
|
||||
irrespective of which MCC/MNC the PCU is using/reporting on Gb.
|
||||
|
||||
==== APN patching
|
||||
|
||||
This will transparently re-write the APN name inside SM ACTIVATE PDP
|
||||
REQUEST messages on the way from the MS to the SGSN. The patching is
|
||||
performed based on matching on the IMSI of the subscriber.
|
||||
|
||||
The configured core-apn will be used towards the SGSN, irrespective
|
||||
of which APN the MS is requesting in its Layer3 signaling.
|
||||
|
||||
APN patching can only be performed if no GPRS encryption is enabled in
|
||||
the network!
|
||||
|
||||
APN patching is useful in case a valid APN cannot reliably be
|
||||
provisioned via other means, such as via the SIM Card, OTA-DM or via
|
||||
CAMEL rewriting in the SGSN.
|
||||
|
||||
==== P-TMSI patching
|
||||
|
||||
This feature transparently rewrite the P-TMSI between MS and SGSN. This
|
||||
is required when using the Secondary SGSN support, as both SGSNs could
|
||||
allocate overlapping TMSIs and we must make sure they're unique across
|
||||
both SGSNs.
|
||||
|
||||
P-TMSI patching is required by (and hence automatically enablede if
|
||||
secondary SGSN support is enabled.
|
||||
|
||||
P-TMSI patching can only be performed if no GPRS encryption is enabled in
|
||||
the network!
|
||||
|
||||
==== IMSI Acquisition
|
||||
|
||||
This is a special feature where the proxy will by itself inject GMM IDENTITY
|
||||
REQUEST messages for the IMSI into the downlink BSSGP traffic in order
|
||||
to establish the IMSI of subscribers for which it is not otherwise known
|
||||
|
||||
IMSI acquisition is automatically enabled if secondary SGSN support is
|
||||
enabled.
|
||||
|
||||
==== Secondary SGSN Support
|
||||
|
||||
This allows the proxy to connect not only to one SGSN, but to two
|
||||
different SGSNs. IMSI matching rules are applied to determine which of
|
||||
the SGSNs is to be used for traffic of this subscriber.
|
||||
|
||||
One possible use case of this feature is to have a "local break-out" for
|
||||
subscribers who are native to this network (and hence save
|
||||
latencies/overhead of back-hauling all related traffic via the
|
||||
SGSN+GGSN) while at the same time maintaining the classic behavior for
|
||||
inbound roaming subscribers, where the roaming agreements mandate that
|
||||
data traffic is brought back to the GGSN in the HPLMN via the SGSN of
|
||||
the VPLMN.
|
||||
39
doc/manuals/chapters/gbproxy-running.adoc
Normal file
39
doc/manuals/chapters/gbproxy-running.adoc
Normal file
@@ -0,0 +1,39 @@
|
||||
== Running OsmoGbPROXY
|
||||
|
||||
The OsmoGbPROXY executable (`osmo-gbproxy`) offers the following command-line
|
||||
options:
|
||||
|
||||
|
||||
=== SYNOPSIS
|
||||
|
||||
*osmo-gbproxy* [-h|-V] [-d 'DBGMASK'] [-D] [-c 'CONFIGFILE'] [-s] [-e 'LOGLEVEL'] [-T]
|
||||
|
||||
|
||||
=== OPTIONS
|
||||
|
||||
*-h, --help*::
|
||||
Print a short help message about the supported options
|
||||
*-V, --version*::
|
||||
Print the compile-time version number of the program
|
||||
*-d, --debug 'DBGMASK','DBGLEVELS'*::
|
||||
Set the log subsystems and levels for logging to stderr. This
|
||||
has mostly been superseded by VTY-based logging configuration,
|
||||
see <<logging>> for further information.
|
||||
*-D, --daemonize*::
|
||||
Fork the process as a daemon into background.
|
||||
*-c, --config-file 'CONFIGFILE'*::
|
||||
Specify the file and path name of the configuration file to be
|
||||
used. If none is specified, use `osmo_sgsn.cfg` in the current
|
||||
working directory.
|
||||
*-s, --disable-color*::
|
||||
Disable colors for logging to stderr. This has mostly been
|
||||
deprecated by VTY based logging configuration, see <<logging>>
|
||||
for more information.
|
||||
*-e, --log-level 'LOGLEVEL'*::
|
||||
Set the global log level for logging to stderr. This has mostly
|
||||
been deprecated by VTY based logging configuration, see
|
||||
<<logging>> for more information.
|
||||
*-T, --timestamp*::
|
||||
Enable prefixing each log line on stderr with a timestamp. This
|
||||
has mostly been deprecated by VTY based logging configuration, see
|
||||
<<logging>> for more information.
|
||||
46
doc/manuals/osmogbproxy-usermanual-docinfo.xml
Normal file
46
doc/manuals/osmogbproxy-usermanual-docinfo.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>1</revnumber>
|
||||
<date>March 21, 2019</date>
|
||||
<authorinitials>HW</authorinitials>
|
||||
<revremark>
|
||||
Initial version.
|
||||
</revremark>
|
||||
</revision>
|
||||
</revhistory>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Harald</firstname>
|
||||
<surname>Welte</surname>
|
||||
<email>hwelte@sysmocom.de</email>
|
||||
<authorinitials>HW</authorinitials>
|
||||
<affiliation>
|
||||
<shortaffil>sysmocom</shortaffil>
|
||||
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
|
||||
<jobtitle>Managing Director</jobtitle>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2013-2019</year>
|
||||
<holder>sysmocom - s.f.m.c. GmbH</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
Permission is granted to copy, distribute and/or modify this
|
||||
document under the terms of the GNU Free Documentation License,
|
||||
Version 1.3 or any later version published by the Free Software
|
||||
Foundation; with no Invariant Sections, no Front-Cover Texts,
|
||||
and no Back-Cover Texts. A copy of the license is included in
|
||||
the section entitled "GNU Free Documentation License".
|
||||
</para>
|
||||
<para>
|
||||
The Asciidoc source code of this manual can be found at
|
||||
<ulink url="https://git.osmocom.org/osmo-sgsn/doc/">
|
||||
https://git.osmocom.org/osmo-sgsn/doc/
|
||||
</ulink>
|
||||
</para>
|
||||
</legalnotice>
|
||||
34
doc/manuals/osmogbproxy-usermanual.adoc
Normal file
34
doc/manuals/osmogbproxy-usermanual.adoc
Normal file
@@ -0,0 +1,34 @@
|
||||
:gfdl-enabled:
|
||||
|
||||
OsmoGbPROXY User Manual
|
||||
=======================
|
||||
Harald Welte <hwelte@sysmocom.de>
|
||||
|
||||
|
||||
include::./common/chapters/preface.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/gbproxy-overview.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/gbproxy-running.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/gbproxy-control.adoc[]
|
||||
|
||||
include::./common/chapters/vty.adoc[]
|
||||
|
||||
include::./common/chapters/logging.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/gbproxy-configuration.adoc[]
|
||||
|
||||
include::./common/chapters/gb.adoc[]
|
||||
|
||||
include::./common/chapters/control_if.adoc[]
|
||||
|
||||
//include::{srcdir}/chapters/counters.adoc[]
|
||||
|
||||
include::./common/chapters/port_numbers.adoc[]
|
||||
|
||||
include::./common/chapters/bibliography.adoc[]
|
||||
|
||||
include::./common/chapters/glossary.adoc[]
|
||||
|
||||
include::./common/chapters/gfdl.adoc[]
|
||||
38
doc/manuals/osmogbproxy-vty-reference.xml
Normal file
38
doc/manuals/osmogbproxy-vty-reference.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
ex:ts=2:sw=42sts=2:et
|
||||
-*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
-->
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
|
||||
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
|
||||
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
|
||||
<!ENTITY sections-vty SYSTEM "generated/docbook_osmogbproxy-vty-reference.xml" >
|
||||
]>
|
||||
|
||||
<book>
|
||||
<info>
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>v1</revnumber>
|
||||
<date>2nd December 2019</date>
|
||||
<authorinitials>hw</authorinitials>
|
||||
<revremark>Initial</revremark>
|
||||
</revision>
|
||||
</revhistory>
|
||||
|
||||
<title>OsmoGbProxy VTY Reference</title>
|
||||
|
||||
<copyright>
|
||||
<year>2019</year>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</info>
|
||||
|
||||
<!-- Main chapters-->
|
||||
&chapter-vty;
|
||||
</book>
|
||||
|
||||
@@ -1,17 +1,77 @@
|
||||
#!/bin/sh -x
|
||||
#!/bin/sh -e
|
||||
|
||||
if [ -z "$DOCKER_PLAYGROUND" ]; then
|
||||
echo "You need to set DOCKER_PLAYGROUND"
|
||||
require_osmo_interact_vty() {
|
||||
if command -v osmo_interact_vty.py >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
echo "ERROR: osmo_interact_vty.py not found. Are osmo-python-tests in PATH?"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
SCRIPT=$(realpath "$0")
|
||||
MANUAL_DIR=$(dirname "$SCRIPT")
|
||||
# $1: "update_vty_reference" or "update_counters"
|
||||
# $2: output file
|
||||
# $3: port
|
||||
# $4-$n: command
|
||||
interact_vty() {
|
||||
action="$1"
|
||||
output="$2"
|
||||
port="$3"
|
||||
log="/tmp/$4.log"
|
||||
shift 3
|
||||
|
||||
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
|
||||
echo "Starting in background: $@"
|
||||
"$@" > "$log" 2>&1 &
|
||||
pid="$!"
|
||||
|
||||
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
|
||||
sleep 0.5
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
echo "ERROR: start failed!"
|
||||
cat "$log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OSMO_SGSN_BRANCH=$COMMIT ./regen_doc.sh osmo-sgsn 4245 \
|
||||
"$MANUAL_DIR/chapters/counters_generated.adoc" \
|
||||
"$MANUAL_DIR/vty/sgsn_vty_reference.xml"
|
||||
case "$action" in
|
||||
"update_vty_reference")
|
||||
echo "Updating VTY reference: $output"
|
||||
osmo_interact_vty.py -X -p "$port" -H 127.0.0.1 -O "$output"
|
||||
;;
|
||||
"update_counters")
|
||||
echo "Updating asciidoc counters: $output"
|
||||
osmo_interact_vty.py -c "enable;show asciidoc counters" -p "$port" -H 127.0.0.1 -O "$output"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: invalid argument: $action"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
kill "$pid"
|
||||
echo "Done (killed $1)"
|
||||
echo
|
||||
}
|
||||
|
||||
DIR="$(cd "$(dirname "$0")"; pwd)"
|
||||
cd "$DIR"
|
||||
|
||||
require_osmo_interact_vty
|
||||
|
||||
interact_vty \
|
||||
"update_vty_reference" \
|
||||
"vty/sgsn_vty_reference.xml" \
|
||||
4245 \
|
||||
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
|
||||
|
||||
interact_vty \
|
||||
"update_vty_reference" \
|
||||
"vty-osmogbproxy/gbproxy_vty_reference.xml" \
|
||||
4246 \
|
||||
osmo-gbproxy -c "../examples/osmo-gbproxy/osmo-gbproxy.cfg"
|
||||
|
||||
interact_vty \
|
||||
"update_counters" \
|
||||
"chapters/counters_generated.adoc" \
|
||||
4245 \
|
||||
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
|
||||
|
||||
|
||||
echo "Done with all"
|
||||
|
||||
5
doc/manuals/vty-osmogbproxy/gbproxy_vty_additions.xml
Normal file
5
doc/manuals/vty-osmogbproxy/gbproxy_vty_additions.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
|
||||
<node id='config-gbproxy'>
|
||||
<description>Configure the Gb proxy</description>
|
||||
</node>
|
||||
</vtydoc>
|
||||
1627
doc/manuals/vty-osmogbproxy/gbproxy_vty_reference.xml
Normal file
1627
doc/manuals/vty-osmogbproxy/gbproxy_vty_reference.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,12 +3,18 @@ noinst_HEADERS = \
|
||||
crc24.h \
|
||||
debug.h \
|
||||
gb_proxy.h \
|
||||
gprs_gb.h \
|
||||
gprs_gb_parse.h \
|
||||
gprs_gmm.h \
|
||||
gprs_gmm_fsm.h \
|
||||
gprs_gmm_attach.h \
|
||||
gprs_mm_state_gb_fsm.h \
|
||||
gprs_mm_state_iu_fsm.h \
|
||||
gprs_llc.h \
|
||||
gprs_llc_xid.h \
|
||||
gprs_ranap.h \
|
||||
gprs_sgsn.h \
|
||||
gprs_sm.h \
|
||||
gprs_sndcp_comp.h \
|
||||
gprs_sndcp_dcomp.h \
|
||||
gprs_sndcp.h \
|
||||
|
||||
@@ -39,6 +39,7 @@ enum {
|
||||
DVLR,
|
||||
DIUCS,
|
||||
DSIGTRAN,
|
||||
DGTP,
|
||||
Debug_LastEntry,
|
||||
};
|
||||
|
||||
|
||||
14
include/osmocom/sgsn/gprs_gb.h
Normal file
14
include/osmocom/sgsn/gprs_gb.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
|
||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
|
||||
bool drop_cipherable);
|
||||
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
|
||||
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx);
|
||||
|
||||
/* page a MS in its routing area */
|
||||
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx);
|
||||
@@ -6,19 +6,16 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown);
|
||||
int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
|
||||
uint8_t cause, uint8_t pco_len, uint8_t *pco_v);
|
||||
int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);
|
||||
int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);
|
||||
int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
|
||||
const struct osmo_auth_vector *vec,
|
||||
uint8_t key_seq, bool force_standby);
|
||||
|
||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
|
||||
bool drop_cipherable);
|
||||
int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
|
||||
uint16_t *sai);
|
||||
int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
struct gprs_llc_llme *llme, bool drop_cipherable);
|
||||
int gsm48_gmm_sendmsg(struct msgb *msg, int command,
|
||||
struct sgsn_mm_ctx *mm, bool encryptable);
|
||||
int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);
|
||||
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
|
||||
struct gprs_llc_llme *llme);
|
||||
@@ -33,8 +30,6 @@ int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
|
||||
|
||||
time_t gprs_max_time_to_idle(void);
|
||||
|
||||
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp);
|
||||
|
||||
int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type);
|
||||
int gsm48_tx_gmm_att_rej(struct sgsn_mm_ctx *mm,
|
||||
uint8_t gmm_cause);
|
||||
@@ -42,9 +37,11 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm);
|
||||
|
||||
int gprs_gmm_attach_req_ies(struct msgb *a, struct msgb *b);
|
||||
|
||||
int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx);
|
||||
/* TODO: move extract_subscr_* when gsm48_gmm_authorize() got removed */
|
||||
void extract_subscr_msisdn(struct sgsn_mm_ctx *ctx);
|
||||
void extract_subscr_hlr(struct sgsn_mm_ctx *ctx);
|
||||
|
||||
void pdp_ctx_detach_mm_ctx(struct sgsn_pdp_ctx *pdp);
|
||||
void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg);
|
||||
void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm);
|
||||
#endif /* _GPRS_GMM_H */
|
||||
|
||||
34
include/osmocom/sgsn/gprs_gmm_fsm.h
Normal file
34
include/osmocom/sgsn/gprs_gmm_fsm.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
/* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */
|
||||
enum gmm_fsm_states {
|
||||
ST_GMM_DEREGISTERED, /* 4.1.3.3.1.1 */
|
||||
ST_GMM_COMMON_PROC_INIT, /* 4.1.3.3.1.2 */
|
||||
ST_GMM_REGISTERED_NORMAL, /* 4.1.3.3.2.1 */
|
||||
ST_GMM_REGISTERED_SUSPENDED, /* 4.1.3.3.2.2 */
|
||||
ST_GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */
|
||||
};
|
||||
|
||||
enum gmm_fsm_events {
|
||||
E_GMM_COMMON_PROC_INIT_REQ,
|
||||
/* E_GMM_COMMON_PROC_FAILED, NOT USED */
|
||||
/* E_GMM_LOWER_LAYER_FAILED, NOT USED */
|
||||
E_GMM_COMMON_PROC_SUCCESS,
|
||||
E_GMM_ATTACH_SUCCESS,
|
||||
/* E_GMM_NET_INIT_DETACH_REQ, NOT USED */
|
||||
/* E_GMM_MS_INIT_DETACH_REQ, NOT USED */
|
||||
/* E_GMM_DETACH_ACCEPTED, */
|
||||
E_GMM_SUSPEND,
|
||||
E_GMM_RESUME,
|
||||
E_GMM_CLEANUP,
|
||||
};
|
||||
|
||||
static inline bool gmm_fsm_is_registered(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
return fi->state == ST_GMM_REGISTERED_NORMAL ||
|
||||
fi->state == ST_GMM_REGISTERED_SUSPENDED;
|
||||
}
|
||||
|
||||
extern struct osmo_fsm gmm_fsm;
|
||||
26
include/osmocom/sgsn/gprs_mm_state_gb_fsm.h
Normal file
26
include/osmocom/sgsn/gprs_mm_state_gb_fsm.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
struct sgsn_mm_ctx;
|
||||
|
||||
|
||||
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
|
||||
enum mm_state_gb_fsm_states {
|
||||
ST_MM_IDLE,
|
||||
ST_MM_READY,
|
||||
ST_MM_STANDBY
|
||||
};
|
||||
|
||||
enum mm_state_gb_fsm_events {
|
||||
E_MM_GPRS_ATTACH,
|
||||
/* E_GPRS_DETACH, TODO: not used */
|
||||
E_MM_PDU_RECEPTION,
|
||||
E_MM_IMPLICIT_DETACH, /* = E_MM_CANCEL_LOCATION */
|
||||
E_MM_READY_TIMER_EXPIRY,
|
||||
/* E_FORCE_TO_STANDBY, TODO: not used */
|
||||
/* E_ABNSORMAL_RLC_CONDITION, TODO: not used */
|
||||
E_MM_RA_UPDATE,
|
||||
};
|
||||
|
||||
extern struct osmo_fsm mm_state_gb_fsm;
|
||||
25
include/osmocom/sgsn/gprs_mm_state_iu_fsm.h
Normal file
25
include/osmocom/sgsn/gprs_mm_state_iu_fsm.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
struct sgsn_mm_ctx;
|
||||
|
||||
|
||||
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
|
||||
enum mm_state_iu_fsm_states {
|
||||
ST_PMM_DETACHED,
|
||||
ST_PMM_CONNECTED,
|
||||
ST_PMM_IDLE
|
||||
};
|
||||
|
||||
enum mm_state_iu_fsm_events {
|
||||
E_PMM_PS_ATTACH,
|
||||
/* E_PS_DETACH, TODO: not used */
|
||||
E_PMM_PS_CONN_RELEASE,
|
||||
E_PMM_PS_CONN_ESTABLISH,
|
||||
E_PMM_IMPLICIT_DETACH, /* = E_PS_ATTACH_REJECT, E_RAU_REJECT */
|
||||
E_PMM_RA_UPDATE, /* = Serving RNC relocation */
|
||||
E_PMM_USER_INACTIVITY, /* when the inactivity timer runs out */
|
||||
};
|
||||
|
||||
extern struct osmo_fsm mm_state_iu_fsm;
|
||||
34
include/osmocom/sgsn/gprs_ranap.h
Normal file
34
include/osmocom/sgsn/gprs_ranap.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
|
||||
#ifdef BUILD_IU
|
||||
#include <osmocom/ranap/ranap_ies_defs.h>
|
||||
#include <osmocom/ranap/ranap_msg_factory.h>
|
||||
#include <osmocom/ranap/iu_client.h>
|
||||
|
||||
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx);
|
||||
int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data);
|
||||
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp);
|
||||
|
||||
/* free the Iu UE context */
|
||||
void sgsn_ranap_iu_free(struct sgsn_mm_ctx *ctx);
|
||||
|
||||
/* send a Iu Release Command and free afterwards the UE context */
|
||||
void sgsn_ranap_iu_release_free(struct sgsn_mm_ctx *ctx,
|
||||
const struct RANAP_Cause *cause);
|
||||
|
||||
int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, uint16_t *sai);
|
||||
|
||||
#else /* ifndef BUILD_IU */
|
||||
inline static void sgsn_ranap_iu_free(void *ctx) {};
|
||||
inline static void sgsn_ranap_iu_release_free(void *ctx, void *cause) {};
|
||||
#endif /* BUILD_IU*/
|
||||
|
||||
struct ranap_ue_conn_ctx;
|
||||
/* On RANAP, Returns pointer to he associated ranap_ue_conn_ctx in msg, filled
|
||||
* in by osmo-iuh's iu_recv_cb().
|
||||
* On Gb, returns NULL */
|
||||
#define MSG_IU_UE_CTX(msg) ((struct ranap_ue_conn_ctx *)(msg)->dst)
|
||||
#define MSG_IU_UE_CTX_SET(msg, val) (msg)->dst = (val)
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
@@ -22,25 +23,6 @@ struct gprs_subscr;
|
||||
|
||||
enum gsm48_gsm_cause;
|
||||
|
||||
/* TS 04.08 4.1.3.3 GMM mobility management states on the network side */
|
||||
enum gprs_gmm_state {
|
||||
GMM_DEREGISTERED, /* 4.1.3.3.1.1 */
|
||||
GMM_COMMON_PROC_INIT, /* 4.1.3.3.1.2 */
|
||||
GMM_REGISTERED_NORMAL, /* 4.1.3.3.2.1 */
|
||||
GMM_REGISTERED_SUSPENDED, /* 4.1.3.3.2.2 */
|
||||
GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */
|
||||
};
|
||||
|
||||
/* TS 23.060 6.1.1 and 6.1.2 Mobility management states A/Gb and Iu mode */
|
||||
enum gprs_pmm_state {
|
||||
PMM_DETACHED,
|
||||
PMM_CONNECTED,
|
||||
PMM_IDLE,
|
||||
MM_IDLE,
|
||||
MM_READY,
|
||||
MM_STANDBY,
|
||||
};
|
||||
|
||||
enum gprs_mm_ctr {
|
||||
GMM_CTR_PKTS_SIG_IN,
|
||||
GMM_CTR_PKTS_SIG_OUT,
|
||||
@@ -113,6 +95,7 @@ enum sgsn_ran_type {
|
||||
MM_CTX_T_GERAN_Iu,
|
||||
#endif
|
||||
};
|
||||
extern const struct value_string sgsn_ran_type_names[];
|
||||
|
||||
struct service_info {
|
||||
uint8_t type;
|
||||
@@ -136,8 +119,7 @@ struct sgsn_mm_ctx {
|
||||
enum sgsn_ran_type ran_type;
|
||||
|
||||
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
enum gprs_gmm_state gmm_state;
|
||||
enum gprs_pmm_state pmm_state; /* Iu: page when in PMM-IDLE mode */
|
||||
struct osmo_fsm_inst *gmm_fsm;
|
||||
uint32_t p_tmsi;
|
||||
uint32_t p_tmsi_old; /* old P-TMSI before new is confirmed */
|
||||
uint32_t p_tmsi_sig;
|
||||
@@ -157,9 +139,8 @@ struct sgsn_mm_ctx {
|
||||
uint32_t tlli;
|
||||
uint32_t tlli_new;
|
||||
|
||||
/* timer for mm state. state=READY: T3314 (aka TS 23.060 "READY timer") */
|
||||
struct osmo_timer_list state_timer;
|
||||
unsigned int state_T; /* Txxxx number but only used for pmm_states */
|
||||
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
|
||||
struct osmo_fsm_inst *mm_state_fsm;
|
||||
} gb;
|
||||
struct {
|
||||
int new_key;
|
||||
@@ -174,6 +155,8 @@ struct sgsn_mm_ctx {
|
||||
/* Voice Support Match Indicator */
|
||||
struct ranap_ue_conn_ctx *ue_ctx;
|
||||
struct service_info service;
|
||||
/* TS 23.060 6.1.2 Mobility Management States (Iu mode) */
|
||||
struct osmo_fsm_inst *mm_state_fsm;
|
||||
} iu;
|
||||
struct {
|
||||
struct osmo_fsm_inst *fsm;
|
||||
@@ -274,15 +257,15 @@ static inline bool sgsn_mm_ctx_is_authenticated(struct sgsn_mm_ctx *ctx)
|
||||
LOGP(DMM, level, "UE(%p){NOTSUPPORTED} " fmt, ue, ## args)
|
||||
#endif
|
||||
|
||||
#define LOGGBP(llme, level, fmt, args...) \
|
||||
LOGP(DMM, level, "LLME(%08x/%08x){%s} " fmt, (llme)->old_tlli, \
|
||||
#define LOGGBP(llme, category, level, fmt, args...) \
|
||||
LOGP(category, level, "LLME(%08x/%08x){%s} " fmt, (llme)->old_tlli, \
|
||||
(llme)->tlli, get_value_string_or_null(gprs_llc_llme_state_names, (llme)->state), ## args);
|
||||
|
||||
#define LOGGBIUP(llme, msg, level, fmt, args...) \
|
||||
do { \
|
||||
struct ranap_ue_conn_ctx * _ue; \
|
||||
if (llme) { \
|
||||
LOGGBP(llme, level, fmt, ## args); \
|
||||
LOGGBP(llme, DMM, level, fmt, ## args); \
|
||||
} else if ((msg) && (_ue = MSG_IU_UE_CTX(msg))) { \
|
||||
LOGIUP(_ue, level, fmt, ## args); \
|
||||
} else { OSMO_ASSERT(0); } \
|
||||
@@ -392,7 +375,7 @@ struct sgsn_ggsn_ctx {
|
||||
struct gsn_t *gsn;
|
||||
struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
|
||||
struct osmo_timer_list echo_timer;
|
||||
int echo_interval;
|
||||
unsigned int echo_interval;
|
||||
};
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
|
||||
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
|
||||
@@ -401,10 +384,16 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr);
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
|
||||
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
|
||||
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
|
||||
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
|
||||
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
|
||||
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
|
||||
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc);
|
||||
|
||||
#define LOGGGSN(ggc, level, fmt, args...) { \
|
||||
char _buf[INET_ADDRSTRLEN]; \
|
||||
LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \
|
||||
} while (0)
|
||||
|
||||
struct apn_ctx {
|
||||
struct llist_head list;
|
||||
struct sgsn_ggsn_ctx *ggsn;
|
||||
@@ -439,7 +428,7 @@ int sgsn_ctrl_cmds_install(void);
|
||||
*/
|
||||
struct imsi_acl_entry {
|
||||
struct llist_head list;
|
||||
char imsi[16+1];
|
||||
char imsi[OSMO_IMSI_BUF_SIZE];
|
||||
};
|
||||
|
||||
/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
|
||||
|
||||
15
include/osmocom/sgsn/gprs_sm.h
Normal file
15
include/osmocom/sgsn/gprs_sm.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
|
||||
int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown);
|
||||
int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
|
||||
uint8_t cause, uint8_t pco_len, uint8_t *pco_v);
|
||||
int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);
|
||||
int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);
|
||||
|
||||
void pdp_ctx_detach_mm_ctx(struct sgsn_pdp_ctx *pdp);
|
||||
|
||||
int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
struct gprs_llc_llme *llme);
|
||||
@@ -130,8 +130,6 @@ struct sgsn_instance {
|
||||
struct osmo_fd gtp_fd0;
|
||||
struct osmo_fd gtp_fd1c;
|
||||
struct osmo_fd gtp_fd1u;
|
||||
/* Timer for libGTP */
|
||||
struct osmo_timer_list gtp_timer;
|
||||
/* GSN instance for libgtp */
|
||||
struct gsn_t *gsn;
|
||||
/* Subscriber */
|
||||
@@ -161,7 +159,7 @@ char *sgsn_gtp_ntoa(struct ul16_t *ul);
|
||||
/* Main input function for Gb proxy */
|
||||
int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci);
|
||||
|
||||
|
||||
/* sgsn_libgtp.c */
|
||||
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
||||
struct sgsn_mm_ctx *mmctx,
|
||||
uint16_t nsapi,
|
||||
@@ -169,6 +167,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
||||
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx);
|
||||
void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);
|
||||
void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
|
||||
int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);
|
||||
|
||||
/* gprs_sndcp.c */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# (C) 2013 by Katerina Barone-Adesi <kat.obsc@gmail.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -23,12 +23,12 @@ app_configs = {
|
||||
}
|
||||
|
||||
|
||||
apps = [(4246, "src/gprs/osmo-gbproxy", "OsmoGbProxy", "gbproxy"),
|
||||
(4245, "src/gprs/osmo-sgsn", "OsmoSGSN", "sgsn"),
|
||||
(4253, "src/gprs/osmo-gtphub", "OsmoGTPhub", "gtphub")
|
||||
apps = [(4246, "src/gbproxy/osmo-gbproxy", "OsmoGbProxy", "gbproxy"),
|
||||
(4245, "src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn"),
|
||||
(4253, "src/gtphub/osmo-gtphub", "OsmoGTPhub", "gtphub")
|
||||
]
|
||||
|
||||
vty_command = ["./src/gprs/osmo-sgsn", "-c",
|
||||
vty_command = ["./src/sgsn/osmo-sgsn", "-c",
|
||||
"doc/examples/osmo-sgsn/osmo-sgsn.cfg"]
|
||||
|
||||
vty_app = apps[1]
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
SUBDIRS = \
|
||||
gprs \
|
||||
sgsn \
|
||||
gbproxy \
|
||||
gtphub \
|
||||
$(NULL)
|
||||
|
||||
46
src/gbproxy/Makefile.am
Normal file
46
src/gbproxy/Makefile.am
Normal file
@@ -0,0 +1,46 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_builddir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-fno-strict-aliasing \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOCTRL_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
$(LIBOSMOGB_CFLAGS) \
|
||||
$(LIBOSMOGSUPCLIENT_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(LIBGTP_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
bin_PROGRAMS = \
|
||||
osmo-gbproxy \
|
||||
$(NULL)
|
||||
|
||||
osmo_gbproxy_SOURCES = \
|
||||
gb_proxy.c \
|
||||
gb_proxy_main.c \
|
||||
gb_proxy_vty.c \
|
||||
gb_proxy_ctrl.c \
|
||||
gb_proxy_patch.c \
|
||||
gb_proxy_tlli.c \
|
||||
gb_proxy_peer.c \
|
||||
$(NULL)
|
||||
osmo_gbproxy_LDADD = \
|
||||
$(top_builddir)/src/gprs/gprs_gb_parse.o \
|
||||
$(top_builddir)/src/gprs/gprs_llc_parse.o \
|
||||
$(top_builddir)/src/gprs/crc24.o \
|
||||
$(top_builddir)/src/gprs/gprs_utils.o \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) \
|
||||
$(LIBOSMOGB_LIBS) \
|
||||
$(LIBGTP_LIBS) \
|
||||
-lrt \
|
||||
$(NULL)
|
||||
@@ -196,6 +196,11 @@ static void handle_options(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind) {
|
||||
fprintf(stderr, "Unsupported positional arguments on command line\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
int gbproxy_vty_is_config_node(struct vty *vty, int node)
|
||||
@@ -26,98 +26,21 @@ AM_CFLAGS += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
OSMO_LIBS = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) \
|
||||
$(LIBOSMOGB_LIBS) \
|
||||
$(LIBGTP_LIBS) \
|
||||
$(NULL)
|
||||
noinst_LTLIBRARIES = libcommon.la
|
||||
|
||||
bin_PROGRAMS = \
|
||||
osmo-gbproxy \
|
||||
osmo-sgsn \
|
||||
osmo-gtphub \
|
||||
$(NULL)
|
||||
|
||||
osmo_gbproxy_SOURCES = \
|
||||
gb_proxy.c \
|
||||
gb_proxy_main.c \
|
||||
gb_proxy_vty.c \
|
||||
gb_proxy_ctrl.c \
|
||||
gb_proxy_patch.c \
|
||||
gb_proxy_tlli.c \
|
||||
gb_proxy_peer.c \
|
||||
libcommon_la_SOURCES = \
|
||||
gprs_gb_parse.c \
|
||||
gprs_llc_parse.c \
|
||||
crc24.c \
|
||||
gprs_utils.c \
|
||||
$(NULL)
|
||||
osmo_gbproxy_LDADD = \
|
||||
$(OSMO_LIBS) \
|
||||
-lrt \
|
||||
sgsn_ares.c \
|
||||
$(NULL)
|
||||
|
||||
osmo_sgsn_SOURCES = \
|
||||
gprs_gmm_attach.c \
|
||||
gprs_gmm.c \
|
||||
gprs_sgsn.c \
|
||||
gprs_sndcp.c \
|
||||
gprs_sndcp_comp.c \
|
||||
gprs_sndcp_dcomp.c \
|
||||
gprs_sndcp_pcomp.c \
|
||||
gprs_sndcp_vty.c \
|
||||
gprs_sndcp_xid.c \
|
||||
sgsn_main.c \
|
||||
sgsn_vty.c \
|
||||
sgsn_libgtp.c \
|
||||
gprs_llc.c \
|
||||
gprs_llc_parse.c \
|
||||
gprs_llc_vty.c \
|
||||
crc24.c \
|
||||
sgsn_ctrl.c \
|
||||
sgsn_auth.c \
|
||||
gprs_subscriber.c \
|
||||
gprs_utils.c \
|
||||
sgsn_cdr.c \
|
||||
sgsn_ares.c \
|
||||
slhc.c \
|
||||
gprs_llc_xid.c \
|
||||
v42bis.c \
|
||||
$(NULL)
|
||||
osmo_sgsn_LDADD = \
|
||||
$(OSMO_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOGSUPCLIENT_LIBS) \
|
||||
$(LIBCARES_LIBS) \
|
||||
$(LIBGTP_LIBS) \
|
||||
-lrt \
|
||||
-lm \
|
||||
$(NULL)
|
||||
if BUILD_IU
|
||||
osmo_sgsn_LDADD += \
|
||||
$(LIBOSMOSIGTRAN_LIBS) \
|
||||
$(LIBOSMORANAP_LIBS) \
|
||||
$(LIBASN1C_LIBS) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
osmo_gtphub_SOURCES = \
|
||||
gtphub_main.c \
|
||||
gtphub.c \
|
||||
gtphub_sock.c \
|
||||
gtphub_ares.c \
|
||||
gtphub_vty.c \
|
||||
sgsn_ares.c \
|
||||
gprs_utils.c \
|
||||
$(NULL)
|
||||
osmo_gtphub_LDADD = \
|
||||
libcommon_la_LIBADD = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBCARES_LIBS) \
|
||||
$(LIBGTP_LIBS) \
|
||||
$(LIBOSMOSIGTRAN_LIBS) \
|
||||
-lrt \
|
||||
$(LIBCARES_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
45
src/gtphub/Makefile.am
Normal file
45
src/gtphub/Makefile.am
Normal file
@@ -0,0 +1,45 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_builddir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-fno-strict-aliasing \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOGSUPCLIENT_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(LIBGTP_CFLAGS) \
|
||||
$(NULL)
|
||||
if BUILD_IU
|
||||
AM_CFLAGS += \
|
||||
$(LIBASN1C_CFLAGS) \
|
||||
$(LIBOSMOSIGTRAN_CFLAGS) \
|
||||
$(LIBOSMORANAP_CFLAGS) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
bin_PROGRAMS = osmo-gtphub
|
||||
|
||||
osmo_gtphub_SOURCES = \
|
||||
gtphub_main.c \
|
||||
gtphub.c \
|
||||
gtphub_sock.c \
|
||||
gtphub_ares.c \
|
||||
gtphub_vty.c \
|
||||
$(NULL)
|
||||
|
||||
osmo_gtphub_LDADD = \
|
||||
$(top_builddir)/src/gprs/sgsn_ares.o \
|
||||
$(top_builddir)/src/gprs/gprs_utils.o \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBCARES_LIBS) \
|
||||
$(LIBGTP_LIBS) \
|
||||
$(LIBOSMOSIGTRAN_LIBS) \
|
||||
-lrt \
|
||||
$(NULL)
|
||||
@@ -322,6 +322,11 @@ static void handle_options(struct cmdline_cfg *ccfg, int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind) {
|
||||
fprintf(stderr, "Unsupported positional arguments on command line\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
93
src/sgsn/Makefile.am
Normal file
93
src/sgsn/Makefile.am
Normal file
@@ -0,0 +1,93 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_builddir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-fno-strict-aliasing \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOCTRL_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
$(LIBOSMOGB_CFLAGS) \
|
||||
$(LIBOSMOGSUPCLIENT_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(LIBCARES_CFLAGS) \
|
||||
$(LIBGTP_CFLAGS) \
|
||||
$(NULL)
|
||||
if BUILD_IU
|
||||
AM_CFLAGS += \
|
||||
$(LIBASN1C_CFLAGS) \
|
||||
$(LIBOSMOSIGTRAN_CFLAGS) \
|
||||
$(LIBOSMORANAP_CFLAGS) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
OSMO_LIBS = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) \
|
||||
$(LIBOSMOGB_LIBS) \
|
||||
$(LIBGTP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
bin_PROGRAMS = \
|
||||
osmo-sgsn \
|
||||
$(NULL)
|
||||
|
||||
osmo_sgsn_SOURCES = \
|
||||
gprs_gb.c \
|
||||
gprs_gmm_attach.c \
|
||||
gprs_gmm.c \
|
||||
gprs_gmm_fsm.c \
|
||||
gprs_mm_state_gb_fsm.c \
|
||||
gprs_sgsn.c \
|
||||
gprs_sm.c \
|
||||
gprs_sndcp.c \
|
||||
gprs_sndcp_comp.c \
|
||||
gprs_sndcp_dcomp.c \
|
||||
gprs_sndcp_pcomp.c \
|
||||
gprs_sndcp_vty.c \
|
||||
gprs_sndcp_xid.c \
|
||||
sgsn_main.c \
|
||||
sgsn_vty.c \
|
||||
sgsn_libgtp.c \
|
||||
gprs_llc.c \
|
||||
gprs_llc_vty.c \
|
||||
sgsn_ctrl.c \
|
||||
sgsn_auth.c \
|
||||
gprs_subscriber.c \
|
||||
sgsn_cdr.c \
|
||||
slhc.c \
|
||||
gprs_llc_xid.c \
|
||||
v42bis.c \
|
||||
$(NULL)
|
||||
osmo_sgsn_LDADD = \
|
||||
$(top_builddir)/src/gprs/gprs_llc_parse.o \
|
||||
$(top_builddir)/src/gprs/crc24.o \
|
||||
$(top_builddir)/src/gprs/gprs_utils.o \
|
||||
$(top_builddir)/src/gprs/sgsn_ares.o \
|
||||
$(OSMO_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOGSUPCLIENT_LIBS) \
|
||||
$(LIBCARES_LIBS) \
|
||||
$(LIBGTP_LIBS) \
|
||||
-lrt \
|
||||
-lm \
|
||||
$(NULL)
|
||||
if BUILD_IU
|
||||
osmo_sgsn_LDADD += \
|
||||
$(LIBOSMOSIGTRAN_LIBS) \
|
||||
$(LIBOSMORANAP_LIBS) \
|
||||
$(LIBASN1C_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
osmo_sgsn_SOURCES += \
|
||||
gprs_mm_state_iu_fsm.c \
|
||||
gprs_ranap.c
|
||||
|
||||
endif
|
||||
105
src/sgsn/gprs_gb.c
Normal file
105
src/sgsn/gprs_gb.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/* Messages on the Gb interface (A/Gb mode) */
|
||||
|
||||
/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2010 by On-Waves
|
||||
* (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
|
||||
#include <osmocom/gprs/gprs_msgb.h>
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
|
||||
#include "bscconfig.h"
|
||||
|
||||
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
|
||||
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
|
||||
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx) {
|
||||
if (mmctx->gb.llme)
|
||||
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
|
||||
}
|
||||
|
||||
/* Main entry point for incoming 04.08 GPRS messages from Gb */
|
||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
|
||||
bool drop_cipherable)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
uint8_t pdisc = gsm48_hdr_pdisc(gh);
|
||||
struct sgsn_mm_ctx *mmctx;
|
||||
struct gprs_ra_id ra_id;
|
||||
int rc = -EINVAL;
|
||||
|
||||
bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
|
||||
mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
|
||||
if (mmctx) {
|
||||
msgid2mmctx(mmctx, msg);
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||
mmctx->gb.llme = llme;
|
||||
gprs_gb_recv_pdu(mmctx);
|
||||
}
|
||||
|
||||
/* MMCTX can be NULL */
|
||||
|
||||
switch (pdisc) {
|
||||
case GSM48_PDISC_MM_GPRS:
|
||||
rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable);
|
||||
break;
|
||||
case GSM48_PDISC_SM_GPRS:
|
||||
rc = gsm0408_rcv_gsm(mmctx, msg, llme);
|
||||
break;
|
||||
default:
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx,
|
||||
"Unknown GSM 04.08 discriminator 0x%02x: %s\n",
|
||||
pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
|
||||
/* FIXME: return status message */
|
||||
break;
|
||||
}
|
||||
|
||||
/* MMCTX can be invalid */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx)
|
||||
{
|
||||
struct bssgp_paging_info pinfo;
|
||||
int rc;
|
||||
|
||||
/* FIXME: page whole routing area, not only the last known cell */
|
||||
|
||||
/* initiate PS PAGING procedure */
|
||||
memset(&pinfo, 0, sizeof(pinfo));
|
||||
pinfo.mode = BSSGP_PAGING_PS;
|
||||
pinfo.scope = BSSGP_PAGING_BVCI;
|
||||
pinfo.bvci = mmctx->gb.bvci;
|
||||
pinfo.imsi = mmctx->imsi;
|
||||
pinfo.ptmsi = &mmctx->p_tmsi;
|
||||
pinfo.drx_params = mmctx->drx_parms;
|
||||
pinfo.qos[0] = 0; // FIXME
|
||||
rc = bssgp_tx_paging(mmctx->gb.nsei, 0, &pinfo);
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PAGING_PS]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -449,7 +449,7 @@ struct osmo_fsm gmm_attach_req_fsm = {
|
||||
|
||||
static __attribute__((constructor)) void gprs_gmm_fsm_init(void)
|
||||
{
|
||||
osmo_fsm_register(&gmm_attach_req_fsm);
|
||||
OSMO_ASSERT(osmo_fsm_register(&gmm_attach_req_fsm) == 0);
|
||||
}
|
||||
|
||||
void gmm_att_req_free(struct sgsn_mm_ctx *mm) {
|
||||
187
src/sgsn/gprs_gmm_fsm.c
Normal file
187
src/sgsn/gprs_gmm_fsm.c
Normal file
@@ -0,0 +1,187 @@
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
||||
#include <osmocom/sgsn/gprs_gmm_fsm.h>
|
||||
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
static const struct osmo_tdef_state_timeout gmm_fsm_timeouts[32] = {
|
||||
[ST_GMM_DEREGISTERED] = { },
|
||||
[ST_GMM_COMMON_PROC_INIT] = { },
|
||||
[ST_GMM_REGISTERED_NORMAL] = { },
|
||||
[ST_GMM_REGISTERED_SUSPENDED] = { },
|
||||
[ST_GMM_DEREGISTERED_INIT] = { },
|
||||
};
|
||||
|
||||
#define gmm_fsm_state_chg(fi, NEXT_STATE) \
|
||||
osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, gmm_fsm_timeouts, sgsn->cfg.T_defs, -1)
|
||||
|
||||
static void st_gmm_deregistered(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_GMM_COMMON_PROC_INIT_REQ:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
|
||||
break;
|
||||
case E_GMM_ATTACH_SUCCESS:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_gmm_common_proc_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
/* TODO: events not used
|
||||
case E_GMM_LOWER_LAYER_FAILED:
|
||||
case E_GMM_COMMON_PROC_FAILED:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
|
||||
break;
|
||||
*/
|
||||
case E_GMM_COMMON_PROC_SUCCESS:
|
||||
case E_GMM_ATTACH_SUCCESS:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_GMM_COMMON_PROC_INIT_REQ:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
|
||||
break;
|
||||
/* case E_GMM_NET_INIT_DETACH_REQ:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT);
|
||||
break; */
|
||||
/* case E_GMM_MS_INIT_DETACH_REQ:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
|
||||
break; */
|
||||
case E_GMM_SUSPEND:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_SUSPENDED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_gmm_registered_suspended(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_GMM_RESUME:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_gmm_deregistered_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
/* TODO: events not used in osmo-sgsn code
|
||||
case E_GMM_DETACH_ACCEPTED:
|
||||
case E_GMM_LOWER_LAYER_FAILED:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
|
||||
break;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
static struct osmo_fsm_state gmm_fsm_states[] = {
|
||||
[ST_GMM_DEREGISTERED] = {
|
||||
.in_event_mask =
|
||||
X(E_GMM_COMMON_PROC_INIT_REQ) |
|
||||
X(E_GMM_ATTACH_SUCCESS),
|
||||
.out_state_mask = X(ST_GMM_COMMON_PROC_INIT),
|
||||
.name = "Deregistered",
|
||||
.action = st_gmm_deregistered,
|
||||
},
|
||||
[ST_GMM_COMMON_PROC_INIT] = {
|
||||
.in_event_mask =
|
||||
/* X(E_GMM_LOWER_LAYER_FAILED) | */
|
||||
/* X(E_GMM_COMMON_PROC_FAILED) | */
|
||||
X(E_GMM_COMMON_PROC_SUCCESS) |
|
||||
X(E_GMM_ATTACH_SUCCESS),
|
||||
.out_state_mask =
|
||||
X(ST_GMM_DEREGISTERED) |
|
||||
X(ST_GMM_REGISTERED_NORMAL),
|
||||
.name = "CommonProcedureInitiated",
|
||||
.action = st_gmm_common_proc_init,
|
||||
},
|
||||
[ST_GMM_REGISTERED_NORMAL] = {
|
||||
.in_event_mask =
|
||||
X(E_GMM_COMMON_PROC_INIT_REQ) |
|
||||
/* X(E_GMM_NET_INIT_DETACH_REQ) | */
|
||||
/* X(E_GMM_MS_INIT_DETACH_REQ) | */
|
||||
X(E_GMM_SUSPEND),
|
||||
.out_state_mask =
|
||||
X(ST_GMM_DEREGISTERED) |
|
||||
X(ST_GMM_COMMON_PROC_INIT) |
|
||||
X(ST_GMM_DEREGISTERED_INIT) |
|
||||
X(ST_GMM_REGISTERED_SUSPENDED),
|
||||
.name = "Registered.NORMAL",
|
||||
.action = st_gmm_registered_normal,
|
||||
},
|
||||
[ST_GMM_REGISTERED_SUSPENDED] = {
|
||||
.in_event_mask = X(E_GMM_RESUME),
|
||||
.out_state_mask =
|
||||
X(ST_GMM_DEREGISTERED) |
|
||||
X(ST_GMM_REGISTERED_NORMAL),
|
||||
.name = "Registered.SUSPENDED",
|
||||
.action = st_gmm_registered_suspended,
|
||||
},
|
||||
[ST_GMM_DEREGISTERED_INIT] = {
|
||||
.in_event_mask = 0
|
||||
/* X(E_GMM_DETACH_ACCEPTED) | */
|
||||
/* X(E_GMM_LOWER_LAYER_FAILED) */,
|
||||
.out_state_mask = X(ST_GMM_DEREGISTERED),
|
||||
.name = "DeregisteredInitiated",
|
||||
.action = st_gmm_deregistered_init,
|
||||
},
|
||||
};
|
||||
|
||||
const struct value_string gmm_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(E_GMM_COMMON_PROC_INIT_REQ),
|
||||
/* OSMO_VALUE_STRING(E_GMM_COMMON_PROC_FAILED), */
|
||||
/* OSMO_VALUE_STRING(E_GMM_LOWER_LAYER_FAILED), */
|
||||
OSMO_VALUE_STRING(E_GMM_COMMON_PROC_SUCCESS),
|
||||
OSMO_VALUE_STRING(E_GMM_ATTACH_SUCCESS),
|
||||
/* OSMO_VALUE_STRING(E_GMM_NET_INIT_DETACH_REQ), */
|
||||
/* OSMO_VALUE_STRING(E_GMM_MS_INIT_DETACH_REQ), */
|
||||
/* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
|
||||
OSMO_VALUE_STRING(E_GMM_SUSPEND),
|
||||
OSMO_VALUE_STRING(E_GMM_CLEANUP),
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
|
||||
switch (event) {
|
||||
case E_GMM_CLEANUP:
|
||||
switch (fi->state) {
|
||||
case ST_GMM_DEREGISTERED:
|
||||
break;
|
||||
default:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int gmm_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct osmo_fsm gmm_fsm = {
|
||||
.name = "GMM",
|
||||
.states = gmm_fsm_states,
|
||||
.num_states = ARRAY_SIZE(gmm_fsm_states),
|
||||
.event_names = gmm_fsm_event_names,
|
||||
.allstate_event_mask = X(E_GMM_CLEANUP),
|
||||
.allstate_action = gmm_fsm_allstate_action,
|
||||
.log_subsys = DMM,
|
||||
.timer_cb = gmm_fsm_timer_cb,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void gmm_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&gmm_fsm) == 0);
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
@@ -68,17 +69,20 @@ static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len,
|
||||
struct gprs_llc_xid_field xid_version;
|
||||
struct gprs_llc_xid_field xid_n201u;
|
||||
struct gprs_llc_xid_field xid_n201i;
|
||||
uint16_t n201_u, n201_i;
|
||||
|
||||
xid_version.type = GPRS_LLC_XID_T_VERSION;
|
||||
xid_version.data = (uint8_t *) "\x00";
|
||||
xid_version.data_len = 1;
|
||||
|
||||
n201_u = htons(lle->params.n201_u);
|
||||
xid_n201u.type = GPRS_LLC_XID_T_N201_U;
|
||||
xid_n201u.data = (uint8_t *) "\x05\xf0";
|
||||
xid_n201u.data = (uint8_t *) &n201_u;
|
||||
xid_n201u.data_len = 2;
|
||||
|
||||
n201_i = htons(lle->params.n201_i);
|
||||
xid_n201i.type = GPRS_LLC_XID_T_N201_I;
|
||||
xid_n201i.data = (uint8_t *) "\x05\xf0";
|
||||
xid_n201i.data = (uint8_t *) &n201_i;
|
||||
xid_n201i.data_len = 2;
|
||||
|
||||
/* Add locally managed XID Fields */
|
||||
@@ -528,7 +532,7 @@ static struct gprs_llc_lle *lle_for_rx_by_tlli_sapi(const uint32_t tlli,
|
||||
struct gprs_llc_llme *llme;
|
||||
/* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
|
||||
llme = llme_alloc(tlli);
|
||||
LOGP(DLLC, LOGL_NOTICE, "LLC RX: unknown TLLI 0x%08x, "
|
||||
LOGGBP(llme, DLLC, LOGL_NOTICE, "LLC RX: unknown TLLI 0x%08x, "
|
||||
"creating LLME on the fly\n", tlli);
|
||||
lle = &llme->lle[sapi];
|
||||
return lle;
|
||||
@@ -1047,6 +1051,10 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
|
||||
uint32_t old_tlli, uint32_t new_tlli)
|
||||
{
|
||||
unsigned int i;
|
||||
bool free = false;
|
||||
|
||||
LOGGBP(llme, DLLC, LOGL_NOTICE, "LLGM Assign pre (%08x => %08x)\n",
|
||||
old_tlli, new_tlli);
|
||||
|
||||
if (old_tlli == TLLI_UNASSIGNED && new_tlli != TLLI_UNASSIGNED) {
|
||||
/* TLLI Assignment 8.3.1 */
|
||||
@@ -1087,10 +1095,16 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
|
||||
struct gprs_llc_lle *l = &llme->lle[i];
|
||||
l->state = GPRS_LLES_UNASSIGNED;
|
||||
}
|
||||
llme_free(llme);
|
||||
free = true;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
LOGGBP(llme, DLLC, LOGL_NOTICE, "LLGM Assign post (%08x => %08x)\n",
|
||||
old_tlli, new_tlli);
|
||||
|
||||
if (free)
|
||||
llme_free(llme);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1104,16 +1118,18 @@ int gprs_llgmm_unassign(struct gprs_llc_llme *llme)
|
||||
int gprs_llgmm_reset(struct gprs_llc_llme *llme)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
|
||||
struct gprs_llc_lle *lle = &llme->lle[1];
|
||||
struct gprs_llc_lle *lle = &llme->lle[GPRS_SAPI_GMM];
|
||||
uint8_t xid_bytes[1024];
|
||||
int xid_bytes_len, rc;
|
||||
uint8_t *xid;
|
||||
|
||||
LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n");
|
||||
LOGGBP(llme, DLLC, LOGL_NOTICE, "LLGM Reset\n");
|
||||
|
||||
rc = osmo_get_rand_id((uint8_t *) &llme->iov_ui, 4);
|
||||
if (rc < 0) {
|
||||
LOGP(DLLC, LOGL_ERROR, "osmo_get_rand_id() failed for LLC XID reset: %s\n", strerror(-rc));
|
||||
LOGGBP(llme, DLLC, LOGL_ERROR,
|
||||
"osmo_get_rand_id() failed for LLC XID reset: %s\n",
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1144,11 +1160,13 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
|
||||
int xid_bytes_len, rc;
|
||||
uint8_t *xid;
|
||||
|
||||
LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n");
|
||||
LOGGBP(llme, DLLC, LOGL_NOTICE, "LLGM Reset (SAPI=%" PRIu8 ")\n", sapi);
|
||||
|
||||
rc = osmo_get_rand_id((uint8_t *) &llme->iov_ui, 4);
|
||||
if (rc < 0) {
|
||||
LOGP(DLLC, LOGL_ERROR, "osmo_get_rand_id() failed for LLC XID reset: %s\n", strerror(-rc));
|
||||
LOGGBP(llme, DLLC, LOGL_ERROR,
|
||||
"osmo_get_rand_id() failed for LLC XID reset: %s\n",
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
129
src/sgsn/gprs_mm_state_gb_fsm.c
Normal file
129
src/sgsn/gprs_mm_state_gb_fsm.c
Normal file
@@ -0,0 +1,129 @@
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
||||
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
static const struct osmo_tdef_state_timeout mm_state_gb_fsm_timeouts[32] = {
|
||||
[ST_MM_IDLE] = { },
|
||||
[ST_MM_READY] = { .T=3314 },
|
||||
[ST_MM_STANDBY] = { },
|
||||
};
|
||||
|
||||
#define mm_state_gb_fsm_state_chg(fi, NEXT_STATE) \
|
||||
osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, mm_state_gb_fsm_timeouts, sgsn->cfg.T_defs, -1)
|
||||
|
||||
static void st_mm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state) {
|
||||
struct sgsn_mm_ctx *ctx = fi->priv;
|
||||
|
||||
/* FIXME: remove this timer when RAU has it's own fsm */
|
||||
if (ctx->T == 3350 && osmo_timer_pending(&ctx->timer))
|
||||
osmo_timer_del(&ctx->timer);
|
||||
|
||||
if (ctx->gb.llme) {
|
||||
gprs_llgmm_unassign(ctx->gb.llme);
|
||||
ctx->gb.llme = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_mm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_MM_GPRS_ATTACH:
|
||||
mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
|
||||
break;
|
||||
case E_MM_PDU_RECEPTION:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_mm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
unsigned long t_secs;
|
||||
|
||||
switch(event) {
|
||||
case E_MM_READY_TIMER_EXPIRY:
|
||||
mm_state_gb_fsm_state_chg(fi, ST_MM_STANDBY);
|
||||
break;
|
||||
case E_MM_IMPLICIT_DETACH:
|
||||
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
|
||||
break;
|
||||
case E_MM_PDU_RECEPTION:
|
||||
/* RE-arm the READY timer upon receival of Gb PDUs */
|
||||
t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3314, OSMO_TDEF_S, -1);
|
||||
osmo_timer_schedule(&fi->timer, t_secs, 0);
|
||||
break;
|
||||
case E_MM_RA_UPDATE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_MM_PDU_RECEPTION:
|
||||
mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
|
||||
[ST_MM_IDLE] = {
|
||||
.in_event_mask = X(E_MM_GPRS_ATTACH) | X(E_MM_PDU_RECEPTION),
|
||||
.out_state_mask = X(ST_MM_READY),
|
||||
.onenter = st_mm_idle_on_enter,
|
||||
.name = "Idle",
|
||||
.action = st_mm_idle,
|
||||
},
|
||||
[ST_MM_READY] = {
|
||||
.in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_IMPLICIT_DETACH) | X(E_MM_PDU_RECEPTION),
|
||||
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_STANDBY),
|
||||
.name = "Ready",
|
||||
.action = st_mm_ready,
|
||||
},
|
||||
[ST_MM_STANDBY] = {
|
||||
.in_event_mask = X(E_MM_PDU_RECEPTION),
|
||||
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
|
||||
.name = "Standby",
|
||||
.action = st_mm_standby,
|
||||
},
|
||||
};
|
||||
|
||||
const struct value_string mm_state_gb_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(E_MM_GPRS_ATTACH),
|
||||
OSMO_VALUE_STRING(E_MM_PDU_RECEPTION),
|
||||
OSMO_VALUE_STRING(E_MM_IMPLICIT_DETACH),
|
||||
OSMO_VALUE_STRING(E_MM_READY_TIMER_EXPIRY),
|
||||
OSMO_VALUE_STRING(E_MM_RA_UPDATE),
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
int mm_state_gb_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
switch(fi->state) {
|
||||
case ST_MM_READY:
|
||||
/* timer for mm state. state=READY: T3314 (aka TS 23.060 "READY timer") */
|
||||
osmo_fsm_inst_dispatch(fi, E_MM_READY_TIMER_EXPIRY, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct osmo_fsm mm_state_gb_fsm = {
|
||||
.name = "MM_STATE_Gb",
|
||||
.states = mm_state_gb_fsm_states,
|
||||
.num_states = ARRAY_SIZE(mm_state_gb_fsm_states),
|
||||
.event_names = mm_state_gb_fsm_event_names,
|
||||
.log_subsys = DMM,
|
||||
.timer_cb = mm_state_gb_fsm_timer_cb,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void mm_state_gb_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&mm_state_gb_fsm) == 0);
|
||||
}
|
||||
150
src/sgsn/gprs_mm_state_iu_fsm.c
Normal file
150
src/sgsn/gprs_mm_state_iu_fsm.c
Normal file
@@ -0,0 +1,150 @@
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
||||
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
|
||||
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
static const struct osmo_tdef_state_timeout mm_state_iu_fsm_timeouts[32] = {
|
||||
[ST_PMM_DETACHED] = { },
|
||||
/* non-spec -T3314 (User inactivity timer) */
|
||||
[ST_PMM_CONNECTED] = { .T=-3314 },
|
||||
[ST_PMM_IDLE] = { },
|
||||
};
|
||||
|
||||
#define mm_state_iu_fsm_state_chg(fi, NEXT_STATE) \
|
||||
osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, mm_state_iu_fsm_timeouts, sgsn->cfg.T_defs, -1)
|
||||
|
||||
static void mmctx_change_gtpu_endpoints_to_sgsn(struct sgsn_mm_ctx *mm_ctx)
|
||||
{
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
llist_for_each_entry(pdp, &mm_ctx->pdp_list, list) {
|
||||
LOGMMCTXP(LOGL_INFO, mm_ctx, "Changing GTP-U endpoints %s -> %s\n",
|
||||
sgsn_gtp_ntoa(&pdp->lib->gsnlu),
|
||||
inet_ntop(AF_INET, &sgsn->cfg.gtp_listenaddr.sin_addr, buf, sizeof(buf)));
|
||||
sgsn_pdp_upd_gtp_u(pdp,
|
||||
&sgsn->cfg.gtp_listenaddr.sin_addr,
|
||||
sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
|
||||
}
|
||||
}
|
||||
|
||||
static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_PMM_PS_ATTACH:
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
|
||||
break;
|
||||
case E_PMM_IMPLICIT_DETACH:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_pmm_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct sgsn_mm_ctx *ctx = fi->priv;
|
||||
const struct RANAP_Cause user_inactive_cause = {
|
||||
.present = RANAP_Cause_PR_radioNetwork,
|
||||
.choice.radioNetwork = RANAP_CauseRadioNetwork_user_inactivity,
|
||||
};
|
||||
|
||||
switch(event) {
|
||||
case E_PMM_PS_CONN_RELEASE:
|
||||
sgsn_ranap_iu_free(ctx);
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_IDLE);
|
||||
break;
|
||||
case E_PMM_IMPLICIT_DETACH:
|
||||
sgsn_ranap_iu_release_free(ctx, NULL);
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
|
||||
break;
|
||||
case E_PMM_USER_INACTIVITY:
|
||||
sgsn_ranap_iu_release_free(ctx, &user_inactive_cause);
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
|
||||
break;
|
||||
case E_PMM_RA_UPDATE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void st_pmm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct sgsn_mm_ctx *ctx = fi->priv;
|
||||
|
||||
mmctx_change_gtpu_endpoints_to_sgsn(ctx);
|
||||
}
|
||||
|
||||
static void st_pmm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_PMM_PS_CONN_ESTABLISH:
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
|
||||
break;
|
||||
case E_PMM_IMPLICIT_DETACH:
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int pmm_state_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
switch(fi->state) {
|
||||
case ST_PMM_CONNECTED:
|
||||
/* timer for pmm state. state=CONNECTED: -T3314 (User inactivity timer) */
|
||||
osmo_fsm_inst_dispatch(fi, E_PMM_USER_INACTIVITY, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct osmo_fsm_state mm_state_iu_fsm_states[] = {
|
||||
[ST_PMM_DETACHED] = {
|
||||
.in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_IMPLICIT_DETACH),
|
||||
.out_state_mask = X(ST_PMM_CONNECTED),
|
||||
.name = "Detached",
|
||||
.action = st_pmm_detached,
|
||||
},
|
||||
[ST_PMM_CONNECTED] = {
|
||||
.in_event_mask = X(E_PMM_PS_CONN_RELEASE) | X(E_PMM_RA_UPDATE)
|
||||
| X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_USER_INACTIVITY),
|
||||
.out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_IDLE),
|
||||
.name = "Connected",
|
||||
.action = st_pmm_connected,
|
||||
},
|
||||
[ST_PMM_IDLE] = {
|
||||
.in_event_mask = X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_PS_CONN_ESTABLISH),
|
||||
.out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_CONNECTED),
|
||||
.name = "Idle",
|
||||
.onenter = st_pmm_idle_on_enter,
|
||||
.action = st_pmm_idle,
|
||||
},
|
||||
};
|
||||
|
||||
const struct value_string mm_state_iu_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(E_PMM_PS_ATTACH),
|
||||
OSMO_VALUE_STRING(E_PMM_PS_CONN_RELEASE),
|
||||
OSMO_VALUE_STRING(E_PMM_PS_CONN_ESTABLISH),
|
||||
OSMO_VALUE_STRING(E_PMM_IMPLICIT_DETACH),
|
||||
OSMO_VALUE_STRING(E_PMM_RA_UPDATE),
|
||||
OSMO_VALUE_STRING(E_PMM_USER_INACTIVITY),
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
struct osmo_fsm mm_state_iu_fsm = {
|
||||
.name = "MM_STATE_Iu",
|
||||
.states = mm_state_iu_fsm_states,
|
||||
.num_states = ARRAY_SIZE(mm_state_iu_fsm_states),
|
||||
.event_names = mm_state_iu_fsm_event_names,
|
||||
.timer_cb = pmm_state_fsm_timer_cb,
|
||||
.log_subsys = DMM,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void mm_state_iu_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&mm_state_iu_fsm) == 0);
|
||||
}
|
||||
260
src/sgsn/gprs_ranap.c
Normal file
260
src/sgsn/gprs_ranap.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/* Messages on the RANAP interface (Iu mode) */
|
||||
|
||||
/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2015 by Holger Hans Peter Freyther
|
||||
* (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bscconfig.h"
|
||||
#include <gtp.h>
|
||||
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
||||
#include <osmocom/ranap/ranap_common.h>
|
||||
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
#include <osmocom/sgsn/gprs_gmm_attach.h>
|
||||
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
|
||||
|
||||
/* Send RAB activation requests for all PDP contexts */
|
||||
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
|
||||
{
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
if (ctx->ran_type != MM_CTX_T_UTRAN_Iu)
|
||||
return;
|
||||
llist_for_each_entry(pdp, &ctx->pdp_list, list) {
|
||||
iu_rab_act_ps(pdp->nsapi, pdp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback for RAB assignment response */
|
||||
static int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
|
||||
{
|
||||
uint8_t rab_id;
|
||||
bool require_pdp_update = false;
|
||||
struct sgsn_pdp_ctx *pdp = NULL;
|
||||
RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
|
||||
|
||||
rab_id = item->rAB_ID.buf[0];
|
||||
|
||||
pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id);
|
||||
if (!pdp) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (item->transportLayerAddress) {
|
||||
LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf,
|
||||
item->transportLayerAddress->size));
|
||||
switch (item->transportLayerAddress->size) {
|
||||
case 7:
|
||||
/* It must be IPv4 inside a X213 NSAP */
|
||||
memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4);
|
||||
break;
|
||||
case 4:
|
||||
/* It must be a raw IPv4 address */
|
||||
memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4);
|
||||
break;
|
||||
case 16:
|
||||
/* TODO: It must be a raw IPv6 address */
|
||||
case 19:
|
||||
/* TODO: It must be IPv6 inside a X213 NSAP */
|
||||
default:
|
||||
LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown "
|
||||
"transport layer address size %u\n",
|
||||
item->transportLayerAddress->size);
|
||||
return -1;
|
||||
}
|
||||
require_pdp_update = true;
|
||||
}
|
||||
|
||||
/* The TEI on the RNC side might have changed, too */
|
||||
if (item->iuTransportAssociation &&
|
||||
item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI &&
|
||||
item->iuTransportAssociation->choice.gTP_TEI.buf &&
|
||||
item->iuTransportAssociation->choice.gTP_TEI.size >= 4) {
|
||||
uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf);
|
||||
LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n",
|
||||
pdp->lib->teid_own, tei);
|
||||
pdp->lib->teid_own = tei;
|
||||
require_pdp_update = true;
|
||||
}
|
||||
|
||||
if (require_pdp_update)
|
||||
gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0);
|
||||
|
||||
if (pdp->state != PDP_STATE_CR_CONF) {
|
||||
send_act_pdp_cont_acc(pdp);
|
||||
pdp->state = PDP_STATE_CR_CONF;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data)
|
||||
{
|
||||
struct sgsn_mm_ctx *mm;
|
||||
int rc = -1;
|
||||
|
||||
mm = sgsn_mm_ctx_by_ue_ctx(ctx);
|
||||
if (!mm) {
|
||||
LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %d\n", type);
|
||||
ranap_iu_free_ue(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case RANAP_IU_EVENT_RAB_ASSIGN:
|
||||
rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data);
|
||||
break;
|
||||
case RANAP_IU_EVENT_IU_RELEASE:
|
||||
/* fall thru */
|
||||
case RANAP_IU_EVENT_LINK_INVALIDATED:
|
||||
/* Clean up ranap_ue_conn_ctx here */
|
||||
LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
|
||||
if (mm->iu.mm_state_fsm->state == ST_PMM_CONNECTED)
|
||||
osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL);
|
||||
else
|
||||
sgsn_ranap_iu_free(mm);
|
||||
|
||||
/* TODO: move this into FSM */
|
||||
if (mm->ran_type == MM_CTX_T_UTRAN_Iu && mm->gmm_att_req.fsm->state != ST_INIT)
|
||||
osmo_fsm_inst_dispatch(mm->gmm_att_req.fsm, E_REJECT, (void *) GMM_DISCARD_MS_WITHOUT_REJECT);
|
||||
rc = 0;
|
||||
break;
|
||||
case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE:
|
||||
/* Continue authentication here */
|
||||
mm->iu.ue_ctx->integrity_active = 1;
|
||||
ranap_iu_tx_common_id(mm->iu.ue_ctx, mm->imsi);
|
||||
|
||||
/* FIXME: remove gmm_authorize */
|
||||
if (mm->pending_req != GSM48_MT_GMM_ATTACH_REQ)
|
||||
gsm48_gmm_authorize(mm);
|
||||
else
|
||||
osmo_fsm_inst_dispatch(mm->gmm_att_req.fsm, E_IU_SECURITY_CMD_COMPLETE, NULL);
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "Unknown event received: %i\n", type);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void sgsn_ranap_iu_free(struct sgsn_mm_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
if (!ctx->iu.ue_ctx)
|
||||
return;
|
||||
|
||||
ranap_iu_free_ue(ctx->iu.ue_ctx);
|
||||
ctx->iu.ue_ctx = NULL;
|
||||
}
|
||||
|
||||
void sgsn_ranap_iu_release_free(struct sgsn_mm_ctx *ctx,
|
||||
const struct RANAP_Cause *cause)
|
||||
{
|
||||
unsigned long X1001;
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
if (!ctx->iu.ue_ctx)
|
||||
return;
|
||||
|
||||
X1001 = osmo_tdef_get(sgsn->cfg.T_defs, -1001, OSMO_TDEF_S, -1);
|
||||
|
||||
ranap_iu_tx_release_free(ctx->iu.ue_ctx,
|
||||
cause,
|
||||
(int) X1001);
|
||||
ctx->iu.ue_ctx = NULL;
|
||||
}
|
||||
|
||||
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct sgsn_mm_ctx *mm = pdp->mm;
|
||||
struct ranap_ue_conn_ctx *uectx;
|
||||
uint32_t ggsn_ip;
|
||||
bool use_x213_nsap;
|
||||
|
||||
uectx = mm->iu.ue_ctx;
|
||||
use_x213_nsap = (uectx->rab_assign_addr_enc == RANAP_NSAP_ADDR_ENC_X213);
|
||||
|
||||
/* Get the IP address for ggsn user plane */
|
||||
memcpy(&ggsn_ip, pdp->lib->gsnru.v, pdp->lib->gsnru.l);
|
||||
ggsn_ip = htonl(ggsn_ip);
|
||||
|
||||
LOGP(DRANAP, LOGL_DEBUG, "Assigning RAB: rab_id=%d, ggsn_ip=%x,"
|
||||
" teid_gn=%x, use_x213_nsap=%d\n",
|
||||
rab_id, ggsn_ip, pdp->lib->teid_gn, use_x213_nsap);
|
||||
|
||||
msg = ranap_new_msg_rab_assign_data(rab_id, ggsn_ip,
|
||||
pdp->lib->teid_gn, use_x213_nsap);
|
||||
msg->l2h = msg->data;
|
||||
return ranap_iu_rab_act(uectx, msg);
|
||||
}
|
||||
|
||||
|
||||
/* Main entry point for incoming 04.08 GPRS messages from Iu */
|
||||
int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
|
||||
uint16_t *sai)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
uint8_t pdisc = gsm48_hdr_pdisc(gh);
|
||||
struct sgsn_mm_ctx *mmctx;
|
||||
int rc = -EINVAL;
|
||||
|
||||
mmctx = sgsn_mm_ctx_by_ue_ctx(MSG_IU_UE_CTX(msg));
|
||||
if (mmctx) {
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||
if (ra_id)
|
||||
memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra));
|
||||
}
|
||||
|
||||
/* MMCTX can be NULL */
|
||||
|
||||
switch (pdisc) {
|
||||
case GSM48_PDISC_MM_GPRS:
|
||||
rc = gsm0408_rcv_gmm(mmctx, msg, NULL, false);
|
||||
#pragma message "set drop_cipherable arg for gsm0408_rcv_gmm() from IuPS?"
|
||||
break;
|
||||
case GSM48_PDISC_SM_GPRS:
|
||||
rc = gsm0408_rcv_gsm(mmctx, msg, NULL);
|
||||
break;
|
||||
default:
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx,
|
||||
"Unknown GSM 04.08 discriminator 0x%02x: %s\n",
|
||||
pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
|
||||
/* FIXME: return status message */
|
||||
break;
|
||||
}
|
||||
|
||||
/* MMCTX can be invalid */
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -39,9 +39,13 @@
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
#include <osmocom/sgsn/gprs_utils.h>
|
||||
#include <osmocom/sgsn/signal.h>
|
||||
#include <osmocom/sgsn/gprs_gmm_attach.h>
|
||||
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_gmm_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
|
||||
#include <pdp.h>
|
||||
@@ -50,10 +54,6 @@
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
|
||||
#if BUILD_IU
|
||||
#include <osmocom/ranap/iu_client.h>
|
||||
#endif
|
||||
|
||||
#define GPRS_LLME_CHECK_TICK 30
|
||||
|
||||
extern struct sgsn_instance *sgsn;
|
||||
@@ -64,6 +64,15 @@ LLIST_HEAD(sgsn_ggsn_ctxts);
|
||||
LLIST_HEAD(sgsn_apn_ctxts);
|
||||
LLIST_HEAD(sgsn_pdp_ctxts);
|
||||
|
||||
const struct value_string sgsn_ran_type_names[] = {
|
||||
{ MM_CTX_T_GERAN_Gb, "GPRS/EDGE via Gb" },
|
||||
{ MM_CTX_T_UTRAN_Iu, "UMTS via Iu" },
|
||||
#if 0
|
||||
{ MM_CTX_T_GERAN_Iu, "GPRS/EDGE via Iu" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct rate_ctr_desc mmctx_ctr_description[] = {
|
||||
{ "sign:packets:in", "Signalling Messages ( In)" },
|
||||
{ "sign:packets:out", "Signalling Messages (Out)" },
|
||||
@@ -218,9 +227,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi)
|
||||
|
||||
}
|
||||
|
||||
/* Allocate a new SGSN MM context for GERAN_Gb */
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
|
||||
const struct gprs_ra_id *raid)
|
||||
/* Allocate a new SGSN MM context, generic part */
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t rate_ctr_id)
|
||||
{
|
||||
struct sgsn_mm_ctx *ctx;
|
||||
|
||||
@@ -228,62 +236,90 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
|
||||
ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, rate_ctr_id);
|
||||
if (!ctx->ctrg) {
|
||||
LOGMMCTXP(LOGL_ERROR, ctx, "Cannot allocate counter group\n");
|
||||
talloc_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->gmm_fsm = osmo_fsm_inst_alloc(&gmm_fsm, ctx, ctx, LOGL_DEBUG, "gmm_fsm");
|
||||
if (!ctx->gmm_fsm)
|
||||
goto out;
|
||||
ctx->gmm_att_req.fsm = osmo_fsm_inst_alloc(&gmm_attach_req_fsm, ctx, ctx, LOGL_DEBUG, "gb_gmm_req");
|
||||
if (!ctx->gmm_att_req.fsm)
|
||||
goto out;
|
||||
ctx->gb.mm_state_fsm = osmo_fsm_inst_alloc(&mm_state_gb_fsm, ctx, ctx, LOGL_DEBUG, NULL);
|
||||
if (!ctx->gb.mm_state_fsm)
|
||||
goto out;
|
||||
#ifdef BUILD_IU
|
||||
ctx->iu.mm_state_fsm = osmo_fsm_inst_alloc(&mm_state_iu_fsm, ctx, ctx, LOGL_DEBUG, NULL);
|
||||
if (!ctx->iu.mm_state_fsm)
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
INIT_LLIST_HEAD(&ctx->pdp_list);
|
||||
|
||||
llist_add(&ctx->list, &sgsn_mm_ctxts);
|
||||
|
||||
return ctx;
|
||||
|
||||
out:
|
||||
if (ctx->iu.mm_state_fsm)
|
||||
osmo_fsm_inst_free(ctx->iu.mm_state_fsm);
|
||||
if (ctx->gb.mm_state_fsm)
|
||||
osmo_fsm_inst_free(ctx->gb.mm_state_fsm);
|
||||
if (ctx->gmm_att_req.fsm)
|
||||
osmo_fsm_inst_free(ctx->gmm_att_req.fsm);
|
||||
if (ctx->gmm_fsm)
|
||||
osmo_fsm_inst_free(ctx->gmm_fsm);
|
||||
|
||||
rate_ctr_group_free(ctx->ctrg);
|
||||
talloc_free(ctx);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/* Allocate a new SGSN MM context for GERAN_Gb */
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
|
||||
const struct gprs_ra_id *raid)
|
||||
{
|
||||
struct sgsn_mm_ctx *ctx;
|
||||
|
||||
ctx = sgsn_mm_ctx_alloc(tlli);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
memcpy(&ctx->ra, raid, sizeof(ctx->ra));
|
||||
ctx->ran_type = MM_CTX_T_GERAN_Gb;
|
||||
ctx->gb.tlli = tlli;
|
||||
ctx->gmm_state = GMM_DEREGISTERED;
|
||||
ctx->pmm_state = MM_IDLE;
|
||||
ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
|
||||
ctx->ciph_algo = sgsn->cfg.cipher;
|
||||
osmo_fsm_inst_update_id_f(ctx->gb.mm_state_fsm, "%" PRIu32, tlli);
|
||||
|
||||
LOGMMCTXP(LOGL_DEBUG, ctx, "Allocated with %s cipher.\n",
|
||||
get_value_string(gprs_cipher_names, ctx->ciph_algo));
|
||||
ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli);
|
||||
if (!ctx->ctrg) {
|
||||
LOGMMCTXP(LOGL_ERROR, ctx, "Cannot allocate counter group\n");
|
||||
talloc_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
ctx->gmm_att_req.fsm = osmo_fsm_inst_alloc(&gmm_attach_req_fsm, ctx, ctx, LOGL_DEBUG, "gb_gmm_req");
|
||||
INIT_LLIST_HEAD(&ctx->pdp_list);
|
||||
|
||||
llist_add(&ctx->list, &sgsn_mm_ctxts);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/* Allocate a new SGSN MM context */
|
||||
/* Allocate a new SGSN MM context for UTRAN_Iu */
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
|
||||
{
|
||||
#if BUILD_IU
|
||||
struct sgsn_mm_ctx *ctx;
|
||||
struct ranap_ue_conn_ctx *ue_ctx = uectx;
|
||||
|
||||
ctx = talloc_zero(tall_sgsn_ctx, struct sgsn_mm_ctx);
|
||||
ctx = sgsn_mm_ctx_alloc(ue_ctx->conn_id);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
/* Need to get RAID from IU conn */
|
||||
ctx->ra = ue_ctx->ra_id;
|
||||
ctx->ran_type = MM_CTX_T_UTRAN_Iu;
|
||||
ctx->iu.ue_ctx = ue_ctx;
|
||||
ctx->iu.ue_ctx->rab_assign_addr_enc = sgsn->cfg.iu.rab_assign_addr_enc;
|
||||
ctx->iu.new_key = 1;
|
||||
ctx->gmm_state = GMM_DEREGISTERED;
|
||||
ctx->pmm_state = PMM_DETACHED;
|
||||
ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
|
||||
ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, ue_ctx->conn_id);
|
||||
if (!ctx->ctrg) {
|
||||
LOGMMCTXP(LOGL_ERROR, ctx, "Cannot allocate counter group for %s.%u\n",
|
||||
mmctx_ctrg_desc.group_name_prefix, ue_ctx->conn_id);
|
||||
talloc_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
ctx->gmm_att_req.fsm = osmo_fsm_inst_alloc(&gmm_attach_req_fsm, ctx, ctx, LOGL_DEBUG, "gb_gmm_req");
|
||||
osmo_fsm_inst_update_id_f(ctx->iu.mm_state_fsm, "%" PRIu32, ue_ctx->conn_id);
|
||||
|
||||
/* Need to get RAID from IU conn */
|
||||
ctx->ra = ctx->iu.ue_ctx->ra_id;
|
||||
|
||||
INIT_LLIST_HEAD(&ctx->pdp_list);
|
||||
|
||||
llist_add(&ctx->list, &sgsn_mm_ctxts);
|
||||
|
||||
return ctx;
|
||||
#else
|
||||
@@ -341,11 +377,6 @@ void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
|
||||
osmo_timer_del(&mm->timer);
|
||||
}
|
||||
|
||||
if (osmo_timer_pending(&mm->gb.state_timer)) {
|
||||
LOGMMCTXP(LOGL_INFO, mm, "Cancelling MM state timer %u\n", mm->gb.state_T);
|
||||
osmo_timer_del(&mm->gb.state_timer);
|
||||
}
|
||||
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
sig_data.mm = mm;
|
||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_MM_FREE, &sig_data);
|
||||
@@ -360,6 +391,12 @@ void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
|
||||
|
||||
if (mm->gmm_att_req.fsm)
|
||||
gmm_att_req_free(mm);
|
||||
if (mm->gb.mm_state_fsm)
|
||||
osmo_fsm_inst_free(mm->gb.mm_state_fsm);
|
||||
if (mm->iu.mm_state_fsm)
|
||||
osmo_fsm_inst_free(mm->iu.mm_state_fsm);
|
||||
if (mm->gmm_fsm)
|
||||
osmo_fsm_inst_free(mm->gmm_fsm);
|
||||
|
||||
sgsn_mm_ctx_free(mm);
|
||||
mm = NULL;
|
||||
@@ -447,7 +484,8 @@ void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
|
||||
|
||||
if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Force the deactivation of the SNDCP layer */
|
||||
sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
|
||||
if (pdp->mm->gb.llme)
|
||||
sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
|
||||
}
|
||||
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
@@ -500,7 +538,7 @@ void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
|
||||
bool pending = osmo_timer_pending(&ggc->echo_timer);
|
||||
|
||||
/* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */
|
||||
if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval > 0) {
|
||||
if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) {
|
||||
if (!pending)
|
||||
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
|
||||
} else {
|
||||
@@ -528,7 +566,6 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
|
||||
ggc->id = id;
|
||||
ggc->gtp_version = 1;
|
||||
ggc->remote_restart_ctr = -1;
|
||||
ggc->echo_interval = -1;
|
||||
/* if we are called from config file parse, this gsn doesn't exist yet */
|
||||
ggc->gsn = sgsn->gsn;
|
||||
INIT_LLIST_HEAD(&ggc->pdp_list);
|
||||
@@ -729,7 +766,7 @@ void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx)
|
||||
{
|
||||
/* the MM context can be deleted while the GGSN is not reachable or
|
||||
* if has been crashed. */
|
||||
if (pctx->mm && pctx->mm->gmm_state == GMM_REGISTERED_NORMAL) {
|
||||
if (pctx->mm && pctx->mm->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL) {
|
||||
gsm48_tx_gsm_deact_pdp_req(pctx, GSM_CAUSE_NET_FAIL, true);
|
||||
sgsn_ggsn_ctx_remove_pdp(pctx->ggsn, pctx);
|
||||
} else {
|
||||
@@ -760,6 +797,11 @@ int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pd
|
||||
return num;
|
||||
}
|
||||
|
||||
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
|
||||
{
|
||||
return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL);
|
||||
}
|
||||
|
||||
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
llist_add(&pdp->ggsn_list, &ggc->pdp_list);
|
||||
754
src/sgsn/gprs_sm.c
Normal file
754
src/sgsn/gprs_sm.c
Normal file
@@ -0,0 +1,754 @@
|
||||
/* Section "9.5 GPRS Session Management Messages"
|
||||
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
|
||||
|
||||
/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2010 by On-Waves
|
||||
* (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "bscconfig.h"
|
||||
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
#include <osmocom/gsm/apn.h>
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
|
||||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_utils.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/gprs_sndcp.h>
|
||||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
|
||||
extern void *tall_sgsn_ctx;
|
||||
|
||||
/* 3GPP TS 04.08 sec 6.1.3.4.3(.a) "Abnormal cases" */
|
||||
#define T339X_MAX_RETRANS 4
|
||||
|
||||
static const struct tlv_definition gsm48_sm_att_tlvdef = {
|
||||
.def = {
|
||||
[GSM48_IE_GSM_APN] = { TLV_TYPE_TLV, 0 },
|
||||
[GSM48_IE_GSM_PROTO_CONF_OPT] = { TLV_TYPE_TLV, 0 },
|
||||
[GSM48_IE_GSM_PDP_ADDR] = { TLV_TYPE_TLV, 0 },
|
||||
[GSM48_IE_GSM_AA_TMR] = { TLV_TYPE_TV, 1 },
|
||||
[GSM48_IE_GSM_NAME_FULL] = { TLV_TYPE_TLV, 0 },
|
||||
[GSM48_IE_GSM_NAME_SHORT] = { TLV_TYPE_TLV, 0 },
|
||||
[GSM48_IE_GSM_TIMEZONE] = { TLV_TYPE_FIXED, 1 },
|
||||
[GSM48_IE_GSM_UTC_AND_TZ] = { TLV_TYPE_FIXED, 7 },
|
||||
[GSM48_IE_GSM_LSA_ID] = { TLV_TYPE_TLV, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
static struct gsm48_qos default_qos = {
|
||||
.delay_class = 4, /* best effort */
|
||||
.reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT,
|
||||
.peak_tput = GSM48_QOS_PEAK_TPUT_32000bps,
|
||||
.preced_class = GSM48_QOS_PC_NORMAL,
|
||||
.mean_tput = GSM48_QOS_MEAN_TPUT_BEST_EFFORT,
|
||||
.traf_class = GSM48_QOS_TC_INTERACTIVE,
|
||||
.deliv_order = GSM48_QOS_DO_UNORDERED,
|
||||
.deliv_err_sdu = GSM48_QOS_ERRSDU_YES,
|
||||
.max_sdu_size = GSM48_QOS_MAXSDU_1520,
|
||||
.max_bitrate_up = GSM48_QOS_MBRATE_63k,
|
||||
.max_bitrate_down = GSM48_QOS_MBRATE_63k,
|
||||
.resid_ber = GSM48_QOS_RBER_5e_2,
|
||||
.sdu_err_ratio = GSM48_QOS_SERR_1e_2,
|
||||
.handling_prio = 3,
|
||||
.xfer_delay = 0x10, /* 200ms */
|
||||
.guar_bitrate_up = GSM48_QOS_MBRATE_0k,
|
||||
.guar_bitrate_down = GSM48_QOS_MBRATE_0k,
|
||||
.sig_ind = 0, /* not optimised for signalling */
|
||||
.max_bitrate_down_ext = 0, /* use octet 9 */
|
||||
.guar_bitrate_down_ext = 0, /* use octet 13 */
|
||||
};
|
||||
|
||||
/* GPRS SESSION MANAGEMENT */
|
||||
|
||||
static void pdpctx_timer_cb(void *_mm);
|
||||
|
||||
static void pdpctx_timer_rearm(struct sgsn_pdp_ctx *pdp, unsigned int T)
|
||||
{
|
||||
unsigned long seconds;
|
||||
if (osmo_timer_pending(&pdp->timer))
|
||||
LOGPDPCTXP(LOGL_ERROR, pdp, "Scheduling PDP timer %u while old "
|
||||
"timer %u pending\n", T, pdp->T);
|
||||
seconds = osmo_tdef_get(sgsn->cfg.T_defs, T, OSMO_TDEF_S, -1);
|
||||
osmo_timer_schedule(&pdp->timer, seconds, 0);
|
||||
}
|
||||
|
||||
static void pdpctx_timer_start(struct sgsn_pdp_ctx *pdp, unsigned int T)
|
||||
{
|
||||
if (osmo_timer_pending(&pdp->timer))
|
||||
LOGPDPCTXP(LOGL_ERROR, pdp, "Starting PDP timer %u while old "
|
||||
"timer %u pending\n", T, pdp->T);
|
||||
pdp->T = T;
|
||||
pdp->num_T_exp = 0;
|
||||
|
||||
osmo_timer_setup(&pdp->timer, pdpctx_timer_cb, pdp);
|
||||
pdpctx_timer_rearm(pdp, pdp->T);
|
||||
}
|
||||
|
||||
static void pdpctx_timer_stop(struct sgsn_pdp_ctx *pdp, unsigned int T)
|
||||
{
|
||||
if (pdp->T != T)
|
||||
LOGPDPCTXP(LOGL_ERROR, pdp, "Stopping PDP timer %u but "
|
||||
"%u is running\n", T, pdp->T);
|
||||
osmo_timer_del(&pdp->timer);
|
||||
}
|
||||
|
||||
void pdp_ctx_detach_mm_ctx(struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
/* Detach from MM context */
|
||||
llist_del(&pdp->list);
|
||||
pdp->mm = NULL;
|
||||
|
||||
/* stop timer 3395 */
|
||||
pdpctx_timer_stop(pdp, 3395);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr)
|
||||
{
|
||||
uint8_t v[6];
|
||||
|
||||
v[0] = PDP_TYPE_ORG_IETF;
|
||||
v[1] = PDP_TYPE_N_IETF_IPv4;
|
||||
*(uint32_t *)(v+2) = htonl(ipaddr);
|
||||
|
||||
msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);
|
||||
}
|
||||
|
||||
static void msgb_put_pdp_addr_ppp(struct msgb *msg)
|
||||
{
|
||||
uint8_t v[2];
|
||||
|
||||
v[0] = PDP_TYPE_ORG_ETSI;
|
||||
v[1] = PDP_TYPE_N_ETSI_PPP;
|
||||
|
||||
msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Chapter 9.4.18 */
|
||||
static int _tx_status(struct msgb *msg, uint8_t cause,
|
||||
struct sgsn_mm_ctx *mmctx)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
/* MMCTX might be NULL! */
|
||||
|
||||
DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, cause));
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
gh->proto_discr = GSM48_PDISC_SM_GPRS;
|
||||
gh->msg_type = GSM48_MT_GSM_STATUS;
|
||||
gh->data[0] = cause;
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0, mmctx, true);
|
||||
}
|
||||
|
||||
static int gsm48_tx_sm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SM STATUS");
|
||||
|
||||
mmctx2msgid(msg, mmctx);
|
||||
return _tx_status(msg, cause, mmctx);
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.5.2: Activate PDP Context Accept */
|
||||
int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP ACC");
|
||||
struct gsm48_hdr *gh;
|
||||
uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */
|
||||
|
||||
LOGPDPCTXP(LOGL_INFO, pdp, "<- ACTIVATE PDP CONTEXT ACK\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_ACCEPT]);
|
||||
|
||||
mmctx2msgid(msg, pdp->mm);
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
|
||||
gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK;
|
||||
|
||||
/* Negotiated LLC SAPI */
|
||||
msgb_v_put(msg, pdp->sapi);
|
||||
|
||||
/* FIXME: copy QoS parameters from original request */
|
||||
//msgb_lv_put(msg, pdp->lib->qos_neg.l, pdp->lib->qos_neg.v);
|
||||
msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos);
|
||||
|
||||
/* Radio priority 10.5.7.2 */
|
||||
msgb_v_put(msg, pdp->lib->radio_pri);
|
||||
|
||||
/* PDP address */
|
||||
/* Highest 4 bits of first byte need to be set to 1, otherwise
|
||||
* the IE is identical with the 04.08 PDP Address IE */
|
||||
pdp->lib->eua.v[0] &= ~0xf0;
|
||||
msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR,
|
||||
pdp->lib->eua.l, pdp->lib->eua.v);
|
||||
pdp->lib->eua.v[0] |= 0xf0;
|
||||
|
||||
/* Optional: Protocol configuration options (FIXME: why 'req') */
|
||||
if (pdp->lib->pco_req.l)
|
||||
msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT,
|
||||
pdp->lib->pco_req.l, pdp->lib->pco_req.v);
|
||||
|
||||
/* Optional: Packet Flow Identifier */
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0, pdp->mm, true);
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.5.3: Activate PDP Context reject */
|
||||
int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
|
||||
uint8_t cause, uint8_t pco_len, uint8_t *pco_v)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP REJ");
|
||||
struct gsm48_hdr *gh;
|
||||
uint8_t transaction_id = tid ^ 0x8; /* flip */
|
||||
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- ACTIVATE PDP CONTEXT REJ: %s\n",
|
||||
get_value_string(gsm48_gsm_cause_names, cause));
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REJECT]);
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
|
||||
gh->msg_type = GSM48_MT_GSM_ACT_PDP_REJ;
|
||||
|
||||
msgb_v_put(msg, cause);
|
||||
if (pco_len && pco_v)
|
||||
msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pco_len, pco_v);
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0, mm, true);
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.5.8: Deactivate PDP Context Request */
|
||||
static int _gsm48_tx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, uint8_t tid,
|
||||
uint8_t sm_cause, bool teardown)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP DET REQ");
|
||||
struct gsm48_hdr *gh;
|
||||
uint8_t transaction_id = tid ^ 0x8; /* flip */
|
||||
uint8_t tear_down_ind = (0x9 << 4) | (!!teardown);
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT REQ\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_REQUEST]);
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
|
||||
gh->msg_type = GSM48_MT_GSM_DEACT_PDP_REQ;
|
||||
|
||||
msgb_v_put(msg, sm_cause);
|
||||
msgb_v_put(msg, tear_down_ind);
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0, mm, true);
|
||||
}
|
||||
int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown)
|
||||
{
|
||||
pdpctx_timer_start(pdp, 3395);
|
||||
|
||||
return _gsm48_tx_gsm_deact_pdp_req(pdp->mm, pdp->ti, sm_cause, teardown);
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */
|
||||
static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP DET ACC");
|
||||
struct gsm48_hdr *gh;
|
||||
uint8_t transaction_id = tid ^ 0x8; /* flip */
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT ACK\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_ACCEPT]);
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
|
||||
gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK;
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0, mm, true);
|
||||
}
|
||||
int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
return _gsm48_tx_gsm_deact_pdp_acc(pdp->mm, pdp->ti);
|
||||
}
|
||||
|
||||
static int activate_ggsn(struct sgsn_mm_ctx *mmctx,
|
||||
struct sgsn_ggsn_ctx *ggsn, const uint8_t transaction_id,
|
||||
const uint8_t req_nsapi, const uint8_t req_llc_sapi,
|
||||
struct tlv_parsed *tp, int destroy_ggsn)
|
||||
{
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
|
||||
LOGMMCTXP(LOGL_DEBUG, mmctx, "Using GGSN %u\n", ggsn->id);
|
||||
ggsn->gsn = sgsn->gsn;
|
||||
pdp = sgsn_create_pdp_ctx(ggsn, mmctx, req_nsapi, tp);
|
||||
if (!pdp)
|
||||
return -1;
|
||||
|
||||
/* Store SAPI and Transaction Identifier */
|
||||
pdp->sapi = req_llc_sapi;
|
||||
pdp->ti = transaction_id;
|
||||
pdp->destroy_ggsn = destroy_ggsn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent *hostent)
|
||||
{
|
||||
struct sgsn_ggsn_ctx *ggsn;
|
||||
struct sgsn_ggsn_lookup *lookup = arg;
|
||||
struct in_addr *addr = NULL;
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
|
||||
/* The context is gone while we made a request */
|
||||
if (!lookup->mmctx) {
|
||||
talloc_free(lookup->orig_msg);
|
||||
talloc_free(lookup);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != ARES_SUCCESS) {
|
||||
struct sgsn_mm_ctx *mmctx = lookup->mmctx;
|
||||
|
||||
LOGMMCTXP(LOGL_ERROR, mmctx, "DNS query failed.\n");
|
||||
|
||||
/* Need to try with three digits now */
|
||||
if (lookup->state == SGSN_GGSN_2DIGIT) {
|
||||
char *hostname;
|
||||
int rc;
|
||||
|
||||
lookup->state = SGSN_GGSN_3DIGIT;
|
||||
hostname = osmo_apn_qualify_from_imsi(mmctx->imsi,
|
||||
lookup->apn_str, 1);
|
||||
LOGMMCTXP(LOGL_DEBUG, mmctx,
|
||||
"Going to query %s\n", hostname);
|
||||
rc = sgsn_ares_query(sgsn, hostname,
|
||||
ggsn_lookup_cb, lookup);
|
||||
if (rc != 0) {
|
||||
LOGMMCTXP(LOGL_ERROR, mmctx, "Couldn't start GGSN\n");
|
||||
goto reject_due_failure;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LOGMMCTXP(LOGL_ERROR, mmctx, "Couldn't resolve GGSN\n");
|
||||
goto reject_due_failure;
|
||||
}
|
||||
|
||||
if (hostent->h_length != sizeof(struct in_addr)) {
|
||||
LOGMMCTXP(LOGL_ERROR, lookup->mmctx,
|
||||
"Wrong addr size(%zu)\n", sizeof(struct in_addr));
|
||||
goto reject_due_failure;
|
||||
}
|
||||
|
||||
/* Get the first addr from the list */
|
||||
addr = (struct in_addr *) hostent->h_addr_list[0];
|
||||
if (!addr) {
|
||||
LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "No host address.\n");
|
||||
goto reject_due_failure;
|
||||
}
|
||||
|
||||
ggsn = sgsn_ggsn_ctx_alloc(UINT32_MAX);
|
||||
if (!ggsn) {
|
||||
LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "Failed to create ggsn.\n");
|
||||
goto reject_due_failure;
|
||||
}
|
||||
ggsn->remote_addr = *addr;
|
||||
LOGMMCTXP(LOGL_NOTICE, lookup->mmctx,
|
||||
"Selected %s as GGSN.\n",
|
||||
inet_ntop(AF_INET, addr, buf, sizeof(buf)));
|
||||
|
||||
/* forget about the ggsn look-up */
|
||||
lookup->mmctx->ggsn_lookup = NULL;
|
||||
|
||||
activate_ggsn(lookup->mmctx, ggsn, lookup->ti, lookup->nsapi,
|
||||
lookup->sapi, &lookup->tp, 1);
|
||||
|
||||
/* Now free it */
|
||||
talloc_free(lookup->orig_msg);
|
||||
talloc_free(lookup);
|
||||
return;
|
||||
|
||||
reject_due_failure:
|
||||
gsm48_tx_gsm_act_pdp_rej(lookup->mmctx, lookup->ti,
|
||||
GMM_CAUSE_NET_FAIL, 0, NULL);
|
||||
lookup->mmctx->ggsn_lookup = NULL;
|
||||
talloc_free(lookup->orig_msg);
|
||||
talloc_free(lookup);
|
||||
}
|
||||
|
||||
static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *delete)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data;
|
||||
uint8_t req_qos_len, req_pdpa_len;
|
||||
uint8_t *req_qos, *req_pdpa;
|
||||
struct tlv_parsed tp;
|
||||
uint8_t transaction_id = gsm48_hdr_trans_id(gh);
|
||||
struct sgsn_ggsn_ctx *ggsn;
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
enum gsm48_gsm_cause gsm_cause;
|
||||
char apn_str[GSM_APN_LENGTH] = { 0, };
|
||||
char *hostname;
|
||||
int rc;
|
||||
struct gprs_llc_lle *lle;
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mmctx, "-> ACTIVATE PDP CONTEXT REQ: SAPI=%u NSAPI=%u ",
|
||||
act_req->req_llc_sapi, act_req->req_nsapi);
|
||||
|
||||
/* FIXME: length checks! */
|
||||
req_qos_len = act_req->data[0];
|
||||
req_qos = act_req->data + 1; /* 10.5.6.5 */
|
||||
req_pdpa_len = act_req->data[1 + req_qos_len];
|
||||
req_pdpa = act_req->data + 1 + req_qos_len + 1; /* 10.5.6.4 */
|
||||
|
||||
switch (req_pdpa[0] & 0xf) {
|
||||
case 0x0:
|
||||
DEBUGPC(DMM, "ETSI ");
|
||||
break;
|
||||
case 0x1:
|
||||
DEBUGPC(DMM, "IETF ");
|
||||
break;
|
||||
case 0xf:
|
||||
DEBUGPC(DMM, "Empty ");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (req_pdpa[1]) {
|
||||
case 0x21:
|
||||
DEBUGPC(DMM, "IPv4 ");
|
||||
if (req_pdpa_len >= 6) {
|
||||
struct in_addr ia;
|
||||
ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2)));
|
||||
DEBUGPC(DMM, "%s ", inet_ntop(AF_INET, &ia, buf, sizeof(buf)));
|
||||
}
|
||||
break;
|
||||
case 0x57:
|
||||
DEBUGPC(DMM, "IPv6 ");
|
||||
if (req_pdpa_len >= 18) {
|
||||
/* FIXME: print IPv6 address */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUGPC(DMM, "0x%02x ", req_pdpa[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
LOGPC(DMM, LOGL_INFO, "\n");
|
||||
|
||||
/* Check if NSAPI is out of range (TS 04.65 / 7.2) */
|
||||
if (act_req->req_nsapi < 5 || act_req->req_nsapi > 15) {
|
||||
/* Send reject with GSM_CAUSE_INV_MAND_INFO */
|
||||
return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
|
||||
GSM_CAUSE_INV_MAND_INFO,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/* Optional: Access Point Name, Protocol Config Options */
|
||||
if (req_pdpa + req_pdpa_len < msg->data + msg->len)
|
||||
tlv_parse(&tp, &gsm48_sm_att_tlvdef, req_pdpa + req_pdpa_len,
|
||||
(msg->data + msg->len) - (req_pdpa + req_pdpa_len), 0, 0);
|
||||
else
|
||||
memset(&tp, 0, sizeof(tp));
|
||||
|
||||
|
||||
/* put the non-TLV elements in the TLV parser structure to
|
||||
* pass them on to the SGSN / GTP code */
|
||||
tp.lv[OSMO_IE_GSM_REQ_QOS].len = req_qos_len;
|
||||
tp.lv[OSMO_IE_GSM_REQ_QOS].val = req_qos;
|
||||
tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].len = req_pdpa_len;
|
||||
tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].val = req_pdpa;
|
||||
|
||||
/* Check if NSAPI is already in use */
|
||||
pdp = sgsn_pdp_ctx_by_nsapi(mmctx, act_req->req_nsapi);
|
||||
if (pdp) {
|
||||
/* Make sure pdp ctx was not already torn down on GTP side */
|
||||
if (!pdp->lib) {
|
||||
gsm_cause = GSM_CAUSE_REACT_RQD;
|
||||
goto no_context;
|
||||
}
|
||||
/* We already have a PDP context for this TLLI + NSAPI tuple */
|
||||
if (pdp->sapi == act_req->req_llc_sapi &&
|
||||
pdp->ti == transaction_id) {
|
||||
/* This apparently is a re-transmission of a PDP CTX
|
||||
* ACT REQ (our ACT ACK must have got dropped) */
|
||||
rc = gsm48_tx_gsm_act_pdp_acc(pdp);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Also re-transmit the SNDCP XID message */
|
||||
lle = &pdp->mm->gb.llme->lle[pdp->sapi];
|
||||
rc = sndcp_sn_xid_req(lle,pdp->nsapi);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send reject with GSM_CAUSE_NSAPI_IN_USE */
|
||||
return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
|
||||
GSM_CAUSE_NSAPI_IN_USE,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
if (mmctx->ggsn_lookup) {
|
||||
if (mmctx->ggsn_lookup->sapi == act_req->req_llc_sapi &&
|
||||
mmctx->ggsn_lookup->ti == transaction_id) {
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx,
|
||||
"Re-transmission while doing look-up. Ignoring.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only increment counter for a real activation, after we checked
|
||||
* for re-transmissions */
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PDP_CTX_ACT]);
|
||||
|
||||
/* Determine GGSN based on APN and subscription options */
|
||||
ggsn = sgsn_mm_ctx_find_ggsn_ctx(mmctx, &tp, &gsm_cause, apn_str);
|
||||
if (ggsn)
|
||||
return activate_ggsn(mmctx, ggsn, transaction_id,
|
||||
act_req->req_nsapi, act_req->req_llc_sapi,
|
||||
&tp, 0);
|
||||
|
||||
if (strlen(apn_str) == 0)
|
||||
goto no_context;
|
||||
if (!sgsn->cfg.dynamic_lookup)
|
||||
goto no_context;
|
||||
|
||||
/* schedule a dynamic look-up */
|
||||
mmctx->ggsn_lookup = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_lookup);
|
||||
if (!mmctx->ggsn_lookup)
|
||||
goto no_context;
|
||||
|
||||
mmctx->ggsn_lookup->state = SGSN_GGSN_2DIGIT;
|
||||
mmctx->ggsn_lookup->mmctx = mmctx;
|
||||
strcpy(mmctx->ggsn_lookup->apn_str, apn_str);
|
||||
|
||||
mmctx->ggsn_lookup->orig_msg = msg;
|
||||
mmctx->ggsn_lookup->tp = tp;
|
||||
|
||||
mmctx->ggsn_lookup->ti = transaction_id;
|
||||
mmctx->ggsn_lookup->nsapi = act_req->req_nsapi;
|
||||
mmctx->ggsn_lookup->sapi = act_req->req_llc_sapi;
|
||||
|
||||
hostname = osmo_apn_qualify_from_imsi(mmctx->imsi,
|
||||
mmctx->ggsn_lookup->apn_str, 0);
|
||||
|
||||
LOGMMCTXP(LOGL_DEBUG, mmctx, "Going to query %s\n", hostname);
|
||||
rc = sgsn_ares_query(sgsn, hostname,
|
||||
ggsn_lookup_cb, mmctx->ggsn_lookup);
|
||||
if (rc != 0) {
|
||||
LOGMMCTXP(LOGL_ERROR, mmctx, "Failed to start ares query.\n");
|
||||
goto no_context;
|
||||
}
|
||||
*delete = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
no_context:
|
||||
LOGMMCTXP(LOGL_ERROR, mmctx, "No GGSN context found!\n");
|
||||
return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
|
||||
gsm_cause, 0, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.5.1: Activate PDP Context Request */
|
||||
static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
|
||||
struct msgb *_msg)
|
||||
{
|
||||
bool delete = 1;
|
||||
struct msgb *msg;
|
||||
int rc;
|
||||
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REQUEST]);
|
||||
|
||||
/*
|
||||
* This is painful. We might not have a static GGSN
|
||||
* configuration and then would need to copy the msg
|
||||
* and re-do most of this routine (or call it again
|
||||
* and make sure it only goes through the dynamic
|
||||
* resolving. The question is what to optimize for
|
||||
* and the dynamic resolution will be the right thing
|
||||
* in the long run.
|
||||
*/
|
||||
msg = bssgp_msgb_copy(_msg, __func__);
|
||||
if (!msg) {
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(_msg);
|
||||
uint8_t transaction_id = gsm48_hdr_trans_id(gh);
|
||||
|
||||
LOGMMCTXP(LOGL_ERROR, mmctx, "-> ACTIVATE PDP CONTEXT REQ failed copy.\n");
|
||||
/* Send reject with GSM_CAUSE_INV_MAND_INFO */
|
||||
return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
|
||||
GSM_CAUSE_NET_FAIL,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
rc = do_act_pdp_req(mmctx, msg, &delete);
|
||||
if (delete)
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.5.8: Deactivate PDP Context Request */
|
||||
static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
uint8_t transaction_id = gsm48_hdr_trans_id(gh);
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n",
|
||||
get_value_string(gsm48_gsm_cause_names, gh->data[0]));
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_REQUEST]);
|
||||
|
||||
pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
|
||||
if (!pdp) {
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "Deactivate PDP Context Request for "
|
||||
"non-existing PDP Context (IMSI=%s, TI=%u)\n",
|
||||
mm->imsi, transaction_id);
|
||||
return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);
|
||||
}
|
||||
|
||||
return sgsn_delete_pdp_ctx(pdp);
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */
|
||||
static int gsm48_rx_gsm_deact_pdp_ack(struct sgsn_mm_ctx *mm, struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
uint8_t transaction_id = gsm48_hdr_trans_id(gh);
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT ACK\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_ACCEPT]);
|
||||
|
||||
pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
|
||||
if (!pdp) {
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "Deactivate PDP Context Accept for "
|
||||
"non-existing PDP Context (IMSI=%s, TI=%u)\n",
|
||||
mm->imsi, transaction_id);
|
||||
return 0;
|
||||
}
|
||||
/* stop timer 3395 */
|
||||
pdpctx_timer_stop(pdp, 3395);
|
||||
if (pdp->ggsn)
|
||||
return sgsn_delete_pdp_ctx(pdp);
|
||||
/* GTP side already detached, freeing */
|
||||
sgsn_pdp_ctx_free(pdp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gsm48_rx_gsm_status(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS SM STATUS (cause: %s)\n",
|
||||
get_value_string(gsm48_gsm_cause_names, gh->data[0]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pdpctx_timer_cb(void *_pdp)
|
||||
{
|
||||
struct sgsn_pdp_ctx *pdp = _pdp;
|
||||
|
||||
pdp->num_T_exp++;
|
||||
|
||||
switch (pdp->T) {
|
||||
case 3395: /* waiting for PDP CTX DEACT ACK */
|
||||
if (pdp->num_T_exp > T339X_MAX_RETRANS) {
|
||||
LOGPDPCTXP(LOGL_NOTICE, pdp, "T3395 expired > %d times\n", T339X_MAX_RETRANS);
|
||||
pdp->state = PDP_STATE_INACTIVE;
|
||||
if (pdp->ggsn)
|
||||
sgsn_delete_pdp_ctx(pdp);
|
||||
else
|
||||
sgsn_pdp_ctx_free(pdp);
|
||||
break;
|
||||
}
|
||||
_gsm48_tx_gsm_deact_pdp_req(pdp->mm, pdp->ti, GSM_CAUSE_NET_FAIL, true);
|
||||
pdpctx_timer_rearm(pdp, 3395);
|
||||
break;
|
||||
default:
|
||||
LOGPDPCTXP(LOGL_ERROR, pdp, "timer expired in unknown mode %u\n",
|
||||
pdp->T);
|
||||
}
|
||||
}
|
||||
|
||||
/* GPRS Session Management */
|
||||
int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
struct gprs_llc_llme *llme)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
int rc;
|
||||
|
||||
/* MMCTX can be NULL when called */
|
||||
|
||||
if (!mmctx) {
|
||||
LOGGBIUP(llme, msg, LOGL_NOTICE, "Cannot handle SM for unknown MM CTX\n");
|
||||
/* 6.1.3.6 */
|
||||
if (gh->msg_type == GSM48_MT_GSM_STATUS)
|
||||
return 0;
|
||||
|
||||
return gsm0408_gprs_force_reattach_oldmsg(msg, llme);
|
||||
}
|
||||
|
||||
switch (gh->msg_type) {
|
||||
case GSM48_MT_GSM_ACT_PDP_REQ:
|
||||
rc = gsm48_rx_gsm_act_pdp_req(mmctx, msg);
|
||||
break;
|
||||
case GSM48_MT_GSM_DEACT_PDP_REQ:
|
||||
rc = gsm48_rx_gsm_deact_pdp_req(mmctx, msg);
|
||||
break;
|
||||
case GSM48_MT_GSM_DEACT_PDP_ACK:
|
||||
rc = gsm48_rx_gsm_deact_pdp_ack(mmctx, msg);
|
||||
break;
|
||||
case GSM48_MT_GSM_STATUS:
|
||||
rc = gsm48_rx_gsm_status(mmctx, msg);
|
||||
break;
|
||||
case GSM48_MT_GSM_REQ_PDP_ACT_REJ:
|
||||
case GSM48_MT_GSM_ACT_AA_PDP_REQ:
|
||||
case GSM48_MT_GSM_DEACT_AA_PDP_REQ:
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx, "Unimplemented GSM 04.08 GSM msg type 0x%02x: %s\n",
|
||||
gh->msg_type, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
|
||||
rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
|
||||
break;
|
||||
default:
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx, "Unknown GSM 04.08 GSM msg type 0x%02x: %s\n",
|
||||
gh->msg_type, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
|
||||
rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/gprs_gb.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_sndcp.h>
|
||||
@@ -745,6 +746,7 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
|
||||
struct sndcp_common_hdr *sch = (struct sndcp_common_hdr *)hdr;
|
||||
struct sndcp_comp_hdr *scomph = NULL;
|
||||
struct sndcp_udata_hdr *suh;
|
||||
struct sgsn_mm_ctx *mmctx;
|
||||
uint8_t *npdu;
|
||||
uint16_t npdu_num __attribute__((unused));
|
||||
int npdu_len;
|
||||
@@ -778,6 +780,15 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
|
||||
/* FIXME: move this RA_ID up to the LLME or even higher */
|
||||
bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg));
|
||||
|
||||
mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &sne->ra_id);
|
||||
if (!mmctx) {
|
||||
LOGP(DSNDCP, LOGL_ERROR, "Message for non-existing MM ctx "
|
||||
"(lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n",
|
||||
lle, lle->llme->tlli, lle->sapi, sch->nsapi);
|
||||
return -EIO;
|
||||
}
|
||||
gprs_gb_recv_pdu(mmctx);
|
||||
|
||||
if (scomph) {
|
||||
sne->defrag.pcomp = scomph->pcomp;
|
||||
sne->defrag.dcomp = scomph->dcomp;
|
||||
@@ -153,9 +153,9 @@ static int cdr_snprintf_pdp(char *buf, size_t size, const char *ev,
|
||||
struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
char apni[(pdp->lib ? pdp->lib->apn_use.l : 0) + 1];
|
||||
char ggsn_addr[INET_ADDRSTRLEN + 1];
|
||||
char sgsn_addr[INET_ADDRSTRLEN + 1];
|
||||
char eua_addr[INET6_ADDRSTRLEN + 1];
|
||||
char ggsn_addr[INET_ADDRSTRLEN];
|
||||
char sgsn_addr[INET_ADDRSTRLEN];
|
||||
char eua_addr[INET6_ADDRSTRLEN];
|
||||
struct tm tm;
|
||||
struct timeval tv;
|
||||
time_t duration;
|
||||
@@ -45,16 +45,16 @@
|
||||
#include <osmocom/sgsn/signal.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_gb.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
#include <osmocom/sgsn/gprs_subscriber.h>
|
||||
#include <osmocom/sgsn/gprs_sndcp.h>
|
||||
|
||||
#ifdef BUILD_IU
|
||||
#include <osmocom/ranap/iu_client.h>
|
||||
#include <osmocom/ranap/ranap_ies_defs.h>
|
||||
#endif
|
||||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
#include <osmocom/sgsn/gprs_gmm_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
|
||||
|
||||
#include <gtp.h>
|
||||
#include <pdp.h>
|
||||
@@ -359,7 +359,7 @@ static const struct cause_map gtp2sm_cause_map[] = {
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx)
|
||||
int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx)
|
||||
{
|
||||
struct sgsn_signal_data sig_data;
|
||||
int rc;
|
||||
@@ -469,75 +469,10 @@ void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen)
|
||||
|
||||
void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc)
|
||||
{
|
||||
gtp_echo_req(ggc->gsn, ggc->gtp_version, NULL, &ggc->remote_addr);
|
||||
LOGGGSN(ggc, LOGL_INFO, "GTP Tx Echo Request\n");
|
||||
gtp_echo_req(ggc->gsn, ggc->gtp_version, ggc, &ggc->remote_addr);
|
||||
}
|
||||
|
||||
#ifdef BUILD_IU
|
||||
/* Callback for RAB assignment response */
|
||||
int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
|
||||
{
|
||||
uint8_t rab_id;
|
||||
bool require_pdp_update = false;
|
||||
struct sgsn_pdp_ctx *pdp = NULL;
|
||||
RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
|
||||
|
||||
rab_id = item->rAB_ID.buf[0];
|
||||
|
||||
pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id);
|
||||
if (!pdp) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (item->transportLayerAddress) {
|
||||
LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf,
|
||||
item->transportLayerAddress->size));
|
||||
switch (item->transportLayerAddress->size) {
|
||||
case 7:
|
||||
/* It must be IPv4 inside a X213 NSAP */
|
||||
memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4);
|
||||
break;
|
||||
case 4:
|
||||
/* It must be a raw IPv4 address */
|
||||
memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4);
|
||||
break;
|
||||
case 16:
|
||||
/* TODO: It must be a raw IPv6 address */
|
||||
case 19:
|
||||
/* TODO: It must be IPv6 inside a X213 NSAP */
|
||||
default:
|
||||
LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown "
|
||||
"transport layer address size %u\n",
|
||||
item->transportLayerAddress->size);
|
||||
return -1;
|
||||
}
|
||||
require_pdp_update = true;
|
||||
}
|
||||
|
||||
/* The TEI on the RNC side might have changed, too */
|
||||
if (item->iuTransportAssociation &&
|
||||
item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI &&
|
||||
item->iuTransportAssociation->choice.gTP_TEI.buf &&
|
||||
item->iuTransportAssociation->choice.gTP_TEI.size >= 4) {
|
||||
uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf);
|
||||
LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n",
|
||||
pdp->lib->teid_own, tei);
|
||||
pdp->lib->teid_own = tei;
|
||||
require_pdp_update = true;
|
||||
}
|
||||
|
||||
if (require_pdp_update)
|
||||
gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0);
|
||||
|
||||
if (pdp->state != PDP_STATE_CR_CONF) {
|
||||
send_act_pdp_cont_acc(pdp);
|
||||
pdp->state = PDP_STATE_CR_CONF;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Confirmation of a PDP Context Delete */
|
||||
static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
{
|
||||
@@ -579,13 +514,15 @@ static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
}
|
||||
|
||||
/* Confirmation of an GTP ECHO request */
|
||||
static int echo_conf(struct pdp_t *pdp, void *cbp, int recovery)
|
||||
static int echo_conf(void *cbp, bool timeout)
|
||||
{
|
||||
if (recovery < 0) {
|
||||
LOGP(DGPRS, LOGL_NOTICE, "GTP Echo Request timed out\n");
|
||||
struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *)cbp;
|
||||
if (timeout) {
|
||||
LOGGGSN(ggc, LOGL_NOTICE, "GTP Echo Request timed out\n");
|
||||
/* FIXME: if version == 1, retry with version 0 */
|
||||
sgsn_ggsn_ctx_drop_all_pdp(ggc);
|
||||
} else {
|
||||
DEBUGP(DGPRS, "GTP Rx Echo Response\n");
|
||||
LOGGGSN(ggc, LOGL_INFO, "GTP Rx Echo Response\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -630,8 +567,8 @@ static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
|
||||
|
||||
switch (type) {
|
||||
case GTP_ECHO_REQ:
|
||||
/* libgtp hands us the RECOVERY number instead of a cause */
|
||||
return echo_conf(pdp, cbp, cause);
|
||||
/* libgtp hands us the RECOVERY number instead of a cause (EOF on timeout) */
|
||||
return echo_conf(cbp, cause == EOF);
|
||||
case GTP_CREATE_PDP_REQ:
|
||||
return create_pdp_conf(pdp, cbp, cause);
|
||||
case GTP_DELETE_PDP_REQ:
|
||||
@@ -649,8 +586,9 @@ static int cb_delete_context(struct pdp_t *pdp)
|
||||
|
||||
LOGPDPX(DGPRS, LOGL_INFO, pdp, "Context %p was deleted\n", pdp);
|
||||
|
||||
/* unlink the now non-existing library handle from the pdp
|
||||
* context */
|
||||
/* unlink the now non-existing library handle from the pdp context.
|
||||
This way we avoid calling pdp_freepdp() on it, since after returning
|
||||
from cb_delete_context callback, libgtp is already doing so. */
|
||||
pctx->lib = NULL;
|
||||
|
||||
sgsn_ggsn_ctx_drop_pdp(pctx);
|
||||
@@ -678,7 +616,6 @@ static int cb_extheader_ind(struct sockaddr_in *peer)
|
||||
/* Called whenever we receive a DATA packet */
|
||||
static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
||||
{
|
||||
struct bssgp_paging_info pinfo;
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
struct sgsn_mm_ctx *mm;
|
||||
struct msgb *msg;
|
||||
@@ -721,26 +658,22 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
||||
msgb_bvci(msg) = mm->gb.bvci;
|
||||
msgb_nsei(msg) = mm->gb.nsei;
|
||||
|
||||
switch (mm->gmm_state) {
|
||||
case GMM_REGISTERED_SUSPENDED:
|
||||
switch (mm->gmm_fsm->state) {
|
||||
case ST_GMM_REGISTERED_SUSPENDED:
|
||||
/* initiate PS PAGING procedure */
|
||||
memset(&pinfo, 0, sizeof(pinfo));
|
||||
pinfo.mode = BSSGP_PAGING_PS;
|
||||
pinfo.scope = BSSGP_PAGING_BVCI;
|
||||
pinfo.bvci = mm->gb.bvci;
|
||||
pinfo.imsi = mm->imsi;
|
||||
pinfo.ptmsi = &mm->p_tmsi;
|
||||
pinfo.drx_params = mm->drx_parms;
|
||||
pinfo.qos[0] = 0; // FIXME
|
||||
bssgp_tx_paging(mm->gb.nsei, 0, &pinfo);
|
||||
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PAGING_PS]);
|
||||
gprs_gb_page_ps_ra(mm);
|
||||
/* FIXME: queue the packet we received from GTP */
|
||||
break;
|
||||
case GMM_REGISTERED_NORMAL:
|
||||
case ST_GMM_REGISTERED_NORMAL:
|
||||
OSMO_ASSERT(mm->gb.mm_state_fsm->state != ST_MM_IDLE);
|
||||
if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY)
|
||||
gprs_gb_page_ps_ra(mm);
|
||||
|
||||
/* FIXME: queue the packet we received from GTP */
|
||||
break;
|
||||
default:
|
||||
LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state "
|
||||
"%u\n", mm->gb.tlli, mm->gmm_state);
|
||||
"%s\n", mm->gb.tlli, osmo_fsm_inst_state_name(mm->gmm_fsm));
|
||||
msgb_free(msg);
|
||||
return -1;
|
||||
}
|
||||
@@ -820,28 +753,6 @@ static int sgsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void sgsn_gtp_tmr_start(struct sgsn_instance *sgi)
|
||||
{
|
||||
struct timeval next;
|
||||
|
||||
/* Retrieve next retransmission as struct timeval */
|
||||
gtp_retranstimeout(sgi->gsn, &next);
|
||||
|
||||
/* re-schedule the timer */
|
||||
osmo_timer_schedule(&sgi->gtp_timer, next.tv_sec, next.tv_usec/1000);
|
||||
}
|
||||
|
||||
/* timer callback for libgtp retransmissions and ping */
|
||||
static void sgsn_gtp_tmr_cb(void *data)
|
||||
{
|
||||
struct sgsn_instance *sgi = data;
|
||||
|
||||
/* Do all the retransmissions as needed */
|
||||
gtp_retrans(sgi->gsn);
|
||||
|
||||
sgsn_gtp_tmr_start(sgi);
|
||||
}
|
||||
|
||||
int sgsn_gtp_init(struct sgsn_instance *sgi)
|
||||
{
|
||||
int rc;
|
||||
@@ -892,10 +803,6 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Start GTP re-transmission timer */
|
||||
osmo_timer_setup(&sgi->gtp_timer, sgsn_gtp_tmr_cb, sgi);
|
||||
sgsn_gtp_tmr_start(sgi);
|
||||
|
||||
/* Register callbackcs with libgtp */
|
||||
gtp_set_cb_delete_context(gsn, cb_delete_context);
|
||||
gtp_set_cb_conf(gsn, cb_conf);
|
||||
@@ -57,6 +57,7 @@
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/ctrl/ports.h>
|
||||
@@ -270,6 +271,11 @@ static void handle_options(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind) {
|
||||
fprintf(stderr, "Unsupported positional arguments on command line\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
/* default categories */
|
||||
@@ -340,7 +346,12 @@ static struct log_info_cat gprs_categories[] = {
|
||||
.name = "DV42BIS",
|
||||
.description = "V.42bis data compression (SNDCP)",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
}
|
||||
},
|
||||
[DGTP] = {
|
||||
.name = "DGTP",
|
||||
.description = "GPRS Tunnelling Protocol (GTP)",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct log_info gprs_log_info = {
|
||||
@@ -349,10 +360,6 @@ static const struct log_info gprs_log_info = {
|
||||
.num_cat = ARRAY_SIZE(gprs_categories),
|
||||
};
|
||||
|
||||
#if BUILD_IU
|
||||
int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data);
|
||||
#endif
|
||||
|
||||
static bool file_exists(const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
@@ -391,7 +398,7 @@ int main(int argc, char **argv)
|
||||
ctrl_vty_init(tall_sgsn_ctx);
|
||||
|
||||
#if BUILD_IU
|
||||
osmo_ss7_init();
|
||||
OSMO_ASSERT(osmo_ss7_init() == 0);
|
||||
osmo_ss7_vty_init_asp(tall_sgsn_ctx);
|
||||
osmo_sccp_vty_init();
|
||||
#endif
|
||||
@@ -90,6 +90,9 @@ const struct value_string sgsn_auth_pol_strs[] = {
|
||||
#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */
|
||||
#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */
|
||||
|
||||
/* Non spec timer */
|
||||
#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
|
||||
|
||||
|
||||
static struct osmo_tdef sgsn_T_defs[] = {
|
||||
{ .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
|
||||
@@ -104,6 +107,10 @@ static struct osmo_tdef sgsn_T_defs[] = {
|
||||
{ .T=3386, .default_val=GSM0408_T3386_SECS, .desc="Wait for MODIFY PDP CTX ACK timer (s)" },
|
||||
{ .T=3395, .default_val=GSM0408_T3395_SECS, .desc="Wait for DEACT PDP CTX ACK timer (s)" },
|
||||
{ .T=3397, .default_val=GSM0408_T3397_SECS, .desc="Wait for DEACT AA PDP CTX ACK timer (s)" },
|
||||
/* non spec timers */
|
||||
{ .T=-1001, .default_val=NONSPEC_X1001_SECS, .desc="RANAP Release timeout. Wait for RANAP Release Complete."
|
||||
"On expiry release Iu connection (s)" },
|
||||
{ .T=-3314, .default_val=GSM0408_T3314_SECS, .desc="Iu User inactivity timer. On expiry release Iu connection (s)" },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -190,8 +197,8 @@ static int config_write_sgsn(struct vty *vty)
|
||||
inet_ntoa(gctx->remote_addr), VTY_NEWLINE);
|
||||
vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id,
|
||||
gctx->gtp_version, VTY_NEWLINE);
|
||||
if (gctx->echo_interval != -1)
|
||||
vty_out(vty, " ggsn %u echo-interval %"PRId32"%s",
|
||||
if (gctx->echo_interval)
|
||||
vty_out(vty, " ggsn %u echo-interval %u%s",
|
||||
gctx->id, gctx->echo_interval, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " ggsn %u no echo-interval%s",
|
||||
@@ -395,7 +402,7 @@ DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
|
||||
uint32_t id = atoi(argv[0]);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
|
||||
|
||||
ggc->echo_interval = -1;
|
||||
ggc->echo_interval = 0;
|
||||
sgsn_ggsn_ctx_check_echo_timer(ggc);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
@@ -476,15 +483,6 @@ DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd,
|
||||
return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2]));
|
||||
}
|
||||
|
||||
const struct value_string gprs_mm_st_strs[] = {
|
||||
{ GMM_DEREGISTERED, "DEREGISTERED" },
|
||||
{ GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" },
|
||||
{ GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" },
|
||||
{ GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" },
|
||||
{ GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
char *sgsn_gtp_ntoa(struct ul16_t *ul)
|
||||
{
|
||||
struct in_addr ia;
|
||||
@@ -525,15 +523,33 @@ static void vty_dump_pdp(struct vty *vty, const char *pfx,
|
||||
static void vty_dump_mmctx(struct vty *vty, const char *pfx,
|
||||
struct sgsn_mm_ctx *mm, int pdp)
|
||||
{
|
||||
uint32_t id = 0;
|
||||
const char *mm_state_name = NULL;
|
||||
|
||||
switch(mm->ran_type) {
|
||||
case MM_CTX_T_UTRAN_Iu:
|
||||
#if BUILD_IU
|
||||
id = mm->iu.ue_ctx->conn_id;
|
||||
mm_state_name = osmo_fsm_inst_state_name(mm->iu.mm_state_fsm);
|
||||
#endif
|
||||
break;
|
||||
case MM_CTX_T_GERAN_Gb:
|
||||
id = mm->gb.tlli;
|
||||
mm_state_name = osmo_fsm_inst_state_name(mm->gb.mm_state_fsm);
|
||||
break;
|
||||
}
|
||||
|
||||
vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
|
||||
pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
|
||||
vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
|
||||
pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
|
||||
vty_out(vty, "%s MM State: %s, Routeing Area: %s, Cell ID: %u%s",
|
||||
pfx, get_value_string(gprs_mm_st_strs, mm->gmm_state),
|
||||
pfx, mm->msisdn, id, mm->hlr, VTY_NEWLINE);
|
||||
vty_out(vty, "%s GMM State: %s, Routeing Area: %s, Cell ID: %u%s",
|
||||
pfx, osmo_fsm_inst_state_name(mm->gmm_fsm),
|
||||
osmo_rai_name(&mm->ra), mm->gb.cell_id, VTY_NEWLINE);
|
||||
vty_out(vty, "%s MM State: %s, RAN Type: %s%s", pfx, mm_state_name,
|
||||
get_value_string(sgsn_ran_type_names, mm->ran_type), VTY_NEWLINE);
|
||||
|
||||
vty_out_rate_ctr_group(vty, " ", mm->ctrg);
|
||||
vty_out_rate_ctr_group(vty, " ", mm->ctrg);
|
||||
|
||||
if (pdp) {
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
@@ -63,7 +63,7 @@ vty-python-test: $(BUILT_SOURCES)
|
||||
vty-transcript-test:
|
||||
osmo_verify_transcript_vty.py -v \
|
||||
-n OsmoSGSN -p 4245 \
|
||||
-r "$(top_builddir)/src/gprs/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \
|
||||
-r "$(top_builddir)/src/sgsn/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \
|
||||
$(U) $${T:-$(srcdir)/*.vty}
|
||||
rm -f $(builddir)/sms.db $(builddir)/gsn_restart
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# (C) 2013 by Jacob Erlbeck <jerlbeck@sysmocom.de>
|
||||
# (C) 2014 by Holger Hans Peter Freyther
|
||||
@@ -53,8 +53,8 @@ class TestCtrlBase(unittest.TestCase):
|
||||
try:
|
||||
self.proc = osmoutil.popen_devnull(osmo_ctrl_cmd)
|
||||
except OSError:
|
||||
print >> sys.stderr, "Current directory: %s" % os.getcwd()
|
||||
print >> sys.stderr, "Consider setting -b"
|
||||
print("Current directory: %s" % os.getcwd(), file=sys.stderr)
|
||||
print("Consider setting -b", file=sys.stderr)
|
||||
time.sleep(2)
|
||||
|
||||
appstring = self.ctrl_app()[2]
|
||||
@@ -72,7 +72,7 @@ class TestCtrlBase(unittest.TestCase):
|
||||
|
||||
def connect(self, host, port):
|
||||
if verbose:
|
||||
print "Connecting to host %s:%i" % (host, port)
|
||||
print("Connecting to host %s:%i" % (host, port))
|
||||
|
||||
retries = 30
|
||||
while True:
|
||||
@@ -92,7 +92,7 @@ class TestCtrlBase(unittest.TestCase):
|
||||
|
||||
def send(self, data):
|
||||
if verbose:
|
||||
print "Sending \"%s\"" %(data)
|
||||
print("Sending \"%s\"" %(data))
|
||||
data = Ctrl().add_header(data)
|
||||
return self.sock.send(data) == len(data)
|
||||
|
||||
@@ -121,9 +121,9 @@ class TestCtrlBase(unittest.TestCase):
|
||||
data = self.sock.recv(4096)
|
||||
while (len(data)>0):
|
||||
(head, data) = IPA().split_combined(data)
|
||||
answer = Ctrl().rem_header(head)
|
||||
answer = Ctrl().rem_header(head).decode()
|
||||
if verbose:
|
||||
print "Got message:", answer
|
||||
print("Got message:", answer)
|
||||
(mtype, id, msg) = answer.split(None, 2)
|
||||
id = int(id)
|
||||
rsp = {'mtype': mtype, 'id': id}
|
||||
@@ -139,27 +139,27 @@ class TestCtrlBase(unittest.TestCase):
|
||||
responses[id] = rsp
|
||||
|
||||
if verbose:
|
||||
print "Decoded replies: ", responses
|
||||
print("Decoded replies: ", responses)
|
||||
|
||||
return responses
|
||||
|
||||
class TestCtrlSGSN(TestCtrlBase):
|
||||
def ctrl_command(self):
|
||||
return ["./src/gprs/osmo-sgsn", "-c",
|
||||
return ["./src/sgsn/osmo-sgsn", "-c",
|
||||
"doc/examples/osmo-sgsn/osmo-sgsn.cfg"]
|
||||
|
||||
def ctrl_app(self):
|
||||
return (4251, "./src/gprs/osmo-sgsn", "OsmoSGSN", "sgsn")
|
||||
return (4251, "./src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn")
|
||||
|
||||
def testListSubscribers(self):
|
||||
# TODO. Add command to mark a subscriber as active
|
||||
r = self.do_get('subscriber-list-active-v1')
|
||||
self.assertEquals(r['mtype'], 'GET_REPLY')
|
||||
self.assertEquals(r['var'], 'subscriber-list-active-v1')
|
||||
self.assertEquals(r['value'], None)
|
||||
self.assertEqual(r['mtype'], 'GET_REPLY')
|
||||
self.assertEqual(r['var'], 'subscriber-list-active-v1')
|
||||
self.assertEqual(r['value'], None)
|
||||
|
||||
def add_sgsn_test(suite, workdir):
|
||||
if not os.path.isfile(os.path.join(workdir, "src/gprs/osmo-sgsn")):
|
||||
if not os.path.isfile(os.path.join(workdir, "src/sgsn/osmo-sgsn")):
|
||||
print("Skipping the SGSN test")
|
||||
return
|
||||
test = unittest.TestLoader().loadTestsFromTestCase(TestCtrlSGSN)
|
||||
@@ -191,9 +191,9 @@ if __name__ == '__main__':
|
||||
if args.p:
|
||||
confpath = args.p
|
||||
|
||||
print "confpath %s, workdir %s" % (confpath, workdir)
|
||||
print("confpath %s, workdir %s" % (confpath, workdir))
|
||||
os.chdir(workdir)
|
||||
print "Running tests for specific control commands"
|
||||
print("Running tests for specific control commands")
|
||||
suite = unittest.TestSuite()
|
||||
add_sgsn_test(suite, workdir)
|
||||
res = unittest.TextTestRunner(verbosity=verbose_level).run(suite)
|
||||
|
||||
@@ -32,10 +32,10 @@ gbproxy_test_LDFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
gbproxy_test_LDADD = \
|
||||
$(top_builddir)/src/gprs/gb_proxy.o \
|
||||
$(top_builddir)/src/gprs/gb_proxy_patch.o \
|
||||
$(top_builddir)/src/gprs/gb_proxy_peer.o \
|
||||
$(top_builddir)/src/gprs/gb_proxy_tlli.o \
|
||||
$(top_builddir)/src/gbproxy/gb_proxy.o \
|
||||
$(top_builddir)/src/gbproxy/gb_proxy_patch.o \
|
||||
$(top_builddir)/src/gbproxy/gb_proxy_peer.o \
|
||||
$(top_builddir)/src/gbproxy/gb_proxy_tlli.o \
|
||||
$(top_builddir)/src/gprs/gprs_gb_parse.o \
|
||||
$(top_builddir)/src/gprs/gprs_llc_parse.o \
|
||||
$(top_builddir)/src/gprs/crc24.o \
|
||||
|
||||
@@ -31,7 +31,7 @@ gtphub_test_LDFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
gtphub_test_LDADD = \
|
||||
$(top_builddir)/src/gprs/gtphub.o \
|
||||
$(top_builddir)/src/gtphub/gtphub.o \
|
||||
$(top_builddir)/src/gprs/gprs_utils.o \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
|
||||
@@ -42,27 +42,31 @@ sgsn_test_LDFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
sgsn_test_LDADD = \
|
||||
$(top_builddir)/src/gprs/gprs_llc_parse.o \
|
||||
$(top_builddir)/src/gprs/gprs_llc.o \
|
||||
$(top_builddir)/src/gprs/crc24.o \
|
||||
$(top_builddir)/src/gprs/gprs_sndcp.o \
|
||||
$(top_builddir)/src/gprs/gprs_gmm_attach.o \
|
||||
$(top_builddir)/src/gprs/gprs_gmm.o \
|
||||
$(top_builddir)/src/gprs/gprs_sgsn.o \
|
||||
$(top_builddir)/src/gprs/sgsn_vty.o \
|
||||
$(top_builddir)/src/gprs/sgsn_libgtp.o \
|
||||
$(top_builddir)/src/gprs/sgsn_auth.o \
|
||||
$(top_builddir)/src/gprs/sgsn_ares.o \
|
||||
$(top_builddir)/src/sgsn/gprs_llc.o \
|
||||
$(top_builddir)/src/sgsn/gprs_gb.o \
|
||||
$(top_builddir)/src/sgsn/gprs_sndcp.o \
|
||||
$(top_builddir)/src/sgsn/gprs_gmm_attach.o \
|
||||
$(top_builddir)/src/sgsn/gprs_gmm.o \
|
||||
$(top_builddir)/src/sgsn/gprs_gmm_fsm.o \
|
||||
$(top_builddir)/src/sgsn/gprs_mm_state_gb_fsm.o \
|
||||
$(top_builddir)/src/sgsn/gprs_sgsn.o \
|
||||
$(top_builddir)/src/sgsn/sgsn_vty.o \
|
||||
$(top_builddir)/src/sgsn/sgsn_libgtp.o \
|
||||
$(top_builddir)/src/sgsn/sgsn_auth.o \
|
||||
$(top_builddir)/src/sgsn/gprs_subscriber.o \
|
||||
$(top_builddir)/src/sgsn/gprs_llc_xid.o \
|
||||
$(top_builddir)/src/sgsn/gprs_sndcp_xid.o \
|
||||
$(top_builddir)/src/sgsn/slhc.o \
|
||||
$(top_builddir)/src/sgsn/gprs_sm.o \
|
||||
$(top_builddir)/src/sgsn/gprs_sndcp_comp.o \
|
||||
$(top_builddir)/src/sgsn/gprs_sndcp_pcomp.o \
|
||||
$(top_builddir)/src/sgsn/v42bis.o \
|
||||
$(top_builddir)/src/sgsn/gprs_sndcp_dcomp.o \
|
||||
$(top_builddir)/src/gprs/gprs_utils.o \
|
||||
$(top_builddir)/src/gprs/gprs_subscriber.o \
|
||||
$(top_builddir)/src/gprs/gprs_llc_parse.o \
|
||||
$(top_builddir)/src/gprs/gprs_gb_parse.o \
|
||||
$(top_builddir)/src/gprs/gprs_llc_xid.o \
|
||||
$(top_builddir)/src/gprs/gprs_sndcp_xid.o \
|
||||
$(top_builddir)/src/gprs/slhc.o \
|
||||
$(top_builddir)/src/gprs/gprs_sndcp_comp.o \
|
||||
$(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \
|
||||
$(top_builddir)/src/gprs/v42bis.o \
|
||||
$(top_builddir)/src/gprs/gprs_sndcp_dcomp.o \
|
||||
$(top_builddir)/src/gprs/crc24.o \
|
||||
$(top_builddir)/src/gprs/sgsn_ares.o \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
@@ -76,6 +80,8 @@ sgsn_test_LDADD = \
|
||||
|
||||
if BUILD_IU
|
||||
sgsn_test_LDADD += \
|
||||
$(top_builddir)/src/sgsn/gprs_ranap.o \
|
||||
$(top_builddir)/src/sgsn/gprs_mm_state_iu_fsm.o \
|
||||
$(LIBOSMORANAP_LIBS) \
|
||||
$(LIBOSMOSIGTRAN_LIBS) \
|
||||
$(LIBASN1C_LIBS) \
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
#include <osmocom/sgsn/gprs_utils.h>
|
||||
#include <osmocom/sgsn/gprs_gb_parse.h>
|
||||
#include <osmocom/sgsn/gprs_gmm_fsm.h>
|
||||
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
|
||||
@@ -192,7 +193,6 @@ static struct sgsn_mm_ctx *alloc_mm_ctx(uint32_t tlli, struct gprs_ra_id *raid)
|
||||
|
||||
lle = gprs_lle_get_or_create(tlli, 3);
|
||||
ctx = sgsn_mm_ctx_alloc_gb(tlli, raid);
|
||||
ctx->gmm_state = GMM_REGISTERED_NORMAL;
|
||||
ctx->gb.llme = lle->llme;
|
||||
|
||||
ictx = sgsn_mm_ctx_by_tlli(tlli, raid);
|
||||
@@ -1286,7 +1286,7 @@ static void test_gmm_cancel(void)
|
||||
|
||||
ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid);
|
||||
OSMO_ASSERT(ctx != NULL);
|
||||
OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT);
|
||||
OSMO_ASSERT(ctx->gmm_fsm->state == ST_GMM_COMMON_PROC_INIT);
|
||||
|
||||
/* we expect an identity request (IMEI) */
|
||||
OSMO_ASSERT(sgsn_tx_counter == 1);
|
||||
@@ -1306,7 +1306,7 @@ static void test_gmm_cancel(void)
|
||||
* authorization */
|
||||
OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid));
|
||||
|
||||
OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT);
|
||||
OSMO_ASSERT(ctx->gmm_fsm->state == ST_GMM_COMMON_PROC_INIT);
|
||||
|
||||
/* we expect an attach accept/reject */
|
||||
OSMO_ASSERT(sgsn_tx_counter == 1);
|
||||
@@ -1320,7 +1320,7 @@ static void test_gmm_cancel(void)
|
||||
send_0408_message(ctx->gb.llme, foreign_tlli, &raid,
|
||||
attach_compl, ARRAY_SIZE(attach_compl));
|
||||
|
||||
OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL);
|
||||
OSMO_ASSERT(ctx->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL);
|
||||
|
||||
/* we don't expect a response */
|
||||
OSMO_ASSERT(sgsn_tx_counter == 0);
|
||||
|
||||
@@ -8,7 +8,7 @@ noinst_PROGRAMS = slhc_test
|
||||
slhc_test_SOURCES = slhc_test.c
|
||||
|
||||
slhc_test_LDADD = \
|
||||
$(top_builddir)/src/gprs/slhc.o \
|
||||
$(top_builddir)/src/sgsn/slhc.o \
|
||||
$(LIBOSMOCORE_LIBS)
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ noinst_PROGRAMS = sndcp_xid_test
|
||||
sndcp_xid_test_SOURCES = sndcp_xid_test.c
|
||||
|
||||
sndcp_xid_test_LDADD = \
|
||||
$(top_builddir)/src/gprs/gprs_sndcp_xid.o \
|
||||
$(top_builddir)/src/sgsn/gprs_sndcp_xid.o \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
|
||||
@@ -12,6 +12,8 @@ T3385 = 8 s Wait for ACT PDP CTX REQ timer (s) (default: 8 s)
|
||||
T3386 = 8 s Wait for MODIFY PDP CTX ACK timer (s) (default: 8 s)
|
||||
T3395 = 8 s Wait for DEACT PDP CTX ACK timer (s) (default: 8 s)
|
||||
T3397 = 8 s Wait for DEACT AA PDP CTX ACK timer (s) (default: 8 s)
|
||||
X1001 = 5 s RANAP Release timeout. Wait for RANAP Release Complete.On expiry release Iu connection (s) (default: 5 s)
|
||||
X3314 = 44 s Iu User inactivity timer. On expiry release Iu connection (s) (default: 44 s)
|
||||
OsmoSGSN# configure terminal
|
||||
OsmoSGSN(config)# list
|
||||
...
|
||||
|
||||
@@ -8,7 +8,7 @@ noinst_PROGRAMS = v42bis_test
|
||||
v42bis_test_SOURCES = v42bis_test.c
|
||||
|
||||
v42bis_test_LDADD = \
|
||||
$(top_builddir)/src/gprs/v42bis.o \
|
||||
$(top_builddir)/src/sgsn/v42bis.o \
|
||||
$(LIBOSMOCORE_LIBS)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# (C) 2013 by Katerina Barone-Adesi <kat.obsc@gmail.com>
|
||||
# (C) 2013 by Holger Hans Peter Freyther
|
||||
@@ -33,9 +33,9 @@ class TestVTYBase(unittest.TestCase):
|
||||
def checkForEndAndExit(self):
|
||||
res = self.vty.command("list")
|
||||
#print ('looking for "exit"\n')
|
||||
self.assert_(res.find(' exit\r') > 0)
|
||||
self.assertTrue(res.find(' exit\r') > 0)
|
||||
#print 'found "exit"\nlooking for "end"\n'
|
||||
self.assert_(res.find(' end\r') > 0)
|
||||
self.assertTrue(res.find(' end\r') > 0)
|
||||
#print 'found "end"\n'
|
||||
|
||||
def vty_command(self):
|
||||
@@ -54,8 +54,8 @@ class TestVTYBase(unittest.TestCase):
|
||||
try:
|
||||
self.proc = osmoutil.popen_devnull(osmo_vty_cmd)
|
||||
except OSError:
|
||||
print >> sys.stderr, "Current directory: %s" % os.getcwd()
|
||||
print >> sys.stderr, "Consider setting -b"
|
||||
print("Current directory: %s" % os.getcwd(), file=sys.stderr)
|
||||
print("Consider setting -b", file=sys.stderr)
|
||||
|
||||
appstring = self.vty_app()[2]
|
||||
appport = self.vty_app()[0]
|
||||
@@ -71,79 +71,79 @@ class TestVTYBase(unittest.TestCase):
|
||||
class TestVTYGbproxy(TestVTYBase):
|
||||
|
||||
def vty_command(self):
|
||||
return ["./src/gprs/osmo-gbproxy", "-c",
|
||||
return ["./src/gbproxy/osmo-gbproxy", "-c",
|
||||
"doc/examples/osmo-gbproxy/osmo-gbproxy.cfg"]
|
||||
|
||||
def vty_app(self):
|
||||
return (4246, "./src/gprs/osmo-gbproxy", "OsmoGbProxy", "gbproxy")
|
||||
return (4246, "./src/gbproxy/osmo-gbproxy", "OsmoGbProxy", "gbproxy")
|
||||
|
||||
def testVtyTree(self):
|
||||
self.vty.enable()
|
||||
self.assertTrue(self.vty.verify('configure terminal', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.checkForEndAndExit()
|
||||
self.assertTrue(self.vty.verify('ns', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-ns')
|
||||
self.assertEqual(self.vty.node(), 'config-ns')
|
||||
self.checkForEndAndExit()
|
||||
self.assertTrue(self.vty.verify('exit', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.assertTrue(self.vty.verify('gbproxy', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-gbproxy')
|
||||
self.assertEqual(self.vty.node(), 'config-gbproxy')
|
||||
self.checkForEndAndExit()
|
||||
self.assertTrue(self.vty.verify('exit', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
|
||||
def testVtyShow(self):
|
||||
res = self.vty.command("show ns")
|
||||
self.assert_(res.find('Encapsulation NS-UDP-IP') >= 0)
|
||||
self.assertTrue(res.find('Encapsulation NS-UDP-IP') >= 0)
|
||||
|
||||
res = self.vty.command("show gbproxy stats")
|
||||
self.assert_(res.find('GBProxy Global Statistics') >= 0)
|
||||
self.assertTrue(res.find('GBProxy Global Statistics') >= 0)
|
||||
|
||||
def testVtyDeletePeer(self):
|
||||
self.vty.enable()
|
||||
self.assertTrue(self.vty.verify('delete-gbproxy-peer 9999 bvci 7777', ['BVC not found']))
|
||||
res = self.vty.command("delete-gbproxy-peer 9999 all dry-run")
|
||||
self.assert_(res.find('Not Deleted 0 BVC') >= 0)
|
||||
self.assert_(res.find('Not Deleted 0 NS-VC') >= 0)
|
||||
self.assertTrue(res.find('Not Deleted 0 BVC') >= 0)
|
||||
self.assertTrue(res.find('Not Deleted 0 NS-VC') >= 0)
|
||||
res = self.vty.command("delete-gbproxy-peer 9999 only-bvc dry-run")
|
||||
self.assert_(res.find('Not Deleted 0 BVC') >= 0)
|
||||
self.assert_(res.find('Not Deleted 0 NS-VC') < 0)
|
||||
self.assertTrue(res.find('Not Deleted 0 BVC') >= 0)
|
||||
self.assertTrue(res.find('Not Deleted 0 NS-VC') < 0)
|
||||
res = self.vty.command("delete-gbproxy-peer 9999 only-nsvc dry-run")
|
||||
self.assert_(res.find('Not Deleted 0 BVC') < 0)
|
||||
self.assert_(res.find('Not Deleted 0 NS-VC') >= 0)
|
||||
self.assertTrue(res.find('Not Deleted 0 BVC') < 0)
|
||||
self.assertTrue(res.find('Not Deleted 0 NS-VC') >= 0)
|
||||
res = self.vty.command("delete-gbproxy-peer 9999 all")
|
||||
self.assert_(res.find('Deleted 0 BVC') >= 0)
|
||||
self.assert_(res.find('Deleted 0 NS-VC') >= 0)
|
||||
self.assertTrue(res.find('Deleted 0 BVC') >= 0)
|
||||
self.assertTrue(res.find('Deleted 0 NS-VC') >= 0)
|
||||
|
||||
class TestVTYSGSN(TestVTYBase):
|
||||
|
||||
def vty_command(self):
|
||||
return ["./src/gprs/osmo-sgsn", "-c",
|
||||
return ["./src/sgsn/osmo-sgsn", "-c",
|
||||
"doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg"]
|
||||
|
||||
def vty_app(self):
|
||||
return (4245, "./src/gprs/osmo-sgsn", "OsmoSGSN", "sgsn")
|
||||
return (4245, "./src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn")
|
||||
|
||||
def testVtyTree(self):
|
||||
self.vty.enable()
|
||||
self.assertTrue(self.vty.verify('configure terminal', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.checkForEndAndExit()
|
||||
self.assertTrue(self.vty.verify('ns', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-ns')
|
||||
self.assertEqual(self.vty.node(), 'config-ns')
|
||||
self.checkForEndAndExit()
|
||||
self.assertTrue(self.vty.verify('exit', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.assertTrue(self.vty.verify('sgsn', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-sgsn')
|
||||
self.assertEqual(self.vty.node(), 'config-sgsn')
|
||||
self.checkForEndAndExit()
|
||||
self.assertTrue(self.vty.verify('exit', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
|
||||
def testVtyShow(self):
|
||||
res = self.vty.command("show ns")
|
||||
self.assert_(res.find('Encapsulation NS-UDP-IP') >= 0)
|
||||
self.assertTrue(res.find('Encapsulation NS-UDP-IP') >= 0)
|
||||
self.assertTrue(self.vty.verify('show bssgp', ['']))
|
||||
self.assertTrue(self.vty.verify('show bssgp stats', ['']))
|
||||
self.assertTrue(self.vty.verify('show bssgp nsei 123', ['']))
|
||||
@@ -154,57 +154,57 @@ class TestVTYSGSN(TestVTYBase):
|
||||
self.assertTrue(self.vty.verify('show pdp-context all', ['']))
|
||||
|
||||
res = self.vty.command("show sndcp")
|
||||
self.assert_(res.find('State of SNDCP Entities') >= 0)
|
||||
self.assertTrue(res.find('State of SNDCP Entities') >= 0)
|
||||
|
||||
res = self.vty.command("show llc")
|
||||
self.assert_(res.find('State of LLC Entities') >= 0)
|
||||
self.assertTrue(res.find('State of LLC Entities') >= 0)
|
||||
|
||||
def testVtyAuth(self):
|
||||
self.vty.enable()
|
||||
self.assertTrue(self.vty.verify('configure terminal', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.assertTrue(self.vty.verify('sgsn', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-sgsn')
|
||||
self.assertEqual(self.vty.node(), 'config-sgsn')
|
||||
self.assertTrue(self.vty.verify('auth-policy accept-all', ['']))
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find('auth-policy accept-all') > 0)
|
||||
self.assertTrue(res.find('auth-policy accept-all') > 0)
|
||||
self.assertTrue(self.vty.verify('auth-policy acl-only', ['']))
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find('auth-policy acl-only') > 0)
|
||||
self.assertTrue(res.find('auth-policy acl-only') > 0)
|
||||
self.assertTrue(self.vty.verify('auth-policy closed', ['']))
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find('auth-policy closed') > 0)
|
||||
self.assertTrue(res.find('auth-policy closed') > 0)
|
||||
self.assertTrue(self.vty.verify('gsup remote-ip 127.0.0.4', ['']))
|
||||
self.assertTrue(self.vty.verify('gsup remote-port 2222', ['']))
|
||||
self.assertTrue(self.vty.verify('auth-policy remote', ['']))
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find('auth-policy remote') > 0)
|
||||
self.assertTrue(res.find('auth-policy remote') > 0)
|
||||
|
||||
def testVtySubscriber(self):
|
||||
self.vty.enable()
|
||||
res = self.vty.command('show subscriber cache')
|
||||
self.assert_(res.find('1234567890') < 0)
|
||||
self.assertTrue(res.find('1234567890') < 0)
|
||||
self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 create', ['']))
|
||||
res = self.vty.command('show subscriber cache')
|
||||
self.assert_(res.find('1234567890') >= 0)
|
||||
self.assert_(res.find('Authorized: 0') >= 0)
|
||||
self.assertTrue(res.find('1234567890') >= 0)
|
||||
self.assertTrue(res.find('Authorized: 0') >= 0)
|
||||
self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 update-location-result ok', ['']))
|
||||
res = self.vty.command('show subscriber cache')
|
||||
self.assert_(res.find('1234567890') >= 0)
|
||||
self.assert_(res.find('Authorized: 1') >= 0)
|
||||
self.assertTrue(res.find('1234567890') >= 0)
|
||||
self.assertTrue(res.find('Authorized: 1') >= 0)
|
||||
self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 cancel update-procedure', ['']))
|
||||
res = self.vty.command('show subscriber cache')
|
||||
self.assert_(res.find('1234567890') >= 0)
|
||||
self.assertTrue(res.find('1234567890') >= 0)
|
||||
self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 destroy', ['']))
|
||||
res = self.vty.command('show subscriber cache')
|
||||
self.assert_(res.find('1234567890') < 0)
|
||||
self.assertTrue(res.find('1234567890') < 0)
|
||||
|
||||
def testVtyGgsn(self):
|
||||
self.vty.enable()
|
||||
self.assertTrue(self.vty.verify('configure terminal', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.assertTrue(self.vty.verify('sgsn', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-sgsn')
|
||||
self.assertEqual(self.vty.node(), 'config-sgsn')
|
||||
self.assertTrue(self.vty.verify('ggsn 0 remote-ip 127.99.99.99', ['']))
|
||||
self.assertTrue(self.vty.verify('ggsn 0 gtp-version 1', ['']))
|
||||
self.assertTrue(self.vty.verify('apn * ggsn 0', ['']))
|
||||
@@ -213,78 +213,78 @@ class TestVTYSGSN(TestVTYBase):
|
||||
self.assertTrue(self.vty.verify('apn apn1.test imsi-prefix 123456 ggsn 0', ['']))
|
||||
self.assertTrue(self.vty.verify('apn apn2.test imsi-prefix 123456 ggsn 0', ['']))
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find('ggsn 0 remote-ip 127.99.99.99') >= 0)
|
||||
self.assert_(res.find('ggsn 0 gtp-version 1') >= 0)
|
||||
self.assert_(res.find('apn * ggsn 0') >= 0)
|
||||
self.assert_(res.find('apn apn1.test ggsn 0') >= 0)
|
||||
self.assert_(res.find('apn apn1.test imsi-prefix 123456 ggsn 0') >= 0)
|
||||
self.assert_(res.find('apn apn2.test imsi-prefix 123456 ggsn 0') >= 0)
|
||||
self.assertTrue(res.find('ggsn 0 remote-ip 127.99.99.99') >= 0)
|
||||
self.assertTrue(res.find('ggsn 0 gtp-version 1') >= 0)
|
||||
self.assertTrue(res.find('apn * ggsn 0') >= 0)
|
||||
self.assertTrue(res.find('apn apn1.test ggsn 0') >= 0)
|
||||
self.assertTrue(res.find('apn apn1.test imsi-prefix 123456 ggsn 0') >= 0)
|
||||
self.assertTrue(res.find('apn apn2.test imsi-prefix 123456 ggsn 0') >= 0)
|
||||
|
||||
def testVtyEasyAPN(self):
|
||||
self.vty.enable()
|
||||
self.assertTrue(self.vty.verify('configure terminal', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.assertTrue(self.vty.verify('sgsn', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-sgsn')
|
||||
self.assertEqual(self.vty.node(), 'config-sgsn')
|
||||
|
||||
res = self.vty.command("show running-config")
|
||||
self.assertEquals(res.find("apn internet"), -1)
|
||||
self.assertEqual(res.find("apn internet"), -1)
|
||||
|
||||
self.assertTrue(self.vty.verify("access-point-name internet.apn", ['']))
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find("apn internet.apn ggsn 0") >= 0)
|
||||
self.assertTrue(res.find("apn internet.apn ggsn 0") >= 0)
|
||||
|
||||
self.assertTrue(self.vty.verify("no access-point-name internet.apn", ['']))
|
||||
res = self.vty.command("show running-config")
|
||||
self.assertEquals(res.find("apn internet"), -1)
|
||||
self.assertEqual(res.find("apn internet"), -1)
|
||||
|
||||
def testVtyCDR(self):
|
||||
self.vty.enable()
|
||||
self.assertTrue(self.vty.verify('configure terminal', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.assertTrue(self.vty.verify('sgsn', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-sgsn')
|
||||
self.assertEqual(self.vty.node(), 'config-sgsn')
|
||||
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find("no cdr filename") > 0)
|
||||
self.assertTrue(res.find("no cdr filename") > 0)
|
||||
|
||||
self.vty.command("cdr filename bla.cdr")
|
||||
res = self.vty.command("show running-config")
|
||||
self.assertEquals(res.find("no cdr filename"), -1)
|
||||
self.assert_(res.find(" cdr filename bla.cdr") > 0)
|
||||
self.assertEqual(res.find("no cdr filename"), -1)
|
||||
self.assertTrue(res.find(" cdr filename bla.cdr") > 0)
|
||||
|
||||
self.vty.command("no cdr filename")
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find("no cdr filename") > 0)
|
||||
self.assertEquals(res.find(" cdr filename bla.cdr"), -1)
|
||||
self.assertTrue(res.find("no cdr filename") > 0)
|
||||
self.assertEqual(res.find(" cdr filename bla.cdr"), -1)
|
||||
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find(" cdr interval 600") > 0)
|
||||
self.assertTrue(res.find(" cdr interval 600") > 0)
|
||||
|
||||
self.vty.command("cdr interval 900")
|
||||
res = self.vty.command("show running-config")
|
||||
self.assert_(res.find(" cdr interval 900") > 0)
|
||||
self.assertEquals(res.find(" cdr interval 600"), -1)
|
||||
self.assertTrue(res.find(" cdr interval 900") > 0)
|
||||
self.assertEqual(res.find(" cdr interval 600"), -1)
|
||||
|
||||
def testVtyTimers(self):
|
||||
self.vty.enable()
|
||||
self.assertTrue(self.vty.verify('configure terminal', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config')
|
||||
self.assertEqual(self.vty.node(), 'config')
|
||||
self.assertTrue(self.vty.verify('sgsn', ['']))
|
||||
self.assertEquals(self.vty.node(), 'config-sgsn')
|
||||
self.assertEqual(self.vty.node(), 'config-sgsn')
|
||||
|
||||
for t in [3312, 3322, 3350, 3360, 3370, 3313, 3314, 3316, 3385, 3395, 3397]:
|
||||
self.assertTrue(self.vty.verify('timer t%d 10' % t, ['']))
|
||||
|
||||
def add_gbproxy_test(suite, workdir):
|
||||
if not os.path.isfile(os.path.join(workdir, "src/gprs/osmo-gbproxy")):
|
||||
if not os.path.isfile(os.path.join(workdir, "src/gbproxy/osmo-gbproxy")):
|
||||
print("Skipping the Gb-Proxy test")
|
||||
return
|
||||
test = unittest.TestLoader().loadTestsFromTestCase(TestVTYGbproxy)
|
||||
suite.addTest(test)
|
||||
|
||||
def add_sgsn_test(suite, workdir):
|
||||
if not os.path.isfile(os.path.join(workdir, "src/gprs/osmo-sgsn")):
|
||||
if not os.path.isfile(os.path.join(workdir, "src/sgsn/osmo-sgsn")):
|
||||
print("Skipping the SGSN test")
|
||||
return
|
||||
test = unittest.TestLoader().loadTestsFromTestCase(TestVTYSGSN)
|
||||
@@ -316,9 +316,9 @@ if __name__ == '__main__':
|
||||
if args.p:
|
||||
confpath = args.p
|
||||
|
||||
print "confpath %s, workdir %s" % (confpath, workdir)
|
||||
print("confpath %s, workdir %s" % (confpath, workdir))
|
||||
os.chdir(workdir)
|
||||
print "Running tests for specific VTY commands"
|
||||
print("Running tests for specific VTY commands")
|
||||
suite = unittest.TestSuite()
|
||||
add_gbproxy_test(suite, workdir)
|
||||
add_sgsn_test(suite, workdir)
|
||||
|
||||
@@ -24,7 +24,7 @@ xid_test_SOURCES = \
|
||||
$(NULL)
|
||||
|
||||
xid_test_LDADD = \
|
||||
$(top_builddir)/src/gprs/gprs_llc_xid.o \
|
||||
$(top_builddir)/src/sgsn/gprs_llc_xid.o \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
|
||||
Reference in New Issue
Block a user