Compare commits

...

36 Commits

Author SHA1 Message Date
Oliver Smith
5997357c69 osmoappdesc.py, tests: switch to python 3
Make build and external tests work with python3, so we can drop
the python2 dependency.

This should be merged shortly after osmo-python-tests was migrated to
python3, and the jenkins build slaves were (automatically) updated to
have the new osmo-python-tests installed.

Related: OS#2819
Depends: osmo-python-tests I3ffc3519bf6c22536a49dad7a966188ddad351a7
Change-Id: I8c07d99c1bc9f0383e4bce17544e0998998cc54d
2019-12-11 09:41:27 +01:00
Harald Welte
de67c001b7 exit(2) on unsupported positional arguments on command line
Change-Id: I4f2d70d0b0f1b7bdb8604c930aba8fbb53d8bd54
2019-12-03 22:28:19 +01:00
Oliver Smith
ad08d17e07 regen_doc.sh: support gbproxy, run without docker
Do not only update the VTY reference and counters of osmo-sgsn, but also
the VTY reference of gbproxy.

This was not possible with the old code path of calling "regen_doc.sh"
inside docker-playground.git, as it expects the program to be updated to
have the same name as the docker image. Using the docker-playground
script also has the disadvantage, that one must push the development
branch to git.osmocom.org before updating the VTY reference/counters,
because that script would build a new docker container with a freshly
cloned repository, check out the same commit that we have already
locally, build that and then finally regenerate the docs.

So instead of adding another parameter for the docker image to the
script in docker-playground.git and calling it twice, simplify the
process by rewriting the regen_doc.sh script in osmo-sgsn.git. Make it
start the locally installed osmo-sgsn and osmo-gbproxy binaries and
call osmo_interact_vty.py on them.

Related: OS#4292
Change-Id: I8b5bd5347ea34266ad650383372630f2a84d5cce
2019-12-03 11:41:21 +01:00
Oliver Smith
118c411e81 doc: add OsmoGbProxy VTY reference
Depends: (osmo-gsm-manuals) I4dea3e07b88175b2a88e577129360af7ec5f87e1
Related: OS#4292
Change-Id: I24c3ca2fc2446673edceefb797c7d800c3a1a5d2
2019-12-03 11:39:26 +01:00
Oliver Smith
fa2656d14e gitignore: fix paths to binaries
Change-Id: Ia968bbc5de34e9068d4b414e5a701b958ae517e5
2019-12-02 14:40:31 +01:00
Harald Welte
6e6347613d manual: Fix copy+paste error
Change-Id: I5753ded676951998a1fd76e4d2c2bf3311213f53
2019-12-01 14:31:16 +01:00
Harald Welte
61557f42c1 check for osmo_ss7_init() error return value
Change-Id: Ic228273aa6fb197b78c70c467a4a99af317e8098
2019-12-01 12:43:17 +00:00
Harald Welte
a868e17c5e check for osmo_fsm_register() error return values
Change-Id: I2028c82ac1b0421101c3f5d04fd999b65abdbf08
2019-12-01 12:43:17 +00:00
Harald Welte
1fd50d9abe Initial OsmoGbPROXY user manual
This adds a very basic manual consisting of nothing more than
the common chapters and a high-level description of what it is
all about.

Change-Id: I80d4ea016376c59995ccfcd8685c7c0e86745bd2
2019-12-01 12:42:58 +00:00
Harald Welte
4146121cc9 LLC: Don't use hard-coded N201-U / N201-I values in XID
The N201 values are negotiated per SAPI, and there are default values
per each SAPI.  Let's use those rather than hard-coded values.

Closes: OS#3954
Change-Id: I447a3c6dd85311772a6e219c62dc820d2726857f
2019-11-30 18:50:50 +00:00
Max
85386dcfad Use libosmocore constant for IMSI length in ACL entry
Presumably the length is chosen to match that of imsi in
osmo_gsup_message.

Change-Id: I138aea409aab0c748c75546e628797fc7498bf40
2019-11-23 19:12:45 +07:00
Pau Espin Pedrol
9203da58e2 gprs_gmm.c: Send XID reset with received TLLI
Otherwise lower layers will end up using a TLLI from PTMSI which was not
yet announced to the MS if it is still not in GMM attached state, as
showcased by SGSN_Tests.TC_attach_req_id_req_ra_update.

Related: OS#3957, OS#4245
Change-Id: Ide51726abb82f5784eca4ab8d62b2ad8512be843
2019-11-21 16:39:23 +01:00
Pau Espin Pedrol
b71d2c5ddd gprs_llc.c: Use enum instead of hardcoded value
Change-Id: I89815f44f615a188f46a13f3785b3f7484f73bb3
2019-11-21 16:15:52 +01:00
Pau Espin Pedrol
029a70e493 Improve logging in gprs_llc.c code
Change-Id: Id89cc6760179fb9b1709a30b5d1af41d466b280b
2019-11-21 14:15:10 +01:00
Pau Espin Pedrol
de80976d94 gmm: Fix assertion hit during RA UPD REQ before completting gmm attach
Output:
20191107021548500 DMM <0002> gprs_gb.c:40 MM_STATE_Gb(2596296189)[0x6120000084a0]{Idle}: Received Event E_MM_PDU_RECEPTION
20191107021548500 DMM <0002> gprs_gmm.c:1531 MM(/d4b6d7af) -> GMM RA UPDATE REQUEST type="RA updating"
20191107021548501 DMM <0002> gprs_gmm.c:1615 MM(/d4b6d7af) The MM context cannot be used, RA: 901-70-2758-208
Assert failed mmctx->gb.llme == NULL gprs_gmm.c:1620

Scenario reproducing the crash can be triggered with TTCN3
SGSN_Tests.TC_attach_req_id_req_ra_update.

Basically, SGSN first receives an ATTACH REQ with a given RA ID, then
SGSN switches to state CommonProcedureInitiated and sends GMM ID REQ,
and MS/PCU answers immediatelly with a RA Update instead with a new RA
ID.

Related: OS#3957, OS#4245
Change-Id: I64fa5cf1b427d3abb99e553e584897261a827ce6
2019-11-08 18:50:29 +01:00
Pau Espin Pedrol
284314ab0a sgsn_libgtp.c: Drop use of deprecated libgtp APIs gtp_retrans*()
Since osmo-ggsn.git c94837c6a401bf0f80791b619a9b4cfbe9160afd, those
APIs are a no-op since timers are tracked internally through osmocom
APIs (and at the same time, new implementation fixes some timing related
bugs).

As a result, osmo-sgsn depends now on at least that libgtp commit. Since
it's not yet avaiable on latest libgtp release, let's track it down in
TODO-RELESE to not forget to update libgtp requirements during osmo-sgsn
release.

Related: OS#4178
Change-Id: Ia9a93d4a6ed63cd0c736f9a99d81d730b958d82e
2019-10-21 08:31:31 +00:00
Alexander Couzens
4d1d2e78b1 sgsn: Gb: implementing PS Paging when MS is MM_STANDBY
When the MS is in MM_STANDBY, the Routing Area is known,
but not the exact cell.
Start the paging procedure. (Even this is only supported
for the last known cell, not the Routing Area. Routing Area
paging is not yet supported.)

Change-Id: Icc2c6ba70f8f74054546a1e31741fc90b232a23c
2019-10-17 08:01:16 +00:00
Alexander Couzens
030824e172 sgsn_libgtp: refactor ps paging into gprs_gb
Paging should be done in gprs_gb
Change-Id: I3020020f52005aa460ca6b245ee2297aec9821b3
2019-10-17 08:01:10 +00:00
Vadim Yanitskiy
0e124d3131 gprs_mm_state_iu_fsm.c: fix: assign timer_cb to mm_state_iu_fsm
GCC warns us that 'pmm_state_fsm_timer_cb' is defined but not used.
This function was introduced in [1], but was not assigned to the FSM.

[1] I66c2ac0350cb074aefd9a22c5121acf723f239d3

Change-Id: Ib040befc87b2676aad2b8fe3671404fb3f5b030b
2019-10-09 18:32:55 +07:00
Alexander Couzens
865bf6f1bf sgsn_mm_ctx_alloc(): check for unallocated fsms
Change-Id: I867612a60236eaf7009400c92f5d871006aaf008
2019-10-08 23:13:10 +00:00
Alexander Couzens
10af11dacc gprs_gmm: release Iu connection on RAU failures
When a RAU fails without an a GMM context, release the Iu
connection after sending a response.

Change-Id: I05a9200f55d608ccfb3f86184c324a2b428da76b
2019-10-08 20:31:56 +00:00
Alexander Couzens
afadd102bf ranap: add non-spec X1001
When the SGSN releases a RANAP connection, it sends a Release Command
and waits for a Release Complete. Use X1001 to release the Iu connection
when the Release Complete is lost/never received.

Change-Id: I39a0169c22a4ac430b3d6f3c281d1f381eaa4756
2019-10-08 20:31:25 +00:00
Alexander Couzens
12235310af sgsn: MM Gb Fsm: fix event handling for implicit detach
Implicit detach means there won't be any Gb state afterwards.

Change-Id: Iececb730e7135e14ebd94f82edb79b03ced1f9e3
2019-10-08 12:38:35 +00:00
Alexander Couzens
d597ee260a gprs_sgsn: always allocate Gb/Iu mm fsm
When moving between RANs we need them at a later point.
Allocate them always to not make the code (more) complex.

Change-Id: I1724790335b0820f153a0cbdb5cfd1cfea36d1e9
2019-10-08 12:38:14 +00:00
Alexander Couzens
743e687496 gprs_ranap: add missing rc = 0
After processing the event, set the return code to success.
Thanks to manatails (redmine).

Change-Id: I73b3b3c3dd330bc953835737758854cf68539495
Fixes: #3969
2019-10-08 12:02:19 +00:00
Alexander Couzens
4c7609a508 gprs_mm_state_gb_fsm: ensure T3350 is not running when entering IDLE
In IDLE there is not further context with the MS. Prevents the Timer from sending
packages to a MS which can not respond

Change-Id: Ibdd913173af11d0e6d04aa392e047d5d9aee1243
2019-10-08 10:34:57 +00:00
Alexander Couzens
62f6f9aebf gprs_ranap: on Iu release, stop the attach fsm if running
A Iu release should stop any active procedure.

Change-Id: I78c6c0c4024657212d6abef51e226ce233018fee
2019-10-08 10:34:28 +00:00
Alexander Couzens
3bad31bcb4 Iu: implement a user inactivity timer
The user inactivity timer is similiar to the Gb READY timer and reduces
the resources taken by an idle UE.

Change-Id: I66c2ac0350cb074aefd9a22c5121acf723f239d3
2019-10-08 10:34:09 +00:00
Alexander Couzens
eb5aee580d gprs_ranap: release Iu UE Context when exiting PMM Connected
PMM Connected defines a Iu signaling connection. The 2 other
PMM states do not have an active Iu signaling connection.

Change-Id: Ie05d2bdf8dfb593b4c7e837107a3a06f22e90119
2019-10-03 20:29:37 +00:00
Alexander Couzens
e30f19542b Avoid compiling unneeded files when building without Iu
Remove gprs_ranap.c and gprs_mm_state_iu_fsm.c
from the Makefile when building without IU.

Change-Id: I2386f8e86bbf0b87eedce9f57eb86b1b64998a69
2019-10-03 19:51:03 +00:00
Alexander Couzens
a8f782502b sgsn: when receiving data PDU notify the Gb GMM fsm
When receiving a PDU, the GMM fsm will change to state MM_READY
and will re-arm the T3314

Relates: OS#1941
Change-Id: I78f40762fb17bbd4a6f35608a793f8e5271e9b86
2019-09-28 17:55:19 +00:00
Pau Espin Pedrol
324bb5a11e Introduce TODO-RELEASE file
It's going to be useful to track new dependency APIs being used which
require dependency version release and version bump during release of
osmo-sgsn.

Change-Id: Ia495a8577001c6a223c31f4ddd7eee289e3523c7
2019-09-19 16:15:32 +02:00
Alexander Couzens
1cb4be9db0 gprs_ranap: refactor REQUIRE_MM define
All branches need a MM context. Exit early if no MM context
present.

Change-Id: Ifa4c55f1f2c199fa63bd755311026b8586a65f3f
2019-09-12 01:43:16 +02:00
Alexander Couzens
6888021bf2 mm_gb_fsm: unassign the llme when entering MM_IDLE
MM_IDLE means there is no known state to this MM.

Change-Id: Ieb0d6cea828842763c13942fe1a63dd89399f799
2019-09-12 01:43:16 +02:00
Alexander Couzens
10b3d70fea gprs_ranap: send CommonId after receiving Security Mode Complete
After Security Mode Complete, the sender has been authenticated.
Send a CommonId to enable paging coordination between CS and PS.

Change-Id: If195c26e87ba3054e159746671babf93a12e7013
2019-09-12 01:43:16 +02:00
Alexander Couzens
8e3766cd38 sgsn_pdp_ctx_terminate: check llme before accessing
Change-Id: Ib4361cdc12f9c1674c89c6fafeeb52a3f42abe1d
2019-09-10 16:01:46 +02:00
39 changed files with 2394 additions and 197 deletions

6
.gitignore vendored
View File

@@ -39,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
View 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.

View File

@@ -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

View 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.

View 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).

View 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.

View 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.

View 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>

View 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[]

View 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>

View File

@@ -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"

View 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>

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,12 @@
#include <stdbool.h>
#include <osmocom/core/msgb.h>
#include <osmocom/sgsn/gprs_rllc.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);

View File

@@ -19,6 +19,7 @@ enum mm_state_iu_fsm_events {
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;

View File

@@ -12,8 +12,19 @@ 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);
#endif
#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

View File

@@ -257,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); } \
@@ -428,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 */

View File

@@ -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 */

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -45,8 +45,6 @@ osmo_sgsn_SOURCES = \
gprs_gmm.c \
gprs_gmm_fsm.c \
gprs_mm_state_gb_fsm.c \
gprs_mm_state_iu_fsm.c \
gprs_ranap.c \
gprs_sgsn.c \
gprs_sm.c \
gprs_sndcp.c \
@@ -87,4 +85,9 @@ osmo_sgsn_LDADD += \
$(LIBOSMORANAP_LIBS) \
$(LIBASN1C_LIBS) \
$(NULL)
osmo_sgsn_SOURCES += \
gprs_mm_state_iu_fsm.c \
gprs_ranap.c
endif

View File

@@ -34,6 +34,12 @@
#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)
@@ -50,7 +56,7 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
msgid2mmctx(mmctx, msg);
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
mmctx->gb.llme = llme;
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
gprs_gb_recv_pdu(mmctx);
}
/* MMCTX can be NULL */
@@ -74,3 +80,26 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
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;
}

View File

@@ -1615,9 +1615,9 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
osmo_rai_name(&mmctx->ra));
/* mmctx is set to NULL and gprs_llgmm_unassign(llme) will be
called below, let's make sure we don't keep dangling llme
pointers in mmctx (OS#3957). */
pointers in mmctx (OS#3957, OS#4245). */
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
OSMO_ASSERT(mmctx->gb.llme == NULL);
mmctx->gb.llme = NULL;
mmctx = NULL;
}
@@ -1625,8 +1625,8 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
if (llme) {
/* send a XID reset to re-set all LLC sequence numbers
* in the MS */
LOGGBP(llme, LOGL_NOTICE, "LLC XID RESET\n");
gprs_llgmm_reset(llme);
LOGGBP(llme, DMM, LOGL_NOTICE, "LLC XID RESET\n");
gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM, llme);
}
/* The MS has to perform GPRS attach */
/* Device is still IMSI attached for CS but initiate GPRS ATTACH,
@@ -1699,6 +1699,12 @@ rejected:
mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ");
else if (llme)
gprs_llgmm_unassign(llme);
#ifdef BUILD_IU
else if (MSG_IU_UE_CTX(msg)) {
unsigned long X1001 = osmo_tdef_get(sgsn->cfg.T_defs, -1001, OSMO_TDEF_S, -1);
ranap_iu_tx_release_free(MSG_IU_UE_CTX(msg), NULL, (int) X1001);
}
#endif
return rc;
}
@@ -1899,7 +1905,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
if (llme && !mmctx &&
gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) {
LOGGBP(llme, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
LOGGBP(llme, DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
/* 4.7.10 */
if (gh->msg_type == GSM48_MT_GMM_STATUS) {
/* TLLI unassignment */

View File

@@ -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) {

View File

@@ -183,5 +183,5 @@ struct osmo_fsm gmm_fsm = {
static __attribute__((constructor)) void gmm_fsm_init(void)
{
osmo_fsm_register(&gmm_fsm);
OSMO_ASSERT(osmo_fsm_register(&gmm_fsm) == 0);
}

View File

@@ -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;
}

View File

@@ -1,6 +1,7 @@
#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>
@@ -16,6 +17,19 @@ static const struct osmo_tdef_state_timeout mm_state_gb_fsm_timeouts[32] = {
#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) {
@@ -33,9 +47,11 @@ static void st_mm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
switch(event) {
case E_MM_READY_TIMER_EXPIRY:
case E_MM_IMPLICIT_DETACH:
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);
@@ -59,6 +75,7 @@ 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,
},
@@ -108,5 +125,5 @@ struct osmo_fsm mm_state_gb_fsm = {
static __attribute__((constructor)) void mm_state_gb_fsm_init(void)
{
osmo_fsm_register(&mm_state_gb_fsm);
OSMO_ASSERT(osmo_fsm_register(&mm_state_gb_fsm) == 0);
}

View File

@@ -6,12 +6,14 @@
#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] = { },
[ST_PMM_CONNECTED] = { },
/* non-spec -T3314 (User inactivity timer) */
[ST_PMM_CONNECTED] = { .T=-3314 },
[ST_PMM_IDLE] = { },
};
@@ -45,11 +47,23 @@ static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data
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:
@@ -76,6 +90,18 @@ static void st_pmm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
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),
@@ -84,7 +110,8 @@ static struct osmo_fsm_state mm_state_iu_fsm_states[] = {
.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),
.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,
@@ -104,6 +131,7 @@ const struct value_string mm_state_iu_fsm_event_names[] = {
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 }
};
@@ -112,10 +140,11 @@ struct osmo_fsm mm_state_iu_fsm = {
.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_fsm_register(&mm_state_iu_fsm);
OSMO_ASSERT(osmo_fsm_register(&mm_state_iu_fsm) == 0);
}

View File

@@ -22,12 +22,10 @@
*/
#include "bscconfig.h"
#ifdef BUILD_IU
#include <gtp.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/tdef.h>
#include <osmocom/ranap/ranap_common.h>
@@ -120,51 +118,82 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
int rc = -1;
mm = sgsn_mm_ctx_by_ue_ctx(ctx);
#define REQUIRE_MM \
if (!mm) { \
LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %d\n", type); \
return rc; \
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:
REQUIRE_MM
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 */
if (mm) {
LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
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
LOGIUP(ctx, LOGL_INFO, "IU release\n");
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:
REQUIRE_MM
/* 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:
if (mm)
LOGMMCTXP(LOGL_NOTICE, mm, "Unknown event received: %i\n", type);
else
LOGIUP(ctx, LOGL_NOTICE, "Unknown event received: %i\n", type);
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;
@@ -229,4 +258,3 @@ int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
return rc;
}
#endif

View File

@@ -243,20 +243,48 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t rate_ctr_id)
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;
char buf[32];
ctx = sgsn_mm_ctx_alloc(tlli);
if (!ctx)
@@ -266,8 +294,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
ctx->ran_type = MM_CTX_T_GERAN_Gb;
ctx->gb.tlli = tlli;
ctx->ciph_algo = sgsn->cfg.cipher;
snprintf(buf, sizeof(buf), "%" PRIu32, tlli);
ctx->gb.mm_state_fsm = osmo_fsm_inst_alloc(&mm_state_gb_fsm, ctx, ctx, LOGL_DEBUG, buf);
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));
@@ -278,7 +305,6 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
{
#if BUILD_IU
char buf[32];
struct sgsn_mm_ctx *ctx;
struct ranap_ue_conn_ctx *ue_ctx = uectx;
@@ -292,8 +318,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
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;
snprintf(buf, sizeof(buf), "%" PRIu32, ue_ctx->conn_id);
ctx->iu.mm_state_fsm = osmo_fsm_inst_alloc(&mm_state_iu_fsm, ctx, ctx, LOGL_DEBUG, buf);
osmo_fsm_inst_update_id_f(ctx->iu.mm_state_fsm, "%" PRIu32, ue_ctx->conn_id);
return ctx;
@@ -459,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));

View File

@@ -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;

View File

@@ -45,6 +45,7 @@
#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>
@@ -53,6 +54,7 @@
#include <osmocom/sgsn/gprs_sndcp.h>
#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>
@@ -614,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;
@@ -660,19 +661,15 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
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 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 "
@@ -756,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;
@@ -828,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);

View File

@@ -271,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 */
@@ -393,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

View File

@@ -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)" },
{}
};

View File

@@ -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,7 +139,7 @@ class TestCtrlBase(unittest.TestCase):
responses[id] = rsp
if verbose:
print "Decoded replies: ", responses
print("Decoded replies: ", responses)
return responses
@@ -154,9 +154,9 @@ class TestCtrlSGSN(TestCtrlBase):
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/sgsn/osmo-sgsn")):
@@ -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)

View File

@@ -44,13 +44,11 @@ sgsn_test_LDFLAGS = \
sgsn_test_LDADD = \
$(top_builddir)/src/sgsn/gprs_llc.o \
$(top_builddir)/src/sgsn/gprs_gb.o \
$(top_builddir)/src/sgsn/gprs_ranap.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_mm_state_iu_fsm.o \
$(top_builddir)/src/sgsn/gprs_sgsn.o \
$(top_builddir)/src/sgsn/sgsn_vty.o \
$(top_builddir)/src/sgsn/sgsn_libgtp.o \
@@ -82,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) \

View File

@@ -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
...

View File

@@ -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]
@@ -80,41 +80,41 @@ class TestVTYGbproxy(TestVTYBase):
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):
@@ -128,22 +128,22 @@ class TestVTYSGSN(TestVTYBase):
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,65 +213,65 @@ 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, ['']))
@@ -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)