Compare commits

...

129 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
Pau Espin Pedrol
d7276bde55 sgsn: Reject PdpActReq if no GTP pdp ctx exists
It could happen that SGSN drops GTP side of a pdp ctx (pdp->lib=NULL)
while still maintaing the other side (to notify about the entire pdp ctx
being torn down). If a PdpActReq arrives during that time, we need to
account for that situation, otherwise osmo-sgsn crashes accessing
pdp->lib.
If no pdp->lib is found at that time, let's reject the request and
expect at some point later in time the entire pdp context will be
destroyed and reestablished.

Related: OS#4173
Change-Id: I6dd87557ebb26fdbd280504abde10d976acecf64
2019-09-06 21:34:31 +02:00
Pau Espin Pedrol
35f0e664bf Split out GPRS SM layer into its own file
Change-Id: Ie61d22e7868af6de73cdf9c731f07130b282599d
2019-09-03 15:22:15 +02:00
Pau Espin Pedrol
31c4657c97 Implement GMM State using osmocom FSM
State machine inspired in the one from TS 24.008 4.1.3.3.1. Some state
transitions are inroduced in the code but are still commented out since
we lack some functionalitites or improvements in the code to handle
different scenarios.

Most of the logic is still outside of the FSM, but at least now the
states are handled in a sane way triggered by events.

Change-Id: Idecb43c10d66224d4f9ba9320825040ce6cf9a07
2019-09-03 15:22:12 +02:00
Pau Espin Pedrol
2e91fee1ad enum gprs_gmm_state: Fix spec reference
Change-Id: I62121e46e5091e5b559397aa01f107ddc23e2c18
2019-09-02 14:03:04 +02:00
Pau Espin Pedrol
33ebedc3d5 gmm: Move code handling GMM PTMSI Realloc Complete to its own function
Change-Id: I3b21a976c6683bea5419a33f0ccb8b56483d6e21
2019-09-02 14:03:04 +02:00
Pau Espin Pedrol
ab264ebba8 gmm: Move code handling GMM Routing Area Update Complete to its own function
Change-Id: I8e28ac03edf82374e804701ebe635e1171a2b36a
2019-09-02 14:03:04 +02:00
Pau Espin Pedrol
a0bcfad99b gmm: Move code handling GMM Attach Complete to its own function
Change-Id: I2d8d947ab1eb4100f404b885461f7a30583c9ac6
2019-09-02 14:03:04 +02:00
Pau Espin Pedrol
762c39ccc6 Move out sgsn to its own subdir
Change-Id: I16fccc0eadf588599b9e5578d0f4dbaf9df81737
2019-09-02 14:03:04 +02:00
Pau Espin Pedrol
ea05d5c5f8 Move out gtphub to its own subdir
Change-Id: I707d5e9b775179e732d281ce3d245de83d648eea
2019-09-02 14:03:04 +02:00
Pau Espin Pedrol
9d016fd499 Move out gbproxy to its own subdir
Change-Id: I2cc98d3a276d953609bbbbaa9782a0112687791e
2019-09-02 14:03:04 +02:00
Pau Espin Pedrol
b8f22bd6c7 src/gprs/Makefile.am: Move build of shared .c files to an internal lib
Build files shared by osmo-sgsn, osmo-gbpy and osmo-gtphub into a .la
library, so we can later split each application into its own subdir and
clearly identify what's used by who.

Due to a dependency error with .Po files,  I cannot depend on the specific
.o files directly in LDADD for each binary, but it works fine on follow up
commits when binaries are splitted into different makefiles, so it will be
done later.

Change-Id: Ib7665c530c086a5f3135c395bb8bf19ed4a882b6
2019-09-02 14:03:00 +02:00
Pau Espin Pedrol
fd815bba12 vty: Print MM state and RAN type in show mm-context
Value presviosuly printed as MM state is actually usually refereed as
GMM state, so rename it.

Change-Id: Ia06c53f0cd2a6348237ed3abeb9367d965745aba
2019-09-02 11:44:58 +02:00
Pau Espin Pedrol
ccd1252bd7 Introduce FSM mm_state_iu_fsm
Implement TS 23.060 6.1.2 Mobility Management States (Iu mode) using
osmocom FSM and drop old implementation.
Most of the logic on each state is still kept in gprs_gmm.c, will be
inserted into the FSM later.

Change-Id: I4c9cf8c27194817c56e8949af0205e1cc14af317
2019-09-02 11:44:58 +02:00
Pau Espin Pedrol
02514bc592 Introduce FSM mm_state_gb_fsm
Implement TS 23.060 6.1.1 Mobility Management States (A/Gb mode) using
osmocom FSM and drop old implementation.
Most of the logic on each state is still kept in gprs_gmm.c, will be
inserted into the FSM later.

Change-Id: I04004423e993107374d5a3549b8a93ac169251dd
2019-09-02 11:44:58 +02:00
Pau Espin Pedrol
9119d50849 sgsn_vty: Print correct Iu mmctx id in 'show mm-context'
Change-Id: I79333bef4a4bf743fcad07812c9a213b368ff2b6
2019-09-02 11:44:58 +02:00
Pau Espin Pedrol
3b848bdc42 sgsn_vty: Fix mmctx rate_ctr output indentation
Change-Id: I1b89c179e1ba08b65e31727fdce90c7b578f4d6d
2019-09-02 11:44:58 +02:00
Pau Espin Pedrol
8b88f5f7f3 sgsn_cdr.c: Fix ip addr string buffer size
INET(6)_ADDRSTRLEN already contains the required extra null byte at the
end, no need to add +1 to it.

Change-Id: I5a16659e007c6883fe21582cce5dac544e6d4bb9
2019-09-02 11:44:58 +02:00
Pau Espin Pedrol
a794811416 gprs_gmm.c: Replace inet_ntoa with inet_ntop
inet_ntop manual states:
"inet_ntoa(3) is now considered to be deprecated in favor of
inet_ntop()".

Change-Id: I0c708d047122f349acf46797a9e5973040e7ae04
2019-09-02 09:42:21 +00:00
Pau Espin Pedrol
87264e6454 Merge common allocation steps for Gb and Iu ctx
This way it's easier to add new common functionalitites without
forgetting to add it on both sides, and simplifies the code.

Change-Id: Ib6c0427ac7b35295cf1caf2f28cb2a5c155b9d9c
2019-09-02 09:42:21 +00:00
Pau Espin Pedrol
0b72240799 Split enum gprs_pmm_state into Iu and Gb counterparts
Those two state sets are not part of the same state machine, and are
used in different scenarios, so let's split them and handle them in Gb
and Iu specific parts of struct sgsn_mm_ctx. This is required in order
to improve related code (for instance, use osmocom fsm).

Change-Id: I6100d607da316da0595886c6968704dd9ccfbde9
2019-09-02 09:42:21 +00:00
Pau Espin Pedrol
8333ef10c9 Move llc->MM/SM Gb specific glue code to its own file
Now that we have RANAP/Iu handling specificities in its own file, let's
have also Gb specific glue code for messages coming from llc up to MM/SM
layer in its own file. This way same entry points in gprs_gmm.c are used
by Gb and Iu: gsm0408_rcv_gmm() (for MM) and gsm0408_rcv_gsm() (for SM).

Change-Id: Iaf57922a0970c1d03f6f1d6337d27ae3d4aaf32c
2019-09-02 09:42:21 +00:00
Pau Espin Pedrol
6dfb5fef40 Move lots of Iu/ranap specific code into its own file
RANAP related functionalities were splitted among several files
(gprs_gmm.c, gprs_sgsn.c and sgsn_libgtp.c). Let's move it into its own
file to shrink complexity/size of existing files.
It also allows to keep a lot of conditionally enabled code (BUILD_IU)
and its dependencies (osmo-iuh) together.

Change-Id: I549042aaff045a378de77d657cc396ee08f22f33
2019-09-02 09:42:21 +00:00
Pau Espin Pedrol
259e303436 sgsn: gtp: Drop related pdp contexts on echo timeout against GGSN
Change-Id: I7e97bac1c13a2c26203eb64e590fd75d77eb44bd
2019-09-02 09:06:13 +00:00
Pau Espin Pedrol
6ec5dc26b3 Introduce log helper LOGGGSN and log category DGTP
It will be used in forthcoming commits.

Change-Id: I30f46f44af1d0eee324b1a995c1dad2e1315af7c
2019-09-02 09:02:38 +00:00
Alexander Couzens
4ec21769b2 gprs_gmm: gsm48_rx_gmm_att_req(): refactor duplicated code
Change-Id: I709f847802a975e1a75d0b87ac5125240cfd0854
2019-09-02 08:59:43 +00:00
Alexander Couzens
c44af53d1e gprs_gmm: clarify comment of Iu follow-on request
Change-Id: Ib6b3a1b250de373656310a3c8f88d1d39bdcee60
2019-09-02 08:59:43 +00:00
Alexander Couzens
f8d3e7fe05 gprs_gmm: only update gb/iu cell information when Iu/Gb present
This function should not do the transistion of Iu/Gb. Only copy simple data

Change-Id: Id52761f3ea655a2d0cc663a950154c6b7c1b5f7a
2019-09-02 08:59:43 +00:00
Pau Espin Pedrol
d8037bcedc gtp: cb_delete_context(): Clarify why pdp->lib is set to NULL
Change-Id: I02c46062d6dc9802d9cae057587e66a68a65436c
2019-08-30 08:24:48 +00:00
Pau Espin Pedrol
aa89f5dffc gtp: make echo_interval unsigned
There's no real need to use -1 to indicate echo timer as disabled, since
0 can also be used (it doesn't make sense to have a timer timeout of 0).
This way code is simplified.

Change-Id: I689034887188a53590eddeffda781629694eb5ed
2019-08-28 16:08:49 +02:00
Pau Espin Pedrol
5623eb8439 gprs_gmm.c: Add spec document to function documentation
Change-Id: Ibb89499e9c1ab588336df34fde26faf3fbf2c72c
2019-08-21 17:18:14 +02:00
Pau Espin Pedrol
d956e16c7b gprs_gmm.c: Print value_string of reject cause
Change-Id: I71d9abcf7e3a836c475b7adbb95a82580e41ae6d
2019-08-21 17:17:11 +02:00
Pau Espin Pedrol
2c90899bc4 vty: Introduce cs7-instance-iu
Similar to what we already have in osmo-msc.

Change-Id: Iaa9e1d06dd0430848ef4f7498a3c15d13f899904
2019-08-21 11:11:09 +02:00
Pau Espin Pedrol
1aaeea4900 examples: Add osmo-sgsn_custom-sccp.cfg
Change-Id: Id3a3ccbf168fbbc28153cbf7f0249294eee34d3d
2019-08-21 09:08:19 +00:00
Pau Espin Pedrol
99bd9d3139 gprs_gmm.c: Use osmo_rai_name() in log line
Change-Id: Ieab9b7696c93de9a5d3d42f614072a6f2181e37d
2019-08-20 17:48:47 +02:00
Alexander Couzens
39cbecd273 gprs/gprs_gmm: implement T3314. Timeout to reset MM state READY->STANDBY
When a MS MM state is READY its exact location is known (PCU).
On Gb, T3314 (aka TS 23.060 "READY timer") sets the MM state from
READY to STANDBY, where only the RA is known.

Introduce a second set of timer variables, because state timer
can run while another packet state timer is timing out.

Related: OS#1941
Change-Id: I4ce23ebe50d141076c20c9c56990b7103cd25e55
2019-08-20 17:48:47 +02:00
Pau Espin Pedrol
5ed3f67f96 tests: Introduce vty-transcript-test tests
Add a few commands to make sure it's working fine, and print all
available timers with default values.

Change-Id: Ifd092b9561d49be1f62769d95ba49f6e4aeb4066
2019-08-20 17:48:47 +02:00
Pau Espin Pedrol
a299d65114 Replace own timer infra with libosmocore osmo_tdef
VTY command "show timer" is also available now.

Change-Id: Ia0cf5f0a49737fbc419e2ccc86312d01c6e0056e
2019-08-20 17:48:31 +02:00
Pau Espin Pedrol
a43fb7b8e5 tests: Verify that timers can be set over VTY
Change-Id: I486fc2a56e235a539836894d2042c1ca6e514ab9
2019-08-20 10:34:29 +00:00
Pau Espin Pedrol
f913265309 gprs_gmm: Avoid spaces in fsm events and enum strings
FSM doesn't expect receiving event names containing spaces (log lines
generated are confusing).

Similar for enums, it's better using code names to match easily and make
log lines more clear.

Change-Id: I16ede8bf8352b09bc772fd7b43fad2c2274b3ec1
2019-08-20 10:34:29 +00:00
Pau Espin Pedrol
5b6c4b8ccd Introduce and use log macros when no mm ctx available
Change-Id: Iba22060d8646bc8ec6227684ccb91d98cb4c7be2
2019-08-20 10:34:29 +00:00
Pau Espin Pedrol
2179dec71d gprs_gmm.c: Call mmctx_set_(p)mm_state only on related ran_type
For new readers it's very confusing why PMM states and MM states are in
the same enum, but handled with different functions, and sometimes
called one right after the other with different enums. Calling them when
on a different ran_type makes the function early return, so let's better
conditionally call the function to make it clear in the flow when the
function is expected to do something.

Change-Id: I65ad9e180177bc9fc7c4a037cd85cfe33b161f73
2019-08-20 10:34:29 +00:00
Pau Espin Pedrol
2844b5ea00 gprs_gmm.c: Fix typo in log message
Change-Id: I357f0af89f5d14d304c3e889a49a5f6c23b7fb7a
2019-08-19 17:29:38 +00:00
Pau Espin Pedrol
f0f596f3d9 sgsn: use sccp_simple_client API to setup ss7 id 0 instead of 1
Implementation of osmo_sccp_simple_client() API internally uses ss7 id
1, which is confusing since there's no 0 in use in osmo-sgsn. Let's
explicitly use the 0 one so it is configured by "cs7 instance 0" in the
VTY.

Related: OS#4157
Change-Id: I0e23a6a76ebcba0b1b424e3d3b20d06c1da44cbe
2019-08-19 17:57:16 +02:00
Pau Espin Pedrol
6e3112579e gprs_gmm.c: Flag mmctx_set_(p)mm_state() functions static
Change-Id: I061144b6994ee40d5b32eb321dd4f3d3786d028d
2019-08-15 13:15:48 +02:00
Pau Espin Pedrol
05140b8dfe gprs_sgsn.h: Flag MM_CTX_T_GERAN_Iu as not supported
Change-Id: I3b53a530ab25434e2b2f4d80ad70a8a5f22bfcac
2019-08-15 13:15:21 +02:00
Pau Espin Pedrol
c21be62380 gprs_gmm.c: Use correct function to set MM_IDLE state during cleanup
Change-Id: Ic6912269d0d69c86f19e57f3271ebda1328e968f
2019-08-15 13:12:36 +02:00
Pau Espin Pedrol
1927052de6 gprs_gmm: Introduce assert to guard against unexpected condition
This may well be the culprit of OS#3957, were already freed llme is accessed from
mmctx context later on, upon some timer is triggered in mmctx.

Related: OS#3957

Change-Id: I8e1eaeb9b3ebee8e45704b4fe007190c7db609e4
2019-08-15 13:12:11 +02:00
Pau Espin Pedrol
c488665f92 gprs_sgsn.c: Remove recently introduced assert
Recent commit added an assert to make sure unexpected conditions were
happening in sgsn_mm_ctx_cleanup_free(). Old code was passing
mm->gb.tlli to gprs_llgmm_assign with "new tlli" being all-1's (aka
unassign mm->gb.tlli).
The commit changed the code to use gprs_llgmm_unassign, which uses
llme->tlli instead of mm->gb.tlli, and the assert was used to make sure
no behavior change occured with the commit.
It seems TTCN3 test TC_attach_auth_id_timeout triggers that assert, and
after closer debug it seems mm->gb.tlli == llme->old_tlli, which makes
sense since there's a mm->gb.tlli_new which is expected to be
llme->tlli.
When TLLI changes in GMM (Attach Request or RA Update), it is stored
into mm->gb.tlli_new and assigned on the LLC layer using gprs_llgm_assign(),
and upon completion signalling from MS, (after handling response to initial request)
it is assigned to mm->gb.tlli (and value kept in mm->gb.tlli_new).
So mm->gb.tlli and mm->gb.tlli_new usually contain the same value unless
a new TLLI is allocated, and during the span of
Request->Response->Complete it is kept different, the LLC layer having assigned
the value of mm->gb.tlli_new.
So, old code (before the commit adding the assert) was wrongly using
mm->gb.tlli instead of mm->gb.tlli_new at the moment of unassigning (but
not really problematic in practice since behavior is the same as long as
"old TLLI" value is not all-1's.
So we are fine and correct using gprs_llgm_unassign() (which passes llme->tlli
as "old TLLI") instead of what used to be done before.
In any case, the expected behavior is to free the llme object and get
rid of everything...

Fixes: 788863cda5
Change-Id: I482acdbdf05ce0cb0a5804206672512854067f5b
2019-08-13 20:58:17 +02:00
Pau Espin Pedrol
982e130144 gprs_gmm: Clarify comment during TLLI assignment
TS 04.64 sec 7.2.1.1 LLGMM-ASSIGN specifies:
"""
If TLLI Old  all 1's and TLLI New  all 1's then TLLI Old and TLLI New are assigned, and TLLI New shall
be used when (re-)transmitting LLC frames. Both TLLI Old and TLLI New shall be accepted when received
from the peer. It shall be treated as a TLLI change according to subclause 8.3.2.
"""

Change-Id: I3a17715bf2dba7b03c1335ad106307eb4d5f564a
2019-08-13 20:23:08 +02:00
Pau Espin Pedrol
788863cda5 gprs_sgsn.c: Warn upon llme free unexpected scenarios
May be useful to detect unexpected conditions which could end up in
memory leaks.

Related: OS#3957
Change-Id: I0d175501083ce458ff1c07ad38761d2cbf4ea470
2019-08-12 18:33:39 +02:00
Pau Espin Pedrol
404d9b8bba Introduce define TLLI_UNASSIGNED
Change-Id: Ib8be5af2a5e92a7403505b73ce4c1751832de40d
2019-08-12 17:50:00 +02:00
Pau Espin Pedrol
d723a97fae gprs_gmm.c: Drop unneeded brackets
Change-Id: Ie8ba2b9da695de8730834abb591df64295bb6172
2019-08-12 17:43:35 +02:00
Pau Espin Pedrol
72b61e4344 gprs_gmm.c: Improve doc on nullable parameters
Change-Id: Iefb9b6dc34d87b4088c7535ef0a246103fe3f7e9
2019-08-12 16:43:58 +02:00
Pau Espin Pedrol
39aa9ee6df gprs_llc.h: Improve documentation of some structs
Change-Id: I1b45f45addc87c74f3ae109e544143a1335180de
2019-08-12 16:23:04 +02:00
Pau Espin Pedrol
dfd7c24e16 gprs_gmm: Introduce macros to access msgb's associated IU UE ctx
Change-Id: I4d1d47af332d4557e8a3a70c1055bcc172166016
2019-08-12 16:06:49 +02:00
Pau Espin Pedrol
d7ef94c0bb Bump version: 1.4.1 → 1.5.0
Change-Id: Ife43559f395b9602f0b131a672f8d87d6ee48ea2
2019-08-08 16:46:31 +02:00
Pau Espin Pedrol
37bc0ff580 Require newer versions of dependencies
New APIs only available since libgtp 1.4.0 are needed, and in turn that
libgtp version requires newer libosmocore 1.1.0.

osmo-sgsn itself requires libosmocore 1.2.0 since it uses GSM23003_TMSI_SGSN_MASK.

Change-Id: I1c67d3e7dda093b4869756c7a63dc7a4549084ae
2019-08-08 16:44:05 +02:00
Pau Espin Pedrol
e456e32f15 Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
Since March 15th 2017, libosmocore API logging_vty_add_cmds() had its
parameter removed (c65c5b4ea075ef6cef11fff9442ae0b15c1d6af7). However,
definition in C file doesn't contain "(void)", which means number of
parameters is undefined and thus compiler doesn't complain. Let's remove
parameters from all callers before enforcing "(void)" on it.
API osmo_stats_vty_add_cmds never had a param list but has seem problem
(no "void"), so some users decided to pass a parameter to it.

Change-Id: Ic4af704958819e6f65ac01be33ef5b3d69628ad0
Related: OS#4138
2019-08-05 16:03:39 +02:00
Daniel Willmann
c9e8d90982 configuration.adoc: Add a section about encryption
Change-Id: I3a2b84d386f55447e9eed35e59fdc0272e5147d1
Related: OS#1720
2019-07-30 09:02:27 +02:00
Daniel Willmann
862bc62975 configuration.adoc: Small fixes
Fix some typos, correct data compression command, add example to turn
off compression.

Change-Id: I6beff8c66eacf12f1081d51dd6b124bdd4478558
Related: OS#1720
2019-07-30 08:59:39 +02:00
Oliver Smith
e18df0e28d osmo-gbproxy.cfg: fix conflict with osmo-sgsn.cfg
Listen on 127.0.0.100 by default, so there is no conflict on
127.0.0.1:23000. This allows starting both services with their default
configuration, like we are doing it in the Osmocom-Debian-install-*
jenkins jobs.

Related: OS#3369
Change-Id: I6e3053de8885a7954296d820c6a069d06276e4df
2019-07-29 08:26:37 +00:00
Daniel Willmann
5f0bce6636 osmo-sgsn: Fix outdated information in usermanual
Quite a few features that are listed as not-implemented in the overview
section are actually implemented now.

Change-Id: I8d499a25293b69babc2aebb2d697438f8ba8141f
Related: OS#1720
2019-07-26 12:05:12 +02:00
Daniel Willmann
03a2ed5b30 Add/fix help string for version option
osmo-sgsn was missing the help text of the -V option
gb_proxy still thought of itself as OpenBSC
Omit the name of the program in the help text to avoid such issues in
the future.

Related: OS#1720
Change-Id: Ib57694b6bff7c98a269dc4b4dbb7173349a57b81
2019-07-26 11:59:00 +02:00
Oliver Smith
40fce10e46 osmo-gtphub.cfg: fix conflict with osmo-sgsn.cfg
Change bind-to-sgsns from 127.0.0.1 to 127.0.0.10, so osmo-gtphub's
default config does not conflict with the osmo-sgsn default config. The
value of bind-to-ggsns does not clash with osmo-ggsn's config, so it was
left unchanged.

Related: OS#3369
Change-Id: Id892e1f4ab2daabbe9824b819b5fed985373b97a
2019-07-24 19:32:05 +00:00
Daniel Willmann
6daac87bd2 manuals: Update vty/counter documentation
Change-Id: Id7245eb1011d1f04d5dfa1503a96d100bc98344c
Related: OS#1700
2019-07-24 10:41:28 +02:00
Eric Wild
05fee6dbee turn -Werror=null-dereference into a warning
There is unfortunately no way to suppres this witha pragma,
and gcc 9 uncovers quite a few new instaces with enabled LTO that can't/won't be fixed
"error: potential null pointer dereference"

Related: OS#4123
Change-Id: I4d1219bf84d3b8dcaf925a60cf54abe733fba263
2019-07-22 19:57:02 +00:00
Vadim Yanitskiy
4b8e309f57 sgsn_mm_ctx_find_ggsn_ctx(): fix: always set gsm_cause
GCC 9 complains that variable 'gsm_cause' in do_act_pdp_req() may
be uninitialized. This may happen if sgsn_mm_ctx_find_ggsn_ctx()
would return NULL due to no static GGSN configured.

Change-Id: I09c608045dd35b9898b82e236a306ab9a6c2c0b9
2019-07-18 15:05:04 +07:00
Ruben Undheim
55fcf111e1 Spelling fixes
Change-Id: Id1511c5022a239db5d0b44ec7adf048cca307751
2019-07-17 10:59:24 +00:00
Oliver Smith
43f16ec403 contrib/jenkins.sh: run "make maintainer-clean"
Related: OS#3047
Change-Id: Ic887518bd149f325a92c3517ee90c655b1368fd8
2019-07-10 13:24:35 +02:00
Daniel Willmann
43c5b7023b manuals: Add script to regenerate vty/counter documentation
Change-Id: I8ee63a3da532285def8de7fe5e90873152adb21e
Related: OS#1700
2019-06-19 14:24:13 +02:00
Eric Wild
df9b39142f replace magic tmsi constant with define
Depends: libosmocore I52b9f6b5f3e96d85a390ba2af21d7814df8aaeec
Change-Id: Icf9f466efce520779c926b47b6e6d6c9815120eb
2019-06-17 13:50:13 +02:00
Pau Espin Pedrol
d1463bc365 sgsn: Have authentication required on by default
Previous commit introduced command "authentication (optional|required)",
which is only meaningful if auth-policy is remote. Upon adding the cmd,
it changed the default logic for remote policy to not require
authentication, which broke TTCN3 tests because sgsn no longer tries to
authenticate the users.

Since it's actually good to enable authentication by default where
possible, let's enable it by default when on auth-policy remote.

In order to do so, let's simply not care about the value of variable
require_authentication if auth_policy is not REMOTE. As a result, we
drop parts of the previous patch and remove unneeded checks (which are
only partially useful based on order of commands during VTY read).

Fixes: 794f446a28
Change-Id: Ic707a95af178b44f08809df3d3bc8354bf34273c
2019-06-13 19:23:36 +02:00
Vadim Yanitskiy
794f446a28 osmo-sgsn: add VTY parameter to toggle authentication
It may be useful to have 'remote' authorization policy, but do not
require authentication in GERAN at the same time, e.g. in combination
with 'subscriber-create-on-demand' feature of OsmoHLR.

This change introduces a new VTY parameter similar to the one
that we already have in OsmoMSC:

  authentication (optional|required)

Please note that 'required' only applies if 'auth-policy' is 'remote'.

Change-Id: I9909145e7e0af587c28827e16301a61b13eedaa9
2019-06-06 19:45:34 +00:00
Pau Espin Pedrol
f7afd20200 sgsn_libgtp: Use new per-GSN libgtp API instead of deprecated API
Depends: osmo-ggsn.git I653cbdc185165592d985e3efab6e3f1add97877b
Related: OS#2873
Change-Id: Iaaffe0ec4d9590309c62b62c446677c6f6732f2a
2019-06-06 15:30:47 +00:00
Vadim Yanitskiy
812a8bd18f doc/manuals/vty: regenerate sgsn_vty_reference.xml
Change-Id: I3dfe3598055457cc9724a371590e676f1920652b
2019-06-05 01:31:57 +07:00
Oliver Smith
eb3a8556be debian: create -doc subpackage with pdf manuals
I have verified, that the resulting debian packages build in my own OBS
namespace (see the -doc packages):
https://download.opensuse.org/repositories/home:/osmith42/Debian_9.0/all/
https://build.opensuse.org/project/show/home:osmith42

Depends: Ib7251cca9116151e473798879375cd5eb48ff3ad (osmo-ci)
Related: OS#3899
Change-Id: I9c09a0cb5c65fa2e2cd9817edb4656b2a1a35bb9
2019-05-29 12:14:20 +02:00
Pau Espin Pedrol
1825ab5bae sgsn: Fix echo timer not started upon first pdp ctx created
Commit 176a4d2f33 moved echo timer related
code to its own function but did some mistakes when moving the logic
from several places into its own function. As a result, echo timer was
only enabled after the 2nd pdp ctx was created, instead of the expected
1st.
First, let's be consistent and always call the function *after* changing
state, since that's what the function expects. This fixes the issue.

Finally make the logic in the function more intuitive by checking in the
if clause the only case where actually the echo timer should be enabled:
Only if policy specifies so and we have at least 1 pdp ctx against that ggsn.

Fixes: 176a4d2f33
Change-Id: I826030978edb61ea5a172c2b72f63758206a6246
2019-05-29 08:45:43 +00:00
Pau Espin Pedrol
20795e3fda Document max retransmit times for T3395
Spec also states same value is used for T3390, which we don't yet
implement.

Change-Id: I1a2276bd42d1ea5706cf9cc26d3e44baa6fbf066
2019-05-28 21:27:56 +02:00
Pau Espin Pedrol
ba2e500395 sgsn: vty: Improve log warning content with spec section
Change-Id: I68e87f29711a282a97a43b175f13b3c70112ab60
2019-05-27 17:35:32 +02:00
Max
ef38b4c55e Fix IMSI padding in imsi-acl
In I73fd54ad3a4ab8be5aff0fee5c722597ad766e9d incorrect fix was added
which only initialize first element of array. Fix this by using explicit
index to initialize entire array.

Change-Id: I26e4aa44f159d1b5b91dda4a586fd4e809711245
2019-05-12 10:35:40 +00:00
efistokl
def0d941f9 gprs_gmm: send Service Reject when no PDP ctxs are available.
Look at PDP Context Status IE: if there are any PDP contexts which are
ACTIVE on MS side and there are no PDP contexts which are ACTIVE on the
network side, then send Service Reject with the cause "NO PDP
ACTIVATED". This forces MS to reactivate the PDP contexts.

3GPP TS 24.008 Section 4.7.13.4 Service request procedure not accepted
by the network. Cause # 40.

Fixes: OS#3937
Change-Id: If610cbef17c25ec44e65d4f1b2340d102c560437
2019-05-11 05:28:49 +00:00
Keith
bfd67d2f69 Echo zero byte XID-Field of Type L3_PAR
After Activate PDP Context request, Motorola KRZR
sends a zero length XID-Field of Type L3 Parameters

If this is not echoed back, the phone will send
Deactivate PDP Context request with SM Cause:
LLC or SNDCP failure(A/Gb only) (25)

Closes: OS#3426

Change-Id: Ibd75f7b943c84ed7264481fa2e4bc3cb2f6745d4
2019-05-02 09:38:28 +00:00
Alexander Couzens
6c0586ac7b gbproxy: parse dtap GSM48_MT_GSM_DEACT_PDP_REQ|ACK
Fix a warning "Unhandled GSM 04.08 message type ...".

Fixes: OS#3466
Change-Id: I20bf4db8da746e0b994bfe3f8178188831b67ed3
2019-04-30 01:04:48 +00:00
Pau Espin Pedrol
b72141458c gprs_sndcp_comp_free: Replace ifelse with switch and better handling of error
gprs_sndcp_dcomp_term asserts if compclass is not
SNDCP_XID_DATA_COMPRESSION, so this way by checking in the caller too we
easily now if the unexpected value is in compclass or in algo.dcomp.

Change-Id: I4600e6a137f42f20fdf69637e4a9048b265c1748
2019-04-27 13:35:07 +02:00
Harald Welte
aed46ec97d gb_proxy: cosmetic: Use 'bool' in data structures where applicable
If we ever only use 0/1 in an 'int', we should have used 'bool'.

Change-Id: I63876f52d5de87e4c99d92669270fd1f487e217c
2019-04-24 15:43:26 +02:00
Harald Welte
d3dcaf0bf2 gb_proxy.h: Add missing comments; improve comments
When the patching and routing features were introduced, a lot of the
new structures were not documented at the same level as the pre-existing
code.  Let's fix that.

Change-Id: I61bdd3b1cec037bce825c234a8a274b70629adc8
2019-04-24 15:43:26 +02:00
Harald Welte
af779d2ab2 LLC: Store the XID inside the LLC Entity, not LLC Mgmg Entity
For every logical session between a MS and the SGSN, there is one LLME
(LLC Management Entity) and a set of LLEs (Logical Link Entities): One
for each SAPI.

The XID procedure used to establish LLC configuration values such as
N201 (MTU) parameters happens on each LLE separately. The negotiated
parameters only affect that one LLE (SAPI) and are not global.

Still, the OsmoSGSN LLC code has the "struct llist_head *xid" member as
part of the gprs_llc_llme, and not as part of the gprs_llc_lle. This
list is a cache of the XID fields we have sent with the last XID
request, which is used in processing the response from the MS.

If two XID handshakes were to occur concurrently on two LLEs, the state
between them would get messed up. It must be maintained separately for
each LLE.

Closes: OS#3955
Change-Id: Iaeb54ca5ac58391be45e56c2e721f531969f3a9e
2019-04-24 15:42:36 +02:00
Harald Welte
1f60bbe8a2 gprs_llc: Correctly refuse any ABM command (SABM, DISC) with DM
According to Section 6.4.1.4 of 3GPP TS 04.64
	The DM unnumbered response shall be used by an LLE to report to
	its peer that the LLE is in a state such that ABM operation
	cannot be performed. An LLE shall transmit a DM response to any
	valid command received that it cannot action.

Closes: OS#3953
Change-Id: Ie8b8e16d5a68f19f21dc4fdb5703c8a794e0173c
2019-04-24 15:42:27 +02:00
Harald Welte
3a0b772d6c LLC: Avoid NOTICE message on LLC NULL
A MS sending LLC NULL frames on cell change is a perfectly normal event,
and we shouldn't log any cryptic NOTICE messages about it.

Change-Id: I6be0b9c8813dfb40a7955422fd8e7cebf94d189c
2019-04-23 23:22:54 +02:00
Harald Welte
37bd02121b LLC: Don't blindly assume all LLC frames have data payload
In reality, only UI, I, SABM, UA and XID frames carry payload.  All
other frames will have llhp.data == NULL.

Let's therefore not do any msgb adjustments unless we actually know
there is a user payload field.

Change-Id: I51bbd0f2c618d477a037af343ff41de1c8a5a3ae
Closes: OS#3952
2019-04-23 23:22:54 +02:00
Harald Welte
321eb8e8c9 LLC XID: Fix string representation of N201_U
Change-Id: I8799e3a3c47377aeeb9923d9d73f5d0b73cd8d0b
2019-04-23 20:51:37 +00:00
Alexander Couzens
932ccf87a0 gprs_gmm: reintroduce calling gsm48_gmm_authorize when not handling GMM Attach Requests
A security command is part of multiple procedures to ensure
integrity (optional also encryption) between MS and RNC.
It should be used for all Iu connections once.
With the rewrite of the GMM Attach FSM the use of the security command
procedure was broken for all procedures e.g. Service Request except GMM
Attach Request.

Relates: OS#3920
Change-Id: I50e8e316f06ae1a6171a6b07e4e2f0761322b779
2019-04-16 11:11:28 +02:00
efistokl
c42e21e81c gsm0408_rcv_gmm: send Iu-ReleaseCommand upon receiving Attach Complete.
UE expects to receive Iu-ReleaseCommand after Attach Complete. If it
doesn't receive it, then it sends Iu-ReleaseRequest after a timeout
which makes the "PS Activation" process long.

Change-Id: Ib5053e3cd655d08ff3fd0fefa48325fabb1797c8
Related: OS#3908
2019-04-08 02:58:18 +00:00
103 changed files with 5434 additions and 1955 deletions

7
.gitignore vendored
View File

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

@@ -39,12 +39,12 @@ AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.0.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.4.0)
PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.0.0)
@@ -61,7 +61,7 @@ AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")
AC_SUBST(osmo_ac_iu)
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.3.0)
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.4.0)
PKG_CHECK_MODULES(LIBCARES, libcares)
dnl checks for header files
@@ -116,7 +116,7 @@ CFLAGS="$CFLAGS -Wall"
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
AX_CHECK_COMPILE_FLAG([-Werror=null-dereference], [CFLAGS="$CFLAGS -Werror=null-dereference"])
AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"])
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
@@ -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

View File

@@ -77,4 +77,5 @@ if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
make -C "$base/doc/manuals" publish
fi
$MAKE maintainer-clean
osmo-clean-workspace.sh

66
debian/changelog vendored
View File

@@ -1,3 +1,69 @@
osmo-sgsn (1.5.0) unstable; urgency=medium
[ Max ]
* Improve 'show subscriber cache' vty command
* GMM: permit VLR_ANSWERED event in attach FSM
* Fix IMSI padding in imsi-acl
[ Harald Welte ]
* gbproxy_test: Fix test expectations of gprs_ns_rcvmsg()
* LLC XID: Fix string representation of N201_U
* LLC: Don't blindly assume all LLC frames have data payload
* LLC: Avoid NOTICE message on LLC NULL
* gprs_llc: Correctly refuse any ABM command (SABM, DISC) with DM
* LLC: Store the XID inside the LLC Entity, not LLC Mgmg Entity
* gb_proxy.h: Add missing comments; improve comments
* gb_proxy: cosmetic: Use 'bool' in data structures where applicable
[ efistokl ]
* gsm0408_rcv_gmm: send Iu-ReleaseCommand upon receiving Attach Complete.
* gprs_gmm: send Service Reject when no PDP ctxs are available.
[ Alexander Couzens ]
* gprs_gmm: reintroduce calling gsm48_gmm_authorize when not handling GMM Attach Requests
* gbproxy: parse dtap GSM48_MT_GSM_DEACT_PDP_REQ|ACK
[ Pau Espin Pedrol ]
* gprs_sndcp_comp_free: Replace ifelse with switch and better handling of error
* sgsn: vty: Improve log warning content with spec section
* Document max retransmit times for T3395
* sgsn: Fix echo timer not started upon first pdp ctx created
* sgsn_libgtp: Use new per-GSN libgtp API instead of deprecated API
* sgsn: Have authentication required on by default
* Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
* Require newer versions of dependencies
[ Keith ]
* Echo zero byte XID-Field of Type L3_PAR
[ Oliver Smith ]
* debian: create -doc subpackage with pdf manuals
* contrib/jenkins.sh: run "make maintainer-clean"
* osmo-gtphub.cfg: fix conflict with osmo-sgsn.cfg
* osmo-gbproxy.cfg: fix conflict with osmo-sgsn.cfg
[ Vadim Yanitskiy ]
* doc/manuals/vty: regenerate sgsn_vty_reference.xml
* osmo-sgsn: add VTY parameter to toggle authentication
* sgsn_mm_ctx_find_ggsn_ctx(): fix: always set gsm_cause
[ Eric Wild ]
* replace magic tmsi constant with define
* turn -Werror=null-dereference into a warning
[ Daniel Willmann ]
* manuals: Add script to regenerate vty/counter documentation
* manuals: Update vty/counter documentation
* Add/fix help string for version option
* osmo-sgsn: Fix outdated information in usermanual
* configuration.adoc: Small fixes
* configuration.adoc: Add a section about encryption
[ Ruben Undheim ]
* Spelling fixes
-- Pau Espin Pedrol <pespin@sysmocom.de> Thu, 08 Aug 2019 16:46:31 +0200
osmo-sgsn (1.4.0) unstable; urgency=medium
[ Alexander Couzens ]

28
debian/control vendored
View File

@@ -10,17 +10,18 @@ Build-Depends: debhelper (>=9),
automake,
libtool,
pkg-config,
libasn1c-dev,
libtalloc-dev,
libc-ares-dev,
libgtp-dev,
libosmocore-dev,
libosmo-abis-dev,
libosmo-ranap-dev,
libosmo-sccp-dev,
libosmo-sigtran-dev,
libosmo-netif-dev,
libosmo-gsup-client-dev
libgtp-dev (>= 1.4.0),
libosmocore-dev (>= 1.2.0),
libosmo-abis-dev (>= 0.6.0),
libosmo-netif-dev (>= 0.4.0),
libosmo-gsup-client-dev (>= 1.0.0),
libasn1c-dev (>= 0.9.30),
libosmo-ranap-dev (>= 0.4.0),
libosmo-sigtran-dev (>= 1.0.0),
libosmo-sccp-dev (>= 1.0.0),
osmo-gsm-manuals-dev
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/osmo-sgsn.git
Vcs-Browser: https://git.osmocom.org/osmo-sgsn
@@ -67,3 +68,12 @@ Section: debug
Priority: extra
Depends: osmo-gbproxy (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for Osmocom GPRS Gb Interface Proxy
Package: osmo-sgsn-doc
Architecture: all
Section: doc
Priority: optional
Depends: ${misc:Depends}
Description: ${misc:Package} PDF documentation
Various manuals: user manual, VTY reference manual and/or
protocol/interface manuals.

62
debian/copyright vendored
View File

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

1
debian/osmo-sgsn-doc.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/share/doc/osmo-sgsn-doc/*.pdf

6
debian/rules vendored
View File

@@ -46,7 +46,7 @@
# debmake generated override targets
# Set options for ./configure
CONFIGURE_FLAGS += --enable-iu --with-systemdsystemunitdir=/lib/systemd/system
CONFIGURE_FLAGS += --enable-iu --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
override_dh_auto_configure:
dh_auto_configure -- $(CONFIGURE_FLAGS)
#
@@ -63,3 +63,7 @@ override_dh_strip:
# Print test results in case of a failure
override_dh_auto_test:
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
override_dh_compress:
dh_compress -X.pdf

View File

@@ -22,4 +22,5 @@ ns
timer tns-alive-retries 10
encapsulation framerelay-gre enabled 0
encapsulation framerelay-gre local-ip 0.0.0.0
encapsulation udp local-ip 127.0.0.100
encapsulation udp local-port 23000

View File

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

View File

@@ -8,7 +8,7 @@ line vty
gtphub
! Local addresses to listen on and send from, each on standard ports
! 2123 and 2152. Setting these addresses is mandatory.
bind-to-sgsns 127.0.0.1
bind-to-sgsns 127.0.0.10
bind-to-ggsns 127.0.0.2
! Local nonstandard ports or separate IPs:

View File

@@ -10,6 +10,7 @@ sgsn
ggsn 0 remote-ip 127.0.0.2
ggsn 0 gtp-version 1
ggsn 0 echo-interval 60
authentication optional
auth-policy accept-all
!
ns

View File

@@ -10,6 +10,7 @@ sgsn
ggsn 0 remote-ip 127.0.0.2
ggsn 0 gtp-version 1
ggsn 0 echo-interval 60
authentication required
auth-policy remote
gsup remote-ip 127.0.0.1
gsup remote-port 4222

View File

@@ -0,0 +1,39 @@
!
! Osmocom SGSN configuration
!
!
line vty
no login
!
cs7 instance 0
point-code 0.23.4
asp asp-clnt-OsmoSGSN-A 2905 0 m3ua
remote-ip 172.18.8.200 ! where to reach the STP
as as-clnt-OsmoSGSN-A m3ua
asp asp-clnt-OsmoSGSN-A
routing-key 3 0.23.4
sgsn
gtp local-ip 127.0.0.1
ggsn 0 remote-ip 127.0.0.2
ggsn 0 gtp-version 1
ggsn 0 echo-interval 60
authentication required
auth-policy remote
gsup remote-ip 127.0.0.1
gsup remote-port 4222
cs7-instance-iu 0
!
ns
timer tns-block 3
timer tns-block-retries 3
timer tns-reset 3
timer tns-reset-retries 3
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-ip 127.0.0.1
encapsulation udp local-port 23000
encapsulation framerelay-gre enabled 0
!
bssgp
!

View File

@@ -1,16 +1,23 @@
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
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
endif

View File

@@ -7,7 +7,7 @@ On the one hand, this is primary because the PCU configuration happens
from the BSC side.
On the other hand, it is because the Gb interface does not need an
explicit configuration of all each PCU connecting to the SGSN. The
explicit configuration of each PCU connecting to the SGSN. The
administrator only has to ensure that the NS and BSSGP layer identities
(NSEI, NSVCI, BVCI) are unique for each PCU connecting to the SGSN.
@@ -17,7 +17,7 @@ The Gp interface is the GTP-C and GTP-U based interface between the SGSN
and the GGSNs. It is implemented via UDP on well-known source and
destination ports.
When a MS requests establishment of a PDP context, it specifies the APN
When an MS requests establishment of a PDP context, it specifies the APN
(Access Point Name) to which the context shall be established. This APN
determines which GGSN shall be used, and that in turn determines which
external IP network the MS will be connected to.
@@ -100,7 +100,7 @@ NOTE: The policy mode *closed* must not be confused with the equally named
policy that is defined for osmo-nitb!
.Example: Assign or change authorization policy:
.Example: Assign or change authorization policy
----
OsmoSGSN> enable
OsmoSGSN# configure terminal
@@ -116,7 +116,7 @@ OsmoSGSN>
<2> Saves current changes to cofiguration to make this policy
persistent
.Example: Access control list:
.Example: Access control list
----
sgsn
auth-policy acl-only <1>
@@ -153,7 +153,7 @@ simplified by use of a binary TLV encoding similar to Layer 3 of
GSM/GPRS.
GSUP performs a challenge-response authentication protocol called OAP,
which uses the standard MILEAGE algorithm for mutual authentication
which uses the standard MILENAGE algorithm for mutual authentication
between OsmoSGSN and the HLR/HLR-GW.
[[sgsn-ex-gsup]]
@@ -251,9 +251,8 @@ _pdp-_), then the following extra CSV fields are appended to the line:
=== User traffic compression
In order to save optimize GPRS bandwith, OsmoSGSN implements header and data
compression schemes. The compression will reduce the packet length in order
to save radio bandwith.
In order to save GPRS bandwith, OsmoSGSN implements header and data
compression schemes which will reduce the packet length.
==== Header compression
@@ -278,18 +277,24 @@ actively request different compression parameters or reject the offered
compression parameters entirely. The number of slots is the maximum number
of packet headers per subscriber that can be stored in the codebook.
.Example: Accept compression if requested:
.Example: Accept compression if requested
----
sgsn
compression rfc1144 passive
----
.Example: Actively promote compression:
.Example: Actively promote compression
----
sgsn
compression rfc1144 active slots 8
----
.Example: Turn off compression
----
sgsn
no compression rfc1144
----
NOTE: The usage of TCP/IP options may disturb the RFC1144 header compression
scheme. TCP/IP options may render RFC1144 ineffective if variable data is
encoded into the option section of the TCP/IP packet. (e.g. TCP option 8,
@@ -299,10 +304,10 @@ Timestamp)
==== Data compression
Data compression works on the raw packet data, including the header part of the
packet. If enabled, header compression is applied before first data compression
packet. If enabled, header compression is applied first before data compression
is applied. OsmoSGSN implements the V.42bis data compression scheme.
*compression rfc1144 passive*::
*compression v42bis passive*::
V42bis data compression has to be actively requested by the modem. The network
will not promote compression by itself. This is the recommended mode of
operation.
@@ -316,14 +321,38 @@ directions will be the preferred option. The following to parameters configure
the codebook size by the maxium number ('codewords') and size ('strlen') of
entries.
.Example: Accept compression if requested:
.Example: Accept compression if requested
----
sgsn
compression v42bis passive
----
.Example: Actively promote compression:
.Example: Actively promote compression
----
sgsn
compression v42bis active direction both codewords 512 strlen 20
----
.Example: Turn off compression
----
sgsn
no compression v42bis
----
=== Encryption
Encryption can be enabled if the auth-policy is set to remote and the
HLR subscriber entries contain the keys of the SIM card. See
<<sgsn-ex-gsup>> on how to connect to an external HLR.
.Example: Turn on encryption (GEA3)
----
sgsn
encryption GEA3
----
.Example: Turn off encryption (GEA0)
----
sgsn
encryption GEA0
----

View File

@@ -1,5 +1,8 @@
// autogenerated by show asciidoc counters
These counters and their description based on OsmoSGSN UNKNOWN (OsmoSGSN).
These counters and their description based on OsmoSGSN 1.4.0.31-05fe (OsmoSGSN).
=== Rate Counters
// generating tables for rate_ctr_group
// rate_ctr_group table BSSGP Peer Statistics
@@ -15,46 +18,15 @@ These counters and their description based on OsmoSGSN UNKNOWN (OsmoSGSN).
| discarded | <<bssgp:bss_ctx_discarded>> | BVC LLC Discarded count
| status | <<bssgp:bss_ctx_status>> | BVC Status count
|===
// rate_ctr_group table BSSGP Peer Statistics
.bssgp:bss_ctx - BSSGP Peer Statistics
[options="header"]
|===
| Name | Reference | Description
| packets:in | <<bssgp:bss_ctx_packets:in>> | Packets at BSSGP Level ( In)
| packets:out | <<bssgp:bss_ctx_packets:out>> | Packets at BSSGP Level (Out)
| bytes:in | <<bssgp:bss_ctx_bytes:in>> | Bytes at BSSGP Level ( In)
| bytes:out | <<bssgp:bss_ctx_bytes:out>> | Bytes at BSSGP Level (Out)
| blocked | <<bssgp:bss_ctx_blocked>> | BVC Blocking count
| discarded | <<bssgp:bss_ctx_discarded>> | BVC LLC Discarded count
| status | <<bssgp:bss_ctx_status>> | BVC Status count
|===
// rate_ctr_group table NSVC Peer Statistics
.ns:nsvc - NSVC Peer Statistics
[options="header"]
|===
| Name | Reference | Description
| packets:in | <<ns:nsvc_packets:in>> | Packets at NS Level ( In)
| packets:out | <<ns:nsvc_packets:out>> | Packets at NS Level (Out)
| bytes:in | <<ns:nsvc_bytes:in>> | Bytes at NS Level ( In)
| bytes:out | <<ns:nsvc_bytes:out>> | Bytes at NS Level (Out)
| blocked | <<ns:nsvc_blocked>> | NS-VC Block count
| dead | <<ns:nsvc_dead>> | NS-VC gone dead count
| replaced | <<ns:nsvc_replaced>> | NS-VC replaced other count
| nsei-chg | <<ns:nsvc_nsei-chg>> | NS-VC changed NSEI count
| inv-nsvci | <<ns:nsvc_inv-nsvci>> | NS-VCI was invalid count
| inv-nsei | <<ns:nsvc_inv-nsei>> | NSEI was invalid count
| lost:alive | <<ns:nsvc_lost:alive>> | ALIVE ACK missing count
| lost:reset | <<ns:nsvc_lost:reset>> | RESET ACK missing count
|===
// rate_ctr_group table SGSN Overall Statistics
.sgsn - SGSN Overall Statistics
[options="header"]
|===
| Name | Reference | Description
| llc:dl_bytes | <<sgsn_llc:dl_bytes>> | Count sent LLC bytes before giving it to the bssgp layer
| llc:ul_bytes | <<sgsn_llc:ul_bytes>> | Count sucessful received LLC bytes (encrypt & fcs correct)
| llc:dl_packets | <<sgsn_llc:dl_packets>> | Count sucessful sent LLC packets before giving it to the bssgp layer
| llc:ul_packets | <<sgsn_llc:ul_packets>> | Count sucessful received LLC packets (encrypt & fcs correct)
| llc:ul_bytes | <<sgsn_llc:ul_bytes>> | Count successful received LLC bytes (encrypt & fcs correct)
| llc:dl_packets | <<sgsn_llc:dl_packets>> | Count successful sent LLC packets before giving it to the bssgp layer
| llc:ul_packets | <<sgsn_llc:ul_packets>> | Count successful received LLC packets (encrypt & fcs correct)
| gprs:attach_requested | <<sgsn_gprs:attach_requested>> | Received attach requests
| gprs:attach_accepted | <<sgsn_gprs:attach_accepted>> | Sent attach accepts
| gprs:attach_rejected | <<sgsn_gprs:attach_rejected>> | Sent attach rejects
@@ -93,6 +65,8 @@ These counters and their description based on OsmoSGSN UNKNOWN (OsmoSGSN).
| lost:alive | <<ns:nsvc_lost:alive>> | ALIVE ACK missing count
| lost:reset | <<ns:nsvc_lost:reset>> | RESET ACK missing count
|===
== Osmo Stat Items
// generating tables for osmo_stat_items
NSVC Peer Statistics
// osmo_stat_item_group table NSVC Peer Statistics
@@ -102,20 +76,7 @@ NSVC Peer Statistics
| Name | Reference | Description | Unit
| alive.delay | <<ns.nsvc_alive.delay>> | ALIVE response time | ms
|===
NSVC Peer Statistics
// osmo_stat_item_group table NSVC Peer Statistics
.ns.nsvc - NSVC Peer Statistics
[options="header"]
|===
| Name | Reference | Description | Unit
| alive.delay | <<ns.nsvc_alive.delay>> | ALIVE response time | ms
|===
== Osmo Counters
// generating tables for osmo_counters
// ungrouped osmo_counters
.ungrouped osmo counters
[options="header"]
|===
| Name | Reference | Description
|===
// there are no ungrouped osmo_counters

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

@@ -74,14 +74,13 @@ The LLC (Logical Link Control) implementation of OsmoSGSN only supports
non-acknowledged mode, as this is the most common use case in real-world
GPRS networks.
Furthermore, it does not support IP header nor payload compression at
this point. Addition of those features is subject to customer demand or
user/customer contributions.
The LLC implementation does support LLC encryption. However, as no HLR
access is implemented yet, there is no way to enable/configure
per-subscriber specific keys.
It does support both TCP/IP header compression according to RFC1144 and
payload compression according to V.42bis
The LLC implementation does support LLC encryption with ciphers GEA3 and GEA4.
For encryption to work the auth policy needs to be set to remote and the SGSN
connected to an HLR containing the subscriber data including key material.
Other auth policys will not work with encryption.
==== Session Management Implementation
@@ -93,11 +92,8 @@ networks while skipping the more esoteric features.
Multiple PDP contexts can be attached by a single MS.
Currently, all PDP contexts are routed to the same GGSN, irrespective of
the APN used/configured in the MS. This is sufficient (and actually
desirable) for small autonomous networks, but of course not suitable for
real networks in roaming scenarios. Please contact sysmocom in case you
require additional features such as DNS-based APN resolving.
Multiple GGSNs can be configured and routing to a GGSN can be configured based
on APN. Dynamic lookup of GGSNs though DNS-based APN resolving is also possible.
=== Limitations
@@ -109,10 +105,5 @@ performing that work.
Known Limitations include:
* No LLC encryption support
* No interface to the OsmoNITB HLR
* No paging coordination between SGSN and MSC
* No SMS over Ps support
* No IuPS interface for 3G (in progress)
* No IP header compression
* No payload compression

View File

@@ -14,7 +14,7 @@ options:
*-h, --help*::
Print a short help message about the supported options
*-V, --version*::
Print the compile-time version number of the OsmoBTS program
Print the compile-time version number of the OsmoSGSN 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,

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>

77
doc/manuals/regen_doc.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/bin/sh -e
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
}
# $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
echo "Starting in background: $@"
"$@" > "$log" 2>&1 &
pid="$!"
sleep 0.5
if ! kill -0 "$pid" 2>/dev/null; then
echo "ERROR: start failed!"
cat "$log"
exit 1
fi
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

@@ -187,7 +187,7 @@
<param name='MASK' doc='List of logging categories to log, e.g. &apos;abc:mno:xyz&apos;. Available log categories depend on the specific application, refer to the &apos;logging level&apos; command. Optionally add individual log levels like &apos;abc,1:mno,3:xyz,5&apos;, where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
</params>
</command>
<command id='logging level (|mm|pag|meas|ref|gprs|ns|bssgp|llc|sndcp|slhc|ranap|sua|v42bis|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
<command id='logging level (|mm|pag|meas|ref|gprs|ns|bssgp|llc|sndcp|slhc|ranap|sua|v42bis|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<params>
<param name='logging' doc='Configure logging' />
<param name='level' doc='Set the log level for a specified category' />
@@ -222,6 +222,7 @@
<param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
<param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
<param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
<param name='lrspro' doc='Remote SIM protocol' />
<param name='debug' doc='Log debug messages and higher levels' />
<param name='info' doc='Log informational messages and higher levels' />
<param name='notice' doc='Log noticeable messages and higher levels' />
@@ -733,7 +734,7 @@
<param name='MASK' doc='List of logging categories to log, e.g. &apos;abc:mno:xyz&apos;. Available log categories depend on the specific application, refer to the &apos;logging level&apos; command. Optionally add individual log levels like &apos;abc,1:mno,3:xyz,5&apos;, where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
</params>
</command>
<command id='logging level (|mm|pag|meas|ref|gprs|ns|bssgp|llc|sndcp|slhc|ranap|sua|v42bis|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
<command id='logging level (|mm|pag|meas|ref|gprs|ns|bssgp|llc|sndcp|slhc|ranap|sua|v42bis|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<params>
<param name='logging' doc='Configure logging' />
<param name='level' doc='Set the log level for a specified category' />
@@ -768,6 +769,7 @@
<param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
<param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
<param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
<param name='lrspro' doc='Remote SIM protocol' />
<param name='debug' doc='Log debug messages and higher levels' />
<param name='info' doc='Log informational messages and higher levels' />
<param name='notice' doc='Log noticeable messages and higher levels' />
@@ -1488,7 +1490,8 @@
<param name='category' doc='Configure log message' />
<param name='0' doc='Don&apos;t prefix each log message' />
<param name='1' doc='Prefix each log message with category/subsystem name' />
</params> </command>
</params>
</command>
<command id='logging print category-hex (0|1)'>
<params>
<param name='logging' doc='Configure logging' />
@@ -1518,7 +1521,7 @@
<param name='[last]' doc='Log source file info at the end of a log line. If omitted, log source file info just before the log text.' />
</params>
</command>
<command id='logging level (|mm|pag|meas|ref|gprs|ns|bssgp|llc|sndcp|slhc|ranap|sua|v42bis|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
<command id='logging level (|mm|pag|meas|ref|gprs|ns|bssgp|llc|sndcp|slhc|ranap|sua|v42bis|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
<params>
<param name='logging' doc='Configure logging' />
<param name='level' doc='Set the log level for a specified category' />
@@ -1553,6 +1556,7 @@
<param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
<param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
<param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
<param name='lrspro' doc='Remote SIM protocol' />
<param name='debug' doc='Log debug messages and higher levels' />
<param name='info' doc='Log informational messages and higher levels' />
<param name='notice' doc='Log noticeable messages and higher levels' />
@@ -1696,10 +1700,11 @@
<param name='login' doc='Enable password checking' />
</params>
</command>
<command id='bind A.B.C.D'>
<command id='bind A.B.C.D [&lt;0-65535&gt;]'>
<params>
<param name='bind' doc='Accept VTY telnet connections on local interface' />
<param name='A.B.C.D' doc='Local interface IP address (default: 127.0.0.1)' />
<param name='[&lt;0-65535&gt;]' doc='Local TCP port number' />
</params>
</command>
</node>
@@ -1762,7 +1767,7 @@
<param name='&lt;0-65535&gt;' doc='NS Entity ID (NSEI)' />
</params>
</command>
<command id='timer (tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries) &lt;0-65535&gt;'>
<command id='timer (tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov) &lt;0-65535&gt;'>
<params>
<param name='timer' doc='Network Service Timer' />
<param name='tns-block' doc='(un)blocking Timer (Tns-block) timeout' />
@@ -1772,6 +1777,7 @@
<param name='tns-test' doc='Test Timer (Tns-test) timeout' />
<param name='tns-alive' doc='Alive Timer (Tns-alive) timeout' />
<param name='tns-alive-retries' doc='Alive Timer (Tns-alive) number of retries' />
<param name='tsns-prov' doc='SNS Provision Timer (Tsns-prov) timeout' />
<param name='&lt;0-65535&gt;' doc='Timer Value' />
</params>
</command>
@@ -2224,6 +2230,13 @@
<param name='remote' doc='Use remote subscription data only (HLR)' />
</params>
</command>
<command id='authentication (optional|required)'>
<params>
<param name='authentication' doc='Whether to enforce MS authentication in GERAN (only with auth-policy remote)' />
<param name='optional' doc='Allow MS to attach via GERAN without authentication (default and only possible value for non-remote auth-policy)' />
<param name='required' doc='Always require authentication (only available for auth-policy remote, default with that auth-policy)' />
</params>
</command>
<command id='encryption (GEA0|GEA1|GEA2|GEA3|GEA4)'>
<params>
<param name='encryption' doc='Set encryption algorithm for SGSN' />
@@ -2234,6 +2247,13 @@
<param name='GEA4' doc='Use GEA4' />
</params>
</command>
<command id='gsup ipa-name NAME'>
<params>
<param name='gsup' doc='GSUP Parameters' />
<param name='ipa-name' doc='Set the IPA name of this SGSN' />
<param name='NAME' doc='A unique name for this SGSN. For example: PLMN + redundancy server number: SGSN-901-70-0. This name is used for GSUP routing and must be set if more than one SGSN is connected to the network. The default is &apos;SGSN-00-00-00-00-00-00&apos;.' />
</params>
</command>
<command id='gsup remote-ip A.B.C.D'>
<params>
<param name='gsup' doc='GSUP Parameters' />
@@ -2325,7 +2345,8 @@
<param name='no' doc='Negate a command or set its defaults' />
<param name='cdr' doc='CDR' />
<param name='trap' doc='Disable sending CDR via TRAP CTRL messages' />
</params> </command>
</params>
</command>
<command id='cdr interval &lt;1-2147483647&gt;'>
<params>
<param name='cdr' doc='CDR' />
@@ -2439,7 +2460,7 @@
<command id='compression rfc1144 active slots &lt;1-256&gt;'>
<params>
<param name='compression' doc='Configure compression' />
<param name='rfc1144' doc='RFC1144 Header compresion scheme' />
<param name='rfc1144' doc='RFC1144 Header compression scheme' />
<param name='active' doc='Compression is actively proposed' />
<param name='slots' doc='Number of compression state slots' />
<param name='&lt;1-256&gt;' doc='Number of compression state slots' />
@@ -2448,7 +2469,7 @@
<command id='compression rfc1144 passive'>
<params>
<param name='compression' doc='Configure compression' />
<param name='rfc1144' doc='RFC1144 Header compresion scheme' />
<param name='rfc1144' doc='RFC1144 Header compression scheme' />
<param name='passive' doc='Compression is available on request' />
</params>
</command>
@@ -2462,7 +2483,7 @@
<command id='compression v42bis active direction (ms|sgsn|both) codewords &lt;512-65535&gt; strlen &lt;6-250&gt;'>
<params>
<param name='compression' doc='Configure compression' />
<param name='v42bis' doc='V.42bis data compresion scheme' />
<param name='v42bis' doc='V.42bis data compression scheme' />
<param name='active' doc='Compression is actively proposed' />
<param name='direction' doc='Direction in which the compression shall be active (p0)' />
<param name='ms' doc='Compress ms-&gt;sgsn direction only' />
@@ -2477,10 +2498,16 @@
<command id='compression v42bis passive'>
<params>
<param name='compression' doc='Configure compression' />
<param name='v42bis' doc='V.42bis data compresion scheme' />
<param name='v42bis' doc='V.42bis data compression scheme' />
<param name='passive' doc='Compression is available on request' />
</params>
</command>
<command id='cs7-instance-iu &lt;0-15&gt;'>
<params>
<param name='cs7-instance-iu' doc='Set SS7 to be used by the Iu-Interface.' />
<param name='&lt;0-15&gt;' doc='SS7 instance reference number (default: 0)' />
</params>
</command>
<command id='iu rab-assign-addr-enc (x213|v4raw)'>
<params>
<param name='iu' doc='Iu interface protocol options' />

View File

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

View File

@@ -39,6 +39,7 @@ enum {
DVLR,
DIUCS,
DSIGTRAN,
DGTP,
Debug_LastEntry,
};

View File

@@ -10,6 +10,7 @@
#include <sys/types.h>
#include <regex.h>
#include <stdbool.h>
#define GBPROXY_INIT_VU_GEN_TX 256
@@ -70,29 +71,30 @@ enum gbproxy_peer_ctr {
};
enum gbproxy_keep_mode {
GBPROX_KEEP_NEVER,
GBPROX_KEEP_REATTACH,
GBPROX_KEEP_IDENTIFIED,
GBPROX_KEEP_ALWAYS,
GBPROX_KEEP_NEVER, /* don't ever keep TLLI/IMSI state of de-registered subscribers */
GBPROX_KEEP_REATTACH, /* keep if re-attach has been requested by SGSN */
GBPROX_KEEP_IDENTIFIED, /* keep if we had resolved an IMSI */
GBPROX_KEEP_ALWAYS, /* always keep */
};
enum gbproxy_match_id {
GBPROX_MATCH_PATCHING,
GBPROX_MATCH_ROUTING,
GBPROX_MATCH_PATCHING, /* match rule on whether or not we should patch */
GBPROX_MATCH_ROUTING, /* match rule on whether or not we should route (2-SGSN) */
GBPROX_MATCH_LAST
};
struct gbproxy_match {
int enable;
char *re_str;
regex_t re_comp;
bool enable; /* is this match enabled? */
char *re_str; /* regular expression (for IMSI) in string format */
regex_t re_comp; /* compiled regular expression (for IMSI) */
};
/* global gb-proxy configuration */
struct gbproxy_config {
/* parsed from config file */
uint16_t nsip_sgsn_nsei;
/* misc */
/* NS instance of libosmogb */
struct gprs_ns_inst *nsi;
/* Linked list of all Gb peers (except SGSN) */
@@ -101,10 +103,13 @@ struct gbproxy_config {
/* Counter */
struct rate_ctr_group *ctrg;
/* force mcc/mnc */
/* MCC/MNC to be patched into RA-ID on the way from BSS to SGSN? */
struct osmo_plmn_id core_plmn;
/* APN to be patched into PDP CTX ACT REQ on the way from BSS to SGSN */
uint8_t* core_apn;
size_t core_apn_size;
/* Frequency (sec) at which timer to clean stale links is fired (0 disabled) */
unsigned int clean_stale_timer_freq;
/* If !0, Max age to consider a struct gbproxy_link_info as stale */
@@ -114,14 +119,18 @@ struct gbproxy_config {
/* If !0, Max len of gbproxy_link_info->stored_msgs (list of msgb) */
uint32_t stored_msgs_max_len;
/* Experimental config */
int patch_ptmsi;
int acquire_imsi;
int route_to_sgsn2;
/* Should the P-TMSI be patched on the fly (required for 2-SGSN config) */
bool patch_ptmsi;
/* Should the IMSI be acquired by the proxy (required for 2-SGSN config) */
bool acquire_imsi;
/* Should we route subscribers to two different SGSNs? */
bool route_to_sgsn2;
/* NSEI of the second SGSN */
uint16_t nsip_sgsn2_nsei;
/* should we keep a cache of per-subscriber state even after de-registration? */
enum gbproxy_keep_mode keep_link_infos;
/* IMSI checking/matching */
/* IMSI checking/matching for 2-SGSN routing and patching */
struct gbproxy_match matches[GBPROX_MATCH_LAST];
};
@@ -133,7 +142,9 @@ struct gbproxy_patch_state {
int logical_link_count;
};
/* one peer at NS level that we interact with (BSS/PCU) */
struct gbproxy_peer {
/* linked to gbproxy_config.bts_peers */
struct llist_head list;
/* point back to the config */
@@ -144,7 +155,7 @@ struct gbproxy_peer {
/* BVCI used for Point-to-Point to this peer */
uint16_t bvci;
int blocked;
bool blocked;
/* Routeing Area that this peer is part of (raw 04.08 encoding) */
uint8_t ra[6];
@@ -152,6 +163,7 @@ struct gbproxy_peer {
/* Counter */
struct rate_ctr_group *ctrg;
/* State related to on-the-fly patching of certain messages */
struct gbproxy_patch_state patch_state;
/* Fired periodically to clean up stale links from list */
@@ -159,33 +171,55 @@ struct gbproxy_peer {
};
struct gbproxy_tlli_state {
/* currently active TLLI */
uint32_t current;
/* newly-assigned TLLI (e.g. during P-TMSI allocation procedure) */
uint32_t assigned;
int bss_validated;
int net_validated;
/* has the BSS side validated (confirmed) the new TLLI? */
bool bss_validated;
/* has the SGSN side validated (confirmed) the new TLLI? */
bool net_validated;
/* NOTE: once both are validated, we set current = assigned and assigned = 0 */
/* The P-TMSI for this subscriber */
uint32_t ptmsi;
};
/* One TLLI (= UE, = Subscriber) served via this proxy */
struct gbproxy_link_info {
/* link to gbproxy_peer.patch_state.logical_links */
struct llist_head list;
/* TLLI on the BSS/PCU side */
struct gbproxy_tlli_state tlli;
/* TLLI on the SGSN side (can be different in case of P-TMSI patching) */
struct gbproxy_tlli_state sgsn_tlli;
/* NSEI of the SGSN serving this link */
uint32_t sgsn_nsei;
/* timestamp when we last had any contact with this UE */
time_t timestamp;
/* IMSI of the subscriber (if/once known) */
uint8_t *imsi;
size_t imsi_len;
int imsi_acq_pending;
/* is the IMSI acquisition still pending? */
bool imsi_acq_pending;
/* queue of stored UL messages (until IMSI acquisition completes and we can
* determine which of the SGSNs we should route this to */
struct llist_head stored_msgs;
uint32_t stored_msgs_len;
/* generated N(U) we use (required due to IMSI acquisition */
unsigned vu_gen_tx_bss;
int is_deregistered;
/* is this subscriber deregistered (TLLI invalidated)? */
bool is_deregistered;
int is_matching[GBPROX_MATCH_LAST];
/* does this link match either the (2-SGSN) routing or the patching rule? */
bool is_matching[GBPROX_MATCH_LAST];
};

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

View File

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

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

View File

@@ -96,6 +96,7 @@ enum gprs_llc_llme_state {
GPRS_LLMS_UNASSIGNED = 1, /* No TLLI yet */
GPRS_LLMS_ASSIGNED = 2, /* TLLI assigned */
};
extern const struct value_string gprs_llc_llme_state_names[];
/* Section 8.9.9 LLC layer parameter default values */
struct gprs_llc_params {
@@ -110,13 +111,13 @@ struct gprs_llc_params {
uint16_t kU;
};
/* Section 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */
/* 3GPP TS 44.064 § 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */
struct gprs_llc_lle {
struct llist_head list;
uint32_t sapi;
struct gprs_llc_llme *llme;
struct gprs_llc_llme *llme; /* backpointer to the Logical Link Management Entity */
enum gprs_llc_lle_state state;
@@ -145,10 +146,18 @@ struct gprs_llc_lle {
unsigned int retrans_ctr;
struct gprs_llc_params params;
/* Copy of the XID fields we have sent with the last
* network originated XID-Request. Since the phone
* may strip the optional fields in the confirmation
* we need to remeber those fields in order to be
* able to create the compression entity. */
struct llist_head *xid;
};
#define NUM_SAPIS 16
/* 3GPP TS 44.064 § 4.7.3: Logical Link Management Entity: One per TLLI */
struct gprs_llc_llme {
struct llist_head list;
@@ -169,13 +178,6 @@ struct gprs_llc_llme {
uint16_t nsei;
struct gprs_llc_lle lle[NUM_SAPIS];
/* Copy of the XID fields we have sent with the last
* network originated XID-Request. Since the phone
* may strip the optional fields in the confirmation
* we need to remeber those fields in order to be
* able to create the compression entity. */
struct llist_head *xid;
/* Compression entities */
struct {
/* In these two list_heads we will store the
@@ -191,6 +193,9 @@ struct gprs_llc_llme {
#define GPRS_LLME_RESET_AGE (0)
/* 3GPP TS 44.064 § 8.3 TLLI assignment procedures */
#define TLLI_UNASSIGNED (0xffffffff)
extern struct llist_head gprs_llc_llmes;
/* LLC low level types */

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

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

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

View File

@@ -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,
@@ -108,9 +90,12 @@ enum sgsn_ran_type {
MM_CTX_T_GERAN_Gb,
/* UMTS via Iu */
MM_CTX_T_UTRAN_Iu,
/* GPRS/EDGE via Iu */
#if 0
/* GPRS/EDGE via Iu, not supported */
MM_CTX_T_GERAN_Iu,
#endif
};
extern const struct value_string sgsn_ran_type_names[];
struct service_info {
uint8_t type;
@@ -134,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;
@@ -154,6 +138,9 @@ struct sgsn_mm_ctx {
struct gprs_llc_llme *llme;
uint32_t tlli;
uint32_t tlli_new;
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
struct osmo_fsm_inst *mm_state_fsm;
} gb;
struct {
int new_key;
@@ -168,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;
@@ -260,6 +249,28 @@ static inline bool sgsn_mm_ctx_is_authenticated(struct sgsn_mm_ctx *ctx)
LOGP(DMM, level, "MM(%s/%08x) " fmt, (mm) ? (mm)->imsi : "---", \
(mm) ? (mm)->p_tmsi : GSM_RESERVED_TMSI, ## args)
#ifdef BUILD_IU
#define LOGIUP(ue, level, fmt, args...) \
LOGP(DMM, level, "UE(0x%x){%s} " fmt, ue->conn_id, osmo_rai_name(&(ue)->ra_id), ## args)
#else
#define LOGIUP(ue, level, fmt, args...) \
LOGP(DMM, level, "UE(%p){NOTSUPPORTED} " fmt, ue, ## args)
#endif
#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, DMM, level, fmt, ## args); \
} else if ((msg) && (_ue = MSG_IU_UE_CTX(msg))) { \
LOGIUP(_ue, level, fmt, ## args); \
} else { OSMO_ASSERT(0); } \
} while (0)
/* look-up a SGSN MM context based on TLLI + RAI */
struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
const struct gprs_ra_id *raid);
@@ -364,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);
@@ -373,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;
@@ -411,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

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

View File

@@ -78,26 +78,16 @@ struct sgsn_config {
struct sockaddr_in gsup_server_addr;
int gsup_server_port;
/* Only meaningful if auth_policy is SGSN_AUTH_POLICY_REMOTE */
int require_authentication;
int require_update_location;
/* CDR configuration */
struct sgsn_cdr cdr;
struct {
int T3312;
int T3322;
int T3350;
int T3360;
int T3370;
int T3313;
int T3314;
int T3316;
int T3385;
int T3386;
int T3395;
int T3397;
} timers;
/* Timer defintions */
struct osmo_tdef *T_defs;
int dynamic_lookup;
@@ -122,6 +112,7 @@ struct sgsn_config {
#if BUILD_IU
struct {
enum ranap_nsap_addr_enc rab_assign_addr_enc;
uint32_t cs7_instance;
} iu;
#endif
@@ -139,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 */
@@ -170,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,
@@ -178,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 */

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

View File

@@ -1,3 +1,6 @@
SUBDIRS = \
gprs \
sgsn \
gbproxy \
gtphub \
$(NULL)

46
src/gbproxy/Makefile.am Normal file
View 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)

View File

@@ -243,7 +243,7 @@ uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer,
break;
}
bss_ptmsi = bss_ptmsi | 0xC0000000;
bss_ptmsi = bss_ptmsi | GSM23003_TMSI_SGSN_MASK;
if (gbproxy_link_info_by_ptmsi(peer, bss_ptmsi))
bss_ptmsi = GSM_RESERVED_TMSI;
@@ -310,7 +310,7 @@ static int gbproxy_restart_imsi_acquisition(struct gbproxy_link_info* link_info)
in_progress = 1;
gbproxy_link_info_discard_messages(link_info);
link_info->imsi_acq_pending = 0;
link_info->imsi_acq_pending = false;
return in_progress;
}
@@ -531,7 +531,7 @@ static int gbproxy_imsi_acquisition(struct gbproxy_peer *peer,
* implementation relies on the MS doing proper retransmissions
* of the triggering message instead */
link_info->imsi_acq_pending = 1;
link_info->imsi_acq_pending = true;
}
return 0;
@@ -836,11 +836,11 @@ static int block_unblock_peer(struct gbproxy_config *cfg, uint16_t ptp_bvci, uin
switch (pdu_type) {
case BSSGP_PDUT_BVC_BLOCK_ACK:
peer->blocked = 1;
peer->blocked = true;
rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_BLOCKED]);
break;
case BSSGP_PDUT_BVC_UNBLOCK_ACK:
peer->blocked = 0;
peer->blocked = false;
rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_UNBLOCKED]);
break;
default:

View File

@@ -140,7 +140,7 @@ static void print_help()
printf(" -c --config-file filename The config file to use [%s]\n", CONFIG_FILE_DEFAULT);
printf(" -s --disable-color\n");
printf(" -T --timestamp Prefix every log line with a timestamp\n");
printf(" -V --version. Print the version of OpenBSC.\n");
printf(" -V --version. Print the version.\n");
printf(" -e --log-level number. Set a global loglevel.\n");
}
@@ -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)
@@ -284,9 +289,9 @@ int main(int argc, char **argv)
vty_info.copyright = openbsc_copyright;
vty_init(&vty_info);
logging_vty_add_cmds(NULL);
logging_vty_add_cmds();
osmo_talloc_vty_add_cmds();
osmo_stats_vty_add_cmds(&gprs_log_info);
osmo_stats_vty_add_cmds();
gbproxy_vty_init();
handle_options(argc, argv);

View File

@@ -398,7 +398,7 @@ void gbproxy_clear_patch_filter(struct gbproxy_match *match)
{
if (match->enable) {
regfree(&match->re_comp);
match->enable = 0;
match->enable = false;
}
talloc_free(match->re_str);
match->re_str = NULL;
@@ -419,7 +419,7 @@ int gbproxy_set_patch_filter(struct gbproxy_match *match, const char *filter,
REG_EXTENDED | REG_NOSUB | REG_ICASE);
if (rc == 0) {
match->enable = 1;
match->enable = true;
match->re_str = talloc_strdup(tall_sgsn_ctx, filter);
return 0;
}

View File

@@ -284,8 +284,8 @@ void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
/* Remember assigned TLLI */
tlli_state->assigned = new_tlli;
tlli_state->bss_validated = 0;
tlli_state->net_validated = 0;
tlli_state->bss_validated = false;
tlli_state->net_validated = false;
}
uint32_t gbproxy_map_tlli(uint32_t other_tlli,
@@ -325,9 +325,9 @@ static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state,
/* See GSM 04.08, 4.7.1.5 */
if (to_bss)
tlli_state->net_validated = 1;
tlli_state->net_validated = true;
else
tlli_state->bss_validated = 1;
tlli_state->bss_validated = true;
if (!tlli_state->bss_validated || !tlli_state->net_validated)
return;
@@ -367,7 +367,7 @@ static int gbproxy_unregister_link_info(struct gbproxy_peer *peer,
link_info->sgsn_tlli.current = 0;
link_info->sgsn_tlli.assigned = 0;
link_info->is_deregistered = 1;
link_info->is_deregistered = true;
gbproxy_reset_link(link_info);
@@ -424,7 +424,7 @@ static void gbproxy_assign_imsi(struct gbproxy_peer *peer,
&peer->cfg->matches[match_id],
parse_ctx->imsi, parse_ctx->imsi_len);
if (imsi_matches >= 0)
link_info->is_matching[match_id] = imsi_matches;
link_info->is_matching[match_id] = imsi_matches ? true : false;
}
}
@@ -498,7 +498,7 @@ static struct gbproxy_link_info *gbproxy_get_link_info_ul(
if (!link_info)
return NULL;
link_info->is_deregistered = 0;
link_info->is_deregistered = false;
return link_info;
}
@@ -577,7 +577,7 @@ static struct gbproxy_link_info *gbproxy_get_link_info_dl(
peer, parse_ctx->imsi, parse_ctx->imsi_len);
if (link_info)
link_info->is_deregistered = 0;
link_info->is_deregistered = false;
return link_info;
}

View File

@@ -241,7 +241,7 @@ DEFUN(cfg_gbproxy_match_imsi,
return CMD_WARNING;
}
g_cfg->acquire_imsi = 1;
g_cfg->acquire_imsi = true;
return CMD_SUCCESS;
}
@@ -256,7 +256,7 @@ DEFUN(cfg_gbproxy_no_match_imsi,
for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id)
gbproxy_clear_patch_filter(&g_cfg->matches[match_id]);
g_cfg->acquire_imsi = 0;
g_cfg->acquire_imsi = false;
return CMD_SUCCESS;
}
@@ -329,7 +329,7 @@ DEFUN(cfg_gbproxy_patch_ptmsi,
"patch-ptmsi",
GBPROXY_PATCH_PTMSI_STR)
{
g_cfg->patch_ptmsi = 1;
g_cfg->patch_ptmsi = true;
return CMD_SUCCESS;
}
@@ -339,7 +339,7 @@ DEFUN(cfg_gbproxy_no_patch_ptmsi,
"no patch-ptmsi",
NO_STR GBPROXY_PATCH_PTMSI_STR)
{
g_cfg->patch_ptmsi = 0;
g_cfg->patch_ptmsi = false;
return CMD_SUCCESS;
}
@@ -355,7 +355,7 @@ DEFUN(cfg_gbproxy_acquire_imsi,
"acquire-imsi",
GBPROXY_ACQUIRE_IMSI_STR)
{
g_cfg->acquire_imsi = 1;
g_cfg->acquire_imsi = true;
return CMD_SUCCESS;
}
@@ -365,7 +365,7 @@ DEFUN(cfg_gbproxy_no_acquire_imsi,
"no acquire-imsi",
NO_STR GBPROXY_ACQUIRE_IMSI_STR)
{
g_cfg->acquire_imsi = 0;
g_cfg->acquire_imsi = false;
return CMD_SUCCESS;
}
@@ -387,10 +387,10 @@ DEFUN(cfg_gbproxy_secondary_sgsn,
return CMD_WARNING;
}
g_cfg->route_to_sgsn2 = 1;
g_cfg->route_to_sgsn2 = true;
g_cfg->nsip_sgsn2_nsei = nsei;
g_cfg->patch_ptmsi = 1;
g_cfg->patch_ptmsi = true;
return CMD_SUCCESS;
}
@@ -400,10 +400,10 @@ DEFUN(cfg_gbproxy_no_secondary_sgsn,
"no secondary-sgsn",
NO_STR GBPROXY_SECOND_SGSN_STR)
{
g_cfg->route_to_sgsn2 = 0;
g_cfg->route_to_sgsn2 = false;
g_cfg->nsip_sgsn2_nsei = 0xFFFF;
g_cfg->patch_ptmsi = 0;
g_cfg->patch_ptmsi = false;
return CMD_SUCCESS;
}
@@ -849,7 +849,7 @@ DEFUN_DEPRECATED(cfg_gbproxy_broken_apn_match,
return CMD_WARNING;
}
g_cfg->acquire_imsi = 1;
g_cfg->acquire_imsi = true;
return CMD_SUCCESS;
}

View File

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

View File

@@ -383,6 +383,14 @@ int gprs_gb_parse_dtap(uint8_t *data, size_t data_len,
parse_ctx->invalidate_tlli = 1;
break;
case GSM48_MT_GSM_DEACT_PDP_REQ:
parse_ctx->llc_msg_name = "DEACT_PDP_REQ";
break;
case GSM48_MT_GSM_DEACT_PDP_ACK:
parse_ctx->llc_msg_name = "DEACT_PDP_ACK";
break;
default:
LOGP(DLLC, LOGL_NOTICE,
"Unhandled GSM 04.08 message type %s for protocol discriminator %s.\n",

45
src/gtphub/Makefile.am Normal file
View 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)

View File

@@ -238,12 +238,12 @@ static void print_help(struct cmdline_cfg *ccfg)
printf(" -e,--log-level <nr> Set a global log level.\n");
printf(" -r,--restart-file <path> File for counting restarts [%s].\n",
ccfg->restart_counter_file);
printf(" -V,--version Print the version number.\n");
printf(" -V,--version Print the version.\n");
}
static void list_categories(void)
{
printf("Avaliable debug categories:\n");
printf("Available debug categories:\n");
int i;
for (i = 0; i < gtphub_log_info.num_cat; ++i) {
if (!gtphub_log_info.cat[i].name)
@@ -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)
@@ -356,7 +361,7 @@ int main(int argc, char **argv)
vty_info.copyright = gtphub_copyright;
vty_init(&vty_info);
logging_vty_add_cmds(NULL);
logging_vty_add_cmds();
osmo_talloc_vty_add_cmds();
gtphub_vty_init(hub, cfg);

93
src/sgsn/Makefile.am Normal file
View 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
View 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

View File

@@ -1,3 +1,5 @@
#include <osmocom/core/tdef.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
@@ -10,6 +12,18 @@
static int require_identity_imei = 1;
static int require_auth = 1;
static const struct osmo_tdef_state_timeout gmm_attach_fsm_timeouts[32] = {
[ST_IDENTIY] = { .T=3370 },
[ST_AUTH] = { .T=3360 },
[ST_ACCEPT] = { .T=3350 },
[ST_ASK_VLR] = { .T=3350 },
[ST_IU_SECURITY_CMD] = { .T=3350 },
};
#define gmm_attach_fsm_state_chg(fi, NEXT_STATE) \
osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, gmm_attach_fsm_timeouts, sgsn->cfg.T_defs, -1)
static void st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct sgsn_mm_ctx *ctx = fi->priv;
@@ -33,14 +47,14 @@ static void st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
if (require_identity_imei) {
ctx->gmm_att_req.id_type = GSM_MI_TYPE_IMEI;
osmo_fsm_inst_state_chg(fi, ST_IDENTIY, sgsn->cfg.timers.T3370, 3370);
gmm_attach_fsm_state_chg(fi, ST_IDENTIY);
} else if (!strlen(ctx->imsi)) {
ctx->gmm_att_req.id_type = GSM_MI_TYPE_IMSI;
osmo_fsm_inst_state_chg(fi, ST_IDENTIY, sgsn->cfg.timers.T3370, 3370);
gmm_attach_fsm_state_chg(fi, ST_IDENTIY);
} else if (require_auth)
osmo_fsm_inst_state_chg(fi, ST_AUTH, sgsn->cfg.timers.T3360, 3360);
gmm_attach_fsm_state_chg(fi, ST_AUTH);
else
osmo_fsm_inst_state_chg(fi, ST_ACCEPT, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
}
static void st_identity_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
@@ -94,11 +108,11 @@ static void st_identity(struct osmo_fsm_inst *fi, uint32_t event, void *data)
if (type == GSM_MI_TYPE_IMEI && !strlen(ctx->imsi)) {
ctx->gmm_att_req.id_type = GSM_MI_TYPE_IMSI;
osmo_fsm_inst_state_chg(fi, ST_IDENTIY, sgsn->cfg.timers.T3370, 3370);
gmm_attach_fsm_state_chg(fi, ST_IDENTIY);
} else if (require_auth)
osmo_fsm_inst_state_chg(fi, ST_AUTH, sgsn->cfg.timers.T3360, 3360);
gmm_attach_fsm_state_chg(fi, ST_AUTH);
else
osmo_fsm_inst_state_chg(fi, ST_ACCEPT, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
}
static void st_auth_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
@@ -124,19 +138,19 @@ static void st_auth_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
switch(auth_state) {
case SGSN_AUTH_UMTS_RESYNC: /* ask the vlr for a new vector to match the simcards seq */
case SGSN_AUTH_UNKNOWN: /* the SGSN doesn know this MS */
osmo_fsm_inst_state_chg(fi, ST_ASK_VLR, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ASK_VLR);
break;
case SGSN_AUTH_REJECTED:
/* TODO: correct GMM cause */
osmo_fsm_inst_dispatch(fi, E_REJECT, (void *) GMM_CAUSE_GPRS_NOTALLOWED);
break;
case SGSN_AUTH_ACCEPTED:
osmo_fsm_inst_state_chg(fi, ST_ACCEPT, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
break;
case SGSN_AUTH_AUTHENTICATE:
if (ctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
/* invalid key material */
osmo_fsm_inst_state_chg(fi, ST_ASK_VLR, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ASK_VLR);
}
struct gsm_auth_tuple *at = &ctx->auth_triplet;
@@ -159,14 +173,14 @@ static void st_auth(struct osmo_fsm_inst *fi, uint32_t event, void *data)
sgsn_auth_request(ctx);
#ifdef BUILD_IU
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active)
osmo_fsm_inst_state_chg(fi, ST_IU_SECURITY_CMD, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_IU_SECURITY_CMD);
else
#endif /* BUILD_IU */
osmo_fsm_inst_state_chg(fi, ST_ACCEPT, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
break;
case E_AUTH_RESP_RECV_RESYNC:
if (ctx->gmm_att_req.auth_reattempt <= 1)
osmo_fsm_inst_state_chg(fi, ST_ASK_VLR, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ASK_VLR);
else
osmo_fsm_inst_dispatch(fi, E_REJECT, (void *) GMM_CAUSE_SYNC_FAIL);
break;
@@ -234,7 +248,7 @@ static void st_ask_vlr(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
case E_VLR_ANSWERED:
osmo_fsm_inst_state_chg(fi, ST_AUTH, sgsn->cfg.timers.T3360, 3360);
gmm_attach_fsm_state_chg(fi, ST_AUTH);
break;
}
}
@@ -246,7 +260,7 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
/* TODO: shouldn't this set always? not only when the integrity_active? */
if (ctx->iu.ue_ctx->integrity_active) {
osmo_fsm_inst_state_chg(fi, ST_ACCEPT, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
return;
}
@@ -259,7 +273,7 @@ static void st_iu_security_cmd(struct osmo_fsm_inst *fi, uint32_t event, void *d
{
switch(event) {
case E_IU_SECURITY_CMD_COMPLETE:
osmo_fsm_inst_state_chg(fi, ST_ACCEPT, sgsn->cfg.timers.T3350, 3350);
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
break;
}
}
@@ -316,16 +330,16 @@ static struct osmo_fsm_state gmm_attach_req_fsm_states[] = {
};
const struct value_string gmm_attach_req_fsm_event_names[] = {
{ E_ATTACH_REQ_RECV, "Received an attach request" },
{ E_IDEN_RESP_RECV, "Identity Request received" },
{ E_AUTH_RESP_RECV_SUCCESS, "Authentication Response received" },
{ E_AUTH_RESP_RECV_RESYNC, "Authentication Failure with resync received" },
{ E_ATTACH_ACCEPTED, "Attach accepted" },
{ E_ATTACH_ACCEPT_SENT, "Attach accept sent" },
{ E_ATTACH_COMPLETE_RECV, "Attach complete received." },
{ E_IU_SECURITY_CMD_COMPLETE, "IU Security Command Complete received." },
{ E_REJECT, "Reject the MS"},
{ E_VLR_ANSWERED, "VLR answered"},
OSMO_VALUE_STRING(E_ATTACH_REQ_RECV),
OSMO_VALUE_STRING(E_IDEN_RESP_RECV),
OSMO_VALUE_STRING(E_AUTH_RESP_RECV_SUCCESS),
OSMO_VALUE_STRING(E_AUTH_RESP_RECV_RESYNC),
OSMO_VALUE_STRING(E_ATTACH_ACCEPTED),
OSMO_VALUE_STRING(E_ATTACH_ACCEPT_SENT),
OSMO_VALUE_STRING(E_ATTACH_COMPLETE_RECV),
OSMO_VALUE_STRING(E_IU_SECURITY_CMD_COMPLETE),
OSMO_VALUE_STRING(E_REJECT),
OSMO_VALUE_STRING(E_VLR_ANSWERED),
{ 0, NULL }
};
@@ -373,6 +387,7 @@ int gmm_attach_timer_cb(struct osmo_fsm_inst *fi)
{
struct sgsn_mm_ctx *ctx = fi->priv;
struct gsm_auth_tuple *at = &ctx->auth_triplet;
unsigned long t_secs;
ctx->num_T_exp++;
@@ -392,7 +407,9 @@ int gmm_attach_timer_cb(struct osmo_fsm_inst *fi)
break;
}
gsm48_tx_gmm_id_req(ctx, ctx->gmm_att_req.id_type);
osmo_timer_schedule(&fi->timer, sgsn->cfg.timers.T3370, 0);
t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3370, OSMO_TDEF_S, -1);
osmo_timer_schedule(&fi->timer, t_secs, 0);
break;
case ST_AUTH:
/* T3360 */
@@ -401,7 +418,8 @@ int gmm_attach_timer_cb(struct osmo_fsm_inst *fi)
break;
}
gsm48_tx_gmm_auth_ciph_req(ctx, &at->vec, at->key_seq, false);
osmo_timer_schedule(&fi->timer, sgsn->cfg.timers.T3360, 0);
t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3360, OSMO_TDEF_S, -1);
osmo_timer_schedule(&fi->timer, t_secs, 0);
break;
case ST_ACCEPT:
/* T3350 */
@@ -410,7 +428,8 @@ int gmm_attach_timer_cb(struct osmo_fsm_inst *fi)
break;
}
gsm48_tx_gmm_att_ack(ctx);
osmo_timer_schedule(&fi->timer, sgsn->cfg.timers.T3350, 0);
t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3350, OSMO_TDEF_S, -1);
osmo_timer_schedule(&fi->timer, t_secs, 0);
break;
}
@@ -430,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
View 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);
}

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>
@@ -41,9 +42,16 @@
#include <osmocom/sgsn/gprs_sndcp_comp.h>
#include <osmocom/sgsn/gprs_sndcp.h>
const struct value_string gprs_llc_llme_state_names[] = {
{ GPRS_LLMS_UNASSIGNED, "UNASSIGNED" },
{ GPRS_LLMS_ASSIGNED, "ASSIGNED" },
{ 0, NULL }
};
static struct gprs_llc_llme *llme_alloc(uint32_t tlli);
static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
int command);
static int gprs_llc_tx_dm(struct gprs_llc_lle *lle);
static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi,
int command, enum gprs_llc_u_cmd u_cmd, int pf_bit);
@@ -52,7 +60,7 @@ static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi,
/* Generate XID message */
static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len,
struct gprs_llc_xid_field *l3_xid_field,
struct gprs_llc_llme *llme)
struct gprs_llc_lle *lle)
{
/* Note: Called by gprs_ll_xid_req() */
@@ -61,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 */
@@ -89,8 +100,8 @@ static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len,
}
/* Store generated XID for later reference */
talloc_free(llme->xid);
llme->xid = gprs_llc_copy_xid(llme, &xid_fields);
talloc_free(lle->xid);
lle->xid = gprs_llc_copy_xid(lle->llme, &xid_fields);
return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields);
}
@@ -98,7 +109,7 @@ static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len,
/* Generate XID message that will cause the GMM to reset */
static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes,
int bytes_len, uint32_t iov_ui,
struct gprs_llc_llme *llme)
struct gprs_llc_lle *lle)
{
/* Called by gprs_llgmm_reset() and
* gprs_llgmm_reset_oldmsg() */
@@ -123,8 +134,8 @@ static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes,
llist_add(&xid_reset.list, &xid_fields);
/* Store generated XID for later reference */
talloc_free(llme->xid);
llme->xid = gprs_llc_copy_xid(llme, &xid_fields);
talloc_free(lle->xid);
lle->xid = gprs_llc_copy_xid(lle->llme, &xid_fields);
return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields);
}
@@ -143,8 +154,8 @@ static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len,
struct gprs_llc_xid_field *xid_field_request_l3 = NULL;
/* Pick layer3 XID from the XID request we have sent last */
if (lle->llme->xid) {
llist_for_each_entry(xid_field_request, lle->llme->xid, list) {
if (lle->xid) {
llist_for_each_entry(xid_field_request, lle->xid, list) {
if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR)
xid_field_request_l3 = xid_field_request;
}
@@ -188,8 +199,8 @@ static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len,
}
/* Flush pending XID fields */
talloc_free(lle->llme->xid);
lle->llme->xid = NULL;
talloc_free(lle->xid);
lle->xid = NULL;
return 0;
}
@@ -324,8 +335,7 @@ int gprs_ll_xid_req(struct gprs_llc_lle *lle,
/* Generate XID */
xid_bytes_len =
gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes),
l3_xid_field, lle->llme);
gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes), l3_xid_field, lle);
/* Only perform XID sending if the XID message contains something */
if (xid_bytes_len > 0) {
@@ -522,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;
@@ -556,7 +566,7 @@ static struct gprs_llc_llme *llme_alloc(uint32_t tlli)
return NULL;
llme->tlli = tlli;
llme->old_tlli = 0xffffffff;
llme->old_tlli = TLLI_UNASSIGNED;
llme->state = GPRS_LLMS_UNASSIGNED;
llme->age_timestamp = GPRS_LLME_RESET_AGE;
llme->cksn = GSM_KEY_SEQ_INVAL;
@@ -576,7 +586,6 @@ static void llme_free(struct gprs_llc_llme *llme)
{
gprs_sndcp_comp_free(llme->comp.proto);
gprs_sndcp_comp_free(llme->comp.data);
talloc_free(llme->xid);
llist_del(&llme->list);
talloc_free(llme);
}
@@ -676,6 +685,18 @@ static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1);
}
static int gprs_llc_tx_dm(struct gprs_llc_lle *lle)
{
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_DM");
/* copy identifiers from LLE to ensure lower layers can route */
msgb_tlli(msg) = lle->llme->tlli;
msgb_bvci(msg) = lle->llme->bvci;
msgb_nsei(msg) = lle->llme->nsei;
return gprs_llc_tx_u(msg, lle->sapi, 0, GPRS_LLC_U_DM_RESP, 1);
}
/* encrypt information field + FCS, if needed! */
static int apply_gea(struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
uint32_t oc, uint8_t sapi, uint8_t *fcs, uint8_t *data)
@@ -802,6 +823,8 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
struct gprs_llc_lle *lle)
{
switch (gph->cmd) {
#if 0
/* we don't fully imoplement ABM, so refuse it properly (OS#3953) */
case GPRS_LLC_SABM: /* Section 6.4.1.1 */
lle->v_sent = lle->v_ack = lle->v_recv = 0;
if (lle->state == GPRS_LLES_ASSIGNED_ADM) {
@@ -827,6 +850,13 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
break;
case GPRS_LLC_FRMR: /* Section 6.4.1.5 */
break;
#else
case GPRS_LLC_SABM:
case GPRS_LLC_DISC:
/* send DM to properly signal we don't do ABM */
gprs_llc_tx_dm(lle);
break;
#endif
case GPRS_LLC_XID: /* Section 6.4.1.6 */
rx_llc_xid(lle, gph);
break;
@@ -860,6 +890,9 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
if ((gph->seq_tx + 1) / 512)
lle->oc_ui_recv += 512;
break;
case GPRS_LLC_NULL:
LOGP(DLLC, LOGL_DEBUG, "TLLI=%08x sends us LLC NULL\n", lle->llme ? lle->llme->tlli : -1);
break;
default:
LOGP(DLLC, LOGL_NOTICE, "Unhandled command: %d\n", gph->cmd);
break;
@@ -945,9 +978,6 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
LOGP(DLLC, LOGL_INFO, "Dropping frame with invalid FCS\n");
return -EIO;
}
/* set l3 layer & remove the fcs */
msg->l3h = llhp.data;
msgb_l3trim(msg, llhp.data_len);
/* Update LLE's (BVCI, NSEI) tuple */
lle->llme->bvci = msgb_bvci(msg);
@@ -958,6 +988,14 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
if (rc < 0)
return rc;
/* there are many frame types that don't carry user information
* and which hence have llhp.data = NULL */
if (llhp.data) {
/* set l3 layer & remove the fcs */
msg->l3h = llhp.data;
msgb_l3trim(msg, llhp.data_len);
}
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_PACKETS]);
rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_BYTES], msg->len);
@@ -1013,20 +1051,24 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
uint32_t old_tlli, uint32_t new_tlli)
{
unsigned int i;
bool free = false;
if (old_tlli == 0xffffffff && new_tlli != 0xffffffff) {
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 */
/* New TLLI shall be assigned and used when (re)transmitting LLC frames */
/* If old TLLI != 0xffffffff was assigned to LLME, then TLLI
/* If old TLLI != TLLI_UNASSIGNED was assigned to LLME, then TLLI
* old is unassigned. Only TLLI new shall be accepted when
* received from peer. */
if (llme->old_tlli != 0xffffffff) {
llme->old_tlli = 0xffffffff;
if (llme->old_tlli != TLLI_UNASSIGNED) {
llme->old_tlli = TLLI_UNASSIGNED;
llme->tlli = new_tlli;
} else {
/* If TLLI old == 0xffffffff was assigned to LLME, then this is
/* If TLLI old == TLLI_UNASSIGNED was assigned to LLME, then this is
* TLLI assignmemt according to 8.3.1 */
llme->old_tlli = 0xffffffff;
llme->old_tlli = TLLI_UNASSIGNED;
llme->tlli = new_tlli;
llme->state = GPRS_LLMS_ASSIGNED;
/* 8.5.3.1 For all LLE's */
@@ -1038,14 +1080,14 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
/* FIXME Set parameters according to table 9 */
}
}
} else if (old_tlli != 0xffffffff && new_tlli != 0xffffffff) {
} else if (old_tlli != TLLI_UNASSIGNED && new_tlli != TLLI_UNASSIGNED) {
/* TLLI Change 8.3.2 */
/* Both TLLI Old and TLLI New are assigned; use New when
* (re)transmitting. Accept both Old and New on Rx */
llme->old_tlli = old_tlli;
llme->tlli = new_tlli;
llme->state = GPRS_LLMS_ASSIGNED;
} else if (old_tlli != 0xffffffff && new_tlli == 0xffffffff) {
} else if (old_tlli != TLLI_UNASSIGNED && new_tlli == TLLI_UNASSIGNED) {
/* TLLI Unassignment 8.3.3) */
llme->tlli = llme->old_tlli = 0;
llme->state = GPRS_LLMS_UNASSIGNED;
@@ -1053,39 +1095,47 @@ 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;
}
/* TLLI unassignment */
int gprs_llgmm_unassign(struct gprs_llc_llme *llme)
{
return gprs_llgmm_assign(llme, llme->tlli, 0xffffffff);
return gprs_llgmm_assign(llme, llme->tlli, TLLI_UNASSIGNED);
}
/* Chapter 7.2.1.2 LLGMM-RESET.req */
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;
}
/* Generate XID message */
xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes,
sizeof(xid_bytes),llme->iov_ui,llme);
xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, sizeof(xid_bytes),
llme->iov_ui, lle);
if (xid_bytes_len < 0)
return -EINVAL;
xid = msgb_put(msg, xid_bytes_len);
@@ -1105,21 +1155,24 @@ int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
struct gprs_llc_llme *llme)
{
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
struct gprs_llc_lle *lle = &llme->lle[sapi];
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 (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;
}
/* Generate XID message */
xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes,
sizeof(xid_bytes),llme->iov_ui,llme);
xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes, sizeof(xid_bytes),
llme->iov_ui, lle);
if (xid_bytes_len < 0)
return -EINVAL;
xid = msgb_put(msg, xid_bytes_len);

View File

@@ -41,7 +41,7 @@ const struct value_string gprs_llc_xid_type_names[] = {
{ GPRS_LLC_XID_T_IOV_I, "IOV_I"},
{ GPRS_LLC_XID_T_T200, "T200"},
{ GPRS_LLC_XID_T_N200, "N200"},
{ GPRS_LLC_XID_T_N201_U, "N201_"},
{ GPRS_LLC_XID_T_N201_U, "N201_U"},
{ GPRS_LLC_XID_T_N201_I, "N201_I"},
{ GPRS_LLC_XID_T_mD, "mD"},
{ GPRS_LLC_XID_T_mU, "mU"},

View 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);
}

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

View File

@@ -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)" },
@@ -103,9 +112,9 @@ static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
static const struct rate_ctr_desc sgsn_ctr_description[] = {
{ "llc:dl_bytes", "Count sent LLC bytes before giving it to the bssgp layer" },
{ "llc:ul_bytes", "Count sucessful received LLC bytes (encrypt & fcs correct)" },
{ "llc:dl_packets", "Count sucessful sent LLC packets before giving it to the bssgp layer" },
{ "llc:ul_packets", "Count sucessful received LLC packets (encrypt & fcs correct)" },
{ "llc:ul_bytes", "Count successful received LLC bytes (encrypt & fcs correct)" },
{ "llc:dl_packets", "Count successful sent LLC packets before giving it to the bssgp layer" },
{ "llc:ul_packets", "Count successful received LLC packets (encrypt & fcs correct)" },
{ "gprs:attach_requested", "Received attach requests" },
{ "gprs:attach_accepted", "Sent attach accepts" },
{ "gprs:attach_rejected", "Sent attach rejects" },
@@ -218,72 +227,99 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi)
}
/* 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;
ctx = talloc_zero(tall_sgsn_ctx, struct sgsn_mm_ctx);
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 = talloc_zero(tall_sgsn_ctx, struct sgsn_mm_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
@@ -313,7 +349,6 @@ static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
{
struct gprs_llc_llme *llme = NULL;
uint32_t tlli = mm->gb.tlli;
struct sgsn_pdp_ctx *pdp, *pdp2;
struct sgsn_signal_data sig_data;
@@ -356,13 +391,20 @@ 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;
if (llme) {
/* TLLI unassignment, must be called after sgsn_mm_ctx_free */
gprs_llgmm_assign(llme, tlli, 0xffffffff);
if (gprs_llgmm_unassign(llme) < 0)
LOGMMCTXP(LOGL_ERROR, mm, "gprs_llgmm_unassign failed, llme not freed!\n");
}
}
@@ -442,6 +484,7 @@ 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 */
if (pdp->mm->gb.llme)
sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
}
@@ -492,12 +535,15 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
{
if (llist_empty(&ggc->pdp_list) || ggc->echo_interval <= 0) {
if (osmo_timer_pending(&ggc->echo_timer))
osmo_timer_del(&ggc->echo_timer);
} else {
if (!osmo_timer_pending(&ggc->echo_timer))
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) {
if (!pending)
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
} else {
if (pending)
osmo_timer_del(&ggc->echo_timer);
}
}
@@ -520,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);
@@ -689,12 +734,12 @@ restart:
* Alternatively, a freeze list could be used if another PRNG is used
* or when this approach proves to be not sufficient.
*/
if (ptmsi >= 0xC0000000) {
if (ptmsi >= GSM23003_TMSI_SGSN_MASK) {
if (!max_retries--)
goto failed;
goto restart;
}
ptmsi |= 0xC0000000;
ptmsi |= GSM23003_TMSI_SGSN_MASK;
if (ptmsi == GSM_RESERVED_TMSI) {
if (!max_retries--)
@@ -721,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 {
@@ -752,11 +797,15 @@ 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)
{
sgsn_ggsn_ctx_check_echo_timer(ggc);
llist_add(&pdp->ggsn_list, &ggc->pdp_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
}
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
@@ -918,6 +967,7 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
LOGMMCTXP(LOGL_NOTICE, mmctx,
"No static GGSN configured. Selected APN '%s'\n",
selected_apn_str);
*gsm_cause = GSM_CAUSE_MISSING_APN;
return NULL;
}
@@ -985,6 +1035,7 @@ struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx)
inst = talloc_zero(talloc_ctx, struct sgsn_instance);
inst->cfg.gtp_statedir = talloc_strdup(inst, "./");
inst->cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED;
inst->cfg.require_authentication = true; /* only applies if auth_policy is REMOTE */
inst->cfg.gsup_server_port = OSMO_GSUP_PORT;
return inst;
}

754
src/sgsn/gprs_sm.c Normal file
View 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;
}

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;
@@ -989,8 +1000,8 @@ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi)
gprs_sndcp_comp_free(lle->llme->comp.data);
lle->llme->comp.proto = gprs_sndcp_comp_alloc(lle->llme);
lle->llme->comp.data = gprs_sndcp_comp_alloc(lle->llme);
talloc_free(lle->llme->xid);
lle->llme->xid = NULL;
talloc_free(lle->xid);
lle->xid = NULL;
/* Generate compression parameter bytestream */
xid_len = gprs_llc_gen_sndcp_xid(l3params, sizeof(l3params), nsapi);
@@ -1120,6 +1131,14 @@ int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication,
OSMO_ASSERT(xid_field_response);
OSMO_ASSERT(lle);
/* Some phones send zero byte length SNDCP frames
* and do require a confirmation response. */
if (xid_field_indication->data_len == 0) {
xid_field_response->type = GPRS_LLC_XID_T_L3_PAR;
xid_field_response->data_len = 0;
return 0;
}
/* Parse SNDCP-CID XID-Field */
comp_fields = gprs_sndcp_parse_xid(&version, lle->llme,
xid_field_indication->data,

View File

@@ -160,16 +160,23 @@ void gprs_sndcp_comp_free(struct llist_head *comp_entities)
llist_for_each_entry(comp_entity, comp_entities, list) {
/* Free compression entity */
if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
switch (comp_entity->compclass) {
case SNDCP_XID_PROTOCOL_COMPRESSION:
LOGP(DSNDCP, LOGL_INFO,
"Deleting header compression entity %d ...\n",
comp_entity->entity);
gprs_sndcp_pcomp_term(comp_entity);
} else {
break;
case SNDCP_XID_DATA_COMPRESSION:
LOGP(DSNDCP, LOGL_INFO,
"Deleting data compression entity %d ...\n",
comp_entity->entity);
gprs_sndcp_dcomp_term(comp_entity);
break;
default:
LOGP(DSNDCP, LOGL_INFO,
"Invalid compression class %d!\n", comp_entity->compclass);
OSMO_ASSERT(false);
}
}

View File

@@ -94,7 +94,7 @@ int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity,
&rx_v42bis_data_handler, NULL,
V42BIS_MAX_OUTPUT_LENGTH);
LOGP(DSNDCP, LOGL_INFO,
"V.42bis data compression initalized.\n");
"V.42bis data compression initialized.\n");
return 0;
}

View File

@@ -59,7 +59,7 @@ int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity,
slhc_init(ctx, comp_field->rfc1144_params->s01 + 1,
comp_field->rfc1144_params->s01 + 1);
LOGP(DSNDCP, LOGL_INFO,
"RFC1144 header compression initalized.\n");
"RFC1144 header compression initialized.\n");
return 0;
}

View File

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

View File

@@ -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>
@@ -153,7 +153,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
imsi_ui64 = imsi_str2gtp(mmctx->imsi);
rc = pdp_newpdp(&pdp, imsi_ui64, nsapi, NULL);
rc = gtp_pdp_newpdp(ggsn->gsn, &pdp, imsi_ui64, nsapi, NULL);
if (rc) {
LOGP(DGPRS, LOGL_ERROR, "Out of libgtp PDP Contexts\n");
return NULL;
@@ -279,7 +279,9 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
pdp->userloc.l = 8;
switch (mmctx->ran_type) {
case MM_CTX_T_GERAN_Gb:
#if 0
case MM_CTX_T_GERAN_Iu:
#endif
pdp->rattype.v[0] = 2;
/* User Location Information */
pdp->userloc_given = 1;
@@ -357,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;
@@ -467,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)
{
@@ -577,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;
}
@@ -628,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:
@@ -647,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);
@@ -676,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;
@@ -719,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;
}
@@ -818,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;
@@ -890,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

@@ -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>
@@ -209,6 +210,7 @@ static void print_help(void)
{
printf("Some useful help...\n");
printf(" -h --help\tthis text\n");
printf(" -V --version\tPrint the version\n");
printf(" -D --daemonize\tFork the process into a background daemon\n");
printf(" -d option --debug\tenable Debugging\n");
printf(" -s --disable-color\n");
@@ -269,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 */
@@ -339,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 = {
@@ -348,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;
@@ -383,14 +391,14 @@ int main(int argc, char **argv)
vty_info.copyright = openbsc_copyright;
vty_init(&vty_info);
logging_vty_add_cmds(NULL);
logging_vty_add_cmds();
osmo_talloc_vty_add_cmds();
osmo_stats_vty_add_cmds(&gprs_log_info);
osmo_stats_vty_add_cmds();
sgsn_vty_init(&sgsn->cfg);
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
@@ -499,7 +507,9 @@ int main(int argc, char **argv)
#if BUILD_IU
/* Note that these are mostly defaults and can be overriden from the VTY */
sccp = osmo_sccp_simple_client(tall_sgsn_ctx, "OsmoSGSN",
sccp = osmo_sccp_simple_client_on_ss7_id(tall_sgsn_ctx,
sgsn->cfg.iu.cs7_instance,
"OsmoSGSN",
(23 << 3) + 4,
OSMO_SS7_ASP_PROT_M3UA,
0, NULL,

View File

@@ -28,6 +28,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/tdef.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gsm/apn.h>
@@ -39,6 +40,7 @@
#include <osmocom/sgsn/vty.h>
#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/vty/tdef_vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
@@ -88,39 +90,49 @@ 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 */
#define DECLARE_TIMER(number, doc) \
DEFUN(cfg_sgsn_T##number, \
cfg_sgsn_T##number##_cmd, \
"timer t" #number " <0-65535>", \
"Configure GPRS Timers\n" \
doc "\nTimer Value in seconds\n") \
{ \
int value = atoi(argv[0]); \
\
if (value < 0 || value > 65535) { \
vty_out(vty, "Timer value %s out of range.%s", \
argv[0], VTY_NEWLINE); \
return CMD_WARNING; \
} \
\
g_cfg->timers.T##number = value; \
return CMD_SUCCESS; \
/* 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)" },
{ .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
{ .T=3314, .default_val=GSM0408_T3314_SECS, .desc="READY timer. Force to STANDBY on expiry timer (s)" },
{ .T=3316, .default_val=GSM0408_T3316_SECS, .desc="AA-Ready timer (s)" },
{ .T=3322, .default_val=GSM0408_T3322_SECS, .desc="Detach request -> accept timer (s)" },
{ .T=3350, .default_val=GSM0408_T3350_SECS, .desc="Waiting for ATT/RAU/TMSI_COMPL timer (s)" },
{ .T=3360, .default_val=GSM0408_T3360_SECS, .desc="Waiting for AUTH/CIPH response timer (s)" },
{ .T=3370, .default_val=GSM0408_T3370_SECS, .desc="Waiting for IDENTITY response timer (s)" },
{ .T=3385, .default_val=GSM0408_T3385_SECS, .desc="Wait for ACT PDP CTX REQ timer (s)" },
{ .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)" },
{}
};
DEFUN(show_timer, show_timer_cmd,
"show timer " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
SHOW_STR "Show timers\n"
OSMO_TDEF_VTY_DOC_T)
{
const char *T_arg = argc > 0 ? argv[0] : NULL;
return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs, T_arg, NULL);
}
DECLARE_TIMER(3312, "Periodic RA Update timer (s)")
DECLARE_TIMER(3322, "Detach request -> accept timer (s)")
DECLARE_TIMER(3350, "Waiting for ATT/RAU/TMSI_COMPL timer (s)")
DECLARE_TIMER(3360, "Waiting for AUTH/CIPH response timer (s)")
DECLARE_TIMER(3370, "Waiting for IDENTITY response timer (s)")
DECLARE_TIMER(3313, "Waiting for paging response timer (s)")
DECLARE_TIMER(3314, "Force to STANDBY on expiry timer (s)")
DECLARE_TIMER(3316, "AA-Ready timer (s)")
DECLARE_TIMER(3385, "Wait for ACT PDP CTX REQ timer (s)")
DECLARE_TIMER(3386, "Wait for MODIFY PDP CTX ACK timer (s)")
DECLARE_TIMER(3395, "Wait for DEACT PDP CTX ACK timer (s)")
DECLARE_TIMER(3397, "Wait for DEACT AA PDP CTX ACK timer (s)")
DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
"timer " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
"Configure or show timers\n"
OSMO_TDEF_VTY_DOC_SET)
{
/* If any arguments are missing, redirect to 'show' */
if (argc < 2)
return show_timer(self, vty, argc, argv);
return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
}
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
{
@@ -185,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",
@@ -211,6 +223,8 @@ static int config_write_sgsn(struct vty *vty)
if (g_cfg->gsup_server_port)
vty_out(vty, " gsup remote-port %d%s",
g_cfg->gsup_server_port, VTY_NEWLINE);
if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE && !g_cfg->require_authentication)
vty_out(vty, " authentication optional%s", VTY_NEWLINE);
vty_out(vty, " auth-policy %s%s",
get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
VTY_NEWLINE);
@@ -251,18 +265,7 @@ static int config_write_sgsn(struct vty *vty)
vty_out(vty, " no cdr trap%s", VTY_NEWLINE);
vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE);
vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE);
vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE);
vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE);
vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE);
vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE);
vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE);
vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE);
vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE);
vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE);
vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE);
vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE);
osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
if (g_cfg->pcomp_rfc1144.active) {
vty_out(vty, " compression rfc1144 active slots %d%s",
@@ -293,6 +296,8 @@ static int config_write_sgsn(struct vty *vty)
vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
#ifdef BUILD_IU
vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
VTY_NEWLINE);
ranap_iu_vty_config_write(vty, " ");
#endif
@@ -381,7 +386,7 @@ DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
ggc->echo_interval = atoi(argv[1]);
if (ggc->echo_interval < 60)
vty_out(vty, "%% 3GPP TS 29.060 section states inteval should " \
vty_out(vty, "%% 3GPP TS 29.060 section 7.2.1 states interval should " \
"not be lower than 60 seconds, use this value for " \
"testing purposes only!%s", VTY_NEWLINE);
@@ -397,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;
@@ -478,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;
@@ -527,13 +523,31 @@ 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);
@@ -636,12 +650,15 @@ DEFUN(imsi_acl, cfg_imsi_acl_cmd,
"Remove IMSI from ACL\n"
"IMSI of subscriber\n")
{
char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1] = { '0' };
char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS + 1];
const char *op = argv[0];
const char *imsi = imsi_sanitized;
size_t len = strnlen(argv[1], GSM23003_IMSI_MAX_DIGITS + 1);
int rc;
memset(imsi_sanitized, '0', GSM23003_IMSI_MAX_DIGITS);
imsi_sanitized[GSM23003_IMSI_MAX_DIGITS] = '\0';
/* Sanitize IMSI */
if (len > GSM23003_IMSI_MAX_DIGITS) {
vty_out(vty, "%% IMSI (%s) too long (max %u digits) -- ignored!%s",
@@ -690,6 +707,27 @@ DEFUN(cfg_encrypt, cfg_encrypt_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_authentication, cfg_authentication_cmd,
"authentication (optional|required)",
"Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
"Allow MS to attach via GERAN without authentication (default and only possible value for non-remote auth-policy)\n"
"Always require authentication (only available for auth-policy remote, default with that auth-policy)\n")
{
int required = (argv[0][0] == 'r');
if (vty->type != VTY_FILE) {
if (g_cfg->auth_policy != SGSN_AUTH_POLICY_REMOTE && required) {
vty_out(vty, "%% Authentication is not possible without HLR, "
"consider setting 'auth-policy' to 'remote'%s",
VTY_NEWLINE);
return CMD_WARNING;
}
}
g_cfg->require_authentication = required;
return CMD_SUCCESS;
}
DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
"auth-policy (accept-all|closed|acl-only|remote)",
"Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
@@ -702,7 +740,6 @@ DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
int val = get_string_value(sgsn_auth_pol_strs, argv[0]);
OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE);
g_cfg->auth_policy = val;
g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE);
g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE);
return CMD_SUCCESS;
@@ -1284,7 +1321,7 @@ DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd,
DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
"compression rfc1144 active slots <1-256>",
COMPRESSION_STR
"RFC1144 Header compresion scheme\n"
"RFC1144 Header compression scheme\n"
"Compression is actively proposed\n"
"Number of compression state slots\n"
"Number of compression state slots\n")
@@ -1298,7 +1335,7 @@ DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd,
DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd,
"compression rfc1144 passive",
COMPRESSION_STR
"RFC1144 Header compresion scheme\n"
"RFC1144 Header compression scheme\n"
"Compression is available on request\n")
{
g_cfg->pcomp_rfc1144.active = 0;
@@ -1318,7 +1355,7 @@ DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd,
DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
"compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>",
COMPRESSION_STR
"V.42bis data compresion scheme\n"
"V.42bis data compression scheme\n"
"Compression is actively proposed\n"
"Direction in which the compression shall be active (p0)\n"
"Compress ms->sgsn direction only\n"
@@ -1351,7 +1388,7 @@ DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd,
DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
"compression v42bis passive",
COMPRESSION_STR
"V.42bis data compresion scheme\n"
"V.42bis data compression scheme\n"
"Compression is available on request\n")
{
g_cfg->dcomp_v42bis.active = 0;
@@ -1359,16 +1396,31 @@ DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd,
return CMD_SUCCESS;
}
#if BUILD_IU
DEFUN(cfg_sgsn_cs7_instance_iu,
cfg_sgsn_cs7_instance_iu_cmd,
"cs7-instance-iu <0-15>",
"Set SS7 to be used by the Iu-Interface.\n" "SS7 instance reference number (default: 0)\n")
{
g_cfg->iu.cs7_instance = atoi(argv[0]);
return CMD_SUCCESS;
}
#endif
int sgsn_vty_init(struct sgsn_config *cfg)
{
g_cfg = cfg;
g_cfg->T_defs = sgsn_T_defs;
osmo_tdefs_reset(g_cfg->T_defs);
install_element_ve(&show_sgsn_cmd);
//install_element_ve(&show_mmctx_tlli_cmd);
install_element_ve(&show_mmctx_imsi_cmd);
install_element_ve(&show_mmctx_all_cmd);
install_element_ve(&show_pdpctx_all_cmd);
install_element_ve(&show_subscr_cache_cmd);
install_element_ve(&show_timer_cmd);
install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
install_element(ENABLE_NODE, &update_subscr_create_cmd);
@@ -1388,6 +1440,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
install_element(SGSN_NODE, &cfg_auth_policy_cmd);
install_element(SGSN_NODE, &cfg_authentication_cmd);
install_element(SGSN_NODE, &cfg_encrypt_cmd);
install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
@@ -1407,18 +1460,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd);
install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd);
install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd);
install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
@@ -1428,6 +1470,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
#ifdef BUILD_IU
install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);
ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
#endif
return 0;
@@ -1440,19 +1483,6 @@ int sgsn_parse_config(const char *config_file)
/* make sure sgsn_vty_init() was called before this */
OSMO_ASSERT(g_cfg);
g_cfg->timers.T3312 = GSM0408_T3312_SECS;
g_cfg->timers.T3322 = GSM0408_T3322_SECS;
g_cfg->timers.T3350 = GSM0408_T3350_SECS;
g_cfg->timers.T3360 = GSM0408_T3360_SECS;
g_cfg->timers.T3370 = GSM0408_T3370_SECS;
g_cfg->timers.T3313 = GSM0408_T3313_SECS;
g_cfg->timers.T3314 = GSM0408_T3314_SECS;
g_cfg->timers.T3316 = GSM0408_T3316_SECS;
g_cfg->timers.T3385 = GSM0408_T3385_SECS;
g_cfg->timers.T3386 = GSM0408_T3386_SECS;
g_cfg->timers.T3395 = GSM0408_T3395_SECS;
g_cfg->timers.T3397 = GSM0408_T3397_SECS;
rc = vty_read_config_file(config_file, NULL);
if (rc < 0) {
fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);

View File

@@ -33,6 +33,7 @@ EXTRA_DIST = \
$(TESTSUITE) \
vty_test_runner.py \
ctrl_test_runner.py \
test_nodes.vty \
$(NULL)
TESTSUITE = $(srcdir)/testsuite
@@ -43,16 +44,38 @@ DISTCLEANFILES = \
if ENABLE_EXT_TESTS
python-tests: $(BUILT_SOURCES)
osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
$(srcdir)/vty_test_runner.py -w $(abs_top_builddir) -v
$(srcdir)/ctrl_test_runner.py -w $(abs_top_builddir) -v
rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
$(MAKE) vty-test
$(MAKE) ctrl-python-test
else
python-tests: $(BUILT_SOURCES)
echo "Not running python-based tests (determined at configure-time)"
endif
vty-python-test: $(BUILT_SOURCES)
osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
$(srcdir)/vty_test_runner.py -w $(abs_top_builddir) -v
rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
# To update the VTY script from current application behavior,
# pass -u to vty_script_runner.py by doing:
# make vty-transcript-test U=-u
vty-transcript-test:
osmo_verify_transcript_vty.py -v \
-n OsmoSGSN -p 4245 \
-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
# don't run multiple tests concurrently so that the ports don't conflict
vty-test:
$(MAKE) vty-python-test
$(MAKE) vty-transcript-test
ctrl-python-test: $(BUILT_SOURCES)
$(srcdir)/ctrl_test_runner.py -w $(abs_top_builddir) -v
rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
check-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
$(MAKE) $(AM_MAKEFLAGS) python-tests

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

View File

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

View File

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

View File

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

View File

@@ -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>
@@ -37,6 +38,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/utils.h>
#include <osmocom/vty/vty.h>
#include <stdio.h>
@@ -191,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);
@@ -1285,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);
@@ -1305,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);
@@ -1319,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);
@@ -1575,6 +1576,22 @@ static void test_ggsn_selection(void)
cleanup_test();
}
bool pdp_status_has_active_nsapis(const uint8_t *pdp_status, const size_t pdp_status_len);
static void test_pdp_status_has_active_nsapis(void)
{
const size_t pdp_status_len = 2;
const uint8_t pdp_status1[] = { 0b00100000, 0b00000000 }; /* PDP NSAPI 5 active */
const uint8_t pdp_status2[] = { 0b00000000, 0b00000000 }; /* no active PDP NSAPI */
const uint8_t pdp_status3[] = { 0b00000000, 0b00000001 }; /* PDP NSAPI 8 active */
printf("Testing pdp_status_has_active_nsapis\n");
OSMO_ASSERT(pdp_status_has_active_nsapis(pdp_status1, pdp_status_len));
OSMO_ASSERT(!pdp_status_has_active_nsapis(pdp_status2, pdp_status_len));
OSMO_ASSERT(pdp_status_has_active_nsapis(pdp_status3, pdp_status_len));
}
static struct log_info_cat gprs_categories[] = {
[DMM] = {
.name = "DMM",
@@ -1630,6 +1647,10 @@ static struct log_info info = {
.num_cat = ARRAY_SIZE(gprs_categories),
};
static struct vty_app_info vty_info = {
.name = "testSGSN",
};
int main(int argc, char **argv)
{
void *osmo_sgsn_ctx;
@@ -1643,6 +1664,8 @@ int main(int argc, char **argv)
sgsn_rate_ctr_init();
sgsn_auth_init(sgsn);
gprs_subscr_init(sgsn);
vty_init(&vty_info);
sgsn_vty_init(&sgsn->cfg);
test_llme();
test_subscriber();
@@ -1657,6 +1680,7 @@ int main(int argc, char **argv)
test_gmm_cancel();
test_apn_matching();
test_ggsn_selection();
test_pdp_status_has_active_nsapis();
printf("Done\n");
talloc_report_full(osmo_sgsn_ctx, stderr);

View File

@@ -24,4 +24,5 @@ Testing GMM reject
Testing cancellation
Testing APN matching
Testing GGSN selection
Testing pdp_status_has_active_nsapis
Done

View File

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

View File

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

63
tests/test_nodes.vty Normal file
View File

@@ -0,0 +1,63 @@
OsmoSGSN> enable
OsmoSGSN# show timer
T3312 = 600 s Periodic RA Update timer (s) (default: 600 s)
T3313 = 30 s Waiting for paging response timer (s) (default: 30 s)
T3314 = 44 s READY timer. Force to STANDBY on expiry timer (s) (default: 44 s)
T3316 = 44 s AA-Ready timer (s) (default: 44 s)
T3322 = 6 s Detach request -> accept timer (s) (default: 6 s)
T3350 = 6 s Waiting for ATT/RAU/TMSI_COMPL timer (s) (default: 6 s)
T3360 = 6 s Waiting for AUTH/CIPH response timer (s) (default: 6 s)
T3370 = 6 s Waiting for IDENTITY response timer (s) (default: 6 s)
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
...
sgsn
ctrl
...
ns
bssgp
...
OsmoSGSN(config)# sgsn
OsmoSGSN(config-sgsn)# list
...
gtp local-ip A.B.C.D
ggsn <0-255> remote-ip A.B.C.D
ggsn <0-255> gtp-version (0|1)
ggsn <0-255> echo-interval <1-36000>
ggsn <0-255> no echo-interval
imsi-acl (add|del) IMSI
auth-policy (accept-all|closed|acl-only|remote)
authentication (optional|required)
encryption (GEA0|GEA1|GEA2|GEA3|GEA4)
gsup ipa-name NAME
gsup remote-ip A.B.C.D
gsup remote-port <0-65535>
gsup oap-id <0-65535>
gsup oap-k K
gsup oap-opc OPC
apn APNAME ggsn <0-255>
apn APNAME imsi-prefix IMSIPRE ggsn <0-255>
access-point-name NAME
no access-point-name NAME
cdr filename NAME
no cdr filename
cdr trap
no cdr trap
cdr interval <1-2147483647>
ggsn dynamic
grx-dns-add A.B.C.D
timer [TNNNN] [(<0-2147483647>|default)]
no compression rfc1144
compression rfc1144 active slots <1-256>
compression rfc1144 passive
no compression v42bis
compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>
compression v42bis passive
...

Some files were not shown because too many files have changed in this diff Show More