Compare commits

...

138 Commits

Author SHA1 Message Date
Oliver Smith b3ce06058c sgsn/sgsn_vty: create state-dir
Prepare to change the state-dir in the default config in a follow-up
commit. Create the directory if it does not exist.

Change-Id: I8db4898cdaa2fcbd6bbf7c543764b9cdf828de83
2024-05-16 10:50:56 +02:00
Oliver Smith 0a6fe9727f debian/postinst: add checks, be verbose
Do not attempt to change permissions/ownership if the package gets
upgraded from a version higher than the next release.

Do not fail if the user deleted the config file.

Be verbose when changing permissions.

Related: OS#4107
Change-Id: I2b01a7625cf66fbb7d203f939ddcc1cbab43cf33
2024-05-14 15:21:06 +02:00
Oliver Smith 7ba62d3061 contrib: remove rpm spec file
Related: https://osmocom.org/news/255
Related: OS#6446
Change-Id: I9e7a3beb861faab1b6852aa5b57847c590986976
2024-05-13 08:39:35 +00:00
Vadim Yanitskiy 62b28ffe1b VTY: sync default UMTS UEA config with osmo-msc
As was reported in OS#6442, nano3g S16 is unhappy when CS and PS
domains use different UEA configuration for simultaneous RANAP
connections.  Bring osmo-sgsn in sync with osmo-msc to avoid this.

Change-Id: I4eb9451b4267fc1436ed90a55ff200cf36f16bf6
Related: OS#6442
2024-05-09 10:50:08 +02:00
Vadim Yanitskiy cdf716cf9a VTY: move default settings to sgsn_instance_alloc()
It's cleaner to have all configuration defaults in one place.

Change-Id: I1a439dcc76272a181986b6ec9368ef16441dc098
Related: OS#6442
2024-05-09 10:48:29 +02:00
Oliver Smith a9c39c04de .deb/.rpm: various fixes related to non-root
* Explicitly chown /var/lib/osmocom to osmocom:osmocom, instead of
  relying on systemd to do it when the service starts up. This does not
  work with the systemd versions in debian 10 and almalinux 8.
* deb: Use "useradd" instead of the interactive "adduser" perl script
  from Debian. This makes it consistent with how we do it in rpm, and
  avoids the dependency on "adduser".
* deb: Consistently use tabs through the file, instead of mixing tabs
  and spaces.
* deb: Remove support for the "dpkg-statoverride --list" logic. This
  seems to be a rather obscure feature to override permissions for
  certain files or directories, for which it does not seem to be a good
  idea to make the postinst script less maintainable. Something similar
  can be achieved by using your own Osmocom config file in a different
  path with different permissions.

Related: OS#4107
Change-Id: I406ff0d625b02991d580c8382aa4be04dba45a00
2024-05-08 06:46:32 +00:00
Vadim Yanitskiy 282de031f1 gmm: mmctx_timer_stop(): warn about timer not running
This turns errors like:

  DMM ERROR MM(262420000000038/e2ff704e) Stopping MM timer 3350 but 0 is running

into warnings with a more accurate reason:

  DMM NOTICE MM(262420000000037/e2ff704e) Stopping *inactive* MM timer 3350

Change-Id: I56ecad9d8f1049974b0896f6d0e7fc61580155ec
2024-05-01 10:44:27 +02:00
Vadim Yanitskiy c3156193da gmm: cosmetic: fix preprocessor macro formatting
Change-Id: I77171d65db23794d8fd9872e0cc4d6f3b50dda0d
2024-05-01 10:44:27 +02:00
Alexander Couzens cd3a8cfad6 docs: front page: use https:// instead of http://
Change-Id: If3c3b8e79f94da7a3bcc9262808da09f6a5a601c
2024-04-28 12:17:10 +00:00
Alexander Couzens e51b3be379 docs: update year to 2024
Change-Id: I85a987eee470d2040c91289d33c5d97c3e90674d
2024-04-28 12:17:10 +00:00
Alexander Couzens b34e0a5720 docs: replace legacy NS with new NS2 chapters
osmo-sgsn already switched to the new NS2 code. Use the correct
NS2 chapter

Change-Id: I9cc86d234e029b5192e36aeb14b0e39d1496842d
2024-04-28 12:17:10 +00:00
Oliver Smith 05363e0a32 contrib/osmo-sgsn.spec: fix build for almalinux:8
Add the missing "%if 0%{?suse_version}" around %service_del/add
commands, as these are only available on opensuse.

Fix for:
  error: line 106: Too many names: %preun  -n osmo-gtphub %service_del_preun   osmo-gtphub.service

Fixes: a07e6d9c (".deb/.rpm: add osmocom user during package install")
Change-Id: I89802f926bfccc0f7b4bb1ff64115b232b1db022
2024-04-26 09:58:51 +02:00
Max a07e6d9c58 .deb/.rpm: add osmocom user during package install
Create osmocom user & group during package installation.
Fix the configuration dir/files permission to match.

Related: OS#4107
Tweaked-By: Oliver Smith <osmith@sysmocom.de>
Change-Id: I55ce205d4b314d01b2641c8f3d52455c051d6282
2024-04-24 11:52:50 +02:00
Harald Welte 1ede89a35a README.md: Add Forum and Issue Tracker sections
Change-Id: I69dfe4124c2a2be30c9ef04e70e3f15d10a2305c
2024-03-23 17:15:07 +01:00
Harald Welte 647304fbe5 README.md: Overhaul (more links; improved formatting)
Change-Id: I0cf9898877aab2f834c886491f4d203d55a8b4b9
2024-03-23 17:07:07 +01:00
Harald Welte 370d6e8b59 Add funding link to github mirror
see https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository

Change-Id: Icf0fd068742eba60c23f0e567e6e72b42063f2c0
2024-03-23 17:03:36 +01:00
Pau Espin dc4c294f94 gsup: Use new libosmogsm struct osmo_gsup_pdp_info fields
This also makes sure it doesn't compile against older libosmogsm gsup
versions which would break ABI.

Change-Id: I0d03d368e73ab62ec631420769f6af91f2ff9987
Related: OS#6091
Depends: libosmocore.git Change-Id 70be3560659c58f24b8db529c4fc85da4bb0ec04
2024-01-29 11:07:03 +01:00
Vadim Yanitskiy f2545b1b8f build: include README.md into the release tarball
Change-Id: Ia467ae8cc6eec0dc9fb36d4c159d2762e965c4f8
2024-01-26 23:37:30 +07:00
Andreas Eversberg 1f1d90f175 Use uniform log format for default config files
Related: OS#6272
Change-Id: I6b6aa5a5100cf0045dcba1b062acc9376d34b0ae
2023-12-01 12:40:54 +01:00
Oliver Smith 2a89bbf66f Bump version: 1.11.0.5-67677-dirty → 1.11.1
Depends: osmo-ggsn I1f116e1cded135f231f22ebc9b817aebf3736fc2
Change-Id: I869eef2032d6025c8ed59a1b25192c6c5c08977e
2023-11-28 13:43:15 +01:00
Daniel Willmann 676777c5f9 libgtp: Check for all successful create_pdp_conf causes
Related: OS#6268
Change-Id: I11ce72908c2dfb983887e6c1db316fd7de42f027
2023-11-23 18:00:07 +01:00
Daniel Willmann ff9c46cc61 vty-tests: Test encryption options
Change-Id: I471c04602dedfb2a80d4408c09125e51c465a8b8
2023-11-22 16:06:43 +01:00
Daniel Willmann 75a0aa78a3 sgsn_vty: Correctly indent encryption cipher-plugin-path
Change-Id: I16b3450c3919bebbceb8d27f73d7c6dde102d0f7
2023-11-22 16:06:43 +01:00
Daniel Willmann 20aef4de28 sgsn_vty: Fix output in config_write_sgsn
The encryption uea option was missing

Change-Id: I2c81ced87c53d69a94b3894441323201f81f1a76
2023-11-22 13:14:25 +01:00
Philipp Maier e746b0bef6 sgsn_rim: forward message based on RIM ROUTING ADDRESS
At the moment we parse the RAN TRANSPARENT CONTAINER to look at the
destination RIM ROUTING INFORMATION. This is not correct. The SGSN
should not decode the RAN TRANSPARENT CONTAINER and use the RIM ROUTING
ADDRESS / RIM ROUTING ADDRESS DISCRIMINATOR IE to make the routing
decision.

Related: OS#6095
Depends: libosmocore.git Ibca1f08906c4ffeecdae80d4e91c6c7b05fe4f8a
Change-Id: Ifd2b915ed2f05130cff8ee77714b82005c17de3d
2023-09-18 21:53:39 +02:00
Pau Espin 57567968ea Bump version: 1.10.0.16-7e4d-dirty → 1.11.0
Change-Id: Ia56d2e1c4247396522f02df2c95b842db655e171
2023-09-12 16:57:03 +02:00
Philipp Maier 7e4dbb4b34 sgsn_rim: do not check the origin of a RIM message
When we forward RIM messages from GTP to BSSGP, we do not have to check
the origin of the message since it does not matter from which origin the
message came when we are forwarding it.

Related: OS#6095
Change-Id: Iea8176dcfe64c25d207bafc0ef61ca9d9ad415be
2023-08-10 10:24:23 +02:00
Philipp Maier 7840375d51 sgsn_rim: get rid of MME check in sgsn_rim_rx_from_gtp:
There is no point in checking the MME any further. When the message has
reached this code path it is about to be forwarded to BSSGP, so the MME
does not play a role in the following code pathes.

The check also relys on the source RIM ROUTING INFORMATION IE inside the
RAN TRANSPARENT CONTAINER, which we are not supposed to decode.

Change-Id: I97c89aeb11537ae54d1fbea48c75619d8a92af61
Related: OS#6095
2023-08-10 10:23:06 +02:00
Philipp Maier 429d332ece sgsn_rim: cosmetic: improve comment
Let's describe more clear what we do in sgsn_bssgp_fwd_rim_to_geran

Related: OS#6095
Change-Id: I54aa82845515bcaa6badc9e0e87fa6248333430e
2023-08-10 10:19:37 +02:00
Philipp Maier f24970a7ca sgsn_rim: fix typo
Related: OS#6095
Change-Id: I86f70ea9a1a3e43523ec327165bfeb1737ad300a
2023-07-28 13:23:49 +02:00
Pau Espin 2365fec0fb gmm: Add missing GSM48_IE_GMM_RX_NPDU_NUM_LIST IE in gsm48_gmm_att_tlvdef
Depends: libosmocore.git Change-Id Ifac09653141758af345efe2eb9cef25ebf4dcff9
Change-Id: I5b43384407b1c9c33790cae9c48c2816213578e6
2023-07-18 17:41:09 +02:00
Pau Espin 5df65b6c30 gmm: Update DRX params during rx RAU REQ
The DRX params where already parsed in GMM Attached Req and transmitted
to PCU over BSSGP DL UD packets, but it was not being updated if the MS
changed it during RAU Req.

TS 24.008 9.4.14.3 DRX parameter:
"This IE shall be included if the MS changes the access network
from GSM to UMTS, or the MS wants to indicate new DRX parameters
to the network."

Change-Id: I1dd7f8f161280dd017c337eacc3aa2be4ccd65ea
2023-07-14 18:11:31 +02:00
Pau Espin 5f1020b963 Write explicit role & sctp-role fields in ASP configurations
Change-Id: I44e251ca2df02e4f1fdfc1492306ec25d0653ef6
2023-06-08 19:34:21 +02:00
Oliver Smith eda1b83f75 systemd: depend on networking-online.target
Related: SYS#6400
Change-Id: Idadcbbf55e976ae035cfac4b85ccd870e0f27b82
2023-05-26 14:10:48 +02:00
Vadim Yanitskiy b83aabaa95 copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH
Change-Id: Ie2d864d5171e0da2e8a6c8551d151fd14f89bf05
2023-05-18 17:22:26 +07:00
Pau Espin 1bebd08a4b gprs_sm.c: Fix load of misaligned ptr address
Got this Asan runtime error in osmo-sgsn while implementing the MS side of SM:
"""
DMM gprs_sm.c:427 MM(901700000015254/c655d609) -> ACTIVATE PDP CONTEXT REQ: SAPI=3 NSAPI=6 IETF IPv4 /osmo-sgsn/src/sgsn/gprs_sm.c:453:16: runtime error: load of misaligned address 0x61f000064ba3 for type 'uint32_t', which requires 4 byte alignment
0x61f000064ba3: note: pointer points here
 00  06 01 21 00 00 00 00 28  09 27 01 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00
              ^
"""

Change-Id: I8069e3457120b22bb6514fd5d192bff486d7d87f
2023-05-03 11:35:24 +02:00
Oliver Smith a86056fdf3 debian: set compat level to 10
Related: OS#5958
Change-Id: Ib45ad7c44cdefa4c5acab2da09f24796253a133d
2023-04-25 16:48:32 +02:00
Vadim Yanitskiy 99ec755643 tests: $(BUILT_SOURCES) is not defined, depend on osmo-sgsn
Change-Id: I4f9e99ed3673bb51fa5f7d374c35c3c92735eacb
2023-03-30 02:11:21 +07:00
Pau Espin d5dca3a67f gmm: Ciphering Key Sequence Number IE has half octet tag
As per 3GPP TS 24.008:
* 10.5.1.2 Ciphering Key Sequence Number
* Table 9.4.9/TS 24.00

The IE is so far being encoded manually, hence why it worked fine until
now.

Change-Id: Ic220113f30377a14cbe3550a04cd04f3caef49cf
2023-03-22 13:36:35 +01:00
Vadim Yanitskiy 3c26a1dc3c tests: use -no-install libtool flag to avoid ./lt-* scripts
This option should be used for any executables which are used only
for testing, or for generating other files and are consequently never
installed.  By specifying this option, we are telling Libtool that
the executable it links will only ever be executed from where it is
built in the build tree.  Libtool is usually able to considerably
speed up the link process for such executables.

Change-Id: I8af6a38d7abbf06aa8268981c80c3bfda2f80a27
2023-03-11 05:02:17 +07:00
arehbein 642019f288 Transition to use of 'telnet_init_default'
Related: OS#5809
Change-Id: Icc57c68337d55c6594c1c36e9bf41624d11dab0a
2023-02-26 21:16:12 +01:00
Oliver Smith f8a5066ad0 Run struct_endianness.py
Ensure there is no diff to prepare to run this in CI.

Related: OS#5884
Change-Id: I808afd0e9833e6e99d30a37675cbd200ced027e4
2023-02-20 10:51:48 +01:00
Pau Espin 8c42673eba Bump version: 1.9.0.56-07fe-dirty → 1.10.0
Change-Id: I89eb79ffeb28b8dae5b4a5c3cc1142d07052692c
2023-02-07 17:34:27 +01:00
Pau Espin 07feb06d54 Fix extra whitespace in pdpctx_ctr_description
Change-Id: I4d9145c681e725b709fde38f6e9b4516d37b4d8c
2023-01-11 12:58:23 +01:00
Pau Espin 86b630cfe1 vty: Introduce encryption cipher-plugin-path command
The load of plugins will eventually be moved to libosmo-gprs
implementation, and path will be passed as a parameter. Once it's moved
inside libosmo-gprs, it will be more strict on load failures, which can
cause internally if the path doesn't exist (unless NULL is passed).
Hence, add a VTY config to allow configuring the right path, and have it
disabled by default.

Change-Id: I4f965c7afafa193f4d7486750dd3e43cca22bb65
2023-01-11 12:58:23 +01:00
Pau Espin 93bc518b53 Move global mmctx list into struct sgsn_instance
Change-Id: Idf8458902321da03b9b0831dad3ad383a9c7afa1
2023-01-11 12:58:23 +01:00
Pau Espin 58101ea587 Split gprs_sgsn.{c,h} -> {auth,mmctx,sgsn}.{c,h}
Some level of split already existed, like sgsn_auth.c, but headers were
entangled together.
Let's clearly separate application centric code (sgsn.c/h), auth related
code (auth.c/h) and mmctx related code (mmctx.c/h).

Change-Id: I048a082851c1275c959649942904205b02acce2a
2023-01-11 12:58:15 +01:00
Pau Espin 6aad14c3fa gtphub.h: Remove dependency on sgsn/gprs_sgsn.h
It is only really needed to import define GSM_APN_LENGTH, which is
actually also available in libosmogsm. Hence simply use the one from
libosmogsm.

Change-Id: I4c6110feeeaa1adfb6b1f0147eeb56dfe34636ec
2023-01-11 12:51:38 +01:00
Pau Espin f44dfa8a0e Rename bscconfig.h -> config.h
Change-Id: I007103be34c1aaab7a9375c44b226d4590fe5b24
2023-01-11 12:51:38 +01:00
Pau Espin e931b39b3c Move LOGGSUBSCRP to gprs_subscriber.h
The define belongs to gprs_subscriber.h header.

Change-Id: Icdb7e55ca8e90dd2ba79ccdb1a8ba650a3942ab3
2023-01-11 12:51:38 +01:00
Pau Espin fd9e82da31 Move sgsn_ctrl_cmds_install() declaration to sgsn.h
sgsn.h is the main header containing all misc app related contents.
This is another step towards shrinking gprs_sgsn.h mess.

Change-Id: I80e3a68e2e368d8c73135c850e4728bdf6cf5f09
2023-01-11 12:51:38 +01:00
Pau Espin f2307c483f Move gtphub header to include/osmocom/gtphub/
Change-Id: I82e1f2a3bc8e22b28747a540879bd661f1704cde
2023-01-11 12:51:38 +01:00
Pau Espin 15a52d92c4 Move global pdp_list inside struct sgsn_instance
This way pdp contexts are managed by the lifcycle of the main global struct
sgsn_instance automatically.

Change-Id: I725218fd54adcc68dceded5eb43675f25771bb96
2023-01-11 12:51:38 +01:00
Pau Espin 05190c36bb Move sgsn_pdp_ctx to its own file pdpctx.{c,h}
This further shrinks the mess in gprs_sgsn.h, and allows to easily see
layer violations (like pdpctx.c requiring llc.h)

Change-Id: Iad4da06efee7d8514ff48423bdaebc0f26413cc1
2023-01-11 12:51:34 +01:00
Pau Espin 3d3c8c55f0 Drop extern declarations of global sgsn_instance in source files
There's an extern declaration already in sgsn.h.

Change-Id: I2375e13c8436a069e8fe60136c8e1759a9adc2d1
2023-01-11 12:46:34 +01:00
Pau Espin 164a1eeb8a Move extern declarations of tall_sgsn_ctx to sgsn.h
Change-Id: Ifbd54b2e92db8d4a0e0cd1c569cfd83dd85165b8
2023-01-11 12:43:18 +01:00
Pau Espin 69569879ae gtp_{ggsn,mme}: Allocate contexts under struct sgsn_instance
This way apns are managed by the lifcycle of the main global struct
sgsn_instance automatically.

Change-Id: Ie65d59632a368c6957c33dca64e856ace792b2c6
2023-01-11 12:31:23 +01:00
Pau Espin fd4d435442 Move global apn_list inside struct sgsn_instance
This way apns are managed by the lifcycle of the main global struct
sgsn_instance automatically.

Change-Id: I8cc8e540cfb64d0f130e9c0aaedf7b0835f8fe16
2023-01-05 19:37:07 +01:00
Pau Espin 8ec269a0e0 Move gtp related functions to gtp.h
The functions are implemented in sgsn_libgtp.c and hence belong to
header file gtp.h

Change-Id: I7f5cf2895b05e03435769548b61051e6284ccb3c
2023-01-05 19:20:43 +01:00
Pau Espin 4bd6f663a7 sndcp: Standarize unitdata function naming
Use sndcp_<sap>_type>_<op> so that it's easier to distinguish and
identify them.

Change-Id: Ib8825570a8f61d0a28d631f86f5244e70d3194aa
2023-01-05 19:00:56 +01:00
Pau Espin 52c9b8e593 Move func defintions of funcs implemented in gprs_sndcp.c to gprs_sndcp.h
Move them to the correct header where they belong, so that the all the
related protocol stuff is placed together.

Change-Id: I9052f48a0af125bb445194f4ae94ebbe49508fda
2023-01-05 18:57:39 +01:00
Pau Espin 51028e2c16 Properly split llc->sndcp->gtp unitdata pathi through extra func call
Beforehand the function handling the LL-UNITDATA primitive from LLC was
already submitting the packet to GTP code which had an SNDCP related
name, so everything was really confusing and layer separation was not
clean.

Change-Id: Ia544a9dd4c0c7647b0c1b64ca110351f40820618
2023-01-05 18:46:23 +01:00
Pau Espin e69f460ae7 sgsn.h: Drop declaration of non existing function
Change-Id: Idabea56d1ff89e51b517b15771a5a1ed3b050ec9
2023-01-05 18:23:03 +01:00
Pau Espin 0e707fc83a Move struct sgsn_subscriber_pdp_data to gprs_subscriber.h
The functions driving its lifcyecles are already in gprs_subscriber.c,
and are used mainly by functions in the same file, hence move it to the
related header to further shrink gprs_sgsn.h.

Change-Id: Iff7be91af130a3317d57d3649c17e3d5d2540e7a
2023-01-05 17:48:17 +01:00
Pau Espin ffd6e37eb5 Move struct apn_ctx and APN related definitions to its own file
This allows further shrinking of gprs_sgsn.{c,h} and also being able to
use GSM_APN_LENGTH on different headers easily (needed by follow-up
patch).

Change-Id: Id225ed8b84e1376f4a30f17dd4b153b6b1a6efa8
2023-01-05 17:45:28 +01:00
Pau Espin 44bde6b85a Move global ggsn_list into struct sgsn_instance
Change-Id: I9d4c74476b777a866af2796dd376ed50da7b5d01
2023-01-05 17:23:43 +01:00
Pau Espin e659f75cf1 Keep sgsn subsystems under struct sgsn_instance lifecycle
Rework initialization and destruction of several sgsn subsystems to be
allocated & released together with the struct sgsn_instance.

This makes it easier to destroy and recreate the entire context and
allows us to start moving global variables scattered around to be under
struct sgsn_instance.

Change-Id: Idf60519b8e475b94d38bbb69e737132a5afaefab
2023-01-05 17:23:43 +01:00
Pau Espin 67e71eac1c Remove unneeded extern declaration from libosmocotrl
Change-Id: I464df2d03538c71f6666046c67170746690e723d
2023-01-05 17:23:43 +01:00
Pau Espin c1cf4af11b Move related structs to gprs_subscriber.h
This allows shrinking a bit more gprs_sgsn.h and and in turn have
everything much more tidy.

Change-Id: Ie39b48a0d612aa632327cc5a21c833b05f5bf297
2023-01-05 15:43:29 +01:00
Pau Espin f37aedbf76 Fix -Werror=old-style-definition
Change-Id: I119d4ba58d9c68df12b433b0cee924468a1473d8
2023-01-05 14:25:47 +01:00
Pau Espin 920c6c8c81 Introduce new header file sgsn/gtp.h
It will be used to store all stuff relatd to libgtp use and GTP
protocol, similar to what we already do for other protocols.

Change-Id: I4aae35cd0ea401856cd822cb507d668350d07a89
2023-01-05 14:15:52 +01:00
Pau Espin df203361e8 Move gprs_sndcp_vty_init() declaration to gprs_sndcp.h
Change-Id: Iea9692e7ef9bd017d89ef654d2f2ae5b30cc4550
2023-01-05 14:15:52 +01:00
Pau Espin b61ab9b9ac gprs_subscriber: Move API declarations to correct header
Change-Id: Iaa1032c38fa54ad57c472d9120cfbb34b2ae90e9
2023-01-05 14:15:50 +01:00
Pau Espin 5f4736aa85 Move struct sgsn_ggsn_ctx to its own file gtp_ggsn.{c,h}
Similar to what we already have for struct sgsn_mme_ctx in
gtp_mme.{c,h}.

This is just the nth step of properly splitting different
protocol layers, data model, etc.

Change-Id: Iad1895f09e43e299df7bb126bf52fdb98268392e
2023-01-05 00:11:57 +01:00
Pau Espin fc1a5538d0 Replace gprs_str_to_apn() with libosmocore API osmo_apn_from_str()
The exact same function exists in libosmocore with a different naming.

Change-Id: Ibef55a648f2d58f4fdd24fa553efde530982af2d
2023-01-04 19:56:39 +01:00
Pau Espin eb967fccb2 Remove unused function gprs_parse_mi_tmsi()
Change-Id: I6fb7688bf54c7ae3ca3e06bf3a1b729fa62d82f9
2023-01-04 16:29:43 +01:00
Pau Espin 13c00008b4 Standarize lle and llme state enum & value_string
Change-Id: Iaf102ce5ca60854fe7eb1af17c73a80e7c76181b
2023-01-04 13:57:52 +01:00
Pau Espin e5614e434f vty: Fix wrong value_string used to print llme state
Change-Id: Id3eec91b47029964092087858e4ae3a824929ce3
2023-01-04 13:53:57 +01:00
Pau Espin b0b582bff8 cosmetic: gprs_llc_vty.c: Fix trailing whitespace
Change-Id: I543fd784f7e1a0f7c82bd7c79e073104becc88da
2023-01-04 13:49:22 +01:00
Pau Espin bc46812bd7 Move gprs_tmr_to_secs() to tests/gprs/gprs_test.c
That function is only used in the test. Let's hence move the function to
the same test file in order to simplify osmo-sgsn code.

Change-Id: I69d80810362d75eb93974af34f61639514f99f8a
2023-01-02 13:38:01 +01:00
Pau Espin 4398ac073b Rename gprs_gb.[c,h] -> gprs_ns.[c,h]
All remaining code in that file is NS protocol related, hence let's
rename it so that we end up with one file per protocol in the Gb stack.

Change-Id: I8312c8a70d60cab48764950c5b57ca02964e9db2
2022-12-28 23:14:20 +01:00
Pau Espin 05d5f28e93 Move some functions gprs_gb.[c,h] -> gprs_gmm.[c,h]
This leaves only NS protocol related code in gprs_gb.[c,h], which will
be renamed to gprs_ns.[c,h] in a follow up patch.

Change-Id: I3dcbe1d0f75cb91ec8b700e239e2ba16fff030a2
2022-12-28 23:12:47 +01:00
Pau Espin 7a74ae492e Create new specific file for BSSGP code
Right now there's no much code there since the related code is totally
entangled with the LLC one.
This will eventually change in the future when we switch to use
libosmo-gprs.
Hence, this commit is a preparation to have already some place to put
new BSSGP specific code in the future.

Change-Id: I816396ab5ccb86032bbc21b41a959934a7768780
2022-12-28 23:11:49 +01:00
Pau Espin 749ca7c850 Move gprs_gb_parse.[c,h] to tests/sgsn/
That big file is really only used by tests/sgsn/sgsn_test nowadays, so
let's keep it out of osmo-sgsn app code base.

Change-Id: Ia5a639832f52b2f015a2800bd0d94a28d7bc689b
2022-12-22 19:49:39 +01:00
Max e7ccfdb4aa ctrl: take both address and port from vty config
Change-Id: Ie1330b152a2e5cdcdb80a1c958e7c1d784b78eab
2022-12-17 21:16:58 +03:00
Oliver Smith e39ff86dd9 osmo-gtphub.cfg: fix conflict with osmo-ggsn.cfg
Change bind-to-ggsns from 127.0.0.2 to 127.0.0.20, so osmo-gtphub's
default config does not confligt with the osmo-ggsn default config. This
change is for the effort of making the configs of all Osmocom programs
not conflict with each other.

A similar change was made in Id892e1f4ab2daabbe9824b819b5fed985373b97a
with bind-to-sgsns.

Related: OS#5817
Change-Id: I57ee457b62139d831707b6ebd6baaea8d33c2d9c
2022-12-08 16:28:32 +01:00
Pau Espin 57b63875c7 sndcp: Put decompress handling code into helper function
This further simplifies code and avoids duplicating it.

Change-Id: Id83f9e4a87139de2b2f64c8523460c186d5b5649
2022-12-06 12:06:26 +01:00
Oliver Smith 55e3dc8ec8 sgsn_libgtp: cb_data_ind: remove mm_idle assert
Log an error message and drop the packet instead of asserting if
mm state fsm is in ST_MM_IDLE while the gmm fsm is in
ST_GMM_REGISTERED_NORMAL.

Fixes: OS#5725
Change-Id: I9dab98917c622b36dae22399bb359d747a598208
2022-11-17 14:08:30 +01:00
Oliver Smith acd967a177 contrib/jenkins.sh: use enable-werror with IU too
Now that the warnings in osmo-iuh have been fixed, we should be able to
build the IU version of OsmoSGSN with --enable-werror too.

Related: OS#4462
Change-Id: I8cc4e209e21acfe513bef72927499f1ccdead783
2022-11-15 13:01:25 +01:00
Pau Espin 8501126031 vty: Make new libgtp tdefs configurable through VTY
Related: OS#5485
Depends: osmo-ggsn.git Change-Id I10bc8e2e197c0e8753b23b684b5ae41025672bf7
Change-Id: I46e9cd158a9f2f721c69f807beb7bb67a459f4a4
2022-11-04 14:27:30 +01:00
Max b43496a60d GMM: permit E_GMM_COMMON_PROC_SUCCESS in normal state
The FSM might be moved out of ST_GMM_COMMON_PROC_INIT state either
by E_GMM_ATTACH_SUCCESS or by E_GMM_COMMON_PROC_SUCCESS events
which are not mutually exclusive. Hence the later event will arrive when we're already in
the ST_GMM_REGISTERED_NORMAL state.

Let's have both events permitted to keep the logs clean from useless error.

Related: OS#5349
Change-Id: Ia97b50aac6c665812ddca9010de7f97b17b78bd5
2022-10-14 15:04:36 +03:00
Max caff83e702 Constify LLC/SNDCP parameters
That makes it easier to track side-effects while reading the code.

Related: OS#5349
Change-Id: I903f8a747a8d3b7f734dac7b0c12373ecbb90b11
2022-10-11 10:54:39 +03:00
Max 61f2186592 GTP: migrate from deprecated function
The gtp_set_cb_recovery3() is similar to gtp_set_cb_recovery2()
with extra parameter representing GSN.

Change-Id: I8b46cf8c52e36b0312eddf37f3e136662b95732e
2022-10-11 10:54:39 +03:00
Max 559636a4a2 SNDCP: log more details on failure
Related: OS#5349
Change-Id: Iad3ebbc28909a827db7b3a0ae2d3e1de7991210f
2022-10-08 20:24:22 +03:00
Vadim Yanitskiy 13ccbc1e61 llc: gprs_llc_fcs(): make the input data pointer const
Change-Id: If95210fe69f915ab1010fe5916cb6bee3faeb7b9
2022-09-08 12:51:54 +00:00
Vadim Yanitskiy d32852664d gprs_llc.h: use '#pragma once'
Change-Id: Iff748fe68dbef83589bfb5e3bea5183deb365fa6
2022-09-08 12:51:43 +00:00
Max 77cdc424cb Set working directory in systemd service file
By default systemd will execute service with root directory (or home directory for user instance) which might result in
attempts to create files in unexpected place. Let's set it to 'osmocom' subdir of state directory (/var/lib for system instance) instead.

Related: OS#4821
Change-Id: I950d84853c6737276d02b3275127b499ae567c38
2022-08-30 19:42:59 +07:00
Vadim Yanitskiy fb6cf3221e gprs_llc: fix misleading spacing in gprs_llc_rcvmsg()
Change-Id: I7ec97a7d9b37f0541887bc13e31f547613f8945e
2022-08-26 05:38:33 +07:00
Vadim Yanitskiy c63a8381e5 configure.ac: do not require unused dlsym/dlopen
Change-Id: I90b383ed45b27d8b59272116dd81acb72912349d
2022-08-16 23:31:22 +07:00
Pau Espin 328ed94040 Bump version: 1.8.0.9-c230-dirty → 1.9.0
Change-Id: If8d3bad88dbd57b620e3aca61d99073e178c2fb6
2022-06-29 11:45:09 +02:00
Harald Welte c230f0c283 README: Major update
* convert to markdown syntax
* bring in-line with other osmo-* README.md files, in terms of
  links to git, mailing list, manuals, etc.

Change-Id: Ia4a4329c6ef6b8c833aa26832776dad662cdc7e9
2022-06-20 10:16:56 +00:00
Harald Welte e2b9b7ee57 update git URLs (git -> https; gitea)
Change-Id: Ib8d2953a6c3f1e65b7c638feea4d8a97ee02e443
2022-06-20 10:15:50 +00:00
Vadim Yanitskiy 199f295d36 tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
When using 'check_PROGRAMS', autoconf/automake generates smarter
Makefiles, so that the test programs are not being compiled during
the normal 'make all', but only during 'make check'.

Change-Id: I8118ee3d3da9bdcd0c691471ef91b95dba21004a
2022-04-13 19:55:36 +03:00
Neels Hofmeyr 3c7656a481 Iu: add UEA encryption
Add vty 'encryption uea 0 1 2', defaults to 'encryption uea 0' to yield
previous behavior.

If any UEA above 0 is enabled, include the UEA key in the Iu Security
Mode Command.

I noticed that only the code bit in st_iu_security_cmd_on_enter()
affects the test. The same code in gsm48_gmm_authorize() seems to be
dead code? But applying the patch there as well just to be safe.

We cannot yet verify the chosen UEA to match a configured UEA level,
because the iu_client.c does not send us message details with the
RANAP_IU_EVENT_SECURITY_MODE_COMPLETE.
Also we cannot yet send the set of configured UEA to the hNodeB, since,
again, iu_client.c does not provide the proper API for it.
The proper solution here is to completely dissolve iu_client.c and do
all Iu handling in osmo-sgsn itself -- see OS#5487.

Related: SYS#5516
Related: I1a7c3b156830058c43f15f55883ea301d2d01d5f (osmo-ttcn3-hacks)
Change-Id: I27e8e0078c45426bf227bb44aac82a4875d18d0f
2022-03-10 19:07:38 +01:00
Neels Hofmeyr 340a7e9339 s/cipher_support_mask/gea_encryption_mask
will add uea_encryption_mask, and find that the name
'cipher_support_mask' is not concise enough.

Related: SYS#5516
Change-Id: Ie8d4a0534c5b751f698bce425427bb1d28ddea31
2022-03-07 15:37:26 +01:00
Pau Espin 938ebfb129 Revert "sgsn: Handle different levels of QoS"
This reverts commit 4bd931f96d.

The commit was wrong, and previous code is correct.
Relevant specs:
* TS 29.060 7.7.34 Quality of Service (QoS) Profile
* TS 24.008 10.5.6.5 Quality of service

As can be seen in TS 24.008 10.5.6.5, OSMO_IE_GSM_REQ_QOS never comes
with the the ARP byte prepended. This is actually always prepended when
sending the GTP message, as explained in TS 29.060 7.7.34.

As a result, the Qos Service sent in Create PDP Context Request sent to
the GGSN contained wrongly formatted Qos Profile IE, which was observed
checking wireshark with a real phone. This was found due to open5gs-smfd
being more strict about the possible lengths of the IE, since the
wrongly formatted IE send in GTP had length=14, which is incorrect due
to folllowing TS 24.008 10.5.6.5 wording:
"Octets 15-22 are optional. If octet 15 is included, then octet 16 shall also be included, and octets 17-22may be
included."
In this case, due to the wrong format it was seen as including octet 15
but not 16.

Change-Id: I4fc5ab823a27d27482858a7459337a2f8ae593c3
Related: SYS#5793
2022-02-18 17:26:14 +01:00
Pau Espin d06c717e30 Drop unneeded ax_check_compile_flag.m4
The macro is no longer used since 2d0e22960c.

Change-Id: I230005acc27e29c679a4ddbb2b316a3aae70874e
2022-01-11 18:13:46 +01:00
Oliver Smith 57425a3805 treewide: remove FSF address
Remove the paragraph about writing to the Free Software Foundation's
mailing address. The FSF has changed addresses in the past, and may do
so again. In 2021 this is not useful, let's rather have a bit less
boilerplate at the start of source files.

Change-Id: I9bc57a7152015e0f37e3d1573921d6d5d3c0449b
2021-12-14 12:21:06 +01:00
Oliver Smith f76428500a llme_free: clean up related sndcp
Fix crash in vty_dump_sne when sndcp->lle has already been deallocated.

Context:
* sndcp->lle is set only once in gprs_sndcp_entity_alloc()
* sndcp->lle is a struct gprs_llc_lle, which gets allocated and
  deallocated together with struct gprs_llc_llme. From gprs_llc.h:

    struct gprs_llc_llme {
            ...
            struct gprs_llc_lle lle[NUM_SAPIS];

Fixes: OS#4824
Change-Id: I707029f78222bc6335837241e5a08c54c5ae6eb3
2021-12-07 17:13:12 +01:00
Pau Espin 0f9966e307 Bump version: 1.7.0.28-245ac-dirty → 1.8.0
Change-Id: I62daba59b9dd1a0cade5292c8705ee5ec5b103c2
2021-11-16 17:57:50 +01:00
Vadim Yanitskiy 245ac9501b tests/Makefile.am: do not try removing non-existing files
Change-Id: Ie9f4a9aa4061e4e4c659b1ad71596846ce75df7b
2021-11-15 04:39:57 +03:00
Oliver Smith 2d0e22960c Revert "Turn some compiler warnings into errors"
Do not turn some compiler warnings into errors by default. This patch
was added before --enable-werror was available.

We build with --enable-werror during development and in CI. If the code
is built with a different compiler that throws additional warnings, it
should not stop the build.

This reverts commit 34f012639d.

Related: OS#5289
Change-Id: I24e0a0d7f93f196dc642e37b03f68464024c09d4
2021-11-04 10:55:57 +01:00
Keith Whyte 6cee1a1ded VTY: Don't display 'PDP Address: invalid' for IPv4v6
We were not handling the case of PDP_TYPE_N_IETF_IPv4v6
in gprs_pdpaddr2str() and showed "invalid" for these addresses.

Depends: libosmocore Change-Id: I1f82f9d8fc13dcc4474760329bd74ae9685b9031
Change-Id: Id36b7520677e4a0af40d05dc503b26d1b0b74a26
2021-09-30 20:45:19 +02:00
Oliver Smith c0e146467a debian/control: remove dh-systemd build-depend
Related: OS#5223
Change-Id: I769bf61a2f3a97d55c65999436d2cb079c9170a0
2021-09-01 16:07:07 +02:00
Oliver Smith ab39b622cc vty: add "page imsi"
Make it easy to manually test pagings from SGSN to the PCU.

Related: SYS#4878
Change-Id: I8a73caa234f6b841e641be866e22e7fa03152eb7
2021-08-06 22:25:10 +02:00
Oliver Smith 3aba7ad2ae gtphub: remove llist_first, llist_last macros
Use list_first_entry_or_null instead of llist_first, which has been
present in libosmocore since the 0.10.0 release.

Use llist_last_entry instead of llist_last (also present since
libosmocore 0.10.0). This macro does not have a check for an empty
list, however the only user is already checking for an empty list
before using the macro.

This solves a build error, as llist_last was defined in libosmocore
Icf455bf6ba9d60bd311af17c9e80febaa42cacc9 (should probably be reverted
for backwards compatibility with previous osmo-sgsn versions?):

gtphub.c:68:0: error: "llist_last" redefined [-Werror]
 #define llist_last(head, type, entry) \

In file included from /build/deps/install/stow/libosmocore/include/osmocom/core/timer.h:46:0,
                 from /build/deps/install/stow/osmo-ggsn/include/gtp.h:17,
                 from gtphub.c:32:
/build/deps/install/stow/libosmocore/include/osmocom/core/linuxlist.h:245:0: note: this is the location of the previous definition
 #define llist_last(head) (head)->prev

Change-Id: Ia0496c24386cd13b1e9e604aa2d425d3fa28d352
2021-07-12 12:20:52 +02:00
Vadim Yanitskiy e9336a72a0 doc/manuals: update configuration.adoc to use new command syntax
The old command is deprecated since [1] has been merged.

Change-Id: Iac985f373de98206fdfb3196295ebec160189780
Related: [1] Ie6700c4e9d2df1eb5fde1b971e287b62668cc2de
Related: SYS#5324
2021-07-03 21:07:43 +02:00
Eric Wild 2f898265d0 add support for multiple encryption algorithms and a5/4
Change-Id: Ie6700c4e9d2df1eb5fde1b971e287b62668cc2de
Related: SYS#5324
2021-06-16 16:43:23 +02:00
Pau Espin a33f00637e Use new stat item/ctr getter APIs
Generated with spatch:
"""
@@
expression E1, E2;
@@
- &E2->ctr[E1]
+ rate_ctr_group_get_ctr(E2, E1)
"""

Change-Id: I2e064883ac6dafa89e41a297a886a9ebd26ce925
2021-06-04 17:27:05 +02:00
Keith Whyte c12c1a6b0c vty: Fix optional display of pdp with mm-context
The vty is randomly including the pdp context when the vty
command 'show mm-context all' is issued without the pdp
parameter.
I do not know why, but I assume that relying on a true/false
test of argv[0] has unpredictable results.

Change-Id: Idcde4dd30a39625b24a1c3a38901349875e0949a
2021-05-20 04:41:22 +02:00
Pau Espin e5c8998f9c Support forwarding RIM messages over GTPCv1 EUTRAN<->GERAN
MMEs connect over Gn interface using GTPCv1 towards the SGSN in order to
exchange RIM PDUs by using "RAN Information Relay" GTPCv1 message type.
For more info, see 3GPP TS 29.060 sec 7.5.14.1 "RAN Information Relay"

In order to support it, this commit does the following:

* Uses new libgtp APIs to rx and tx RAN Information Relay messages. The
  same "gsn" object is reused, ie. the local GTPCv1 socket address used
  for exchanging messages against GGSN is reused.
* Adds a new "sgsn_mme_ctx" struct holding information about MMEs
  allowed by the SGSN, each one containing information about the GTP
  address it uses, the in/out routing based on TAI requests, etc. The
  set of MMEs and their config can be set up using new VTY node introduced
  in this commit.
* The RIM related code in SGSN is refactored to allow forwarding from
  and to several types of addresses/interfaces.

Depends: osmo-ggsn.git Change-Id Iea3eb032ccd4aed5187baca7f7719349d76039d4
Depends: libosmocore.git Change-Id I534db7d8bc5ceb19a2a6866f07d5f5c70e456c5c
Related: SYS#5314
Change-Id: I396450b8d8b66595dab8ff7bf41cbf964bb40d93
2021-05-19 11:45:05 +02:00
Pau Espin 8969db7a49 gtp: Delete ctx upon receive UpdateCtxResp with cause Non-existent
Related: SYS#5435
Change-Id: Ic5f682a79663acc65fd364dd7a3a7cc554534414
2021-05-08 09:00:45 +00:00
Pau Espin 0b0b59a8ff Drop unused GBRPOXY enum field
Change-Id: I85dbc65addfbb072a75b6f62fcc4306b7fbb6a91
2021-05-03 18:19:23 +02:00
Pau Espin 888052e71c mm_state_{gb,iu}_fsm: Improve naming for detach event
The E_(P)MM_IMPLICIT_DETACH event was actually sent and handled when the
UE was considered to be detached, no matter the reason, be it due to
implicit detach, or Detach Request received, etc.
So, let's properly name the event to avoid confusions in the code.

Related: SYS#5389
Change-Id: I224ea9db80b4d96696934cea06349dab036f919b
2021-04-14 13:27:36 +02:00
Pau Espin 913dbcd552 mm_state_{gb,iu}_fsm: Add missing license block, improve spec references
Change-Id: Ifcfd9c11005a388220c599e7b2f6901175141f1c
2021-04-14 13:18:31 +02:00
Pau Espin 922684f318 gprs_ranap.c: Clean up code path releasing IU conn
Let's always send the event to the FSM and keep logic of whether it's a
good event to sent or not inside the FSM, not in the caller.
The logic is kept the same: if the event is not expected (not handled),
keep forcing free of the IU connection.
In theory this should never happen since only a PMM in Connected state
should have a established connection (hence only a PMM in Connected
state can have it released). In any case let's keep the safety check,
but let the FSM receive the event and log an error about unexpected
event, which is more interesting from debug point of view.

While at it, clean up the related logging line: There's no need to print
the imsi explicitly, since LOGMMCTXP already does it. Furthermore, print
the exact low level event which triggered the code path.

Related: SYS#5389
Change-Id: I45017562ea7f27c2248b7de56f99ce7ca88e89b2
2021-04-14 12:42:02 +02:00
Pau Espin 3caa7f6d97 Iu: Drop timer X3314
This Iu timer is Osmocom specific, but is made to resemble T3314
timer from GERAN (also named READY timer).

The idea of this activity timer was to arm it whenever PMM state
transitions to CONNECTED, and then rearm it every time there's some
sort of activity, until there's none for some time, then we send a
Release Command to close the conn with the HNGBW/RNC. That's the
same principle as per spec-defined READY timer T3314.

However, there's still a fundamental problem with it: GTP-U in
GERAN passes through the SGSN, but in UTRAN, the GTP-U stream
goes directly from the HnodeB to the GGSN. Hence, there's no proper
way to re-arm this timer upon activity in UTRAN, basically because
the SGSN will never see (userplane data) activity. That explains why
the E_MM_PDU_RECEPTION event exists for mm_state_gb_fsm, but doesn't
exist for mm_state_iu_fsm.
As a result, the timer is currently never rearmed, which means it
will transition to IDLE always after 44 seconds (default value) once
it went into CONNECTED state.

In UTRAN, there is a SCCP connection for each subscriber between
RNC/hNB and SGSN. If the subscriber is no longer in the respective
state, the RNC/hNB should release that IuPS SCCP connection, whcih
in turn means the SGSN cleans up its state.
Furthermore, SCCP has a built-in IT (inactivity timer). So should
the RNC/hNB die, that timer would time out, and the SGSN-side local
SCCP stack (provider) wold send a RELEASE.ind for that connection
to the user (SGSN).

TLDR; this timer is not really needed and cannot be implemented
properly in UTRAN, so let's remove it.

Related: OS#5116
Change-Id: Ibc71829e417bf2dd0c27deb842369dd4f17010d6
2021-04-14 12:14:52 +02:00
Pau Espin 223754fde5 mm_state_iu_fsm: T3314 expiry must lead to PMM IDLE, not PMM DETACHED
This Iu timer is Osmocom specific, but is made to resemble T3314 timer
from GERAN (also named READY timer). The READY timer mission is to make
the MM state transition from READY to STANDBY, which in PMM (UTRAN)
matches the transition from CONNECTED to IDLE.
Instead, the patch introducing the timer was making it transition to
DETACHED directly, but this was clearly not the intention:
* Detaching a UE after 44 seconds (default value for T3314) is overkill.
* The comment describing it says: "Iu User inactivity timer. On expiry
  release Iu connection". The release of Iu connection happens during
  the CONNECTED->IDLE transition (that's basically the difference between
  both states).

The transition CONNECTED->IDLE is done by means of calling
sgsn_ranap_iu_release_free(), which will eventually answer with a event
RANAP_IU_EVENT_IU_RELEASE from lower layers when the Release Complete is
received. At that point, osmo-sgsn code frees the connection and
transitions to IDLE state. This way we maintain the state according to
the connection existance.

Related: SYS#5389
Related: osmo-iuh.git Change-Id Iac822c74e56750dc40e94573eae0e20853ff68c0
Fixes: 3bad31bcb4
Change-Id: I7279102ad51b0c39eb6d04c129986984112d15cc
2021-04-13 20:36:06 +02:00
Pau Espin f025e582bb gprs_gmm.c: State proper GMM prefix logging rx/tx of GMM messages
Change-Id: I58af41acdc4a04870b4cf2ea34a272d46d896254
2021-04-13 11:58:59 +02:00
Pau Espin e8cd6856a5 mm_iu: Expect E_PMM_PS_ATTACH when in ST_PMM_IDLE
It can happen that the MS tries to attach while SGSN's MM Iu state is
ST_PMM_IDLE (eg because UE was hard rebooted). Since Attach is a
specific case of getting a Connection Established, also allow it as a
trigger to transit to state ST_PMM_CONNECTED.

Related: SYS#5389
Change-Id: Ia74a062ddc3052faad569f1428f0ddd02e5b188d
2021-03-25 17:58:07 +01:00
Pau Espin c67c90b47e mm_iu: Send event E_PMM_PS_CONN_ESTABLISH upon rx GMM SERVICE REQUEST
Attach event should only be triggered by rx Attach Request, not other
messages. Furthermore, currently E_PMM_PS_CONN_ESTABLISH is defined and
expected in FSM but not sent by anyone.
Also, The opposite transition is done by E_PMM_PS_CONN_RELEASE:

"""
MM_STATE_Iu(0)[0x81379b0]{Connected}: Received Event E_PMM_PS_CONN_RELEASE
MM_STATE_Iu(0)[0x81379b0]{Connected}: state_chg to Idle
...
MM(001010123456063/c8b8bd08) -> GMM SERVICE REQUEST MI(3367550216) type="signalling"
MM_STATE_Iu(0)[0x81379b0]{Idle}: Received Event E_PMM_PS_ATTACH
MM_STATE_Iu(0)[0x81379b0]{Idle}: Event E_PMM_PS_ATTACH not permitted
"""

Related: SYS#5389
Change-Id: Ica00891f91834522f4dea2508b62af34e4c4eca7
2021-03-25 17:58:03 +01:00
Pau Espin c26072a77f gmm_fsm: Expect E_GMM_COMMON_PROC_INIT_REQ when in ST_GMM_COMMON_PROC_INIT
Due to whatever errors, the MS may re-init the Common Procedure by
retransmitting a GPRS Attach Request while we are for instance aiting
for Identity to be resolved.

See this log:
MM(---/ffffffff) -> GMM ATTACH REQUEST MI(3903513414) type="GPRS attach"
GMM(gmm_fsm)[0x8136110]{Deregistered}: Allocated
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x81383c0]{Init}: Allocated
MM_STATE_Gb[0x8138ac0]{Idle}: Allocated
MM_STATE_Iu[0x8138bb0]{Detached}: Allocated
GMM(gmm_fsm)[0x8136110]{Deregistered}: Received Event E_GMM_COMMON_PROC_INIT_REQ
GMM(gmm_fsm)[0x8136110]{Deregistered}: state_chg to CommonProcedureInitiated
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x81383c0]{Init}: Received Event E_ATTACH_REQ_RECV
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x81383c0]{Init}: state_chg to CheckIdentity
MM(/fba673a2) <- GPRS IDENTITY REQUEST: mi_type=IMEI
UE(0x2){001-01-10422-99} Received GSM 04.08 message type 0x16, but no MM context available
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x81383c0]{CheckIdentity}: Timeout of T3370
MM(/fba673a2) <- GPRS IDENTITY REQUEST: mi_type=IMEI
[Failure to handle GSM48_MT_GMM_ID_RESP and subsequent retransmission of GPRS IDENTITY REQUEST happens a couple times here]
MM(---/ffffffff) -> GMM ATTACH REQUEST MI(3903513414) type="GPRS attach"
GMM(gmm_fsm)[0x8136110]{CommonProcedureInitiated}: Received Event E_GMM_COMMON_PROC_INIT_REQ
GMM(gmm_fsm)[0x8136110]{CommonProcedureInitiated}: Event E_GMM_COMMON_PROC_INIT_REQ not permitted
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x81383c0]{CheckIdentity}: Received Event E_ATTACH_REQ_RECV
[Here IDENTITY REQUEST is sent again, and this time MS answers ID RESPONSE back and goes forward]

Related: SYS#5389
Change-Id: I93d7d6bc694c84223a11d075d24c234b82b73389
2021-03-25 16:57:24 +01:00
Pau Espin ce0a0e9beb gmm: Expect E_VLR_ANSWERED when in ST_IU_SECURITY_CMD
GSUP message is sent immediately before moving onto state
ST_IU_SECURITY_CMD, so it's expected to receive a response for it, which
will trigger event E_VLR_ANSWERED being sent.
See following log showing the scenario:

"""
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x8137b88]{Authenticate}: Received Event E_AUTH_RESP_RECV_SUCCESS
MM(001010123456789/f8bab3dc) Requesting authorization
MM(001010123456789/f8bab3dc) Missing information, requesting subscriber data
MM(001010123456789/f8bab3dc) Requesting subscriber data update
SUBSCR(001010123456789) subscriber data is not available
SUBSCR(001010123456789) Sending GSUP, will send: 04 01 08 00 01 01 21 43 65 60 f3 28 01 01
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x8137b88]{Authenticate}: state_chg to IuSecurityCommand
SUBSCR(001010123456789) Received GSUP message OSMO_GSUP_MSGT_INSERT_DATA_REQUEST
SUBSCR(001010123456789) Will set PDP info, context id = 1, APN = 01 2a
SUBSCR(001010123456789) Updating subscriber data
MM(001010123456789/f8bab3dc) Subscriber data update
MM(001010123456789/f8bab3dc) Updating authorization (authenticate -> accepted)
MM(001010123456789/f8bab3dc) Got authorization update: state authenticate -> accepted
MM(001010123456789/f8bab3dc) Authorized, continuing procedure, IMSI=001010123456789
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x8137b88]{IuSecurityCommand}: Received Event E_VLR_ANSWERED
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x8137b88]{IuSecurityCommand}: Event E_VLR_ANSWERED not permitted
SUBSCR(001010123456789) Sending GSUP, will send: 12 01 08 00 01 01 21 43 65 60 f3 28 01 01
SUBSCR(001010123456789) Received GSUP message OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT
SUBSCR(001010123456789) Updating subscriber data
MM(001010123456789/f8bab3dc) Subscriber data update
MM(001010123456789/f8bab3dc) Updating authorization (accepted -> accepted)
sccp_sap_up(N-DATA.indication)
N-DATA.ind(2, 20 06 00 08 00 00 01 00 06 00 01 00 )
handle_co(dir=2, proc=6)
Transmitting RANAP CommonID (SCCP conn_id 2)
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x8137b88]{IuSecurityCommand}: Received Event E_IU_SECURITY_CMD_COMPLETE
GMM_ATTACH_REQ_FSM(gb_gmm_req)[0x8137b88]{IuSecurityCommand}: state_chg to WaitAttachComplete
"""

Related: SYS#5389
Change-Id: If348ff32faa4a709b59ee1b9b043883a7d46cf93
2021-03-25 16:35:07 +01:00
Pau Espin c8ace5a03c gmm: log GMM msg type name instead of number
Change-Id: I2dc6eb5bfb0f44caf2687e582d660f71fdd647a2
2021-03-25 16:03:05 +01:00
Pau Espin 183e6c3367 ranap: log ranap iu event type name instead of number
Change-Id: If66e9d5989b46abe01855a5c1183d567d358abeb
2021-03-25 15:54:45 +01:00
Vadim Yanitskiy 8de4be261d main: resurrect removed 'ns' logging category as deprecated
This logging category has been removed completely in [1], and now
osmo-sgsn fails to start with old configuration files:

  There is no such command.
  Error occurred during reading the below line:
   logging level ns info

Let's accept it and print a deprecation warning.

Change-Id: I2036170af41db89484c299e18e0b703c97427dc1
Fixes: [1] Ia4723ab344ad6a1927029a2d5d0dda020266b39d
2021-03-14 20:59:08 +01:00
Daniel Willmann 6fd19da165 manuals: Regenerate counters/VTY through docker
Change-Id: I09b01d2e4bc7b1c17588100b16ac9f04cf72cf99
2021-03-12 07:27:24 +00:00
Harald Welte adcf97d095 Remove bogus DNS log category
When we switched to the libosmogb NS2 implementation, we should have
removed the DNS category, as NS2 uses DLNS internally and hence DNS
is unused.

Change-Id: Ia4723ab344ad6a1927029a2d5d0dda020266b39d
Closes: OS#5058
2021-03-10 12:30:05 +00:00
110 changed files with 3345 additions and 1898 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
open_collective: osmocom

4
.gitignore vendored
View File

@ -6,8 +6,8 @@ debian/*.log
.deps
Makefile
Makefile.in
bscconfig.h
bscconfig.h.in
config.h
config.h.in
*.*~
*.sw?
.libs

View File

@ -19,7 +19,7 @@ SUBDIRS = \
BUILT_SOURCES = $(top_srcdir)/.version
EXTRA_DIST = \
.version \
contrib/osmo-sgsn.spec.in \
README.md \
debian \
git-version-gen \
osmoappdesc.py \

17
README
View File

@ -1,17 +0,0 @@
About OsmoSGSN
==============
OsmoSGSN originated from the OpenBSC project, as a separate program within
openbsc.git. In 2017, OpenBSC was split in separate repositories, and hence
OsmoSGSN was given its own separate git repository.
OsmoSGSN exposes
- GSUP towards OsmoHLR (or a MAP proxy);
- GTP towards a GGSN (e.g. OsmoGGSN);
- Gb towards a BSS (e.g. OsmoPCU);
- IuPS towards an RNC or HNB-GW (e.g. OsmoHNBGW) for 3G data;
- The Osmocom typical telnet VTY and CTRL interfaces.
Find OsmoSGSN issue tracker and wiki online at
https://osmocom.org/projects/osmosgsn
https://osmocom.org/projects/osmosgsn/wiki

100
README.md Normal file
View File

@ -0,0 +1,100 @@
osmo-sgsn - Osmocom SGSN Implementation
=======================================
This repository contains a C-language implementation of a *Serving GPRS
Support Node (SGSN)* for 2.5/2.75G (GPRS/EDGE) and 3G (UMTS). It is part of the
[Osmocom](https://osmocom.org/) Open Source Mobile Communications
project.
OsmoSGSN exposes
* *Gb* towards PCUs (e.g. [OsmoPCU](https://osmocom.org/projects/osmopcu/wiki/OsmoPCU)): Various GbIP flavors + Gb/FR/E1
* *GTP* towards a GGSN (e.g. [OsmoGGSN](https://osmocom.org/projects/openggsn/wiki))
* IuPS over IP towards RNCs / HNBGW (e.g. [osmo-hnbgw](https://osmocom.org/projects/osmohnbgw/wiki))
* The Osmocom typical telnet *VTY* and *CTRL* interfaces.
* The Osmocom typical *statsd* exporter.
* GSUP (custom MAP-like protocol) towards [osmo-hlr](https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR)
OsmoSGSN implements
* GPRS mobility management
* GPRS session management
Homepage
--------
You can find the OsmoSGSN homepage online at <https://osmocom.org/projects/osmosgsn/wiki>.
GIT Repository
--------------
You can clone from the official osmo-sgsn.git repository using
git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn>
Documentation
-------------
User Manuals and VTY reference manuals are [optionally] built in PDF form
as part of the build process.
Pre-rendered PDF version of the current "master" can be found at
[User Manual](https://ftp.osmocom.org/docs/latest/osmosgsn-usermanual.pdf)
as well as the [VTY Reference Manual](https://ftp.osmocom.org/docs/latest/osmosgsn-vty-reference.pdf)
Forum
-----
We welcome any osmo-sgsn related discussions in the
[Cellular Network Infratructure -> 2G/3G Core Network](https://discourse.osmocom.org/c/cni/2g-3g-cn).
section of the osmocom discourse (web based Forum).
Mailing List
------------
Discussions related to osmo-sgsn are happening on the
osmocom-net-gprs@lists.osmocom.org mailing list, please see
<https://lists.osmocom.org/postorius/lists/osmocom-net-gprs.lists.osmocom.org/> for subscription
options and the list archive.
Please observe the [Osmocom Mailing List
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
when posting.
Issue Tracker
-------------
We use the [issue tracker of the osmo-sgsn project on osmocom.org](https://osmocom.org/projects/osmosgsn/issues) for
tracking the state of bug reports and feature requests. Feel free to submit any issues you may find, or help
us out by resolving existing issues.
Contributing
------------
Our coding standards are described at
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
We us a gerrit based patch submission/review process for managing
contributions. Please see
<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
more details
The current patch queue for osmo-sgsn can be seen at
<https://gerrit.osmocom.org/#/q/project:osmo-sgsn+status:open>
History
-------
OsmoSGSN originated from the OpenBSC project, as a separate program within
openbsc.git. In 2017, OpenBSC was split in separate repositories, and hence
OsmoSGSN was given its own separate git repository.

View File

@ -1,6 +1,6 @@
To run the configuration parsing and output (VTY) test suite, first install
git://git.osmocom.org/python/osmo-python-tests
https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests
and pass the following configure options here:

View File

@ -1 +1,2 @@
#component what description / commit summary line
libosmocore > 1.9.0 gsup.h: Using new fields in struct osmo_gsup_pdp_info (ABI break)

View File

@ -34,45 +34,32 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
fi
PKG_PROG_PKG_CONFIG([0.20])
dnl check for AX_CHECK_COMPILE_FLAG
m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
])
dnl use a defined standard across all builds and don't depend on compiler default
CFLAGS="$CFLAGS -std=gnu11"
dnl checks for libraries
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DLSYM)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.4.0)
PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.7.0)
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.11.0)
# Enable/disable 3G aka IuPS + IuCS support?
AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS and IuCS interfaces])],
[osmo_ac_iu="$enableval"],[osmo_ac_iu="no"])
if test "x$osmo_ac_iu" = "xyes" ; then
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.4.0)
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.8.0)
PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.30)
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.7.0)
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 1.5.0)
AC_DEFINE(BUILD_IU, 1, [Define if we want to build IuPS and IuCS interfaces support])
fi
AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")
AC_SUBST(osmo_ac_iu)
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.7.0)
PKG_CHECK_MODULES(LIBCARES, libcares)
dnl checks for header files
@ -124,13 +111,6 @@ AC_SUBST(SYMBOL_VISIBILITY)
CPPFLAGS="$CPPFLAGS -Wall -Wno-trigraphs"
CFLAGS="$CFLAGS -Wall -Wno-trigraphs"
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([-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"])
# Coverage build taken from WebKit's configure.in
AC_MSG_CHECKING([whether to enable code coverage support])
AC_ARG_ENABLE(coverage,
@ -181,7 +161,7 @@ if test "x$enable_ext_tests" = "xyes" ; then
fi
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.])
AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
fi
fi
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
@ -250,11 +230,12 @@ AC_MSG_RESULT([CFLAGS="$CFLAGS"])
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
dnl Generate the output
AM_CONFIG_HEADER(bscconfig.h)
AM_CONFIG_HEADER(config.h)
AC_OUTPUT(
include/Makefile
include/osmocom/Makefile
include/osmocom/gtphub/Makefile
include/osmocom/sgsn/Makefile
src/Makefile
src/gprs/Makefile
@ -274,5 +255,4 @@ AC_OUTPUT(
doc/manuals/Makefile
contrib/Makefile
contrib/systemd/Makefile
contrib/osmo-sgsn.spec
Makefile)

View File

@ -37,14 +37,11 @@ osmo-build-dep.sh libosmo-netif
osmo-build-dep.sh osmo-ggsn
osmo-build-dep.sh osmo-hlr
enable_werror=""
if [ "x$IU" = "x--enable-iu" ]; then
osmo-build-dep.sh libosmo-sccp
osmo-build-dep.sh libasn1c
#osmo-build-dep.sh asn1c aper-prefix # only needed for make regen in osmo-iuh
osmo-build-dep.sh osmo-iuh
else
enable_werror="--enable-werror"
fi
# Additional configure options and depends
@ -63,12 +60,12 @@ set -x
cd "$base"
autoreconf --install --force
./configure --enable-sanitize $enable_werror $IU --enable-external-tests $CONFIG
./configure --enable-sanitize --enable-werror $IU --enable-external-tests $CONFIG
$MAKE $PARALLEL_MAKE
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|| cat-testlogs.sh
LD_LIBRARY_PATH="$inst/lib" \
DISTCHECK_CONFIGURE_FLAGS="$enable_werror $IU --enable-external-tests $CONFIG" \
DISTCHECK_CONFIGURE_FLAGS="--enable-werror $IU --enable-external-tests $CONFIG" \
$MAKE $PARALLEL_MAKE distcheck \
|| cat-testlogs.sh

View File

@ -1,118 +0,0 @@
#
# spec file for package osmo-sgsn
#
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
## Disable LTO for now since it breaks compilation of the tests
## https://osmocom.org/issues/4116
%define _lto_cflags %{nil}
%define with_iu 1
Name: osmo-sgsn
Version: @VERSION@
Release: 0
Summary: Osmocom's SGSN for 2G and 3G packet-switched mobile networks
License: AGPL-3.0-or-later AND GPL-2.0-or-later
Group: Productivity/Telephony/Servers
URL: https://osmocom.org/projects/osmosgsn
Source: %{name}-%{version}.tar.xz
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: pkgconfig
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libcares)
BuildRequires: pkgconfig(libcrypto) >= 0.9.5
BuildRequires: pkgconfig(libgtp) >= 1.7.0
BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.3.0
BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
BuildRequires: pkgconfig(libosmoabis) >= 1.1.0
BuildRequires: pkgconfig(libosmocore) >= 1.5.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0
BuildRequires: pkgconfig(libosmogb) >= 1.5.0
BuildRequires: pkgconfig(libosmogsm) >= 1.5.0
BuildRequires: pkgconfig(libosmovty) >= 1.5.0
%{?systemd_requires}
%if %{with_iu}
BuildRequires: pkgconfig(libasn1c)
BuildRequires: pkgconfig(libosmo-ranap) >= 0.7.0
BuildRequires: pkgconfig(libosmo-sigtran) >= 1.4.0
%endif
%description
OsmoSGSN is Osmocom's Serving GPRS Support Node for 2G and 3G
packet-switched mobile networks.
%package -n osmo-gtphub
Summary: Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs
Group: Productivity/Telephony/Servers
%description -n osmo-gtphub
Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs.
%prep
%setup -q
%build
echo "%{version}" >.tarball-version
autoreconf -fi
%configure \
%if %{with_iu}
--enable-iu \
%endif
--docdir=%{_docdir}/%{name} \
--with-systemdsystemunitdir=%{_unitdir}
make %{?_smp_mflags}
%install
%make_install
%if 0%{?suse_version}
%preun %service_del_preun %{name}.service
%postun %service_del_postun %{name}.service
%pre %service_add_pre %{name}.service
%post %service_add_post %{name}.service
%preun -n osmo-gtphub %service_del_preun osmo-gtphub.service
%postun -n osmo-gtphub %service_del_postun osmo-gtphub.service
%pre -n osmo-gtphub %service_add_pre osmo-gtphub.service
%post -n osmo-gtphub %service_add_post osmo-gtphub.service
%endif
%check
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%files
%doc AUTHORS README
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-sgsn
%exclude %{_docdir}/%{name}/examples/osmo-gtphub
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn.cfg
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
%{_bindir}/osmo-sgsn
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-sgsn.cfg
%{_unitdir}/%{name}.service
%files -n osmo-gtphub
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-gtphub
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub.cfg
%{_bindir}/osmo-gtphub
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-gtphub.cfg
%{_unitdir}/osmo-gtphub.service
%changelog

View File

@ -1,9 +1,15 @@
[Unit]
Description=Osmocom GTP Hub
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=osmocom
Group=osmocom
ExecStart=/usr/bin/osmo-gtphub -c /etc/osmocom/osmo-gtphub.cfg
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
Restart=always
RestartSec=2
RestartPreventExitStatus=1

View File

@ -3,10 +3,16 @@ Description=Osmocom SGSN (Serving GPRS Support Node)
Wants=osmo-hlr.service
After=osmo-hlr.service
After=osmo-hnbgw.service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
Restart=always
User=osmocom
Group=osmocom
ExecStart=/usr/bin/osmo-sgsn -c /etc/osmocom/osmo-sgsn.cfg
RestartSec=2

180
debian/changelog vendored
View File

@ -1,3 +1,183 @@
osmo-sgsn (1.11.1) unstable; urgency=medium
[ Philipp Maier ]
* sgsn_rim: forward message based on RIM ROUTING ADDRESS
[ Daniel Willmann ]
* sgsn_vty: Fix output in config_write_sgsn
* sgsn_vty: Correctly indent encryption cipher-plugin-path
* vty-tests: Test encryption options
* libgtp: Check for all successful create_pdp_conf causes
-- Oliver Smith <osmith@sysmocom.de> Tue, 28 Nov 2023 13:32:46 +0100
osmo-sgsn (1.11.0) unstable; urgency=medium
[ Oliver Smith ]
* Run struct_endianness.py
* debian: set compat level to 10
* systemd: depend on networking-online.target
[ arehbein ]
* Transition to use of 'telnet_init_default'
[ Vadim Yanitskiy ]
* tests: use -no-install libtool flag to avoid ./lt-* scripts
* tests: $(BUILT_SOURCES) is not defined, depend on osmo-sgsn
* copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH
[ Pau Espin Pedrol ]
* gmm: Ciphering Key Sequence Number IE has half octet tag
* gprs_sm.c: Fix load of misaligned ptr address
* Write explicit role & sctp-role fields in ASP configurations
* gmm: Update DRX params during rx RAU REQ
* gmm: Add missing GSM48_IE_GMM_RX_NPDU_NUM_LIST IE in gsm48_gmm_att_tlvdef
[ Philipp Maier ]
* sgsn_rim: fix typo
* sgsn_rim: cosmetic: improve comment
* sgsn_rim: get rid of MME check in sgsn_rim_rx_from_gtp:
* sgsn_rim: do not check the origin of a RIM message
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 16:57:02 +0200
osmo-sgsn (1.10.0) unstable; urgency=medium
[ Vadim Yanitskiy ]
* configure.ac: do not require unused dlsym/dlopen
* gprs_llc: fix misleading spacing in gprs_llc_rcvmsg()
* gprs_llc.h: use '#pragma once'
* llc: gprs_llc_fcs(): make the input data pointer const
[ Max ]
* Set working directory in systemd service file
* SNDCP: log more details on failure
* GTP: migrate from deprecated function
* Constify LLC/SNDCP parameters
* GMM: permit E_GMM_COMMON_PROC_SUCCESS in normal state
* ctrl: take both address and port from vty config
[ Pau Espin Pedrol ]
* vty: Make new libgtp tdefs configurable through VTY
* sndcp: Put decompress handling code into helper function
* Move gprs_gb_parse.[c,h] to tests/sgsn/
* Create new specific file for BSSGP code
* Move some functions gprs_gb.[c,h] -> gprs_gmm.[c,h]
* Rename gprs_gb.[c,h] -> gprs_ns.[c,h]
* Move gprs_tmr_to_secs() to tests/gprs/gprs_test.c
* cosmetic: gprs_llc_vty.c: Fix trailing whitespace
* vty: Fix wrong value_string used to print llme state
* Standarize lle and llme state enum & value_string
* Remove unused function gprs_parse_mi_tmsi()
* Replace gprs_str_to_apn() with libosmocore API osmo_apn_from_str()
* Move struct sgsn_ggsn_ctx to its own file gtp_ggsn.{c,h}
* gprs_subscriber: Move API declarations to correct header
* Move gprs_sndcp_vty_init() declaration to gprs_sndcp.h
* Introduce new header file sgsn/gtp.h
* Fix -Werror=old-style-definition
* Move related structs to gprs_subscriber.h
* Remove unneeded extern declaration from libosmocotrl
* Keep sgsn subsystems under struct sgsn_instance lifecycle
* Move global ggsn_list into struct sgsn_instance
* Move struct apn_ctx and APN related definitions to its own file
* Move struct sgsn_subscriber_pdp_data to gprs_subscriber.h
* sgsn.h: Drop declaration of non existing function
* Properly split llc->sndcp->gtp unitdata pathi through extra func call
* Move func defintions of funcs implemented in gprs_sndcp.c to gprs_sndcp.h
* sndcp: Standarize unitdata function naming
* Move gtp related functions to gtp.h
* Move global apn_list inside struct sgsn_instance
* gtp_{ggsn,mme}: Allocate contexts under struct sgsn_instance
* Move extern declarations of tall_sgsn_ctx to sgsn.h
* Drop extern declarations of global sgsn_instance in source files
* Move sgsn_pdp_ctx to its own file pdpctx.{c,h}
* Move global pdp_list inside struct sgsn_instance
* Move gtphub header to include/osmocom/gtphub/
* Move sgsn_ctrl_cmds_install() declaration to sgsn.h
* Move LOGGSUBSCRP to gprs_subscriber.h
* Rename bscconfig.h -> config.h
* gtphub.h: Remove dependency on sgsn/gprs_sgsn.h
* Split gprs_sgsn.{c,h} -> {auth,mmctx,sgsn}.{c,h}
* Move global mmctx list into struct sgsn_instance
* vty: Introduce encryption cipher-plugin-path command
* Fix extra whitespace in pdpctx_ctr_description
[ Oliver Smith ]
* contrib/jenkins.sh: use enable-werror with IU too
* sgsn_libgtp: cb_data_ind: remove mm_idle assert
* osmo-gtphub.cfg: fix conflict with osmo-ggsn.cfg
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 17:34:26 +0100
osmo-sgsn (1.9.0) unstable; urgency=medium
[ Oliver Smith ]
* llme_free: clean up related sndcp
* treewide: remove FSF address
[ Pau Espin Pedrol ]
* Drop unneeded ax_check_compile_flag.m4
* Revert "sgsn: Handle different levels of QoS"
[ Neels Hofmeyr ]
* s/cipher_support_mask/gea_encryption_mask
* Iu: add UEA encryption
[ Vadim Yanitskiy ]
* tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
[ Harald Welte ]
* update git URLs (git -> https; gitea)
* README: Major update
-- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 29 Jun 2022 11:45:08 +0200
osmo-sgsn (1.8.0) unstable; urgency=medium
[ Harald Welte ]
* Remove bogus DNS log category
[ Daniel Willmann ]
* manuals: Regenerate counters/VTY through docker
[ Vadim Yanitskiy ]
* main: resurrect removed 'ns' logging category as deprecated
* doc/manuals: update configuration.adoc to use new command syntax
* tests/Makefile.am: do not try removing non-existing files
[ Pau Espin Pedrol ]
* ranap: log ranap iu event type name instead of number
* gmm: log GMM msg type name instead of number
* gmm: Expect E_VLR_ANSWERED when in ST_IU_SECURITY_CMD
* gmm_fsm: Expect E_GMM_COMMON_PROC_INIT_REQ when in ST_GMM_COMMON_PROC_INIT
* mm_iu: Send event E_PMM_PS_CONN_ESTABLISH upon rx GMM SERVICE REQUEST
* mm_iu: Expect E_PMM_PS_ATTACH when in ST_PMM_IDLE
* gprs_gmm.c: State proper GMM prefix logging rx/tx of GMM messages
* mm_state_iu_fsm: T3314 expiry must lead to PMM IDLE, not PMM DETACHED
* Iu: Drop timer X3314
* gprs_ranap.c: Clean up code path releasing IU conn
* mm_state_{gb,iu}_fsm: Add missing license block, improve spec references
* mm_state_{gb,iu}_fsm: Improve naming for detach event
* Drop unused GBRPOXY enum field
* gtp: Delete ctx upon receive UpdateCtxResp with cause Non-existent
* Support forwarding RIM messages over GTPCv1 EUTRAN<->GERAN
* Use new stat item/ctr getter APIs
[ Keith ]
* vty: Fix optional display of pdp with mm-context
* VTY: Don't display 'PDP Address: invalid' for IPv4v6
[ Eric ]
* add support for multiple encryption algorithms and a5/4
[ Oliver Smith ]
* gtphub: remove llist_first, llist_last macros
* vty: add "page imsi"
* debian/control: remove dh-systemd build-depend
* Revert "Turn some compiler warnings into errors"
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 17:57:50 +0100
osmo-sgsn (1.7.0) unstable; urgency=medium
[ Daniel Willmann ]

2
debian/compat vendored
View File

@ -1 +1 @@
9
10

25
debian/control vendored
View File

@ -2,9 +2,8 @@ Source: osmo-sgsn
Section: net
Priority: extra
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Build-Depends: debhelper (>=9),
Build-Depends: debhelper (>= 10),
dh-autoreconf,
dh-systemd (>= 1.5),
autotools-dev,
autoconf,
automake,
@ -12,19 +11,19 @@ Build-Depends: debhelper (>=9),
pkg-config,
libtalloc-dev,
libc-ares-dev,
libgtp-dev (>= 1.7.0),
libosmocore-dev (>= 1.5.0),
libosmo-abis-dev (>= 1.1.0),
libosmo-netif-dev (>= 1.1.0),
libosmo-gsup-client-dev (>= 1.3.0),
libgtp-dev (>= 1.11.0),
libosmocore-dev (>= 1.9.0),
libosmo-abis-dev (>= 1.5.0),
libosmo-netif-dev (>= 1.4.0),
libosmo-gsup-client-dev (>= 1.7.0),
libasn1c-dev (>= 0.9.30),
libosmo-ranap-dev (>= 0.7.0),
libosmo-sigtran-dev (>= 1.4.0),
libosmo-sccp-dev (>= 1.4.0),
osmo-gsm-manuals-dev (>= 1.1.0)
libosmo-ranap-dev (>= 1.5.0),
libosmo-sigtran-dev (>= 1.8.0),
libosmo-sccp-dev (>= 1.8.0),
osmo-gsm-manuals-dev (>= 1.5.0)
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/osmo-sgsn.git
Vcs-Browser: https://git.osmocom.org/osmo-sgsn
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
Homepage: https://projects.osmocom.org/projects/osmo-sgsn

8
debian/copyright vendored
View File

@ -1,6 +1,6 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: osmo-sgsn
Source: git://git.osmocom.org/osmo-sgsn
Source: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
Files: .gitignore
.gitreview
@ -33,7 +33,6 @@ Files: .gitignore
include/osmocom/sgsn/crc24.h
include/osmocom/sgsn/debug.h
include/osmocom/sgsn/gb_proxy.h
include/osmocom/sgsn/gprs_gb_parse.h
include/osmocom/sgsn/gprs_gmm.h
include/osmocom/sgsn/gprs_llc.h
include/osmocom/sgsn/gprs_sgsn.h
@ -53,6 +52,7 @@ Files: .gitignore
tests/gprs/gprs_test.ok
tests/gtphub/Makefile.am
tests/gtphub/gtphub_test.ok
tests/sgsn/gprs_gb_parse.h
tests/sgsn/Makefile.am
tests/sgsn/sgsn_test.ok
tests/slhc/Makefile.am
@ -74,11 +74,10 @@ Files: include/osmocom/sgsn/a_reset.h
include/osmocom/sgsn/gprs_sndcp_pcomp.h
include/osmocom/sgsn/gprs_sndcp_xid.h
include/osmocom/sgsn/gprs_utils.h
include/osmocom/sgsn/gtphub.h
include/osmocom/gtphub/gtphub.h
include/osmocom/sgsn/signal.h
src/gprs/gprs_llc_parse.c
src/gprs/crc24.c
src/gprs/gprs_gb_parse.c
src/gprs/gprs_utils.c
src/gprs/sgsn_ares.c
src/gtphub/gtphub.c
@ -103,6 +102,7 @@ Files: include/osmocom/sgsn/a_reset.h
src/sgsn/sgsn_main.c
src/sgsn/sgsn_vty.c
tests/gtphub/gtphub_test.c
tests/sgsn/gprs_gb_parse.c
tests/sgsn/sgsn_test.c
tests/slhc/slhc_test.c
tests/sndcp_xid/sndcp_xid_test.c

38
debian/postinst vendored Executable file
View File

@ -0,0 +1,38 @@
#!/bin/sh -e
case "$1" in
configure)
# Create the osmocom group and user (if it doesn't exist yet)
if ! getent group osmocom >/dev/null; then
groupadd --system osmocom
fi
if ! getent passwd osmocom >/dev/null; then
useradd \
--system \
--gid osmocom \
--home-dir /var/lib/osmocom \
--shell /sbin/nologin \
--comment "Open Source Mobile Communications" \
osmocom
fi
# Fix permissions of previous (root-owned) install (OS#4107)
if dpkg --compare-versions "$2" le "1.12.0"; then
if [ -e /etc/osmocom/osmo-sgsn.cfg ]; then
chown -v osmocom:osmocom /etc/osmocom/osmo-sgsn.cfg
chmod -v 0660 /etc/osmocom/osmo-sgsn.cfg
fi
if [ -d /etc/osmocom ]; then
chown -v root:osmocom /etc/osmocom
chmod -v 2775 /etc/osmocom
fi
mkdir -p /var/lib/osmocom
chown -R -v osmocom:osmocom /var/lib/osmocom
fi
;;
esac
# dh_installdeb(1) will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#

View File

@ -5,6 +5,14 @@
! For the test, try to use most config commands.
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
line vty
no login

View File

@ -2,6 +2,14 @@
! Osmocom gtphub configuration
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
line vty
no login
@ -9,7 +17,7 @@ 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.10
bind-to-ggsns 127.0.0.2
bind-to-ggsns 127.0.0.20
! Local nonstandard ports or separate IPs:
!bind-to-sgsns ctrl 127.0.0.1 2342 user 127.0.0.1 4223

View File

@ -2,6 +2,14 @@
! Osmocom SGSN configuration
!
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
line vty
no login
!

View File

@ -2,6 +2,14 @@
! Osmocom SGSN configuration
!
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
line vty
no login
!

View File

@ -2,6 +2,14 @@
! Osmocom SGSN configuration
!
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
line vty
no login
!
@ -9,6 +17,8 @@ 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
role asp
sctp-role client
as as-clnt-OsmoSGSN-A m3ua
asp asp-clnt-OsmoSGSN-A
routing-key 3 0.23.4

View File

@ -11,7 +11,8 @@ 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.
=== Configuring the Gp interface
[[gp-if-ggsn]]
=== Configuring the Gp interface (towards GGSN)
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
@ -67,6 +68,58 @@ OsmoSGSN(config-sgsn)# grx-dns-add 1.2.3.4 <3>
<2> Enable the dynamic GGSN resolving mode
<3> Specify the IP address of a DNS server for APN resolution
[[gp-if-mme]]
=== Configuring the Gp interface (towards MME)
The Gp interface also contains the GTP-C v1 based interface between the SGSN
and the MMEs. This interface between SGSN and MMEs is used to transfer _RAN
Information Relay_ GTP-C messages between them, which are used as containers to
allow PCUs under the SGSN and eNodeBs under MMEs to exchange cell information
(RIM).
In the SGSN, this interface re-uses the same socket local configuration as per
the GGSN connections (see _gtp local-ip_ VTY command in <<gp-if-ggsn>>).
Similarly as with GGSNs, (again see <<gp-if-ggsn>>), selection of destination
peers for the _RAN Information Relay_ message can be configured statically or
dynamically over GRX.
==== Static MME/TAI configuration
In this mode, there is a static list of MMEs and TAIs configured in
OsmoSGSN via the VTY / config file. One MME in the list can be configured as the
_default route_, where all unspecified TAIs are routed too.
This is a non-standard method outside of the 3GPP specifications for the
SGSN, and is typically only used in private/small GPRS networks without
any access to a GRX.
.Example: Static MME/TAI configuration (single catch-all GGSN)
----
sgsn
...
gtp local-ip 192.168.0.10 <1>
mme test-mme0 <2>
gtp remote-ip 192.168.0.20 <3>
gtp ran-info-relay 262 42 3 <4>
gtp ran-info-relay 262 42 4
mme test-mme1 <5>
gtp remote-ip 192.168.0.30
gtp ran-info-relay default <6>
----
<1> Configure the local IP address at the SGSN used for Gp/GTP
<2> Configure an MME named "test-mme0"
<3> Specify the remote IP address of the MME (for MME "test-mme0")
<4> Route specified TAIs towards this MME
<5> Configure an MME named "test-mme1"
<6> Route all TAIs with an unspecified MME towards MM "test-mme1"
==== Dynamic MME/TAI configuration
Dynamic MME/TAI peer look up over GRX is not yet supported by OsmoSGSN.
[[auth-pol]]
=== Authorization Policy
@ -345,16 +398,16 @@ 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)
.Example: Turn on encryption (GEA3 and GEA4)
----
sgsn
encryption GEA3
encryption gea 3 4
----
.Example: Turn off encryption (GEA0)
----
sgsn
encryption GEA0
encryption gea 0
----
=== Configure SCCP/M3UA to accept _IuPS_ links
@ -369,6 +422,7 @@ cs7 instance 0
point-code 0.23.4
asp asp-clnt-OsmoSGSN 2905 0 m3ua
remote-ip 127.0.0.1
role asp
sctp-role client
as as-clnt-OsmoSGSN m3ua
asp asp-clnt-OsmoSGSN

View File

@ -15,6 +15,14 @@
Conversion to asciidoc, removal of sysmoBTS specific parts.
</revremark>
</revision>
<revision>
<revnumber>3</revnumber>
<date>April 2024</date>
<authorinitials>AC</authorinitials>
<revremark>
Replace NS chapter with new NS2 chapter to match the code.
</revremark>
</revision>
</revhistory>
<authorgroup>
@ -29,10 +37,21 @@
<jobtitle>Managing Director</jobtitle>
</affiliation>
</author>
<author>
<firstname>Alexander</firstname>
<surname>Couzens</surname>
<email>acouzens@sysmocom.de</email>
<authorinitials>AC</authorinitials>
<affiliation>
<shortaffil>sysmocom</shortaffil>
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
<jobtitle>Developer</jobtitle>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2013-2016</year>
<year>2013-2024</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
@ -47,8 +66,8 @@
</para>
<para>
The Asciidoc source code of this manual can be found at
<ulink url="http://git.osmocom.org/osmo-gsm-manuals/">
http://git.osmocom.org/osmo-gsm-manuals/
<ulink url="https://git.osmocom.org/osmo-gsm-manuals/">
https://git.osmocom.org/osmo-gsm-manuals/
</ulink>
</para>
</legalnotice>

View File

@ -21,7 +21,7 @@ include::{srcdir}/chapters/configuration.adoc[]
include::./common/chapters/cs7-config.adoc[]
include::./common/chapters/gb.adoc[]
include::./common/chapters/gb-ns2.adoc[]
include::./common/chapters/control_if.adoc[]

View File

@ -1,71 +1,17 @@
#!/bin/sh -e
#!/bin/sh -x
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?"
if [ -z "$DOCKER_PLAYGROUND" ]; then
echo "You need to set DOCKER_PLAYGROUND"
exit 1
}
fi
# $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
SCRIPT=$(realpath "$0")
MANUAL_DIR=$(dirname "$SCRIPT")
echo "Starting in background: $@"
"$@" > "$log" 2>&1 &
pid="$!"
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
sleep 0.5
if ! kill -0 "$pid" 2>/dev/null; then
echo "ERROR: start failed!"
cat "$log"
exit 1
fi
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
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_counters" \
"chapters/counters_generated.adoc" \
4245 \
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
echo "Done with all"
OSMO_BSC_BRANCH=$COMMIT ./regen_doc.sh osmo-sgsn 4245 \
"$MANUAL_DIR/chapters/counters_generated.adoc" \
"$MANUAL_DIR/vty/sgsn_vty_reference.xml"

View File

@ -1,3 +1,4 @@
SUBDIRS = \
gtphub \
sgsn \
$(NULL)

View File

@ -0,0 +1,3 @@
noinst_HEADERS = \
gtphub.h \
$(NULL)

View File

@ -27,9 +27,7 @@
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/gsm/apn.h>
/* support */
@ -428,7 +426,7 @@ struct gtphub_resolved_ggsn {
/* The APN OI, the Operator Identifier, is the combined address,
* including parts of the IMSI and APN NI, and ending with ".gprs". */
char apn_oi_str[GSM_APN_LENGTH];
char apn_oi_str[APN_MAXLEN+1];
/* Which address and port we resolved that to. */
struct gtphub_peer_port *peer;

View File

@ -1,18 +1,19 @@
noinst_HEADERS = \
apn.h \
auth.h \
common.h \
crc24.h \
debug.h \
gprs_gb.h \
gprs_gb_parse.h \
gprs_bssgp.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_ns.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 \
@ -21,7 +22,11 @@ noinst_HEADERS = \
gprs_sndcp_xid.h \
gprs_subscriber.h \
gprs_utils.h \
gtphub.h \
gtp.h \
gtp_ggsn.h \
gtp_mme.h \
mmctx.h \
pdpctx.h \
sgsn.h \
sgsn_rim.h \
signal.h \

View File

@ -0,0 +1,20 @@
#pragma once
#include <osmocom/core/linuxlist.h>
struct sgsn_ggsn_ctx;
#define GSM_APN_LENGTH 102
struct apn_ctx {
struct llist_head list;
struct sgsn_ggsn_ctx *ggsn;
char *name;
char *imsi_prefix;
char *description;
};
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix);
void sgsn_apn_ctx_free(struct apn_ctx *actx);
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix);
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix);

View File

@ -0,0 +1,39 @@
/* MS authorization and subscriber data handling */
#pragma once
#include <osmocom/core/linuxlist.h>
struct sgsn_config;
struct sgsn_instance;
struct sgsn_mm_ctx;
struct gsm_auth_tuple;
/* Authorization/ACL handling */
enum sgsn_auth_state {
SGSN_AUTH_UNKNOWN,
SGSN_AUTH_AUTHENTICATE,
SGSN_AUTH_UMTS_RESYNC,
SGSN_AUTH_ACCEPTED,
SGSN_AUTH_REJECTED
};
extern const struct value_string *sgsn_auth_state_names;
void sgsn_auth_init(struct sgsn_instance *sgsn);
/* Request authorization */
enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm);
int sgsn_auth_request(struct sgsn_mm_ctx *mm);
void sgsn_auth_update(struct sgsn_mm_ctx *mm);
struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
unsigned key_seq);
/*
* Authorization/ACL handling
*/
struct imsi_acl_entry {
struct llist_head list;
char imsi[OSMO_IMSI_BUF_SIZE];
};
struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg);
int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg);
int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg);

View File

@ -5,6 +5,6 @@
#define INIT_CRC24 0xffffff
uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len);
uint32_t crc24_calc(uint32_t fcs, const uint8_t *cp, unsigned int len);
#endif

View File

@ -13,7 +13,6 @@ enum {
DMEAS,
DREF,
DGPRS,
DNS,
DLLC,
DSNDCP,
DSLHC,

View File

@ -0,0 +1,12 @@
#pragma once
#include <osmocom/core/msgb.h>
/* Called by bssgp layer when a prim is received from lower layers. */
int sgsn_bssgp_rx_prim(struct osmo_prim_hdr *oph);
/* called by the bssgp layer to send NS PDUs */
int sgsn_bssgp_dispatch_ns_unitdata_req_cb(void *ctx, struct msgb *msg);
/* page a MS in its routing area */
int sgsn_bssgp_page_ps_ra(struct sgsn_mm_ctx *mmctx);

View File

@ -1,20 +0,0 @@
#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, const struct msgb *msg);
/* page a MS in its routing area */
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx);
/* called by the bssgp layer to send NS PDUs */
int gprs_gb_send_cb(void *ctx, struct msgb *msg);
/* called by the ns layer */
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);

View File

@ -1,11 +1,15 @@
#ifndef _GPRS_GMM_H
#define _GPRS_GMM_H
#include <osmocom/core/msgb.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <stdbool.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/crypt/auth.h>
struct sgsn_mm_ctx;
struct gprs_llc_llme;
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);
@ -28,6 +32,11 @@ int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli);
int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
uint8_t suspend_ref);
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, const struct msgb *msg);
time_t gprs_max_time_to_idle(void);
int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type);

View File

@ -1,8 +1,10 @@
#pragma once
#include <osmocom/core/fsm.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
struct gprs_llc_llme;
/* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */
enum gmm_fsm_states {

View File

@ -1,11 +1,16 @@
#ifndef _GPRS_LLC_H
#define _GPRS_LLC_H
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/sgsn/gprs_llc_xid.h>
struct sgsn_mm_ctx;
/* Section 4.7 LLC Layer Structure */
enum gprs_llc_sapi {
GPRS_SAPI_GMM = 1,
@ -91,6 +96,7 @@ enum gprs_llc_lle_state {
GPRS_LLES_LOCAL_REL = 6, /* Local Release */
GPRS_LLES_TIMER_REC = 7, /* Timer Recovery */
};
extern const struct value_string gprs_llc_lle_state_names[];
enum gprs_llc_llme_state {
GPRS_LLMS_UNASSIGNED = 1, /* No TLLI yet */
@ -272,18 +278,15 @@ static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur)
}
/* LLC low level functions */
void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme);
void gprs_llme_copy_key(const struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme);
/* parse a GPRS LLC header, also check for invalid frames */
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
uint8_t *llc_hdr, int len);
void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph, struct gprs_llc_lle *lle);
int gprs_llc_fcs(uint8_t *data, unsigned int len);
int gprs_llc_fcs(const uint8_t *data, unsigned int len);
/* LLME handling routines */
struct llist_head *gprs_llme_list(void);
struct gprs_llc_lle *gprs_lle_get_or_create(const uint32_t tlli, uint8_t sapi);
#endif

View File

@ -5,7 +5,7 @@
struct sgsn_mm_ctx;
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
/* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */
enum mm_state_gb_fsm_states {
ST_MM_IDLE,
ST_MM_READY,
@ -14,9 +14,8 @@ enum mm_state_gb_fsm_states {
enum mm_state_gb_fsm_events {
E_MM_GPRS_ATTACH,
/* E_GPRS_DETACH, TODO: not used */
E_MM_GPRS_DETACH, /* MS becomes detached: due to Detach Req, RAU reject, implicit detach, etc. */
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 */

View File

@ -4,8 +4,7 @@
struct sgsn_mm_ctx;
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
/* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */
enum mm_state_iu_fsm_states {
ST_PMM_DETACHED,
ST_PMM_CONNECTED,
@ -14,12 +13,10 @@ enum mm_state_iu_fsm_states {
enum mm_state_iu_fsm_events {
E_PMM_PS_ATTACH,
/* E_PS_DETACH, TODO: not used */
E_PMM_PS_DETACH, /* UE becomes detached: due to Detach Req, RAU reject, implicit detach, etc. */
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,9 @@
#pragma once
#include <stdbool.h>
#include <osmocom/core/msgb.h>
#include <osmocom/sgsn/gprs_llc.h>
/* called by the ns layer */
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);

View File

@ -1,13 +1,15 @@
#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>
struct sgsn_mm_ctx;
struct sgsn_pdp_ctx;
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);

View File

@ -1,7 +1,10 @@
#pragma once
#include <osmocom/core/msgb.h>
#include <osmocom/sgsn/gprs_sgsn.h>
struct sgsn_mm_ctx;
struct sgsn_pdp_ctx;
struct gprs_llc_llme;
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,

View File

@ -3,6 +3,9 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsm48.h>
struct gprs_llc_lle;
/* A fragment queue header, maintaining list of fragments for one N-PDU */
struct defrag_state {
@ -60,6 +63,8 @@ struct gprs_sndcp_entity {
extern struct llist_head gprs_sndcp_entities;
int gprs_sndcp_vty_init(void);
/* Set of SNDCP-XID negotiation (See also: TS 144 065,
* Section 6.8 XID parameter negotiation) */
int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi);
@ -68,7 +73,7 @@ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi);
* Section 6.8 XID parameter negotiation) */
int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication,
struct gprs_llc_xid_field *xid_field_response,
struct gprs_llc_lle *lle);
const struct gprs_llc_lle *lle);
/* Process SNDCP-XID indication
* (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
@ -76,4 +81,21 @@ int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf,
struct gprs_llc_xid_field *xid_field_request,
struct gprs_llc_lle *lle);
/* Clean up all gprs_sndcp_entities related to llme (OS#4824) */
void gprs_sndcp_sm_deactivate_ind_by_llme(const struct gprs_llc_llme *llme);
/* Called by SNDCP when it has received/re-assembled a N-PDU */
int sndcp_sn_unitdata_ind(struct gprs_sndcp_entity *sne, struct msgb *msg,
uint32_t npdu_len, uint8_t *npdu);
int sndcp_sn_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
void *mmcontext);
/* Entry point for the SNSM-ACTIVATE.indication */
int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
/* Entry point for the SNSM-DEACTIVATE.indication */
int sndcp_sm_deactivate_ind(const struct gprs_llc_lle *lle, uint8_t nsapi);
int sndcp_ll_unitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
uint8_t *hdr, uint16_t len);
#endif /* INT_SNDCP_H */

View File

@ -4,10 +4,70 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/socket.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/sgsn/apn.h>
struct sgsn_instance;
struct sgsn_mm_ctx;
extern struct llist_head * const gprs_subscribers;
#define GPRS_SUBSCRIBER_FIRST_CONTACT 0x00000001
#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16)
#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17)
#define GPRS_SUBSCRIBER_CANCELLED (1 << 18)
#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19)
#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \
GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \
GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \
)
struct gsm_auth_tuple {
int use_count;
int key_seq;
struct osmo_auth_vector vec;
};
#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */
struct sgsn_subscriber_data {
struct sgsn_mm_ctx *mm;
struct gsm_auth_tuple auth_triplets[5];
int auth_triplets_updated;
struct llist_head pdp_list;
int error_cause;
uint8_t msisdn[9];
size_t msisdn_len;
uint8_t hlr[9];
size_t hlr_len;
uint8_t pdp_charg[2];
bool has_pdp_charg;
};
/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
/* see GSM 09.02, B.1, gprsSubscriptionData */
struct sgsn_subscriber_pdp_data {
struct llist_head list;
unsigned int context_id;
enum gsm48_pdp_type_org pdp_type_org;
enum gsm48_pdp_type_nr pdp_type_nr;
struct osmo_sockaddr pdp_address[2];
char apn_str[GSM_APN_LENGTH];
uint8_t qos_subscribed[20];
size_t qos_subscribed_len;
uint8_t pdp_charg[2];
bool has_pdp_charg;
};
struct sgsn_subscriber_pdp_data *sgsn_subscriber_pdp_data_alloc(struct sgsn_subscriber_data *sdata);
struct gprs_subscr {
struct llist_head entry;
int use_count;
@ -29,3 +89,22 @@ struct gprs_subscr *_gprs_subscr_put(struct gprs_subscr *gsub,
const char *file, int line);
#define gprs_subscr_get(gsub) _gprs_subscr_get(gsub, __FILE__, __LINE__)
#define gprs_subscr_put(gsub) _gprs_subscr_put(gsub, __FILE__, __LINE__)
int gprs_subscr_init(struct sgsn_instance *sgi);
int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
const uint8_t *auts,
const uint8_t *auts_rand);
void gprs_subscr_cleanup(struct gprs_subscr *subscr);
struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi);
struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx);
struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi);
void gprs_subscr_cancel(struct gprs_subscr *subscr);
void gprs_subscr_update(struct gprs_subscr *subscr);
void gprs_subscr_update_auth_info(struct gprs_subscr *subscr);
int gprs_subscr_rx_gsup_message(struct msgb *msg);
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
(subscr) ? (subscr)->imsi : "---", \
## args)

View File

@ -29,15 +29,11 @@
struct msgb;
struct gprs_ra_id;
int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str);
/* GSM 04.08, 10.5.7.3 GPRS Timer */
int gprs_tmr_to_secs(uint8_t tmr);
uint8_t gprs_secs_to_tmr_floor(int secs);
int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len);
int gprs_is_mi_imsi(const uint8_t *value, size_t value_len);
int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi);
void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi);
int gprs_ra_id_equals(const struct gprs_ra_id *id1, const struct gprs_ra_id *id2);

View File

@ -0,0 +1,30 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/gprs/gprs_bssgp_rim.h>
struct gprs_ra_id;
struct sgsn_instance;
struct sgsn_ggsn_ctx;
struct sgsn_pdp_ctx;
struct sgsn_mm_ctx;
struct sgsn_mme_ctx;
int sgsn_gtp_init(struct sgsn_instance *sgi);
int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu);
void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
struct sgsn_mm_ctx *mmctx,
uint16_t nsapi,
struct tlv_parsed *tp);
int sgsn_gtp_data_req(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
struct msgb *msg, uint32_t npdu_len, uint8_t *npdu);
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);
int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);

View File

@ -0,0 +1,41 @@
#pragma once
#include <stdint.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/gprs/protocol/gsm_24_301.h>
struct gsn_t;
struct sgsn_pdp_ctx;
struct sgsn_instance;
struct sgsn_ggsn_ctx {
struct llist_head list;
uint32_t id;
unsigned int gtp_version;
struct in_addr remote_addr;
int remote_restart_ctr;
struct gsn_t *gsn;
struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
struct osmo_timer_list echo_timer;
unsigned int echo_interval;
};
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(struct sgsn_instance *sgsn, uint32_t id);
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(struct sgsn_instance *sgsn, uint32_t id);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct sgsn_instance *sgsn, struct in_addr *addr);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(struct sgsn_instance *sgsn, 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)

View File

@ -0,0 +1,41 @@
#pragma once
#include <netinet/in.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/gprs/protocol/gsm_24_301.h>
struct gsn_t;
struct mme_rim_route {
struct llist_head list; /* item in struct sgsn_mme_ctx */
struct osmo_eutran_tai tai;
};
struct sgsn_mme_ctx {
struct llist_head list; /* item in sgsn_mme_ctxts */
struct llist_head routes; /* list of struct mme_rim_route */
struct sgsn_instance *sgsn; /* backpointer */
char *name;
struct in_addr remote_addr;
/* is it the default route for outgoing message? are all incoming messages accepted? */
bool default_route;
};
struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name);
struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name);
void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme);
struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name);
struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr);
struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai);
struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn);
void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
#define LOGMME(mme, cat, level, fmt, args...) { \
char _buf[INET_ADDRSTRLEN]; \
LOGP(cat, level, "MME(%s:%s): " fmt, (mme)->name, inet_ntop(AF_INET, &(mme)->remote_addr, _buf, sizeof(_buf)), ## args); \
} while (0)

View File

@ -1,5 +1,4 @@
#ifndef _GPRS_SGSN_H
#define _GPRS_SGSN_H
#pragma once
#include <stdint.h>
#include <netinet/in.h>
@ -14,12 +13,17 @@
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/sgsn/apn.h>
#include <osmocom/sgsn/auth.h>
#include <osmocom/sgsn/gprs_subscriber.h>
#define GSM_EXTENSION_LENGTH 15
#define GSM_APN_LENGTH 102
struct gprs_llc_lle;
struct ctrl_handle;
struct gprs_subscr;
struct sgsn_ggsn_ctx;
struct sgsn_pdp_ctx;
enum gsm48_gsm_cause;
@ -37,13 +41,6 @@ enum gprs_mm_ctr {
GMM_CTR_RA_UPDATE,
};
enum gprs_pdp_ctx {
PDP_CTR_PKTS_UDATA_IN,
PDP_CTR_PKTS_UDATA_OUT,
PDP_CTR_BYTES_UDATA_IN,
PDP_CTR_BYTES_UDATA_OUT,
};
enum gprs_t3350_mode {
GMM_T3350_MODE_NONE,
GMM_T3350_MODE_ATT,
@ -51,17 +48,6 @@ enum gprs_t3350_mode {
GMM_T3350_MODE_PTMSI_REALL,
};
/* Authorization/ACL handling */
enum sgsn_auth_state {
SGSN_AUTH_UNKNOWN,
SGSN_AUTH_AUTHENTICATE,
SGSN_AUTH_UMTS_RESYNC,
SGSN_AUTH_ACCEPTED,
SGSN_AUTH_REJECTED
};
#define MS_RADIO_ACCESS_CAPA
enum sgsn_ggsn_lookup_state {
SGSN_GGSN_2DIGIT,
SGSN_GGSN_3DIGIT,
@ -104,13 +90,6 @@ struct service_info {
struct ranap_ue_conn_ctx;
struct gsm_auth_tuple {
int use_count;
int key_seq;
struct osmo_auth_vector vec;
};
#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */
/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */
/* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */
struct sgsn_mm_ctx {
@ -175,6 +154,7 @@ struct sgsn_mm_ctx {
/* Iu: CK, IK, KSI */
/* CKSN */
enum gprs_ciph_algo ciph_algo;
uint8_t ue_cipher_mask;
/* Auth & Ciphering Request reference from 3GPP TS 24.008 § 10.5.5.19: */
uint8_t ac_ref_nr_used;
@ -294,64 +274,6 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
enum gsm48_gsm_cause *gsm_cause,
char *apn_str);
enum pdp_ctx_state {
PDP_STATE_NONE,
PDP_STATE_CR_REQ,
PDP_STATE_CR_CONF,
/* 04.08 / Figure 6.2 / 6.1.2.2 */
PDP_STATE_INACT_PEND,
PDP_STATE_INACTIVE = PDP_STATE_NONE,
};
enum pdp_type {
PDP_TYPE_NONE,
PDP_TYPE_ETSI_PPP,
PDP_TYPE_IANA_IPv4,
PDP_TYPE_IANA_IPv6,
};
struct sgsn_pdp_ctx {
struct llist_head list; /* list_head for mmctx->pdp_list */
struct llist_head g_list; /* list_head for global list */
struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */
int destroy_ggsn; /* destroy it on destruction */
struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */
struct llist_head ggsn_list; /* list_head for ggsn->pdp_list */
struct rate_ctr_group *ctrg;
//unsigned int id;
struct pdp_t *lib; /* pointer to libgtp PDP ctx */
enum pdp_ctx_state state;
enum pdp_type type;
uint32_t address;
char *apn_subscribed;
//char *apn_used;
uint16_t nsapi; /* SNDCP */
uint16_t sapi; /* LLC */
uint8_t ti; /* transaction identifier */
int vplmn_allowed;
uint32_t qos_profile_subscr;
//uint32_t qos_profile_req;
//uint32_t qos_profile_neg;
uint8_t radio_prio;
//uint32_t charging_id;
struct osmo_timer_list timer;
unsigned int T; /* Txxxx number */
unsigned int num_T_exp; /* number of consecutive T expirations */
struct osmo_timer_list cdr_timer; /* CDR record wird timer */
struct timespec cdr_start; /* The start of the CDR */
uint64_t cdr_bytes_in;
uint64_t cdr_bytes_out;
uint32_t cdr_charging_id;
};
#define LOGPDPCTXP(level, pdp, fmt, args...) \
LOGP(DGPRS, level, "PDP(%s/%u) " \
fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args)
/* look up PDP context by MM context and NSAPI */
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
uint8_t nsapi);
@ -359,168 +281,7 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
uint8_t tid);
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
struct sgsn_ggsn_ctx *ggsn,
uint8_t nsapi);
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
struct sgsn_ggsn_ctx {
struct llist_head list;
uint32_t id;
unsigned int gtp_version;
struct in_addr remote_addr;
int remote_restart_ctr;
struct gsn_t *gsn;
struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
struct osmo_timer_list echo_timer;
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);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
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;
char *name;
char *imsi_prefix;
char *description;
};
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix);
void sgsn_apn_ctx_free(struct apn_ctx *actx);
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix);
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix);
extern struct llist_head sgsn_mm_ctxts;
extern struct llist_head sgsn_ggsn_ctxts;
extern struct llist_head sgsn_apn_ctxts;
extern struct llist_head sgsn_pdp_ctxts;
uint32_t sgsn_alloc_ptmsi(void);
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx);
void sgsn_inst_init(struct sgsn_instance *sgsn);
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len);
/*
* ctrl interface related work
*/
int sgsn_ctrl_cmds_install(void);
/*
* Authorization/ACL handling
*/
struct imsi_acl_entry {
struct llist_head list;
char imsi[OSMO_IMSI_BUF_SIZE];
};
/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
/* see GSM 09.02, B.1, gprsSubscriptionData */
struct sgsn_subscriber_pdp_data {
struct llist_head list;
unsigned int context_id;
uint16_t pdp_type;
char apn_str[GSM_APN_LENGTH];
uint8_t qos_subscribed[20];
size_t qos_subscribed_len;
uint8_t pdp_charg[2];
bool has_pdp_charg;
};
struct sgsn_subscriber_data {
struct sgsn_mm_ctx *mm;
struct gsm_auth_tuple auth_triplets[5];
int auth_triplets_updated;
struct llist_head pdp_list;
int error_cause;
uint8_t msisdn[9];
size_t msisdn_len;
uint8_t hlr[9];
size_t hlr_len;
uint8_t pdp_charg[2];
bool has_pdp_charg;
};
#define SGSN_ERROR_CAUSE_NONE (-1)
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
(subscr) ? (subscr)->imsi : "---", \
## args)
struct sgsn_config;
struct sgsn_instance;
extern const struct value_string *sgsn_auth_state_names;
void sgsn_auth_init(struct sgsn_instance *sgsn);
struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg);
int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg);
int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg);
/* Request authorization */
int sgsn_auth_request(struct sgsn_mm_ctx *mm);
enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm);
void sgsn_auth_update(struct sgsn_mm_ctx *mm);
struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
unsigned key_seq);
/*
* GPRS subscriber data
*/
#define GPRS_SUBSCRIBER_FIRST_CONTACT 0x00000001
#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16)
#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17)
#define GPRS_SUBSCRIBER_CANCELLED (1 << 18)
#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19)
#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \
GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \
GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \
)
int gprs_subscr_init(struct sgsn_instance *sgi);
int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
const uint8_t *auts,
const uint8_t *auts_rand);
int gprs_subscr_auth_sync(struct gprs_subscr *subscr,
const uint8_t *auts, const uint8_t *auts_rand);
void gprs_subscr_cleanup(struct gprs_subscr *subscr);
struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi);
struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx( struct sgsn_mm_ctx *mmctx);
struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi);
void gprs_subscr_cancel(struct gprs_subscr *subscr);
void gprs_subscr_update(struct gprs_subscr *subscr);
void gprs_subscr_update_auth_info(struct gprs_subscr *subscr);
int gprs_subscr_rx_gsup_message(struct msgb *msg);
/* Called on subscriber data updates */
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx);
int gprs_sndcp_vty_init(void);
struct sgsn_instance;
int sgsn_gtp_init(struct sgsn_instance *sgi);
void sgsn_rate_ctr_init();
#endif /* _GPRS_SGSN_H */

View File

@ -0,0 +1,94 @@
#pragma once
#include <stdint.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/sgsn/apn.h>
#include <osmocom/sgsn/gprs_subscriber.h>
struct sgsn_mm_ctx;
struct sgsn_ggsn_ctx;
enum gprs_pdp_ctx {
PDP_CTR_PKTS_UDATA_IN,
PDP_CTR_PKTS_UDATA_OUT,
PDP_CTR_BYTES_UDATA_IN,
PDP_CTR_BYTES_UDATA_OUT,
};
enum pdp_ctx_state {
PDP_STATE_NONE,
PDP_STATE_CR_REQ,
PDP_STATE_CR_CONF,
/* 04.08 / Figure 6.2 / 6.1.2.2 */
PDP_STATE_INACT_PEND,
PDP_STATE_INACTIVE = PDP_STATE_NONE,
};
enum pdp_type {
PDP_TYPE_NONE,
PDP_TYPE_ETSI_PPP,
PDP_TYPE_IANA_IPv4,
PDP_TYPE_IANA_IPv6,
};
struct sgsn_pdp_ctx {
struct llist_head list; /* list_head for mmctx->pdp_list */
struct llist_head g_list; /* list_head for global list */
struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */
int destroy_ggsn; /* destroy it on destruction */
struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */
struct llist_head ggsn_list; /* list_head for ggsn->pdp_list */
struct rate_ctr_group *ctrg;
//unsigned int id;
struct pdp_t *lib; /* pointer to libgtp PDP ctx */
enum pdp_ctx_state state;
enum pdp_type type;
uint32_t address;
char *apn_subscribed;
//char *apn_used;
uint16_t nsapi; /* SNDCP */
uint16_t sapi; /* LLC */
uint8_t ti; /* transaction identifier */
int vplmn_allowed;
uint32_t qos_profile_subscr;
//uint32_t qos_profile_req;
//uint32_t qos_profile_neg;
uint8_t radio_prio;
//uint32_t charging_id;
struct osmo_timer_list timer;
unsigned int T; /* Txxxx number */
unsigned int num_T_exp; /* number of consecutive T expirations */
struct osmo_timer_list cdr_timer; /* CDR record wird timer */
struct timespec cdr_start; /* The start of the CDR */
uint64_t cdr_bytes_in;
uint64_t cdr_bytes_out;
uint32_t cdr_charging_id;
};
#define LOGPDPCTXP(level, pdp, fmt, args...) \
LOGP(DGPRS, level, "PDP(%s/%u) " \
fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args)
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
struct sgsn_ggsn_ctx *ggsn,
uint8_t nsapi);
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6);

View File

@ -6,12 +6,15 @@
#include <osmocom/core/select.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/auth.h>
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/gsm/oap_client.h>
#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/sgsn/common.h>
#include "../../bscconfig.h"
#include "../../config.h"
#if BUILD_IU
#include <osmocom/ranap/iu_client.h>
@ -22,6 +25,8 @@
struct hostent;
#define SGSN_ERROR_CAUSE_NONE (-1)
enum sgsn_auth_policy {
SGSN_AUTH_POLICY_OPEN,
SGSN_AUTH_POLICY_CLOSED,
@ -72,8 +77,10 @@ struct sgsn_config {
/* misc */
struct gprs_ns2_inst *nsi;
char *crypt_cipher_plugin_path;
enum sgsn_auth_policy auth_policy;
enum gprs_ciph_algo cipher;
uint8_t gea_encryption_mask;
uint8_t uea_encryption_mask;
struct llist_head imsi_acl;
struct sockaddr_in gsup_server_addr;
@ -89,6 +96,7 @@ struct sgsn_config {
/* Timer defintions */
struct osmo_tdef *T_defs;
struct osmo_tdef *T_defs_gtp;
int dynamic_lookup;
@ -145,9 +153,23 @@ struct sgsn_instance {
struct ares_addr_node *ares_servers;
struct rate_ctr_group *rate_ctrs;
struct llist_head apn_list; /* list of struct sgsn_apn_ctx */
struct llist_head ggsn_list; /* list of struct sgsn_ggsn_ctx */
struct llist_head mme_list; /* list of struct sgsn_mme_ctx */
struct llist_head mm_list; /* list of struct sgsn_mm_ctx */
struct llist_head pdp_list; /* list of struct sgsn_pdp_ctx */
struct ctrl_handle *ctrlh;
};
extern struct sgsn_instance *sgsn;
extern void *tall_sgsn_ctx;
/*
* ctrl interface related work (sgsn_ctrl.c)
*/
int sgsn_ctrl_cmds_install(void);
/* sgsn_vty.c */
@ -156,39 +178,13 @@ int sgsn_parse_config(const char *config_file);
char *sgsn_gtp_ntoa(struct ul16_t *ul);
/* sgsn.c */
/* Main input function for Gb proxy */
int sgsn_rcvmsg(struct msgb *msg, struct gprs_ns2_vc *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,
struct tlv_parsed *tp);
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 */
/* Entry point for the SNSM-ACTIVATE.indication */
int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
/* Entry point for the SNSM-DEACTIVATE.indication */
int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
/* Called by SNDCP when it has received/re-assembled a N-PDU */
int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
struct msgb *msg, uint32_t npdu_len, uint8_t *npdu);
int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
void *mmcontext);
int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
uint8_t *hdr, uint16_t len);
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx);
int sgsn_inst_init(struct sgsn_instance *sgsn);
/*
* CDR related functionality
*/
int sgsn_cdr_init(struct sgsn_instance *sgsn);
void sgsn_cdr_release(struct sgsn_instance *sgsn);
/*

View File

@ -1,3 +1,6 @@
#pragma once
int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg);
struct sgsn_mme_ctx;
int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg);
int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address);

View File

@ -17,10 +17,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*! \page v42bis_page V.42bis modem data compression

View File

@ -17,10 +17,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#if !defined(_SPANDSP_PRIVATE_V42BIS_H_)

View File

@ -3,7 +3,7 @@
#include <osmocom/vty/command.h>
enum bsc_vty_node {
GBPROXY_NODE = _LAST_OSMOVTY_NODE + 1,
SGSN_NODE,
SGSN_NODE = _LAST_OSMOVTY_NODE + 1,
GTPHUB_NODE,
MME_NODE,
};

View File

@ -1,74 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 4
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

View File

@ -29,7 +29,6 @@ endif
noinst_LTLIBRARIES = libcommon.la
libcommon_la_SOURCES = \
gprs_gb_parse.c \
gprs_llc_parse.c \
crc24.c \
gprs_utils.c \

View File

@ -59,7 +59,7 @@ static const uint32_t tbl_crc24[256] = {
#define INIT_CRC24 0xffffff
uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len)
uint32_t crc24_calc(uint32_t fcs, const uint8_t *cp, unsigned int len)
{
while (len--)
fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff];

View File

@ -29,7 +29,7 @@
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/crc24.h>
@ -55,7 +55,7 @@ static const struct value_string llc_cmd_strs[] = {
#define N202 4
#define CRC24_LENGTH 3
int gprs_llc_fcs(uint8_t *data, unsigned int len)
int gprs_llc_fcs(const uint8_t *data, unsigned int len)
{
uint32_t fcs_calc;

View File

@ -30,56 +30,6 @@
#include <string.h>
int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str)
{
uint8_t *last_len_field;
int len;
/* Can we even write the length field to the output? */
if (max_len == 0)
return -1;
/* Remember where we need to put the length once we know it */
last_len_field = apn_enc;
len = 1;
apn_enc += 1;
while (str[0]) {
if (len >= max_len)
return -1;
if (str[0] == '.') {
*last_len_field = (apn_enc - last_len_field) - 1;
last_len_field = apn_enc;
} else {
*apn_enc = str[0];
}
apn_enc += 1;
str += 1;
len += 1;
}
*last_len_field = (apn_enc - last_len_field) - 1;
return len;
}
/* GSM 04.08, 10.5.7.3 GPRS Timer */
int gprs_tmr_to_secs(uint8_t tmr)
{
switch (tmr & GPRS_TMR_UNIT_MASK) {
case GPRS_TMR_2SECONDS:
return 2 * (tmr & GPRS_TMR_FACT_MASK);
default:
case GPRS_TMR_MINUTE:
return 60 * (tmr & GPRS_TMR_FACT_MASK);
case GPRS_TMR_6MINUTE:
return 360 * (tmr & GPRS_TMR_FACT_MASK);
case GPRS_TMR_DEACTIVATED:
return -1;
}
}
/* This functions returns a tmr value such that
* - f is monotonic
* - f(s) <= s
@ -132,19 +82,6 @@ int gprs_is_mi_imsi(const uint8_t *value, size_t value_len)
return 1;
}
int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi)
{
uint32_t tmsi_be;
if (!gprs_is_mi_tmsi(value, value_len))
return 0;
memcpy(&tmsi_be, value + 1, sizeof(tmsi_be));
*tmsi = ntohl(tmsi_be);
return 1;
}
void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi)
{
uint32_t tmsi_be;

View File

@ -24,8 +24,6 @@
#include <netdb.h>
extern void *tall_sgsn_ctx;
struct cares_event_fd {
struct llist_head head;
struct osmo_fd fd;

View File

@ -32,7 +32,7 @@
#include <gtp.h>
#include <gtpie.h>
#include <osmocom/sgsn/gtphub.h>
#include <osmocom/gtphub/gtphub.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_utils.h>
@ -59,15 +59,6 @@ void *osmo_gtphub_ctx;
/* TODO move this to osmocom/core/select.h ? */
typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what);
/* TODO move this to osmocom/core/linuxlist.h ? */
#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
#define llist_first(head, type, entry) \
llist_entry(__llist_first(head), type, entry)
#define __llist_last(head) (((head)->next == (head)) ? NULL : (head)->prev)
#define llist_last(head, type, entry) \
llist_entry(__llist_last(head), type, entry)
/* TODO move GTP header stuff to openggsn/gtp/ ? See gtp_decaps*() */
enum gtp_rc {
@ -484,7 +475,7 @@ static int get_ie_imsi_str(union gtpie_member *ie[], int i,
* present but cannot be decoded. */
static int get_ie_apn_str(union gtpie_member *ie[], const char **apn_str)
{
static char apn_buf[GSM_APN_LENGTH];
static char apn_buf[APN_MAXLEN+1];
unsigned int len;
if (gtpie_gettlv(ie, GTPIE_APN, 0,
&len, apn_buf, sizeof(apn_buf)) != 0)
@ -613,7 +604,7 @@ void expiry_add(struct expiry *exq, struct expiring_item *item, time_t now)
OSMO_ASSERT(llist_empty(&exq->items)
|| (item->expiry
>= llist_last(&exq->items, struct expiring_item, entry)->expiry));
>= llist_last_entry(&exq->items, struct expiring_item, entry)->expiry));
/* Add/move to the tail to always sort by expiry, ascending. */
llist_del(&item->entry);
@ -980,7 +971,7 @@ static inline void set_tei(struct gtp_packet_desc *p, uint32_t tei)
static void gtphub_mapping_del_cb(struct expiring_item *expi);
static struct nr_mapping *gtphub_mapping_new()
static struct nr_mapping *gtphub_mapping_new(void)
{
struct nr_mapping *nrm;
nrm = talloc_zero(osmo_gtphub_ctx, struct nr_mapping);
@ -1004,7 +995,7 @@ static const char *gtphub_tunnel_side_str(struct gtphub_tunnel *tun,
char *pos = buf;
int left = sizeof(buf);
int l;
struct gtphub_tunnel_endpoint *c, *u;
c = &tun->endpoint[side_idx][GTPH_PLANE_CTRL];
u = &tun->endpoint[side_idx][GTPH_PLANE_USER];
@ -1113,7 +1104,7 @@ static void gtphub_tunnel_del_cb(struct expiring_item *expi)
/* rate counter index for hubs: [7; 10] */
#define CTR_IDX_HUB(s, p) CTR_IDX(s, p, 3, 2)
static struct gtphub_tunnel *gtphub_tunnel_new()
static struct gtphub_tunnel *gtphub_tunnel_new(void)
{
struct gtphub_tunnel *tun;
tun = talloc_zero(osmo_gtphub_ctx, struct gtphub_tunnel);
@ -1142,9 +1133,7 @@ static const char *gtphub_peer_strb(struct gtphub_peer *peer, char *buf,
if (llist_empty(&peer->addresses))
return "(addressless)";
struct gtphub_peer_addr *a = llist_first(&peer->addresses,
struct gtphub_peer_addr,
entry);
struct gtphub_peer_addr *a = llist_first_entry_or_null(&peer->addresses, struct gtphub_peer_addr, entry);
return gsn_addr_to_strb(&a->addr, buf, buflen);
}
@ -2125,7 +2114,7 @@ int gtphub_handle_buf(struct gtphub *hub,
struct gtphub_bind *from_bind = &hub->to_gsns[side_idx][plane_idx];
struct gtphub_bind *to_bind = &hub->to_gsns[other_side_idx(side_idx)][plane_idx];
rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_IN],
rate_ctr_add(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_BYTES_IN),
received);
struct gtp_packet_desc p;
@ -2147,7 +2136,7 @@ int gtphub_handle_buf(struct gtphub *hub,
return -1;
}
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_IN]);
rate_ctr_inc(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_PKTS_IN));
int reply_len;
reply_len = gtphub_handle_echo_req(hub, &p, reply_buf);
@ -2156,8 +2145,8 @@ int gtphub_handle_buf(struct gtphub *hub,
sgsn_sockaddr_copy(to_addr, from_addr);
*to_ofd = &from_bind->ofd;
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
rate_ctr_inc(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_PKTS_OUT));
rate_ctr_add(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_BYTES_OUT),
reply_len);
LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n",
(side_idx == GTPH_SIDE_GGSN)? "-->" : "<--",
@ -2236,9 +2225,9 @@ int gtphub_handle_buf(struct gtphub *hub,
return -1;
}
rate_ctr_add(&from_peer->counters_io->ctr[GTPH_CTR_BYTES_IN],
rate_ctr_add(rate_ctr_group_get_ctr(from_peer->counters_io, GTPH_CTR_BYTES_IN),
received);
rate_ctr_inc(&from_peer->counters_io->ctr[GTPH_CTR_PKTS_IN]);
rate_ctr_inc(rate_ctr_group_get_ctr(from_peer->counters_io, GTPH_CTR_PKTS_IN));
LOG(LOGL_DEBUG, "from %s peer: %s\n", gtphub_side_idx_names[side_idx],
gtphub_port_str(from_peer));
@ -2257,9 +2246,9 @@ int gtphub_handle_buf(struct gtphub *hub,
if (p.tun) {
struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[p.side_idx][p.plane_idx];
rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_IN],
rate_ctr_add(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_BYTES_IN),
received);
rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_IN]);
rate_ctr_inc(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_PKTS_IN));
}
if ((!to_peer) && (side_idx == GTPH_SIDE_SGSN)) {
@ -2294,7 +2283,7 @@ int gtphub_handle_buf(struct gtphub *hub,
!= 0)
return -1;
}
/* Either to_peer was resolved from an existing tunnel,
* or a PDP Ctx and thus a tunnel has just been created,
* or the tunnel has been deleted due to this message. */
@ -2311,19 +2300,19 @@ int gtphub_handle_buf(struct gtphub *hub,
*reply_buf = (uint8_t*)p.data;
if (received) {
rate_ctr_inc(&to_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
rate_ctr_add(&to_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
rate_ctr_inc(rate_ctr_group_get_ctr(to_bind->counters_io, GTPH_CTR_PKTS_OUT));
rate_ctr_add(rate_ctr_group_get_ctr(to_bind->counters_io, GTPH_CTR_BYTES_OUT),
received);
rate_ctr_inc(&to_peer->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
rate_ctr_add(&to_peer->counters_io->ctr[GTPH_CTR_BYTES_OUT],
rate_ctr_inc(rate_ctr_group_get_ctr(to_peer->counters_io, GTPH_CTR_PKTS_OUT));
rate_ctr_add(rate_ctr_group_get_ctr(to_peer->counters_io, GTPH_CTR_BYTES_OUT),
received);
}
if (p.tun) {
struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[other_side_idx(p.side_idx)][p.plane_idx];
rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_OUT],
rate_ctr_inc(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_PKTS_OUT));
rate_ctr_add(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_BYTES_OUT),
received);
}
@ -2701,7 +2690,7 @@ static struct gtphub_peer_addr *gtphub_addr_have(struct gtphub *hub,
struct gtphub_peer *peer = gtphub_peer_new(hub, bind);
a = gtphub_peer_add_addr(peer, addr);
LOG(LOGL_DEBUG, "New peer address: %s %s\n",
bind->label,
gsn_addr_to_str(&a->addr));

View File

@ -28,11 +28,12 @@
#include <string.h>
#include <unistd.h>
#include <osmocom/sgsn/gtphub.h>
#include <osmocom/gtphub/gtphub.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
/* TODO split GRX ares from sgsn into a separate struct and allow use without
* globals. */
@ -56,8 +57,8 @@ struct ggsn_lookup {
struct gtphub *hub;
char imsi_str[GSM23003_IMSI_MAX_DIGITS+1];
char apn_ni_str[GSM_APN_LENGTH];
char apn_oi_str[GSM_APN_LENGTH];
char apn_ni_str[APN_MAXLEN+1];
char apn_oi_str[APN_MAXLEN+1];
int have_3dig_mnc;
};

View File

@ -34,6 +34,7 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/msgb.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/telnet_interface.h>
@ -41,10 +42,10 @@
#include <osmocom/vty/misc.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gtphub.h>
#include <osmocom/gtphub/gtphub.h>
#include <osmocom/sgsn/vty.h>
#include "../../bscconfig.h"
#include "../../config.h"
#if BUILD_IU
#include <osmocom/sigtran/osmo_ss7.h>
@ -353,8 +354,7 @@ int main(int argc, char **argv)
}
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(),
OSMO_VTY_PORT_GTPHUB);
rc = telnet_init_default(osmo_gtphub_ctx, NULL, OSMO_VTY_PORT_GTPHUB);
if (rc < 0)
exit(1);

View File

@ -25,7 +25,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <osmocom/sgsn/gtphub.h>
#include <errno.h>
#include <string.h>
#include <osmocom/core/utils.h>
#include <osmocom/gtphub/gtphub.h>
#include <osmocom/sgsn/debug.h>
/* Convenience makro, note: only within this C file. */

View File

@ -31,7 +31,7 @@
#include <osmocom/vty/misc.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/sgsn/gtphub.h>
#include <osmocom/gtphub/gtphub.h>
/* TODO split GRX ares from sgsn into a separate struct and allow use without
* globals. */

View File

@ -40,12 +40,13 @@ bin_PROGRAMS = \
$(NULL)
osmo_sgsn_SOURCES = \
gprs_gb.c \
apn.c \
gprs_bssgp.c \
gprs_gmm_attach.c \
gprs_gmm.c \
gprs_gmm_fsm.c \
gprs_mm_state_gb_fsm.c \
gprs_sgsn.c \
gprs_ns.c \
gprs_sm.c \
gprs_sndcp.c \
gprs_sndcp_comp.c \
@ -53,11 +54,16 @@ osmo_sgsn_SOURCES = \
gprs_sndcp_pcomp.c \
gprs_sndcp_vty.c \
gprs_sndcp_xid.c \
gtp_ggsn.c \
gtp_mme.c \
sgsn.c \
sgsn_main.c \
sgsn_vty.c \
sgsn_libgtp.c \
gprs_llc.c \
gprs_llc_vty.c \
mmctx.c \
pdpctx.c \
sgsn_ctrl.c \
sgsn_auth.c \
gprs_subscriber.c \

123
src/sgsn/apn.c Normal file
View File

@ -0,0 +1,123 @@
/* APN contexts */
/* (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 <string.h>
#include <talloc.h>
#include <osmocom/sgsn/apn.h>
#include <osmocom/sgsn/sgsn.h>
static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
{
struct apn_ctx *actx;
actx = talloc_zero(sgsn, struct apn_ctx);
if (!actx)
return NULL;
actx->name = talloc_strdup(actx, ap_name);
actx->imsi_prefix = talloc_strdup(actx, imsi_prefix);
llist_add_tail(&actx->list, &sgsn->apn_list);
return actx;
}
void sgsn_apn_ctx_free(struct apn_ctx *actx)
{
llist_del(&actx->list);
talloc_free(actx);
}
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi)
{
struct apn_ctx *actx;
struct apn_ctx *found_actx = NULL;
size_t imsi_prio = 0;
size_t name_prio = 0;
size_t name_req_len = strlen(name);
llist_for_each_entry(actx, &sgsn->apn_list, list) {
size_t name_ref_len, imsi_ref_len;
const char *name_ref_start, *name_match_start;
imsi_ref_len = strlen(actx->imsi_prefix);
if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0)
continue;
if (imsi_ref_len < imsi_prio)
continue;
/* IMSI matches */
name_ref_start = &actx->name[0];
if (name_ref_start[0] == '*') {
/* Suffix match */
name_ref_start += 1;
name_ref_len = strlen(name_ref_start);
if (name_ref_len > name_req_len)
continue;
} else {
name_ref_len = strlen(name_ref_start);
if (name_ref_len != name_req_len)
continue;
}
name_match_start = name + (name_req_len - name_ref_len);
if (strcasecmp(name_match_start, name_ref_start) != 0)
continue;
/* IMSI and name match */
if (imsi_ref_len == imsi_prio && name_ref_len < name_prio)
/* Lower priority, skip */
continue;
imsi_prio = imsi_ref_len;
name_prio = name_ref_len;
found_actx = actx;
}
return found_actx;
}
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix)
{
struct apn_ctx *actx;
llist_for_each_entry(actx, &sgsn->apn_list, list) {
if (strcasecmp(name, actx->name) == 0 &&
strcasecmp(imsi_prefix, actx->imsi_prefix) == 0)
return actx;
}
return NULL;
}
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix)
{
struct apn_ctx *actx;
actx = sgsn_apn_ctx_by_name(name, imsi_prefix);
if (!actx)
actx = sgsn_apn_ctx_alloc(name, imsi_prefix);
return actx;
}

95
src/sgsn/gprs_bssgp.c Normal file
View File

@ -0,0 +1,95 @@
/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
* (C) 2022 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/prim.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/sgsn_rim.h>
#include <osmocom/sgsn/mmctx.h>
/* call-back function for the BSSGP protocol */
int sgsn_bssgp_rx_prim(struct osmo_prim_hdr *oph)
{
struct osmo_bssgp_prim *bp;
bp = container_of(oph, struct osmo_bssgp_prim, oph);
switch (oph->sap) {
case SAP_BSSGP_LL:
switch (oph->primitive) {
case PRIM_BSSGP_UL_UD:
return gprs_llc_rcvmsg(oph->msg, bp->tp);
}
break;
case SAP_BSSGP_GMM:
switch (oph->primitive) {
case PRIM_BSSGP_GMM_SUSPEND:
return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli);
case PRIM_BSSGP_GMM_RESUME:
return gprs_gmm_rx_resume(bp->ra_id, bp->tlli,
bp->u.resume.suspend_ref);
}
break;
case SAP_BSSGP_NM:
break;
case SAP_BSSGP_RIM:
return sgsn_rim_rx_from_gb(bp, oph->msg);
}
return 0;
}
int sgsn_bssgp_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(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PAGING_PS));
return rc;
}
/* called by the bssgp layer to send NS PDUs */
int sgsn_bssgp_dispatch_ns_unitdata_req_cb(void *ctx, struct msgb *msg)
{
struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx;
struct osmo_gprs_ns2_prim nsp = {};
nsp.nsei = msgb_nsei(msg);
nsp.bvci = msgb_bvci(msg);
osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
return gprs_ns2_recv_prim(nsi, &nsp.oph);
}

View File

@ -30,7 +30,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include "bscconfig.h"
#include "config.h"
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
@ -41,13 +41,14 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/tdef.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/crypt/utran_cipher.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/gprs_subscriber.h>
@ -59,17 +60,17 @@
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/pdpctx.h>
#include <pdp.h>
#define PTMSI_ALLOC
extern struct sgsn_instance *sgsn;
extern void *tall_sgsn_ctx;
static const struct tlv_definition gsm48_gmm_att_tlvdef = {
.def = {
[GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 1 },
[GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_SINGLE_TV, 1 },
[GSM48_IE_GMM_TIMER_READY] = { TLV_TYPE_TV, 1 },
[GSM48_IE_GMM_ALLOC_PTMSI] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_PTMSI_SIG] = { TLV_TYPE_FIXED, 3 },
@ -78,6 +79,7 @@ static const struct tlv_definition gsm48_gmm_att_tlvdef = {
[GSM48_IE_GMM_AUTH_RES_EXT] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_AUTH_FAIL_PAR] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_IMEISV] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_RX_NPDU_NUM_LIST] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_DRX_PARAM] = { TLV_TYPE_FIXED, 2 },
[GSM48_IE_GMM_MS_NET_CAPA] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_PDP_CTX_STATUS] = { TLV_TYPE_TLV, 0 },
@ -109,9 +111,14 @@ static void mmctx_timer_start(struct sgsn_mm_ctx *mm, unsigned int T)
static void mmctx_timer_stop(struct sgsn_mm_ctx *mm, unsigned int T)
{
if (mm->T != T)
if (!osmo_timer_pending(&mm->timer)) {
LOGMMCTXP(LOGL_NOTICE, mm, "Stopping *inactive* MM timer %u\n", T);
return;
}
if (mm->T != T) {
LOGMMCTXP(LOGL_ERROR, mm, "Stopping MM timer %u but "
"%u is running\n", T, mm->T);
}
osmo_timer_del(&mm->timer);
}
@ -131,7 +138,7 @@ int gsm48_gmm_sendmsg(struct msgb *msg, int command,
struct sgsn_mm_ctx *mm, bool encryptable)
{
if (mm) {
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
rate_ctr_inc(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_PKTS_SIG_OUT));
#ifdef BUILD_IU
if (mm->ran_type == MM_CTX_T_UTRAN_Iu)
return ranap_iu_tx(msg, GPRS_SAPI_GMM);
@ -197,10 +204,10 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
switch(ctx->ran_type) {
case MM_CTX_T_UTRAN_Iu:
osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
break;
case MM_CTX_T_GERAN_Gb:
osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
break;
}
@ -215,7 +222,7 @@ static int _tx_status(struct msgb *msg, uint8_t cause,
/* MMCTX might be NULL! */
DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n",
DEBUGP(DMM, "<- GMM STATUS (cause: %s)\n",
get_value_string(gsm48_gmm_cause_names, cause));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
@ -241,7 +248,7 @@ static int _tx_detach_req(struct msgb *msg, uint8_t detach_type, uint8_t cause,
/* MMCTX might be NULL! */
DEBUGP(DMM, "<- GPRS MM DETACH REQ (type: %s, cause: %s)\n",
DEBUGP(DMM, "<- GMM DETACH REQ (type: %s, cause: %s)\n",
get_value_string(gprs_det_t_mt_strs, detach_type),
get_value_string(gsm48_gmm_cause_names, cause));
@ -290,8 +297,8 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
uint8_t *ptsig;
#endif
LOGMMCTXP(LOGL_INFO, mm, "<- GPRS ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_ACKED]);
LOGMMCTXP(LOGL_INFO, mm, "<- GMM ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_ACKED));
mmctx2msgid(msg, mm);
@ -354,9 +361,9 @@ static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause,
{
struct gsm48_hdr *gh;
LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS ATTACH REJECT: %s\n",
LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM ATTACH REJECT: %s\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause));
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REJECTED]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REJECTED));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM_GPRS;
@ -388,8 +395,8 @@ static int _tx_detach_ack(struct msgb *msg, uint8_t force_stby,
/* MMCTX might be NULL! */
DEBUGP(DMM, "<- GPRS MM DETACH ACC (force-standby: %d)\n", force_stby);
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_ACKED]);
DEBUGP(DMM, "<- GMM DETACH ACC (force-standby: %d)\n", force_stby);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_ACKED));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM_GPRS;
@ -421,7 +428,7 @@ int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ");
struct gsm48_hdr *gh;
LOGMMCTXP(LOGL_DEBUG, mm, "<- GPRS IDENTITY REQUEST: mi_type=%s\n",
LOGMMCTXP(LOGL_DEBUG, mm, "<- GMM IDENTITY REQUEST: mi_type=%s\n",
gsm48_mi_type_name(id_type));
mmctx2msgid(msg, mm);
@ -445,6 +452,17 @@ static bool mmctx_is_r99(const struct sgsn_mm_ctx *mm)
return false;
}
static enum gprs_ciph_algo gprs_ms_net_select_best_gea(uint8_t net_mask, uint8_t ms_mask) {
uint8_t common_mask = net_mask & ms_mask;
uint8_t r = 0;
while (common_mask >>= 1) {
r++;
}
return r;
}
/* 3GPP TS 24.008 § 9.4.9: Authentication and Ciphering Request */
int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
const struct osmo_auth_vector *vec,
@ -456,7 +474,7 @@ int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
uint8_t *m_rand, *m_cksn, rbyte;
int rc;
LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s,"
LOGMMCTXP(LOGL_INFO, mm, "<- GMM AUTH AND CIPHERING REQ (rand = %s,"
" mmctx_is_r99=%d, vec->auth_types=0x%x",
osmo_hexdump(vec->rand, sizeof(vec->rand)),
mmctx_is_r99(mm), vec->auth_types);
@ -519,7 +537,7 @@ static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REJ");
struct gsm48_hdr *gh;
LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS AUTH AND CIPH REJECT\n");
LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM AUTH AND CIPH REJECT\n");
mmctx2msgid(msg, mm);
@ -599,7 +617,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
uint8_t res_len;
int rc;
LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH RESPONSE\n");
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH RESPONSE\n");
if (ctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
LOGMMCTXP(LOGL_NOTICE, ctx,
@ -650,7 +668,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
ctx->sec_ctx = check_auth_resp(ctx, false, &at->vec, res, res_len);
if (!sgsn_mm_ctx_is_authenticated(ctx)) {
rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
mm_ctx_cleanup_free(ctx, "GPRS AUTH AND CIPH REJECT");
mm_ctx_cleanup_free(ctx, "GMM AUTH AND CIPH REJECT");
return rc;
}
@ -673,7 +691,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
const uint8_t *auts;
int rc;
LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH FAILURE (cause = %s)\n",
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH FAILURE (cause = %s)\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause));
tlv_parse(&tp, &gsm48_gmm_att_tlvdef, gh->data+1, msg->len - 1, 0, 0);
@ -713,7 +731,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
LOGMMCTXP(LOGL_NOTICE, ctx, "Authentication failed\n");
rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
mm_ctx_cleanup_free(ctx, "GPRS AUTH FAILURE");
mm_ctx_cleanup_free(ctx, "GMM AUTH FAILURE");
return rc;
}
@ -792,7 +810,7 @@ static int gsm48_tx_gmm_service_ack(struct sgsn_mm_ctx *mm)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE ACK");
struct gsm48_hdr *gh;
LOGMMCTXP(LOGL_INFO, mm, "<- GPRS SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
LOGMMCTXP(LOGL_INFO, mm, "<- GMM SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
mmctx2msgid(msg, mm);
@ -813,7 +831,7 @@ static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause,
{
struct gsm48_hdr *gh;
LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n",
LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM SERVICE REJECT: %s\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
@ -905,7 +923,13 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
/* The MS is authorized */
#ifdef BUILD_IU
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) {
rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key);
/* Is any encryption above UEA0 enabled? */
bool send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n",
send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask);
/* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this
* is not possible in the iu_client API. See OS#5487. */
rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key);
ctx->iu.new_key = 0;
return rc;
}
@ -936,7 +960,7 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
#ifdef BUILD_IU
case GSM48_MT_GMM_SERVICE_REQ:
ctx->pending_req = 0;
osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_CONN_ESTABLISH, NULL);
rc = gsm48_tx_gmm_service_ack(ctx);
if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING)
@ -1087,7 +1111,7 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
"p_tmsi_old=0x%08x\n",
ictx->p_tmsi);
mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
mm_ctx_cleanup_free(ictx, "GMM IMSI re-use");
}
}
OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
@ -1147,6 +1171,21 @@ static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
}
static uint8_t gprs_ms_net_cap_gea_mask(const uint8_t *ms_net_cap, uint8_t cap_len)
{
uint8_t mask = (1 << GPRS_ALGO_GEA0);
mask |= (0x80 & ms_net_cap[0]) ? (1 << GPRS_ALGO_GEA1) : 0;
if (cap_len < 2)
return mask;
/* extended GEA bits start from 2nd bit of the next byte */
mask |= (0x40 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA2) : 0;
mask |= (0x20 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA3) : 0;
mask |= (0x10 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA4) : 0;
return mask;
}
/* 3GPP TS 24.008 § 9.4.1 Attach request */
static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
struct gprs_llc_llme *llme)
@ -1163,7 +1202,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
int rc;
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REQUEST]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REQUEST));
/* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either
* with a foreign TLLI (P-TMSI that was allocated to the MS before),
@ -1290,15 +1329,27 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
ctx->ms_radio_access_capa.len);
ctx->ms_network_capa.len = msnc_len;
memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);
if (!gprs_ms_net_cap_gea_supported(ctx->ms_network_capa.buf, msnc_len,
ctx->ciph_algo)) {
ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf, msnc_len);
if (!(ctx->ue_cipher_mask & sgsn->cfg.gea_encryption_mask)) {
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
"%s because MS do not support required %s "
"encryption\n", mi_log_string,
get_value_string(gprs_cipher_names,ctx->ciph_algo));
"%s because MS do not support required encryption, mask UE:0x%02x NW:0x%02x \n",
mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
goto rejected;
}
/* just assume that everythig is fine if the phone offers a5/4:
* it requires a valid umts security context which we can only have after
* 1) IDENTITY REQUEST to know what to ask the HLR for
* 2) and AUTHENTICATION AND CIPHERING REQUEST
* ... but 2) already requires selecting a cipher mode.
* So let's just assume we will have the auth data required to make it work.
*/
ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
#ifdef PTMSI_ALLOC
/* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
ptmsi_update(ctx);
@ -1330,7 +1381,7 @@ rejected:
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
rc = gsm48_tx_gmm_att_rej_oldmsg(msg, reject_cause);
if (ctx)
mm_ctx_cleanup_free(ctx, "GPRS ATTACH REJ");
mm_ctx_cleanup_free(ctx, "GMM ATTACH REJ");
else if (llme)
gprs_llgmm_unassign(llme);
@ -1343,13 +1394,13 @@ static int gsm48_rx_gmm_att_compl(struct sgsn_mm_ctx *mmctx)
{
struct sgsn_signal_data sig_data;
/* only in case SGSN offered new P-TMSI */
LOGMMCTXP(LOGL_INFO, mmctx, "-> ATTACH COMPLETE\n");
LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM ATTACH COMPLETE\n");
#ifdef BUILD_IU
#ifdef BUILD_IU
if (mmctx->iu.ue_ctx) {
ranap_iu_tx_release(mmctx->iu.ue_ctx, NULL);
}
#endif
#endif
mmctx_timer_stop(mmctx, 3350);
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
@ -1410,7 +1461,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
power_off = gh->data[0] & 0x8;
/* FIXME: In 24.008 there is an optional P-TMSI and P-TMSI signature IE */
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_REQUEST]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_REQUEST));
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM DETACH REQUEST TLLI=0x%08x type=%s %s\n",
msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type),
power_off ? "Power-off" : "");
@ -1430,7 +1481,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
memset(&sig_data, 0, sizeof(sig_data));
sig_data.mm = ctx;
osmo_signal_dispatch(SS_SGSN, S_SGSN_DETACH, &sig_data);
mm_ctx_cleanup_free(ctx, "GPRS DETACH REQUEST");
mm_ctx_cleanup_free(ctx, "GMM DETACH REQUEST");
}
return rc;
@ -1449,8 +1500,8 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
struct osmo_mobile_identity mi;
#endif
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);
LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_ACKED));
LOGMMCTXP(LOGL_INFO, mm, "<- GMM ROUTING AREA UPDATE ACCEPT\n");
mmctx2msgid(msg, mm);
@ -1505,7 +1556,7 @@ int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
struct gsm48_hdr *gh;
LOGP(DMM, LOGL_NOTICE, "<- ROUTING AREA UPDATE REJECT\n");
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REJECT]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REJECT));
gmm_copy_id(msg, old_msg);
@ -1585,7 +1636,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Update Type 10.5.5.18 */
upd_type = *cur++ & 0x07;
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REQUEST]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REQUEST));
LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM RA UPDATE REQUEST type=\"%s\"\n",
get_value_string(gprs_upd_t_strs, upd_type));
@ -1713,7 +1764,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */
msgid2mmctx(mmctx, msg);
/* Bump the statistics of received signalling msgs for this MM context */
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
/* Update the MM context with the new RA-ID */
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb && msgb_bcid(msg)) {
@ -1721,10 +1772,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Update the MM context with the new (i.e. foreign) TLLI */
mmctx->gb.tlli = msgb_tlli(msg);
}
/* Update the MM context with the new DRX params */
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_DRX_PARAM))
memcpy(&mmctx->drx_parms, TLVP_VAL(&tp, GSM48_IE_GMM_DRX_PARAM), sizeof(mmctx->drx_parms));
/* FIXME: Update the MM context with the MS radio acc capabilities */
/* FIXME: Update the MM context with the MS network capabilities */
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]);
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_RA_UPDATE));
#ifdef PTMSI_ALLOC
ptmsi_update(mmctx);
@ -1770,7 +1825,7 @@ rejected:
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause);
if (mmctx)
mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ");
mm_ctx_cleanup_free(mmctx, "GMM RA UPDATE REJ");
else if (llme)
gprs_llgmm_unassign(llme);
#ifdef BUILD_IU
@ -1952,7 +2007,7 @@ static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
LOGMMCTXP(LOGL_INFO, mmctx, "-> GPRS MM STATUS (cause: %s)\n",
LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM STATUS (cause: %s)\n",
get_value_string(gsm48_gmm_cause_names, gh->data[0]));
return 0;
@ -2071,7 +2126,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
if (!mmctx)
goto null_mmctx;
LOGMMCTXP(LOGL_INFO, mmctx, "-> DETACH ACK\n");
mm_ctx_cleanup_free(mmctx, "GPRS DETACH ACK");
mm_ctx_cleanup_free(mmctx, "GMM DETACH ACK");
rc = 0;
break;
case GSM48_MT_GMM_ATTACH_COMPL:
@ -2111,9 +2166,9 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
null_mmctx:
LOGGBIUP(llme, msg, LOGL_ERROR,
"Received GSM 04.08 message type 0x%02x,"
"Received GSM 04.08 message type %s,"
" but no MM context available\n",
gh->msg_type);
get_value_string(gprs_msgt_gmm_names, gh->msg_type));
return -EINVAL;
}
@ -2180,7 +2235,7 @@ static void mmctx_timer_cb(void *_mm)
if (mm->num_T_exp >= 5) {
LOGMMCTXP(LOGL_NOTICE, mm, "T3370 expired >= 5 times\n");
gsm48_tx_gmm_att_rej(mm, GMM_CAUSE_MS_ID_NOT_DERIVED);
mm_ctx_cleanup_free(mm, "GPRS ATTACH REJECT (T3370)");
mm_ctx_cleanup_free(mm, "GMM ATTACH REJECT (T3370)");
break;
}
/* re-tranmit IDENTITY REQUEST and re-start timer */
@ -2268,3 +2323,51 @@ int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RESUME, NULL);
return 0;
}
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg)
{
msgid2mmctx(mmctx, msg);
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) {
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
mmctx->gb.llme = llme;
gprs_gb_recv_pdu(mmctx, msg);
}
/* 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;
}

View File

@ -1,10 +1,12 @@
#include <osmocom/core/tdef.h>
#include <osmocom/crypt/utran_cipher.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/sgsn.h>
#define X(s) (1 << (s))
@ -257,6 +259,7 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
{
#ifdef BUILD_IU
struct sgsn_mm_ctx *ctx = fi->priv;
bool send_ck;
/* TODO: shouldn't this set always? not only when the integrity_active? */
if (ctx->iu.ue_ctx->integrity_active) {
@ -264,7 +267,14 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
return;
}
ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key);
/* Is any encryption above UEA0 enabled? */
send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n",
send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask);
/* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this
* is not possible in the iu_client API. See OS#5487. */
ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key);
ctx->iu.new_key = 0;
#endif
}
@ -272,6 +282,13 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
static void st_iu_security_cmd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
case E_VLR_ANSWERED:
/* We may receive an event due to rx
* OSMO_GSUP_MSGT_INSERT_DATA_REQUEST here. Do nothing, update of
* subscriber is done by lower layers before event is signalled.
* In this state we simply wait for E_IU_SECURITY_CMD_COMPLETE
*/
break;
case E_IU_SECURITY_CMD_COMPLETE:
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
break;
@ -308,7 +325,7 @@ static struct osmo_fsm_state gmm_attach_req_fsm_states[] = {
.action = st_auth,
},
[ST_IU_SECURITY_CMD] = {
.in_event_mask = X(E_IU_SECURITY_CMD_COMPLETE),
.in_event_mask = X(E_IU_SECURITY_CMD_COMPLETE) | X(E_VLR_ANSWERED),
.out_state_mask = X(ST_INIT) | X(ST_AUTH) | X(ST_ACCEPT) | X(ST_REJECT),
.name = "IuSecurityCommand",
.onenter = st_iu_security_cmd_on_enter,

View File

@ -1,6 +1,6 @@
/* GMM mobility management states on the network side, 3GPP TS 24.008 § 4.1.3.3 */
/*
* (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
@ -57,6 +57,10 @@ static void st_gmm_deregistered(struct osmo_fsm_inst *fi, uint32_t event, void *
static void st_gmm_common_proc_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
case E_GMM_COMMON_PROC_INIT_REQ:
/* MS may retransmit GPRS Attach Request if for some reason
* CommonProcedure didn't go forward correctly */
break;
/* TODO: events not used
case E_GMM_LOWER_LAYER_FAILED:
case E_GMM_COMMON_PROC_FAILED:
@ -76,6 +80,11 @@ static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, v
case E_GMM_COMMON_PROC_INIT_REQ:
gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
break;
case E_GMM_COMMON_PROC_SUCCESS:
/* If we were moved from ST_GMM_COMMON_PROC_INIT here by
* E_GMM_ATTACH_SUCCESS instead of E_GMM_COMMON_PROC_SUCCESS then we'll receive the latter here:
* we should simply ignore it */
break;
/* case E_GMM_NET_INIT_DETACH_REQ:
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT);
break; */
@ -126,7 +135,8 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
/* X(E_GMM_LOWER_LAYER_FAILED) | */
/* X(E_GMM_COMMON_PROC_FAILED) | */
X(E_GMM_COMMON_PROC_SUCCESS) |
X(E_GMM_ATTACH_SUCCESS),
X(E_GMM_ATTACH_SUCCESS) |
X(E_GMM_COMMON_PROC_INIT_REQ),
.out_state_mask =
X(ST_GMM_DEREGISTERED) |
X(ST_GMM_REGISTERED_NORMAL),
@ -136,6 +146,7 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
[ST_GMM_REGISTERED_NORMAL] = {
.in_event_mask =
X(E_GMM_COMMON_PROC_INIT_REQ) |
X(E_GMM_COMMON_PROC_SUCCESS) |
/* X(E_GMM_NET_INIT_DETACH_REQ) | */
/* X(E_GMM_MS_INIT_DETACH_REQ) | */
X(E_GMM_SUSPEND),
@ -194,9 +205,9 @@ void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *dat
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
default:
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
mmctx->gb.llme = rat_chg->llme;
}

View File

@ -33,7 +33,7 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/crc24.h>
@ -42,16 +42,29 @@
#include <osmocom/sgsn/gprs_sndcp_comp.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/crypt/kdf.h>
const struct value_string gprs_llc_llme_state_names[] = {
{ GPRS_LLMS_UNASSIGNED, "UNASSIGNED" },
{ GPRS_LLMS_ASSIGNED, "ASSIGNED" },
{ 0, NULL }
};
const struct value_string gprs_llc_lle_state_names[] = {
{ GPRS_LLES_UNASSIGNED, "TLLI Unassigned" },
{ GPRS_LLES_ASSIGNED_ADM, "TLLI Assigned" },
{ GPRS_LLES_LOCAL_EST, "Local Establishment" },
{ GPRS_LLES_REMOTE_EST, "Remote Establishment" },
{ GPRS_LLES_ABM, "Asynchronous Balanced Mode" },
{ GPRS_LLES_LOCAL_REL, "Local Release" },
{ GPRS_LLES_TIMER_REC, "Timer Recovery" },
{ 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,
static int gprs_llc_tx_xid(const 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_dm(const 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);
@ -210,7 +223,7 @@ static int gprs_llc_process_xid_ind(uint8_t *bytes_request,
int bytes_request_len,
uint8_t *bytes_response,
int bytes_response_maxlen,
struct gprs_llc_lle *lle)
const struct gprs_llc_lle *lle)
{
/* Note: This function computes the response that is sent back to the
* MS when a mobile originated XID is received. The function is
@ -286,7 +299,7 @@ static int gprs_llc_process_xid_ind(uint8_t *bytes_request,
/* Dispatch XID indications and responses comming from the MS */
static void rx_llc_xid(struct gprs_llc_lle *lle,
struct gprs_llc_hdr_parsed *gph)
const struct gprs_llc_hdr_parsed *gph)
{
uint8_t response[1024];
int response_len;
@ -588,6 +601,7 @@ static struct gprs_llc_llme *llme_alloc(uint32_t tlli)
static void llme_free(struct gprs_llc_llme *llme)
{
gprs_sndcp_sm_deactivate_ind_by_llme(llme);
gprs_sndcp_comp_free(llme->comp.proto);
gprs_sndcp_comp_free(llme->comp.data);
llist_del(&llme->list);
@ -670,15 +684,15 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
/* Identifiers passed down: (BVCI, NSEI) */
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]);
rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_PACKETS));
rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_BYTES), msg->len);
/* Send BSSGP-DL-UNITDATA.req */
return _bssgp_tx_dl_ud(msg, NULL);
}
/* Send XID response to LLE */
static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
static int gprs_llc_tx_xid(const struct gprs_llc_lle *lle, struct msgb *msg,
int command)
{
/* copy identifiers from LLE to ensure lower layers can route */
@ -689,7 +703,7 @@ 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)
static int gprs_llc_tx_dm(const struct gprs_llc_lle *lle)
{
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_DM");
@ -702,7 +716,7 @@ static int gprs_llc_tx_dm(struct gprs_llc_lle *lle)
}
/* encrypt information field + FCS, if needed! */
static int apply_gea(struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
static int apply_gea(const struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
uint32_t oc, uint8_t sapi, uint8_t *fcs, uint8_t *data)
{
uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
@ -814,8 +828,8 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
}
}
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]);
rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_PACKETS));
rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_BYTES), msg->len);
/* Identifiers passed down: (BVCI, NSEI) */
@ -962,9 +976,9 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
llhp.data);
if (rc < 0)
return rc;
llhp.fcs = *(llhp.data + llhp.data_len);
llhp.fcs |= *(llhp.data + llhp.data_len + 1) << 8;
llhp.fcs |= *(llhp.data + llhp.data_len + 2) << 16;
llhp.fcs = *(llhp.data + llhp.data_len);
llhp.fcs |= *(llhp.data + llhp.data_len + 1) << 8;
llhp.fcs |= *(llhp.data + llhp.data_len + 2) << 16;
} else {
LOGP(DLLC, LOGL_NOTICE, "encrypted frame for LLC that "
"has no KC/Algo! Dropping.\n");
@ -1000,8 +1014,8 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
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);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_UL_PACKETS));
rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_UL_BYTES), msg->len);
/* llhp.data is only set when we need to send LL_[UNIT]DATA_IND up */
if (llhp.cmd == GPRS_LLC_UI && llhp.data && llhp.data_len) {
@ -1016,7 +1030,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
case GPRS_SAPI_SNDCP9:
case GPRS_SAPI_SNDCP11:
/* send LL_DATA_IND/LL_UNITDATA_IND to SNDCP */
rc = sndcp_llunitdata_ind(msg, lle, llhp.data, llhp.data_len);
rc = sndcp_ll_unitdata_ind(msg, lle, llhp.data, llhp.data_len);
break;
case GPRS_SAPI_SMS:
/* FIXME */
@ -1034,7 +1048,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
}
/* Propagate crypto parameters MM -> LLME */
void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
void gprs_llme_copy_key(const struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
{
if (!mm)
return;
@ -1042,8 +1056,13 @@ void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
llme->algo = mm->ciph_algo;
if (llme->cksn != mm->auth_triplet.key_seq &&
mm->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {
memcpy(llme->kc, mm->auth_triplet.vec.kc,
gprs_cipher_key_length(mm->ciph_algo));
/* gea4 needs kc128 */
if (mm->ciph_algo == GPRS_ALGO_GEA4)
osmo_kdf_kc128(mm->auth_triplet.vec.ck, mm->auth_triplet.vec.ik, llme->kc);
else
memcpy(llme->kc, mm->auth_triplet.vec.kc, gprs_cipher_key_length(mm->ciph_algo));
llme->cksn = mm->auth_triplet.key_seq;
}
} else

View File

@ -39,22 +39,11 @@
#include <osmocom/vty/vty.h>
#include <osmocom/vty/command.h>
struct value_string gprs_llc_state_strs[] = {
{ GPRS_LLES_UNASSIGNED, "TLLI Unassigned" },
{ GPRS_LLES_ASSIGNED_ADM, "TLLI Assigned" },
{ GPRS_LLES_LOCAL_EST, "Local Establishment" },
{ GPRS_LLES_REMOTE_EST, "Remote Establishment" },
{ GPRS_LLES_ABM, "Asynchronous Balanced Mode" },
{ GPRS_LLES_LOCAL_REL, "Local Release" },
{ GPRS_LLES_TIMER_REC, "Timer Recovery" },
{ 0, NULL }
};
static void vty_dump_lle(struct vty *vty, struct gprs_llc_lle *lle)
{
struct gprs_llc_params *par = &lle->params;
vty_out(vty, " SAPI %2u State %s VUsend=%u, VUrecv=%u", lle->sapi,
get_value_string(gprs_llc_state_strs, lle->state),
vty_out(vty, " SAPI %2u State %s VUsend=%u, VUrecv=%u", lle->sapi,
get_value_string(gprs_llc_lle_state_names, lle->state),
lle->vu_send, lle->vu_recv);
vty_out(vty, " Vsent=%u Vack=%u Vrecv=%u, RetransCtr=%u%s",
lle->v_sent, lle->v_ack, lle->v_recv,
@ -79,7 +68,7 @@ static void vty_dump_llme(struct vty *vty, struct gprs_llc_llme *llme)
get_value_string(gprs_cipher_names, llme->algo), llme->iov_ui,
llme->cksn, llme->age_timestamp == GPRS_LLME_RESET_AGE ? 0 :
(int)(now_tp.tv_sec - (time_t)llme->age_timestamp),
get_value_string(gprs_llc_state_strs, llme->state), VTY_NEWLINE);
get_value_string(gprs_llc_llme_state_names, llme->state), VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(valid_sapis); i++) {
struct gprs_llc_lle *lle;

View File

@ -1,3 +1,25 @@
/* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */
/*
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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/tdef.h>
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
@ -5,6 +27,7 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#define X(s) (1 << (s))
@ -49,7 +72,7 @@ static void st_mm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_MM_READY_TIMER_EXPIRY:
mm_state_gb_fsm_state_chg(fi, ST_MM_STANDBY);
break;
case E_MM_IMPLICIT_DETACH:
case E_MM_GPRS_DETACH:
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
break;
case E_MM_PDU_RECEPTION:
@ -68,7 +91,7 @@ static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_MM_PDU_RECEPTION:
mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
break;
case E_MM_IMPLICIT_DETACH:
case E_MM_GPRS_DETACH:
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
break;
}
@ -83,13 +106,13 @@ static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
.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),
.in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_GPRS_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) | X(E_MM_IMPLICIT_DETACH),
.in_event_mask = X(E_MM_PDU_RECEPTION) | X(E_MM_GPRS_DETACH),
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
.name = "Standby",
.action = st_mm_standby,
@ -99,7 +122,7 @@ static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
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_GPRS_DETACH),
OSMO_VALUE_STRING(E_MM_READY_TIMER_EXPIRY),
OSMO_VALUE_STRING(E_MM_RA_UPDATE),
{ 0, NULL }

View File

@ -1,3 +1,25 @@
/* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */
/*
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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 <arpa/inet.h>
#include <osmocom/core/tdef.h>
@ -7,13 +29,15 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/mmctx.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_CONNECTED] = { },
[ST_PMM_IDLE] = { },
};
@ -40,7 +64,7 @@ static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data
case E_PMM_PS_ATTACH:
mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
break;
case E_PMM_IMPLICIT_DETACH:
case E_PMM_PS_DETACH:
break;
}
}
@ -48,24 +72,16 @@ static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data
static void st_pmm_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct sgsn_mm_ctx *ctx = fi->priv;
const struct RANAP_Cause user_inactive_cause = {
.present = RANAP_Cause_PR_radioNetwork,
.choice.radioNetwork = RANAP_CauseRadioNetwork_user_inactivity,
};
switch(event) {
case E_PMM_PS_CONN_RELEASE:
sgsn_ranap_iu_free(ctx);
mm_state_iu_fsm_state_chg(fi, ST_PMM_IDLE);
break;
case E_PMM_IMPLICIT_DETACH:
case E_PMM_PS_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;
}
@ -81,43 +97,37 @@ static void st_pmm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
static void st_pmm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
case E_PMM_PS_ATTACH:
case E_PMM_PS_CONN_ESTABLISH:
mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
break;
case E_PMM_IMPLICIT_DETACH:
case E_PMM_PS_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),
.in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_PS_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),
.in_event_mask =
X(E_PMM_PS_CONN_RELEASE) |
X(E_PMM_RA_UPDATE) |
X(E_PMM_PS_DETACH),
.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),
.in_event_mask =
X(E_PMM_PS_DETACH) |
X(E_PMM_PS_CONN_ESTABLISH) |
X(E_PMM_PS_ATTACH),
.out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_CONNECTED),
.name = "Idle",
.onenter = st_pmm_idle_on_enter,
@ -129,9 +139,8 @@ 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_PS_DETACH),
OSMO_VALUE_STRING(E_PMM_RA_UPDATE),
OSMO_VALUE_STRING(E_PMM_USER_INACTIVITY),
{ 0, NULL }
};
@ -140,7 +149,6 @@ struct osmo_fsm mm_state_iu_fsm = {
.states = mm_state_iu_fsm_states,
.num_states = ARRAY_SIZE(mm_state_iu_fsm_states),
.event_names = mm_state_iu_fsm_event_names,
.timer_cb = pmm_state_fsm_timer_cb,
.log_subsys = DMM,
};

View File

@ -29,95 +29,10 @@
#include <osmocom/gprs/gprs_bssgp_bss.h>
#include <osmocom/sgsn/gprs_llc.h>
#include "bscconfig.h"
#include "config.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, const struct msgb *msg) {
msgid2mmctx(mmctx, msg);
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) {
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
mmctx->gb.llme = llme;
gprs_gb_recv_pdu(mmctx, msg);
}
/* 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;
}
/* called by the bssgp layer to send NS PDUs */
int gprs_gb_send_cb(void *ctx, struct msgb *msg)
{
struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx;
struct osmo_gprs_ns2_prim nsp = {};
nsp.nsei = msgb_nsei(msg);
nsp.bvci = msgb_bvci(msg);
osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
return gprs_ns2_recv_prim(nsi, &nsp.oph);
}
void gprs_ns_prim_status_cb(struct osmo_gprs_ns2_prim *nsp)
{
switch (nsp->u.status.cause) {

View File

@ -21,7 +21,7 @@
*
*/
#include "bscconfig.h"
#include "config.h"
#include <gtp.h>
#include <osmocom/core/rate_ctr.h>
@ -37,6 +37,10 @@
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/mmctx.h>
/* Send RAB activation requests for all PDP contexts */
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
@ -120,7 +124,8 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
mm = sgsn_mm_ctx_by_ue_ctx(ctx);
if (!mm) {
LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %d\n", type);
LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %s\n",
ranap_iu_event_type_str(type));
ranap_iu_free_ue(ctx);
return rc;
}
@ -133,10 +138,9 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
/* 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
LOGMMCTXP(LOGL_INFO, mm, "IU release (cause=%s)\n", ranap_iu_event_type_str(type));
rc = osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL);
if (rc < 0)
sgsn_ranap_iu_free(mm);
/* TODO: move this into FSM */
@ -145,6 +149,11 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
rc = 0;
break;
case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE:
/* FIXME: verify that a permitted UEA level was chosen. Compare how osmo-msc does it in
* msc_a_ran_dec_from_msc_i(), case RAN_MSG_CIPHER_MODE_COMPLETE.
* We should dissolve iu_client.c, it was a design mistake when first implementing Iu support. osmo-msc
* has moved away from it a long time ago.
*/
/* Continue authentication here */
mm->iu.ue_ctx->integrity_active = 1;
ranap_iu_tx_common_id(mm->iu.ue_ctx, mm->imsi);
@ -232,7 +241,7 @@ int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
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]);
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
if (ra_id)
memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra));
}

View File

@ -26,7 +26,7 @@
#include <arpa/inet.h>
#include <netdb.h>
#include "bscconfig.h"
#include "config.h"
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/tdef.h>
@ -36,13 +36,15 @@
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/gtp_ggsn.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;
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/mmctx.h>
/* 3GPP TS 04.08 sec 6.1.3.4.3(.a) "Abnormal cases" */
#define T339X_MAX_RETRANS 4
@ -186,7 +188,7 @@ int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)
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]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_ACCEPT));
mmctx2msgid(msg, pdp->mm);
@ -232,7 +234,7 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
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]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_REJECT));
mmctx2msgid(msg, mm);
@ -257,7 +259,7 @@ static int _gsm48_tx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, uint8_t tid,
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]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_DL_DEACTIVATE_REQUEST));
mmctx2msgid(msg, mm);
@ -285,7 +287,7 @@ static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)
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]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_DL_DEACTIVATE_ACCEPT));
mmctx2msgid(msg, mm);
@ -376,7 +378,7 @@ static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent *
goto reject_due_failure;
}
ggsn = sgsn_ggsn_ctx_alloc(UINT32_MAX);
ggsn = sgsn_ggsn_ctx_alloc(sgsn, UINT32_MAX);
if (!ggsn) {
LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "Failed to create ggsn.\n");
goto reject_due_failure;
@ -448,7 +450,7 @@ static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *del
DEBUGPC(DMM, "IPv4 ");
if (req_pdpa_len >= 6) {
struct in_addr ia;
ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2)));
ia.s_addr = osmo_load32be(req_pdpa+2);
DEBUGPC(DMM, "%s ", inet_ntop(AF_INET, &ia, buf, sizeof(buf)));
}
break;
@ -533,7 +535,7 @@ static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *del
/* Only increment counter for a real activation, after we checked
* for re-transmissions */
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PDP_CTX_ACT]);
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, 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);
@ -591,7 +593,7 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
struct msgb *msg;
int rc;
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REQUEST]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_REQUEST));
/*
* This is painful. We might not have a static GGSN
@ -629,7 +631,7 @@ static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
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]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_UL_DEACTIVATE_REQUEST));
pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
if (!pdp) {
@ -654,7 +656,7 @@ static int gsm48_rx_gsm_deact_pdp_ack(struct sgsn_mm_ctx *mm, struct msgb *msg)
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]);
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_UL_DEACTIVATE_ACCEPT));
pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
if (!pdp) {

View File

@ -32,7 +32,7 @@
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_gb.h>
#include <osmocom/sgsn/gprs_ns.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_sndcp.h>
@ -41,6 +41,9 @@
#include <osmocom/sgsn/gprs_sndcp_pcomp.h>
#include <osmocom/sgsn/gprs_sndcp_dcomp.h>
#include <osmocom/sgsn/gprs_sndcp_comp.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gtp.h>
#define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */
@ -66,7 +69,7 @@ static uint16_t calc_ip_csum(uint8_t *data, int len)
}
/* Calculate TCP/IP checksum */
static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len)
static uint16_t calc_tcpip_csum(const void *ctx, const uint8_t *packet, int len)
{
uint8_t *buf;
uint16_t csum;
@ -84,7 +87,7 @@ static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len)
}
/* Show some ip packet details */
static void debug_ip_packet(uint8_t *data, int len, int dir, char *info)
static void debug_ip_packet(const uint8_t *data, int len, int dir, const char *info)
{
uint8_t tcp_flags;
char flags_debugmsg[256];
@ -173,7 +176,7 @@ struct sndcp_common_hdr {
uint8_t first:1;
uint8_t spare:1;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
uint8_t spare:1, first:1, type:1, more:1, nsapi:4;
#endif
} __attribute__((packed));
@ -185,7 +188,7 @@ struct sndcp_comp_hdr {
uint8_t pcomp:4;
uint8_t dcomp:4;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
uint8_t dcomp:4, pcomp:4;
#endif
} __attribute__((packed));
@ -198,7 +201,7 @@ struct sndcp_udata_hdr {
/* octet 4 */
uint8_t npdu_low;
#elif OSMO_IS_BIG_ENDIAN
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
uint8_t seg_nr:4, npdu_high:4;
uint8_t npdu_low;
#endif
@ -221,7 +224,8 @@ struct defrag_queue_entry {
LLIST_HEAD(gprs_sndcp_entities);
/* Check if any compression parameters are set in the sgsn configuration */
static inline int any_pcomp_or_dcomp_active(struct sgsn_instance *sgsn) {
static inline int any_pcomp_or_dcomp_active(const struct sgsn_instance *sgsn)
{
if (sgsn->cfg.pcomp_rfc1144.active || sgsn->cfg.pcomp_rfc1144.passive ||
sgsn->cfg.dcomp_v42bis.active || sgsn->cfg.dcomp_v42bis.passive)
return true;
@ -260,7 +264,7 @@ static int defrag_enqueue(struct gprs_sndcp_entity *sne, uint8_t seg_nr,
}
/* return if we have all segments of this N-PDU */
static int defrag_have_all_segments(struct gprs_sndcp_entity *sne)
static int defrag_have_all_segments(const struct gprs_sndcp_entity *sne)
{
uint32_t seg_needed = 0;
unsigned int i;
@ -275,7 +279,7 @@ static int defrag_have_all_segments(struct gprs_sndcp_entity *sne)
return 0;
}
static struct defrag_queue_entry *defrag_get_seg(struct gprs_sndcp_entity *sne,
static struct defrag_queue_entry *defrag_get_seg(const struct gprs_sndcp_entity *sne,
uint32_t seg_nr)
{
struct defrag_queue_entry *dqe;
@ -289,13 +293,62 @@ static struct defrag_queue_entry *defrag_get_seg(struct gprs_sndcp_entity *sne,
return NULL;
}
/* Returns talloced buffer containing decompressed data, NULL on error. */
static uint8_t *decompress_segment(struct gprs_sndcp_entity *sne, void *ctx,
const uint8_t *compressed_data, unsigned int compressed_data_len,
unsigned int *decompressed_data_len)
{
int rc;
uint8_t *expnd = NULL;
*decompressed_data_len = 0;
#if DEBUG_IP_PACKETS == 1
DEBUGP(DSNDCP, "\n");
DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
DEBUGP(DSNDCP, "===================================================\n");
#endif
expnd = talloc_zero_size(ctx, compressed_data_len * MAX_DATADECOMPR_FAC +
MAX_HDRDECOMPR_INCR);
memcpy(expnd, compressed_data, compressed_data_len);
/* Apply data decompression */
rc = gprs_sndcp_dcomp_expand(expnd, compressed_data_len, sne->defrag.dcomp,
sne->defrag.data);
if (rc < 0) {
LOGP(DSNDCP, LOGL_ERROR,
"Data decompression failed!\n");
talloc_free(expnd);
return NULL;
}
/* Apply header decompression */
rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp, sne->defrag.proto);
if (rc < 0) {
LOGP(DSNDCP, LOGL_ERROR,
"TCP/IP Header decompression failed!\n");
talloc_free(expnd);
return NULL;
}
*decompressed_data_len = rc;
#if DEBUG_IP_PACKETS == 1
debug_ip_packet(expnd, *decompressed_data_len, 1, "defrag_segments()");
DEBUGP(DSNDCP, "===================================================\n");
DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
DEBUGP(DSNDCP, "\n");
#endif
return expnd;
}
/* Perform actual defragmentation and create an output packet */
static int defrag_segments(struct gprs_sndcp_entity *sne)
{
struct msgb *msg;
unsigned int seg_nr;
uint8_t *npdu;
int npdu_len;
unsigned int npdu_len;
int rc;
uint8_t *expnd = NULL;
@ -336,53 +389,20 @@ static int defrag_segments(struct gprs_sndcp_entity *sne)
* hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */
/* Decompress packet */
#if DEBUG_IP_PACKETS == 1
DEBUGP(DSNDCP, " \n");
DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
DEBUGP(DSNDCP, "===================================================\n");
#endif
if (any_pcomp_or_dcomp_active(sgsn)) {
expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC +
MAX_HDRDECOMPR_INCR);
memcpy(expnd, npdu, npdu_len);
/* Apply data decompression */
rc = gprs_sndcp_dcomp_expand(expnd, npdu_len, sne->defrag.dcomp,
sne->defrag.data);
if (rc < 0) {
LOGP(DSNDCP, LOGL_ERROR,
"Data decompression failed!\n");
talloc_free(expnd);
return -EIO;
expnd = decompress_segment(sne, msg, npdu, npdu_len, &npdu_len);
if (!expnd) {
rc = -EIO;
goto ret_free;
}
/* Apply header decompression */
rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp,
sne->defrag.proto);
if (rc < 0) {
LOGP(DSNDCP, LOGL_ERROR,
"TCP/IP Header decompression failed!\n");
talloc_free(expnd);
return -EIO;
}
/* Modify npu length, expnd is handed directly handed
* over to gsn_rx_sndcp_ud_ind(), see below */
npdu_len = rc;
} else
} else {
expnd = npdu;
#if DEBUG_IP_PACKETS == 1
debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()");
DEBUGP(DSNDCP, "===================================================\n");
DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
DEBUGP(DSNDCP, " \n");
#endif
}
/* Hand off packet to gtp */
rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli,
sne->nsapi, msg, npdu_len, expnd);
/* Hand off packet to SGSN (SNDCP SN-UNITDATA.ind), which will forward it to GGSN (GTP): */
rc = sndcp_sn_unitdata_ind(sne, msg, npdu_len, expnd);
ret_free:
/* we must free the memory we allocated above; ownership is not transferred
* downwards in the call above */
msgb_free(msg);
@ -522,7 +542,7 @@ int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
}
/* Entry point for the SNSM-DEACTIVATE.indication */
int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
int sndcp_sm_deactivate_ind(const struct gprs_llc_lle *lle, uint8_t nsapi)
{
struct gprs_sndcp_entity *sne;
@ -544,6 +564,20 @@ int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
return 0;
}
/* Clean up all gprs_sndcp_entities related to llme (OS#4824) */
void gprs_sndcp_sm_deactivate_ind_by_llme(const struct gprs_llc_llme *llme)
{
struct gprs_sndcp_entity *sne, *sne2;
llist_for_each_entry_safe(sne, sne2, &gprs_sndcp_entities, list) {
if (sne->lle->llme == llme) {
LOGP(DSNDCP, LOGL_INFO, "SNSM-DEACTIVATE.ind for SNDCP attached to llme=%p\n", llme);
/* Free and remove from list */
sndcp_sm_deactivate_ind(sne->lle, sne->nsapi);
}
}
}
/* Fragmenter state */
struct sndcp_frag_state {
uint8_t frag_nr;
@ -651,7 +685,7 @@ static int sndcp_send_ud_frag(struct sndcp_frag_state *fs,
}
/* Request transmission of a SN-PDU over specified LLC Entity + SAPI */
int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
int sndcp_sn_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
void *mmcontext)
{
struct gprs_sndcp_entity *sne;
@ -709,13 +743,14 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi
sne = gprs_sndcp_entity_by_lle(lle, nsapi);
if (!sne) {
LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity\n");
LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity (lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n",
lle, lle->llme->tlli, lle->sapi, nsapi);
msgb_free(msg);
return -EIO;
}
/* Check if we need to fragment this N-PDU into multiple SN-PDUs */
if (msg->len > lle->params.n201_u -
if (msg->len > lle->params.n201_u -
(sizeof(*sch) + sizeof(*suh) + sizeof(*scomph))) {
/* initialize the fragmenter state */
fs.msg = msg;
@ -760,7 +795,7 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi
}
/* Section 5.1.2.17 LL-UNITDATA.ind */
int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
int sndcp_ll_unitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
uint8_t *hdr, uint16_t len)
{
struct gprs_sndcp_entity *sne;
@ -830,63 +865,40 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len);
return -EIO;
}
/* actually send the N-PDU to the SGSN core code, which then
* hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */
/* actually send the N-PDU to the SGSN core code (SNDCP SN-UNITDATA.ind) */
/* Decompress packet */
#if DEBUG_IP_PACKETS == 1
DEBUGP(DSNDCP, " \n");
DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
DEBUGP(DSNDCP, "===================================================\n");
#endif
if (any_pcomp_or_dcomp_active(sgsn)) {
expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC +
MAX_HDRDECOMPR_INCR);
memcpy(expnd, npdu, npdu_len);
/* Apply data decompression */
rc = gprs_sndcp_dcomp_expand(expnd, npdu_len, sne->defrag.dcomp,
sne->defrag.data);
if (rc < 0) {
LOGP(DSNDCP, LOGL_ERROR,
"Data decompression failed!\n");
talloc_free(expnd);
return -EIO;
expnd = decompress_segment(sne, msg, npdu, npdu_len, (unsigned int *)&npdu_len);
if (!expnd) {
rc = -EIO;
goto ret_free;
}
/* Apply header decompression */
rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp,
sne->defrag.proto);
if (rc < 0) {
LOGP(DSNDCP, LOGL_ERROR,
"TCP/IP Header decompression failed!\n");
talloc_free(expnd);
return -EIO;
}
/* Modify npu length, expnd is handed directly handed
* over to gsn_rx_sndcp_ud_ind(), see below */
npdu_len = rc;
} else
} else {
expnd = npdu;
#if DEBUG_IP_PACKETS == 1
debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()");
DEBUGP(DSNDCP, "===================================================\n");
DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
DEBUGP(DSNDCP, " \n");
#endif
}
/* Hand off packet to gtp */
rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli,
sne->nsapi, msg, npdu_len, expnd);
rc = sndcp_sn_unitdata_ind(sne, msg, npdu_len, expnd);
ret_free:
if (any_pcomp_or_dcomp_active(sgsn))
talloc_free(expnd);
return rc;
}
/* 5.1.1.4 SN-UNITDATA.indication
* Called by SNDCP when it has received/re-assembled a N-PDU
*/
int sndcp_sn_unitdata_ind(struct gprs_sndcp_entity *sne,
struct msgb *msg, uint32_t npdu_len, uint8_t *npdu)
{
/* Hand it off N-PDU to the correct GTP tunnel + GGSN: */
return sgsn_gtp_data_req(&sne->ra_id, sne->lle->llme->tlli,
sne->nsapi, msg, npdu_len, npdu);
}
#if 0
/* Section 5.1.2.1 LL-RESET.ind */
static int sndcp_ll_reset_ind(struct gprs_sndcp_entity *se)
@ -1042,7 +1054,7 @@ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi)
/* Handle header compression entites */
static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field,
struct gprs_llc_lle *lle)
const struct gprs_llc_lle *lle)
{
/* Note: This functions also transforms the comp_field into its
* echo form (strips comp values, resets propose bit etc...)
@ -1092,7 +1104,7 @@ static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field,
/* Hanle data compression entites */
static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field,
struct gprs_llc_lle *lle)
const struct gprs_llc_lle *lle)
{
/* See note in handle_pcomp_entities() */
@ -1134,7 +1146,7 @@ static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field,
* (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication,
struct gprs_llc_xid_field *xid_field_response,
struct gprs_llc_lle *lle)
const struct gprs_llc_lle *lle)
{
/* Note: This function computes the SNDCP-XID response that is sent
* back to the ms when a ms originated XID is received. The

View File

@ -30,7 +30,7 @@
#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_utils.h>
@ -48,8 +48,6 @@
(gsup)->imsi, \
## args)
extern void *tall_sgsn_ctx;
LLIST_HEAD(_gprs_subscribers);
struct llist_head * const gprs_subscribers = &_gprs_subscribers;
@ -378,7 +376,8 @@ static void gprs_subscr_gsup_insert_data(struct gprs_subscr *subscr,
}
OSMO_ASSERT(pdp_data != NULL);
pdp_data->pdp_type = pdp_info->pdp_type;
pdp_data->pdp_type_org = pdp_info->pdp_type_org;
pdp_data->pdp_type_nr = pdp_info->pdp_type_nr;
osmo_apn_to_str(pdp_data->apn_str,
pdp_info->apn_enc, pdp_info->apn_enc_len);

178
src/sgsn/gtp_ggsn.c Normal file
View File

@ -0,0 +1,178 @@
/* GGSN context (peer) */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2023 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 <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/pdpctx.h>
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
{
bool pending = osmo_timer_pending(&ggc->echo_timer);
/* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */
if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) {
if (!pending)
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
} else {
if (pending)
osmo_timer_del(&ggc->echo_timer);
}
}
/* GGSN contexts */
static void echo_timer_cb(void *data)
{
struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data;
sgsn_ggsn_echo_req(ggc);
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(struct sgsn_instance *sgsn, uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
ggc = talloc_zero(sgsn, struct sgsn_ggsn_ctx);
if (!ggc)
return NULL;
ggc->id = id;
ggc->gtp_version = 1;
ggc->remote_restart_ctr = -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);
osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc);
llist_add(&ggc->list, &sgsn->ggsn_list);
return ggc;
}
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
{
OSMO_ASSERT(llist_empty(&ggc->pdp_list));
llist_del(&ggc->list);
talloc_free(ggc);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(struct sgsn_instance *sgsn, uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
llist_for_each_entry(ggc, &sgsn->ggsn_list, list) {
if (id == ggc->id)
return ggc;
}
return NULL;
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct sgsn_instance *sgsn, struct in_addr *addr)
{
struct sgsn_ggsn_ctx *ggc;
llist_for_each_entry(ggc, &sgsn->ggsn_list, list) {
if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr)))
return ggc;
}
return NULL;
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(struct sgsn_instance *sgsn, uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
ggc = sgsn_ggsn_ctx_by_id(sgsn, id);
if (!ggc)
ggc = sgsn_ggsn_ctx_alloc(sgsn, id);
return ggc;
}
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_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 {
/* FIXME: GPRS paging in case MS is SUSPENDED */
LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN "
"recovery\n");
/* FIXME: how to tell this to libgtp? */
sgsn_pdp_ctx_free(pctx);
}
}
/* High-level function to be called in case a GGSN has disappeared or
* otherwise lost state (recovery procedure). It will detach all related pdp ctx
* from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
* be kept alive to allow handling later message which contained the Recovery IE. */
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except)
{
int num = 0;
struct sgsn_pdp_ctx *pdp, *pdp2;
llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) {
if (pdp == except)
continue;
sgsn_ggsn_ctx_drop_pdp(pdp);
num++;
}
return num;
}
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
{
return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL);
}
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
llist_add(&pdp->ggsn_list, &ggc->pdp_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
}
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
llist_del(&pdp->ggsn_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
if (pdp->destroy_ggsn)
sgsn_ggsn_ctx_free(pdp->ggsn);
pdp->ggsn = NULL;
/* Drop references to libgtp since the conn is down */
if (pdp->lib)
pdp_freepdp(pdp->lib);
pdp->lib = NULL;
}

143
src/sgsn/gtp_mme.c Normal file
View File

@ -0,0 +1,143 @@
/* TS 29.060 § 7.5.14 RAN Information Management Messages */
/*
* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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 <talloc.h>
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/sgsn.h>
static bool _eutran_tai_equal(const struct osmo_eutran_tai *t1, const struct osmo_eutran_tai *t2)
{
return t1->mcc == t2->mcc &&
t1->mnc == t2->mnc &&
t1->mnc_3_digits == t2->mnc_3_digits &&
t1->tac == t2->tac;
}
struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name)
{
struct sgsn_mme_ctx *mme;
mme = talloc_zero(sgsn, struct sgsn_mme_ctx);
if (!mme)
return NULL;
/* if we are called from config file parse, this gsn doesn't exist yet */
mme->sgsn = sgsn;
mme->name = talloc_strdup(mme, name);
INIT_LLIST_HEAD(&mme->routes);
llist_add_tail(&mme->list, &sgsn->mme_list);
return mme;
}
void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme)
{
struct mme_rim_route *rt, *rt2;
llist_del(&mme->list);
llist_for_each_entry_safe(rt, rt2, &mme->routes, list) {
llist_del(&rt->list);
talloc_free(rt);
}
talloc_free(mme);
}
struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name)
{
struct sgsn_mme_ctx *mme;
mme = sgsn_mme_ctx_by_name(sgsn, name);
if (!mme)
mme = sgsn_mme_ctx_alloc(sgsn, name);
return mme;
}
void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai)
{
struct mme_rim_route *rt = talloc_zero(mme, struct mme_rim_route);
rt->tai = *tai;
llist_add_tail(&rt->list, &mme->routes);
}
void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai)
{
struct mme_rim_route *rt;
llist_for_each_entry(rt, &mme->routes, list) {
if (_eutran_tai_equal(tai, &rt->tai)) {
llist_del(&rt->list);
talloc_free(rt);
return;
}
}
}
struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name)
{
struct sgsn_mme_ctx *mme;
llist_for_each_entry(mme, &sgsn->mme_list, list) {
if (!strcmp(name, mme->name))
return mme;
}
return NULL;
}
struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr)
{
struct sgsn_mme_ctx *mme;
llist_for_each_entry(mme, &sgsn->mme_list, list) {
if (!memcmp(addr, &mme->remote_addr, sizeof(*addr)))
return mme;
}
return NULL;
}
struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai)
{
struct sgsn_mme_ctx *mme;
llist_for_each_entry(mme, &sgsn->mme_list, list) {
struct mme_rim_route *rt;
llist_for_each_entry(rt, &mme->routes, list) {
if (_eutran_tai_equal(tai, &rt->tai)) {
return mme;
}
}
}
return NULL;
}
struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn)
{
struct sgsn_mme_ctx *mme;
llist_for_each_entry(mme, &sgsn->mme_list, list) {
if (mme->default_route)
return mme;
}
return NULL;
}

View File

@ -1,4 +1,4 @@
/* GPRS SGSN functionality */
/* Mobility Management context */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
@ -27,6 +27,8 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/backtrace.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
@ -36,7 +38,7 @@
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_sm.h>
@ -47,22 +49,16 @@
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/pdpctx.h>
#include <pdp.h>
#include <time.h>
#include "../../bscconfig.h"
#define GPRS_LLME_CHECK_TICK 30
extern struct sgsn_instance *sgsn;
extern void *tall_sgsn_ctx;
LLIST_HEAD(sgsn_mm_ctxts);
LLIST_HEAD(sgsn_ggsn_ctxts);
LLIST_HEAD(sgsn_apn_ctxts);
LLIST_HEAD(sgsn_pdp_ctxts);
#include "../../config.h"
const struct value_string sgsn_ran_type_names[] = {
{ MM_CTX_T_GERAN_Gb, "GPRS/EDGE via Gb" },
@ -95,66 +91,12 @@ static const struct rate_ctr_group_desc mmctx_ctrg_desc = {
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
};
static const struct rate_ctr_desc pdpctx_ctr_description[] = {
{ "udata:packets:in", "User Data Messages ( In)" },
{ "udata:packets:out", "User Data Messages (Out)" },
{ "udata:bytes:in", "User Data Bytes ( In)" },
{ "udata:bytes:out", "User Data Bytes (Out)" },
};
static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
.group_name_prefix = "sgsn:pdpctx",
.group_description = "SGSN PDP Context Statistics",
.num_ctr = ARRAY_SIZE(pdpctx_ctr_description),
.ctr_desc = pdpctx_ctr_description,
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
};
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 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" },
{ "gprs:detach_requested", "Received detach requests" },
{ "gprs:detach_acked", "Sent detach acks" },
{ "gprs:routing_area_requested", "Received routing area requests" },
{ "gprs:routing_area_requested", "Sent routing area acks" },
{ "gprs:routing_area_requested", "Sent routing area rejects" },
{ "pdp:activate_requested", "Received activate requests" },
{ "pdp:activate_rejected", "Sent activate rejects" },
{ "pdp:activate_accepted", "Sent activate accepts" },
{ "pdp:request_activated", "unused" },
{ "pdp:request_activate_rejected", "unused" },
{ "pdp:modify_requested", "unused" },
{ "pdp:modify_accepted", "unused" },
{ "pdp:dl_deactivate_requested", "Sent deactivate requests" },
{ "pdp:dl_deactivate_accepted", "Sent deactivate accepted" },
{ "pdp:ul_deactivate_requested", "Received deactivate requests" },
{ "pdp:ul_deactivate_accepted", "Received deactivate accepts" },
};
static const struct rate_ctr_group_desc sgsn_ctrg_desc = {
"sgsn",
"SGSN Overall Statistics",
OSMO_STATS_CLASS_GLOBAL,
ARRAY_SIZE(sgsn_ctr_description),
sgsn_ctr_description,
};
void sgsn_rate_ctr_init() {
sgsn->rate_ctrs = rate_ctr_group_alloc(tall_sgsn_ctx, &sgsn_ctrg_desc, 0);
OSMO_ASSERT(sgsn->rate_ctrs);
}
/* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx)
{
struct sgsn_mm_ctx *ctx;
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu
&& uectx == ctx->iu.ue_ctx)
return ctx;
@ -169,7 +111,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
{
struct sgsn_mm_ctx *ctx;
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if ((tlli == ctx->gb.tlli || tlli == ctx->gb.tlli_new) &&
gprs_ra_id_equals(raid, &ctx->ra))
return ctx;
@ -193,7 +135,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
if (tlli_type != TLLI_FOREIGN && tlli_type != TLLI_LOCAL)
return NULL;
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if ((gprs_tmsi2tlli(ctx->p_tmsi, tlli_type) == tlli ||
gprs_tmsi2tlli(ctx->p_tmsi_old, tlli_type) == tlli) &&
gprs_ra_id_equals(raid, &ctx->ra))
@ -207,7 +149,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi)
{
struct sgsn_mm_ctx *ctx;
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if (p_tmsi == ctx->p_tmsi ||
(ctx->p_tmsi_old && ctx->p_tmsi_old == p_tmsi))
return ctx;
@ -219,7 +161,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi)
{
struct sgsn_mm_ctx *ctx;
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if (!strcmp(imsi, ctx->imsi))
return ctx;
}
@ -261,7 +203,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t rate_ctr_id)
INIT_LLIST_HEAD(&ctx->pdp_list);
llist_add(&ctx->list, &sgsn_mm_ctxts);
llist_add(&ctx->list, &sgsn->mm_list);
return ctx;
@ -293,11 +235,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
memcpy(&ctx->ra, raid, sizeof(ctx->ra));
ctx->ran_type = MM_CTX_T_GERAN_Gb;
ctx->gb.tlli = tlli;
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));
return ctx;
}
@ -435,288 +374,6 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
return NULL;
}
/* you don't want to use this directly, call sgsn_create_pdp_ctx() */
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
struct sgsn_ggsn_ctx *ggsn,
uint8_t nsapi)
{
struct sgsn_pdp_ctx *pdp;
pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
if (pdp)
return NULL;
pdp = talloc_zero(tall_sgsn_ctx, struct sgsn_pdp_ctx);
if (!pdp)
return NULL;
pdp->mm = mm;
pdp->ggsn = ggsn;
pdp->nsapi = nsapi;
pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi);
if (!pdp->ctrg) {
LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n");
talloc_free(pdp);
return NULL;
}
llist_add(&pdp->list, &mm->pdp_list);
sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp);
llist_add(&pdp->g_list, &sgsn_pdp_ctxts);
return pdp;
}
/*
* This function will not trigger any GSM DEACT PDP ACK messages, so you
* probably want to call sgsn_delete_pdp_ctx() instead if the connection
* isn't detached already.
*/
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
{
struct sgsn_signal_data sig_data;
OSMO_ASSERT(pdp->mm != NULL);
/* There might still be pending callbacks in libgtp. So the parts of
* this object relevant to GTP need to remain intact in this case. */
LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n");
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);
}
memset(&sig_data, 0, sizeof(sig_data));
sig_data.pdp = pdp;
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_TERMINATE, &sig_data);
/* Detach from MM context */
pdp_ctx_detach_mm_ctx(pdp);
if (pdp->ggsn)
sgsn_delete_pdp_ctx(pdp);
}
/*
* Don't call this function directly unless you know what you are doing.
* In normal conditions use sgsn_delete_pdp_ctx and in unspecified or
* implementation dependent abnormal ones sgsn_pdp_ctx_terminate.
*/
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
{
struct sgsn_signal_data sig_data;
memset(&sig_data, 0, sizeof(sig_data));
sig_data.pdp = pdp;
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
if (osmo_timer_pending(&pdp->timer)) {
LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
osmo_timer_del(&pdp->timer);
}
rate_ctr_group_free(pdp->ctrg);
if (pdp->mm)
llist_del(&pdp->list);
if (pdp->ggsn)
sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp);
llist_del(&pdp->g_list);
/* _if_ we still have a library handle, at least set it to NULL
* to avoid any dereferences of the now-deleted PDP context from
* sgsn_libgtp:cb_data_ind() */
if (pdp->lib) {
struct pdp_t *lib = pdp->lib;
LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still "
"has a libgtp handle attached to it, this shouldn't "
"happen!\n");
osmo_generate_backtrace();
lib->priv = NULL;
}
talloc_free(pdp);
}
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
{
bool pending = osmo_timer_pending(&ggc->echo_timer);
/* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */
if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) {
if (!pending)
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
} else {
if (pending)
osmo_timer_del(&ggc->echo_timer);
}
}
/* GGSN contexts */
static void echo_timer_cb(void *data)
{
struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data;
sgsn_ggsn_echo_req(ggc);
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
ggc = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_ctx);
if (!ggc)
return NULL;
ggc->id = id;
ggc->gtp_version = 1;
ggc->remote_restart_ctr = -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);
osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc);
llist_add(&ggc->list, &sgsn_ggsn_ctxts);
return ggc;
}
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
{
OSMO_ASSERT(llist_empty(&ggc->pdp_list));
llist_del(&ggc->list);
talloc_free(ggc);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
if (id == ggc->id)
return ggc;
}
return NULL;
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr)
{
struct sgsn_ggsn_ctx *ggc;
llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr)))
return ggc;
}
return NULL;
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
ggc = sgsn_ggsn_ctx_by_id(id);
if (!ggc)
ggc = sgsn_ggsn_ctx_alloc(id);
return ggc;
}
/* APN contexts */
static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
{
struct apn_ctx *actx;
actx = talloc_zero(tall_sgsn_ctx, struct apn_ctx);
if (!actx)
return NULL;
actx->name = talloc_strdup(actx, ap_name);
actx->imsi_prefix = talloc_strdup(actx, imsi_prefix);
llist_add_tail(&actx->list, &sgsn_apn_ctxts);
return actx;
}
void sgsn_apn_ctx_free(struct apn_ctx *actx)
{
llist_del(&actx->list);
talloc_free(actx);
}
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi)
{
struct apn_ctx *actx;
struct apn_ctx *found_actx = NULL;
size_t imsi_prio = 0;
size_t name_prio = 0;
size_t name_req_len = strlen(name);
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
size_t name_ref_len, imsi_ref_len;
const char *name_ref_start, *name_match_start;
imsi_ref_len = strlen(actx->imsi_prefix);
if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0)
continue;
if (imsi_ref_len < imsi_prio)
continue;
/* IMSI matches */
name_ref_start = &actx->name[0];
if (name_ref_start[0] == '*') {
/* Suffix match */
name_ref_start += 1;
name_ref_len = strlen(name_ref_start);
if (name_ref_len > name_req_len)
continue;
} else {
name_ref_len = strlen(name_ref_start);
if (name_ref_len != name_req_len)
continue;
}
name_match_start = name + (name_req_len - name_ref_len);
if (strcasecmp(name_match_start, name_ref_start) != 0)
continue;
/* IMSI and name match */
if (imsi_ref_len == imsi_prio && name_ref_len < name_prio)
/* Lower priority, skip */
continue;
imsi_prio = imsi_ref_len;
name_prio = name_ref_len;
found_actx = actx;
}
return found_actx;
}
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix)
{
struct apn_ctx *actx;
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
if (strcasecmp(name, actx->name) == 0 &&
strcasecmp(imsi_prefix, actx->imsi_prefix) == 0)
return actx;
}
return NULL;
}
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix)
{
struct apn_ctx *actx;
actx = sgsn_apn_ctx_by_name(name, imsi_prefix);
if (!actx)
actx = sgsn_apn_ctx_alloc(name, imsi_prefix);
return actx;
}
uint32_t sgsn_alloc_ptmsi(void)
{
struct sgsn_mm_ctx *mm;
@ -752,7 +409,7 @@ restart:
goto restart;
}
llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
llist_for_each_entry(mm, &sgsn->mm_list, list) {
if (mm->p_tmsi == ptmsi) {
if (!max_retries--)
goto failed;
@ -767,64 +424,6 @@ failed:
return GSM_RESERVED_TMSI;
}
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_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 {
/* FIXME: GPRS paging in case MS is SUSPENDED */
LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN "
"recovery\n");
/* FIXME: how to tell this to libgtp? */
sgsn_pdp_ctx_free(pctx);
}
}
/* High-level function to be called in case a GGSN has disappeared or
* otherwise lost state (recovery procedure). It will detach all related pdp ctx
* from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
* be kept alive to allow handling later message which contained the Recovery IE. */
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except)
{
int num = 0;
struct sgsn_pdp_ctx *pdp, *pdp2;
llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) {
if (pdp == except)
continue;
sgsn_ggsn_ctx_drop_pdp(pdp);
num++;
}
return num;
}
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
{
return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL);
}
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
llist_add(&pdp->ggsn_list, &ggc->pdp_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
}
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
{
llist_del(&pdp->ggsn_list);
sgsn_ggsn_ctx_check_echo_timer(ggc);
if (pdp->destroy_ggsn)
sgsn_ggsn_ctx_free(pdp->ggsn);
pdp->ggsn = NULL;
/* Drop references to libgtp since the conn is down */
if (pdp->lib)
pdp_freepdp(pdp->lib);
pdp->lib = NULL;
}
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
{
OSMO_ASSERT(mmctx != NULL);
@ -899,7 +498,7 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
insert_extra(tp, mmctx->subscr->sgsn_data, pdp);
continue;
}
if (!llist_empty(&sgsn_apn_ctxts)) {
if (!llist_empty(&sgsn->apn_list)) {
apn_ctx = sgsn_apn_ctx_match(req_apn_str, mmctx->imsi);
/* Not configured */
if (apn_ctx == NULL)
@ -952,13 +551,13 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
if (apn_ctx != NULL) {
ggsn = apn_ctx->ggsn;
} else if (llist_empty(&sgsn_apn_ctxts)) {
} else if (llist_empty(&sgsn->apn_list)) {
/* No configuration -> use GGSN 0 */
ggsn = sgsn_ggsn_ctx_by_id(0);
ggsn = sgsn_ggsn_ctx_by_id(sgsn, 0);
} else if (allow_any_apn &&
(selected_apn_str == NULL || strlen(selected_apn_str) == 0)) {
/* No APN given and no default configuration -> Use GGSN 0 */
ggsn = sgsn_ggsn_ctx_by_id(0);
ggsn = sgsn_ggsn_ctx_by_id(sgsn, 0);
} else {
/* No matching configuration found */
LOGMMCTXP(LOGL_NOTICE, mmctx,
@ -983,70 +582,3 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
return ggsn;
}
static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme)
{
struct sgsn_mm_ctx *mmctx = NULL;
llist_for_each_entry(mmctx, &sgsn_mm_ctxts, list) {
if (llme == mmctx->gb.llme) {
gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
return;
}
}
/* No MM context found */
LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n",
llme->tlli);
gprs_llgmm_unassign(llme);
}
static void sgsn_llme_check_cb(void *data_)
{
struct gprs_llc_llme *llme, *llme_tmp;
struct timespec now_tp;
time_t now, age;
time_t max_age = gprs_max_time_to_idle();
int rc;
rc = osmo_clock_gettime(CLOCK_MONOTONIC, &now_tp);
OSMO_ASSERT(rc >= 0);
now = now_tp.tv_sec;
LOGP(DGPRS, LOGL_DEBUG,
"Checking for inactive LLMEs, time = %u\n", (unsigned)now);
llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) {
if (llme->age_timestamp == GPRS_LLME_RESET_AGE)
llme->age_timestamp = now;
age = now - llme->age_timestamp;
if (age > max_age || age < 0) {
LOGP(DGPRS, LOGL_INFO,
"Inactivity timeout for TLLI 0x%08x, age %d\n",
llme->tlli, (int)age);
sgsn_llme_cleanup_free(llme);
}
}
osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
}
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx)
{
struct sgsn_instance *inst;
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;
}
void sgsn_inst_init(struct sgsn_instance *sgsn)
{
osmo_timer_setup(&sgsn->llme_timer, sgsn_llme_check_cb, NULL);
osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
}

158
src/sgsn/pdpctx.c Normal file
View File

@ -0,0 +1,158 @@
/* PDP context functionality */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* 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 <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gprs_llc_xid.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/gtp.h>
static const struct rate_ctr_desc pdpctx_ctr_description[] = {
{ "udata:packets:in", "User Data Messages ( In)" },
{ "udata:packets:out", "User Data Messages (Out)" },
{ "udata:bytes:in", "User Data Bytes ( In)" },
{ "udata:bytes:out", "User Data Bytes (Out)" },
};
static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
.group_name_prefix = "sgsn:pdpctx",
.group_description = "SGSN PDP Context Statistics",
.num_ctr = ARRAY_SIZE(pdpctx_ctr_description),
.ctr_desc = pdpctx_ctr_description,
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
};
/* you don't want to use this directly, call sgsn_create_pdp_ctx() */
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
struct sgsn_ggsn_ctx *ggsn,
uint8_t nsapi)
{
struct sgsn_pdp_ctx *pdp;
pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
if (pdp)
return NULL;
pdp = talloc_zero(sgsn, struct sgsn_pdp_ctx);
if (!pdp)
return NULL;
pdp->mm = mm;
pdp->ggsn = ggsn;
pdp->nsapi = nsapi;
pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi);
if (!pdp->ctrg) {
LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n");
talloc_free(pdp);
return NULL;
}
llist_add(&pdp->list, &mm->pdp_list);
sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp);
llist_add(&pdp->g_list, &sgsn->pdp_list);
return pdp;
}
/*
* This function will not trigger any GSM DEACT PDP ACK messages, so you
* probably want to call sgsn_delete_pdp_ctx() instead if the connection
* isn't detached already.
*/
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
{
struct sgsn_signal_data sig_data;
OSMO_ASSERT(pdp->mm != NULL);
/* There might still be pending callbacks in libgtp. So the parts of
* this object relevant to GTP need to remain intact in this case. */
LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n");
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);
}
memset(&sig_data, 0, sizeof(sig_data));
sig_data.pdp = pdp;
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_TERMINATE, &sig_data);
/* Detach from MM context */
pdp_ctx_detach_mm_ctx(pdp);
if (pdp->ggsn)
sgsn_delete_pdp_ctx(pdp);
}
/*
* Don't call this function directly unless you know what you are doing.
* In normal conditions use sgsn_delete_pdp_ctx and in unspecified or
* implementation dependent abnormal ones sgsn_pdp_ctx_terminate.
*/
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
{
struct sgsn_signal_data sig_data;
memset(&sig_data, 0, sizeof(sig_data));
sig_data.pdp = pdp;
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
if (osmo_timer_pending(&pdp->timer)) {
LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
osmo_timer_del(&pdp->timer);
}
rate_ctr_group_free(pdp->ctrg);
if (pdp->mm)
llist_del(&pdp->list);
if (pdp->ggsn)
sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp);
llist_del(&pdp->g_list);
/* _if_ we still have a library handle, at least set it to NULL
* to avoid any dereferences of the now-deleted PDP context from
* sgsn_libgtp:cb_data_ind() */
if (pdp->lib) {
struct pdp_t *lib = pdp->lib;
LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still "
"has a libgtp handle attached to it, this shouldn't "
"happen!\n");
osmo_generate_backtrace();
lib->priv = NULL;
}
talloc_free(pdp);
}

220
src/sgsn/sgsn.c Normal file
View File

@ -0,0 +1,220 @@
/* SGSN instance */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* 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 <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/backtrace.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/gsup.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/crypt/utran_cipher.h>
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/debug.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 <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/pdpctx.h>
#include <pdp.h>
#include <time.h>
#define GPRS_LLME_CHECK_TICK 30
extern struct osmo_tdef sgsn_T_defs[];
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 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" },
{ "gprs:detach_requested", "Received detach requests" },
{ "gprs:detach_acked", "Sent detach acks" },
{ "gprs:routing_area_requested", "Received routing area requests" },
{ "gprs:routing_area_requested", "Sent routing area acks" },
{ "gprs:routing_area_requested", "Sent routing area rejects" },
{ "pdp:activate_requested", "Received activate requests" },
{ "pdp:activate_rejected", "Sent activate rejects" },
{ "pdp:activate_accepted", "Sent activate accepts" },
{ "pdp:request_activated", "unused" },
{ "pdp:request_activate_rejected", "unused" },
{ "pdp:modify_requested", "unused" },
{ "pdp:modify_accepted", "unused" },
{ "pdp:dl_deactivate_requested", "Sent deactivate requests" },
{ "pdp:dl_deactivate_accepted", "Sent deactivate accepted" },
{ "pdp:ul_deactivate_requested", "Received deactivate requests" },
{ "pdp:ul_deactivate_accepted", "Received deactivate accepts" },
};
static const struct rate_ctr_group_desc sgsn_ctrg_desc = {
"sgsn",
"SGSN Overall Statistics",
OSMO_STATS_CLASS_GLOBAL,
ARRAY_SIZE(sgsn_ctr_description),
sgsn_ctr_description,
};
static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme)
{
struct sgsn_mm_ctx *mmctx = NULL;
llist_for_each_entry(mmctx, &sgsn->mm_list, list) {
if (llme == mmctx->gb.llme) {
gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
return;
}
}
/* No MM context found */
LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n",
llme->tlli);
gprs_llgmm_unassign(llme);
}
static void sgsn_llme_check_cb(void *data_)
{
struct gprs_llc_llme *llme, *llme_tmp;
struct timespec now_tp;
time_t now, age;
time_t max_age = gprs_max_time_to_idle();
int rc;
rc = osmo_clock_gettime(CLOCK_MONOTONIC, &now_tp);
OSMO_ASSERT(rc >= 0);
now = now_tp.tv_sec;
LOGP(DGPRS, LOGL_DEBUG,
"Checking for inactive LLMEs, time = %u\n", (unsigned)now);
llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) {
if (llme->age_timestamp == GPRS_LLME_RESET_AGE)
llme->age_timestamp = now;
age = now - llme->age_timestamp;
if (age > max_age || age < 0) {
LOGP(DGPRS, LOGL_INFO,
"Inactivity timeout for TLLI 0x%08x, age %d\n",
llme->tlli, (int)age);
sgsn_llme_cleanup_free(llme);
}
}
osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
}
static int sgsn_instance_talloc_destructor(struct sgsn_instance *sgi)
{
sgsn_cdr_release(sgi);
osmo_timer_del(&sgi->llme_timer);
rate_ctr_group_free(sgi->rate_ctrs);
return 0;
}
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx)
{
struct sgsn_instance *inst;
inst = talloc_zero(talloc_ctx, struct sgsn_instance);
talloc_set_destructor(inst, sgsn_instance_talloc_destructor);
inst->cfg.gtp_statedir = talloc_strdup(inst, "./");
inst->cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED;
inst->cfg.gea_encryption_mask = (1 << GPRS_ALGO_GEA0); /* no encryption */
inst->cfg.uea_encryption_mask = (1 << OSMO_UTRAN_UEA2) | (1 << OSMO_UTRAN_UEA1);
inst->cfg.require_authentication = true; /* only applies if auth_policy is REMOTE */
inst->cfg.gsup_server_port = OSMO_GSUP_PORT;
inst->cfg.T_defs = sgsn_T_defs;
osmo_tdefs_reset(inst->cfg.T_defs);
inst->cfg.T_defs_gtp = gtp_T_defs;
osmo_tdefs_reset(inst->cfg.T_defs_gtp);
inst->rate_ctrs = rate_ctr_group_alloc(inst, &sgsn_ctrg_desc, 0);
OSMO_ASSERT(inst->rate_ctrs);
INIT_LLIST_HEAD(&inst->apn_list);
INIT_LLIST_HEAD(&inst->ggsn_list);
INIT_LLIST_HEAD(&inst->mme_list);
INIT_LLIST_HEAD(&inst->mm_list);
INIT_LLIST_HEAD(&inst->pdp_list);
osmo_timer_setup(&inst->llme_timer, sgsn_llme_check_cb, NULL);
osmo_timer_schedule(&inst->llme_timer, GPRS_LLME_CHECK_TICK, 0);
/* These are mostly setting up stuff not related to VTY cfg, so they can be set up here: */
sgsn_auth_init(inst);
sgsn_cdr_init(inst);
return inst;
}
/* To be called after VTY config parsing: */
int sgsn_inst_init(struct sgsn_instance *sgsn)
{
int rc;
/* start control interface after reading config for
* ctrl_vty_get_bind_addr() */
sgsn->ctrlh = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_SGSN, NULL);
if (!sgsn->ctrlh) {
LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n");
return -EIO;
}
rc = sgsn_ctrl_cmds_install();
if (rc != 0) {
LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n");
return -EFAULT;
}
rc = gprs_subscr_init(sgsn);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Cannot set up SGSN\n");
return rc;
}
return 0;
}

View File

@ -22,7 +22,7 @@
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/core/utils.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/debug.h>

View File

@ -27,6 +27,9 @@
#include <osmocom/gsm/apn.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/mmctx.h>
#include <gtp.h>
#include <pdp.h>
@ -38,10 +41,6 @@
#include <stdio.h>
#include <inttypes.h>
/* TODO...avoid going through a global */
extern struct sgsn_instance *sgsn;
extern struct ctrl_handle *g_ctrlh;
/**
* The CDR module will generate an entry like:
*
@ -64,7 +63,7 @@ extern struct ctrl_handle *g_ctrlh;
static void send_cdr_trap(char *value)
{
if (ctrl_cmd_send_trap(g_ctrlh, "cdr-v1", value) < 0)
if (ctrl_cmd_send_trap(sgsn->ctrlh, "cdr-v1", value) < 0)
LOGP(DGPRS, LOGL_ERROR, "Failed to create and send TRAP cdr-v1\n");
}
@ -299,3 +298,8 @@ int sgsn_cdr_init(struct sgsn_instance *sgsn)
return 0;
}
void sgsn_cdr_release(struct sgsn_instance *sgsn)
{
osmo_signal_unregister_handler(SS_SGSN, handle_sgsn_sig, sgsn);
}

View File

@ -21,20 +21,19 @@
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/debug.h>
#include <pdp.h>
extern vector ctrl_node_vec;
static int get_subscriber_list(struct ctrl_cmd *cmd, void *d)
{
struct sgsn_mm_ctx *mm;
cmd->reply = talloc_strdup(cmd, "");
llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
llist_for_each_entry(mm, &sgsn->mm_list, list) {
char *addr = NULL;
struct sgsn_pdp_ctx *pdp;
@ -43,7 +42,7 @@ static int get_subscriber_list(struct ctrl_cmd *cmd, void *d)
llist_for_each_entry(pdp, &mm->pdp_list, list)
addr = gprs_pdpaddr2str(pdp->lib->eua.v,
pdp->lib->eua.l);
pdp->lib->eua.l, false);
cmd->reply = talloc_asprintf_append(
cmd->reply,

View File

@ -34,7 +34,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include "bscconfig.h"
#include "config.h"
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
@ -45,9 +45,9 @@
#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_ns.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/gprs_subscriber.h>
@ -55,6 +55,11 @@
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/sgsn_rim.h>
#include <osmocom/sgsn/gprs_bssgp.h>
#include <osmocom/sgsn/pdpctx.h>
#include <gtp.h>
#include <pdp.h>
@ -226,18 +231,11 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
qos = TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS);
}
if (qos_len <= 3) {
pdp->qos_req.l = qos_len + 1;
if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
pdp->qos_req.l = sizeof(pdp->qos_req.v);
pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */
memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1);
} else {
pdp->qos_req.l = qos_len;
if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
pdp->qos_req.l = sizeof(pdp->qos_req.v);
memcpy(pdp->qos_req.v, qos, pdp->qos_req.l);
}
pdp->qos_req.l = qos_len + 1;
if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
pdp->qos_req.l = sizeof(pdp->qos_req.v);
pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */
memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1);
/* charging characteristics if present */
if (TLVP_LEN(tp, OSMO_IE_GSM_CHARG_CHAR) >= sizeof(pdp->cch_pdp))
@ -419,7 +417,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
}
/* Check for cause value if it was really successful */
if (cause != GTPCAUSE_ACC_REQ) {
if (!gtp_cause_successful(cause)) {
reject_cause = cause_map(gtp2sm_cause_map, cause,
GSM_CAUSE_ACT_REJ_GGSN);
goto reject;
@ -479,6 +477,70 @@ void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc)
gtp_echo_req(ggc->gsn, ggc->gtp_version, ggc, &ggc->remote_addr);
}
int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu)
{
char ri_src_str[64], ri_dest_str[64];
int ri_len;
struct msgb *msg;
struct bssgp_normal_hdr *bgph;
int rc;
uint8_t ri_buf[64];
uint8_t *ri_ptr = &ri_buf[0];
struct sockaddr_in sk_in = {
.sin_family = AF_INET,
.sin_port = htons(GTP1C_PORT),
.sin_addr = mme->remote_addr,
};
msg = bssgp_encode_rim_pdu(pdu);
if (!msg) {
LOGMME(mme, DRIM, LOGL_ERROR, "Tx GTP RAN Information Relay: failed to encode pdu\n");
return -EINVAL;
}
bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
DEBUGP(DLBSSGP, "Tx GTP RAN Information Relay: RIM-PDU:%s, src=%s, dest=%s\n",
bssgp_pdu_str(bgph->pdu_type),
bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &pdu->routing_info_src),
bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &pdu->routing_info_dest));
if ((ri_len = bssgp_create_rim_ri(ri_ptr, &pdu->routing_info_dest)) < 0) {
ri_ptr = NULL;
ri_len = 0;
}
rc = gtp_ran_info_relay_req(mme->sgsn->gsn, &sk_in, msgb_data(msg), msgb_length(msg),
ri_ptr, ri_len, pdu->routing_info_dest.discr);
msgb_free(msg);
return rc;
}
/* Confirmation of a PDP Context Update */
static int update_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
struct sgsn_pdp_ctx *pctx = cbp;
int rc;
LOGPDPCTXP(LOGL_INFO, pctx, "Received Update PDP CTX CONF, cause=%d(%s)\n",
cause, get_value_string(gtp_cause_strs, cause));
/* 3GPP TS 29.060 "7.3.4":
* "If the SGSN receives an Update PDP Context Response with a Cause
* value other than "Request accepted", it shall abort the update of the
* PDP context.""
* "If the SGSN receives an Update PDP Context Response with
* a Cause value "Non-existent", it shall delete the PDP Context."
*/
if (cause != GTPCAUSE_NON_EXIST)
return 0; /* Nothing to do */
LOGPDPCTXP(LOGL_INFO, pctx, "PDP CTX we tried to update doesn't exist in "
"the GGSN anymore, deleting it locally.\n");
rc = gtp_freepdp(pctx->ggsn->gsn, pctx->lib);
/* related mmctx is torn down in cb_delete_context called by gtp_freepdp() */
return rc;
}
/* Confirmation of a PDP Context Delete */
static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
@ -534,12 +596,12 @@ static int echo_conf(void *cbp, bool timeout)
}
/* Any message received by GGSN contains a recovery IE */
static int cb_recovery2(struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
static int cb_recovery3(struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
{
struct sgsn_ggsn_ctx *ggsn;
struct sgsn_pdp_ctx *pctx = NULL;
ggsn = sgsn_ggsn_ctx_by_addr(&peer->sin_addr);
ggsn = sgsn_ggsn_ctx_by_addr(sgsn, &peer->sin_addr);
if (!ggsn) {
LOGP(DGPRS, LOGL_NOTICE, "Received Recovery IE for unknown GGSN\n");
return -EINVAL;
@ -577,6 +639,8 @@ static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
return echo_conf(cbp, cause == EOF);
case GTP_CREATE_PDP_REQ:
return create_pdp_conf(pdp, cbp, cause);
case GTP_UPDATE_PDP_REQ:
return update_pdp_conf(pdp, cbp, cause);
case GTP_DELETE_PDP_REQ:
return delete_pdp_conf(pdp, cbp, cause);
default:
@ -619,6 +683,74 @@ static int cb_extheader_ind(struct sockaddr_in *peer)
return 0;
}
static int cb_gtp_ran_info_relay_ind(struct sockaddr_in *peer, union gtpie_member **ie)
{
char addrbuf[INET_ADDRSTRLEN];
struct sgsn_mme_ctx *mme = sgsn_mme_ctx_by_addr(sgsn, &peer->sin_addr);
if (!mme) {
LOGP(DGTP, LOGL_NOTICE, "Rx GTP RAN Information Relay from unknown MME %s\n",
inet_ntop(AF_INET, &peer->sin_addr, addrbuf, sizeof(addrbuf)));
return -ECONNREFUSED;
}
LOGMME(mme, DGTP, LOGL_INFO, "Rx GTP RAN Information Relay\n");
int rc;
unsigned int len = 0;
struct msgb *msg = bssgp_msgb_alloc();
uint8_t rim_ra_encoded[256];
unsigned int rim_ra_encoded_len = 0;
struct bssgp_rim_routing_info rim_ra;
unsigned int rim_ra_discr_encoded_len = 0;
uint8_t rim_ra_discr;
/* Read RIM Routing Address Discriminator (optional) */
rc = gtpie_gettlv(ie, GTPIE_RIM_RA_DISCR, 0, &rim_ra_discr_encoded_len, &rim_ra_discr,
sizeof(rim_ra_discr));
if (rc || rim_ra_discr_encoded_len <= 0) {
LOGMME(mme, DGTP, LOGL_NOTICE, "Rx GTP RAN Information Relay: No RIM Routing Address Discriminator IE found!\n");
/* It is not an error when the RIM ROUTING ADDRESS DISCRIMINATOR IE is missing. The RIM ROUTING ADDRESS
* DISCRIMINATOR IE is an optional IE. When it is missing, the RIM Routing Address shall be processed
* as an RNC address ("0001") See also: 3GPP TS 29.060 */
rim_ra_discr = BSSGP_RIM_ROUTING_INFO_UTRAN;
}
/* Read RIM Routing Address (optional) */
rc = gtpie_gettlv(ie, GTPIE_RIM_ROUT_ADDR, 0, &rim_ra_encoded_len, rim_ra_encoded, sizeof(rim_ra_encoded));
if (rc || rim_ra_encoded_len <= 0) {
LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No RIM Routing Address IE found!\n");
/* TODO: The (usually included) RIM ROUTING ADDRESS field is an optional field. However, we cannot
* proceed without a destination address. A possible way to fix this would be a default route that
* can be configured via the VTY. */
goto ret_error;
} else {
rc = bssgp_parse_rim_ra(&rim_ra, rim_ra_encoded, rim_ra_encoded_len, rim_ra_discr);
if (rc < 0) {
LOGMME(mme, DGTP, LOGL_ERROR,
"Rx GTP RAN Information Relay: Failed parsing RIM Routing Address/RIM Routing Address Discriminator IE!\n");
goto ret_error;
}
}
if (gtpie_gettlv(ie, GTPIE_RAN_T_CONTAIN, 0, &len, msgb_data(msg), 4096) || len <= 0) {
LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No Transparent Container IE found!\n");
goto ret_error;
}
msgb_put(msg, len);
msgb_bssgph(msg) = msg->data;
msgb_nsei(msg) = 0;
return sgsn_rim_rx_from_gtp(msg, &rim_ra);
ret_error:
msgb_free(msg);
return -EINVAL;
}
/* Called whenever we receive a DATA packet */
static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
{
@ -671,15 +803,24 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
msgb_free(msg);
return -1;
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) {
switch (mm->gb.mm_state_fsm->state) {
case ST_MM_IDLE:
LOGP(DGPRS, LOGL_ERROR, "Dropping DL packet for MS in MM state %s\n",
osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
msgb_free(msg);
return -1;
case ST_MM_READY:
/* Go ahead */
break;
case ST_MM_STANDBY:
LOGMMCTXP(LOGL_INFO, mm, "Paging MS in GMM state %s, MM state %s\n",
osmo_fsm_inst_state_name(mm->gmm_fsm),
osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
gprs_gb_page_ps_ra(mm);
}
sgsn_bssgp_page_ps_ra(mm);
/* FIXME: queue the packet we received from GTP */
/* FIXME: queue the packet we received from GTP */
break;
}
break;
default:
LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state "
@ -688,20 +829,20 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
return -1;
}
rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_OUT]);
rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_OUT], len);
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_UDATA_OUT]);
rate_ctr_add(&mm->ctrg->ctr[GMM_CTR_BYTES_UDATA_OUT], len);
rate_ctr_inc(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_PKTS_UDATA_OUT));
rate_ctr_add(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_BYTES_UDATA_OUT), len);
rate_ctr_inc(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_PKTS_UDATA_OUT));
rate_ctr_add(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_BYTES_UDATA_OUT), len);
/* It is easier to have a global count */
pdp->cdr_bytes_out += len;
return sndcp_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
return sndcp_sn_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
pdp->nsapi, mm);
}
/* Called by SNDCP when it has received/re-assembled a N-PDU */
int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
int sgsn_gtp_data_req(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
struct msgb *msg, uint32_t npdu_len, uint8_t *npdu)
{
struct sgsn_mm_ctx *mmctx;
@ -726,10 +867,10 @@ int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
return -EIO;
}
rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_IN]);
rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_IN], npdu_len);
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_UDATA_IN]);
rate_ctr_add(&mmctx->ctrg->ctr[GMM_CTR_BYTES_UDATA_IN], npdu_len);
rate_ctr_inc(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_PKTS_UDATA_IN));
rate_ctr_add(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_BYTES_UDATA_IN), npdu_len);
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_UDATA_IN));
rate_ctr_add(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_BYTES_UDATA_IN), npdu_len);
/* It is easier to have a global count */
pdp->cdr_bytes_in += npdu_len;
@ -804,10 +945,11 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
/* Register callbackcs with libgtp */
gtp_set_cb_delete_context(gsn, cb_delete_context);
gtp_set_cb_conf(gsn, cb_conf);
gtp_set_cb_recovery2(gsn, cb_recovery2);
gtp_set_cb_recovery3(gsn, cb_recovery3);
gtp_set_cb_data_ind(gsn, cb_data_ind);
gtp_set_cb_unsup_ind(gsn, cb_unsup_ind);
gtp_set_cb_extheader_ind(gsn, cb_extheader_ind);
gtp_set_cb_ran_info_relay_ind(gsn, cb_gtp_ran_info_relay_ind);
return 0;
}

View File

@ -59,17 +59,18 @@
#include <osmocom/sgsn/vty.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gb.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/sgsn/gprs_ns.h>
#include <osmocom/sgsn/gprs_bssgp.h>
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/gtp.h>
#include <gtp.h>
#include <osmocom/sgsn/sgsn_rim.h>
#include "../../bscconfig.h"
#include "../../config.h"
#if BUILD_IU
#include <osmocom/sigtran/osmo_ss7.h>
@ -81,7 +82,6 @@
#include <getopt.h>
void *tall_sgsn_ctx;
struct ctrl_handle *g_ctrlh;
struct gprs_ns2_inst *sgsn_nsi;
static int daemonize = 0;
@ -97,34 +97,11 @@ const char *openbsc_copyright =
struct sgsn_instance *sgsn;
/* call-back function for the BSSGP protocol */
/* call-back function for the BSSGP protocol.
* Must be left here so that we can add a new one in tests/sgsn_test */
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
struct osmo_bssgp_prim *bp;
bp = container_of(oph, struct osmo_bssgp_prim, oph);
switch (oph->sap) {
case SAP_BSSGP_LL:
switch (oph->primitive) {
case PRIM_BSSGP_UL_UD:
return gprs_llc_rcvmsg(oph->msg, bp->tp);
}
break;
case SAP_BSSGP_GMM:
switch (oph->primitive) {
case PRIM_BSSGP_GMM_SUSPEND:
return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli);
case PRIM_BSSGP_GMM_RESUME:
return gprs_gmm_rx_resume(bp->ra_id, bp->tlli,
bp->u.resume.suspend_ref);
}
break;
case SAP_BSSGP_NM:
break;
case SAP_BSSGP_RIM:
return sgsn_rim_rx(bp, oph->msg);
}
return 0;
return sgsn_bssgp_rx_prim(oph);
}
static void signal_handler(int signum)
@ -162,15 +139,36 @@ static void signal_handler(int signum)
}
}
static int sgsn_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
case SGSN_NODE:
vty->node = CONFIG_NODE;
break;
case MME_NODE:
vty->node = SGSN_NODE;
vty->index = NULL;
break;
default:
#if BUILD_IU
osmo_ss7_vty_go_parent(vty);
#else
vty->node = CONFIG_NODE;
vty->index = NULL;
#endif
break;
}
return vty->node;
}
/* NSI that BSSGP uses when transmitting on NS */
extern struct gprs_ns_inst *bssgp_nsi;
static struct vty_app_info vty_info = {
.name = "OsmoSGSN",
.version = PACKAGE_VERSION,
#if BUILD_IU
.go_parent_cb = osmo_ss7_vty_go_parent,
#endif
.go_parent_cb = sgsn_vty_go_parent,
};
static void print_help(void)
@ -310,11 +308,6 @@ static struct log_info_cat gprs_categories[] = {
.description = "GPRS Packet Service",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DNS] = {
.name = "DNS",
.description = "GPRS Network Service (NS)",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DLLC] = {
.name = "DLLC",
.description = "GPRS Logical Link Control Protocol (LLC)",
@ -410,6 +403,7 @@ int main(int argc, char **argv)
rate_ctr_init(tall_sgsn_ctx);
logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "bssgp");
logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "ns");
sgsn_nsi = gprs_ns2_instantiate(tall_sgsn_ctx, &gprs_ns_prim_cb, NULL);
if (!sgsn_nsi) {
@ -417,19 +411,12 @@ int main(int argc, char **argv)
exit(1);
}
sgsn->cfg.nsi = sgsn_nsi;
bssgp_set_bssgp_callback(gprs_gb_send_cb, sgsn_nsi);
gprs_llc_init("/usr/local/lib/osmocom/crypt/");
sgsn_rate_ctr_init();
sgsn_inst_init(sgsn);
bssgp_set_bssgp_callback(sgsn_bssgp_dispatch_ns_unitdata_req_cb, sgsn_nsi);
gprs_ns2_vty_init(sgsn_nsi);
bssgp_vty_init();
gprs_llc_vty_init();
gprs_sndcp_vty_init();
sgsn_auth_init(sgsn);
sgsn_cdr_init(sgsn);
handle_options(argc, argv);
@ -455,25 +442,11 @@ int main(int argc, char **argv)
}
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(tall_sgsn_ctx, NULL,
vty_get_bind_addr(), OSMO_VTY_PORT_SGSN);
rc = telnet_init_default(tall_sgsn_ctx, NULL, OSMO_VTY_PORT_SGSN);
if (rc < 0)
exit(1);
/* start control interface after reading config for
* ctrl_vty_get_bind_addr() */
g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
OSMO_CTRL_PORT_SGSN, NULL);
if (!g_ctrlh) {
LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n");
exit(1);
}
if (sgsn_ctrl_cmds_install() != 0) {
LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n");
exit(1);
}
gprs_llc_init(sgsn->cfg.crypt_cipher_plugin_path);
rc = sgsn_gtp_init(sgsn);
if (rc) {
@ -482,9 +455,9 @@ int main(int argc, char **argv)
} else
LOGP(DGPRS, LOGL_NOTICE, "libGTP v%s initialized\n", gtp_version());
rc = gprs_subscr_init(sgsn);
rc = sgsn_inst_init(sgsn);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Cannot set up subscriber management\n");
LOGP(DGPRS, LOGL_FATAL, "Cannot set up SGSN\n");
exit(2);
}

View File

@ -11,57 +11,117 @@
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_bssgp_rim.h>
#include <osmocom/sgsn/sgsn_rim.h>
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
/* Find an NSEI for the destination cell, this function works only for GERAN! */
static int find_dest_nsei_geran(struct bssgp_rim_routing_info *dest_rim_ri, uint16_t nsei)
static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *pdu)
{
struct bssgp_bvc_ctx *bvc_ctx;
OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_GERAN);
OSMO_ASSERT(dest_rim_ri->discr == BSSGP_RIM_ROUTING_INFO_GERAN);
bvc_ctx = btsctx_by_raid_cid(&dest_rim_ri->geran.raid, dest_rim_ri->geran.cid);
/* Resolve RIM ROUTING ADDRESS to a BVC context */
bvc_ctx = btsctx_by_raid_cid(&pdu->routing_info_dest.geran.raid, pdu->routing_info_dest.geran.cid);
if (!bvc_ctx) {
LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) cannot find NSEI for destination cell\n", nsei);
LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n",
bssgp_rim_ri_name(&pdu->routing_info_dest));
return -EINVAL;
}
return bvc_ctx->nsei;
/* Forward PDU to the NSEI of the resolved BVC context */
return bssgp_tx_rim(pdu, bvc_ctx->nsei);
}
int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg)
static int sgsn_bssgp_fwd_rim_to_geran_encoded(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address)
{
struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
int d_nsei;
uint16_t nsei = msgb_nsei(msg);
struct bssgp_bvc_ctx *bvc_ctx;
OSMO_ASSERT(rim_routing_address->discr == BSSGP_RIM_ROUTING_INFO_GERAN);
/* At the moment we only support GERAN, so we block all other network
* types here. */
if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGP(DRIM, LOGL_ERROR,
"BSSGP RIM (NSEI=%u) only GERAN supported, destination cell is not a GERAN cell -- rejected.\n",
nsei);
/* At the moment we can only handle GERAN addresses, any other
* type of address will be consideres as an invalid address.
* see also: 3GPP TS 48.018, section 8c.3.1.3 */
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
/* Resolve RIM ROUTING ADDRESS to a BVC context */
bvc_ctx = btsctx_by_raid_cid(&rim_routing_address->geran.raid, rim_routing_address->geran.cid);
if (!bvc_ctx) {
LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n",
bssgp_rim_ri_name(rim_routing_address));
return -EINVAL;
}
/* Forward PDU to the NSEI of the resolved BVC context */
return bssgp_tx_rim_encoded(msg, bvc_ctx->nsei);
}
static int sgsn_bssgp_fwd_rim_to_eutran(const struct bssgp_ran_information_pdu *pdu)
{
struct sgsn_mme_ctx *mme;
OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_EUTRAN);
mme = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_dest.eutran.tai);
if (!mme) { /* See if we have a default route configured */
mme = sgsn_mme_ctx_by_default_route(sgsn);
if (!mme) {
LOGP(DRIM, LOGL_ERROR, "Unable to find MME for destination cell %s\n",
bssgp_rim_ri_name(&pdu->routing_info_dest));
return -EINVAL;
}
}
return sgsn_mme_ran_info_req(mme, pdu);
}
/* Receive a RIM PDU from BSSGP (GERAN) */
int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg)
{
uint16_t nsei = msgb_nsei(msg);
struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGP(DRIM, LOGL_ERROR,
"BSSGP RIM (NSEI=%u) only GERAN supported, source cell is not a GERAN cell -- rejected.\n", nsei);
/* See comment above */
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
"Rx BSSGP RIM (NSEI=%u): Expected src %s, got %s\n", nsei,
bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),
bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr));
goto err;
}
d_nsei = find_dest_nsei_geran(&pdu->routing_info_dest, nsei);
if (d_nsei < 0) {
LOGP(DRIM, LOGL_NOTICE, "BSSGP RIM (NSEI=%u) Cell %s unknown to this sgsn\n",
nsei, bssgp_rim_ri_name(&pdu->routing_info_dest));
/* In case of an invalid destination address we respond with
* a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
switch (pdu->routing_info_dest.discr) {
case BSSGP_RIM_ROUTING_INFO_GERAN:
return sgsn_bssgp_fwd_rim_to_geran(pdu);
case BSSGP_RIM_ROUTING_INFO_EUTRAN:
return sgsn_bssgp_fwd_rim_to_eutran(pdu);
default:
/* At the moment we can only handle GERAN/EUTRAN addresses, any
* other type of address will be considered as an invalid
* address. see also: 3GPP TS 48.018, section 8c.3.1.3
*/
LOGP(DRIM, LOGL_ERROR,
"Rx BSSGP RIM (NSEI=%u): Unsupported dst %s\n", nsei,
bssgp_rim_routing_info_discr_str(pdu->routing_info_dest.discr));
}
/* Forward PDU as it is to the correct interface */
return bssgp_tx_rim(pdu, (uint16_t) d_nsei);
LOGP(DRIM, LOGL_INFO, "Rx BSSGP RIM (NSEI=%u): for dest cell %s\n", nsei,
bssgp_rim_ri_name(&pdu->routing_info_dest));
err:
/* In case of an invalid destination address we respond with
* a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
return -1;
}
/* Receive a RIM PDU from GTPv1C (EUTRAN) */
int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address)
{
/* TODO: In this code path, we currently only support RIM message forwarding to GERAN (BSSGP). However, it
* technically also be possible to route a message back to GTP (BSSGP_RIM_ROUTING_INFO_EUTRAN) or to
* IuPS (BSSGP_RIM_ROUTING_INFO_UTRAN) */
if (rim_routing_address->discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGP(DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected dst %s, got %s\n",
bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),
bssgp_rim_routing_info_discr_str(rim_routing_address->discr));
return -EINVAL;
}
LOGP(DRIM, LOGL_INFO, "Rx GTP RAN Information Relay for dest cell %s\n",
bssgp_rim_ri_name(rim_routing_address));
return sgsn_bssgp_fwd_rim_to_geran_encoded(msg, rim_routing_address);
}

View File

@ -24,6 +24,8 @@
#include <arpa/inet.h>
#include <time.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
@ -35,9 +37,14 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/sgsn/gprs_ns.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/gprs_bssgp.h>
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/vty/tdef_vty.h>
@ -45,6 +52,7 @@
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/crypt/utran_cipher.h>
#include <osmocom/abis/ipa.h>
#include <osmocom/gprs/gprs_bssgp.h>
@ -52,14 +60,12 @@
#include <pdp.h>
#include <gtp.h>
#include "../../bscconfig.h"
#include "../../config.h"
#ifdef BUILD_IU
#include <osmocom/ranap/iu_client.h>
#endif
extern void *tall_sgsn_ctx;
static struct sgsn_config *g_cfg = NULL;
const struct value_string sgsn_auth_pol_strs[] = {
@ -94,7 +100,7 @@ const struct value_string sgsn_auth_pol_strs[] = {
#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
static struct osmo_tdef sgsn_T_defs[] = {
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)" },
@ -110,7 +116,6 @@ static struct osmo_tdef sgsn_T_defs[] = {
/* 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)" },
{}
};
@ -134,7 +139,27 @@ DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
}
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
DEFUN(show_timer_gtp, show_timer_gtp_cmd,
"show timer gtp " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
SHOW_STR "Show timers\n" "GTP (libgtp) 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_gtp, T_arg, NULL);
}
DEFUN(cfg_sgsn_timer_gtp, cfg_sgsn_timer_gtp_cmd,
"timer gtp " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
"Configure or show timers\n" "GTP (libgtp) 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_gtp, argv);
}
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6)
{
static char str[INET6_ADDRSTRLEN + 10];
@ -147,15 +172,28 @@ char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
case PDP_TYPE_N_IETF_IPv4:
if (len < 2 + 4)
break;
strcpy(str, "IPv4 ");
osmo_strlcpy(str, "IPv4 ", sizeof(str));
inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
return str;
case PDP_TYPE_N_IETF_IPv6:
if (len < 2 + 8)
break;
strcpy(str, "IPv6 ");
osmo_strlcpy(str, "IPv6 ", sizeof(str));
inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
return str;
case PDP_TYPE_N_IETF_IPv4v6:
if (len < 2 + 20)
break;
if (return_ipv6) {
/* The IPv6 token, (rightmost four fields) is a duplicate of
* the site prefix + subnetID (leftmost fields) in pdpa here */
osmo_strlcpy(str, "IPv6 ", sizeof(str));
inet_ntop(AF_INET6, pdpa+6, str+5, sizeof(str)-5);
return str;
}
osmo_strlcpy(str, "IPv4 ", sizeof(str));
inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
return str;
default:
break;
}
@ -177,12 +215,36 @@ static struct cmd_node sgsn_node = {
1,
};
static struct cmd_node mme_node = {
MME_NODE,
"%s(config-sgsn-mme)# ",
1,
};
static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)
{
struct mme_rim_route *rt;
vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);
vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);
if (mme->default_route)
vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);
llist_for_each_entry(rt, &mme->routes, list) {
vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,
osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),
rt->tai.tac, VTY_NEWLINE);
}
}
static int config_write_sgsn(struct vty *vty)
{
struct sgsn_ggsn_ctx *gctx;
struct imsi_acl_entry *acl;
struct apn_ctx *actx;
struct ares_addr_node *server;
struct sgsn_mme_ctx *mme;
int i;
vty_out(vty, "sgsn%s", VTY_NEWLINE);
@ -191,7 +253,7 @@ static int config_write_sgsn(struct vty *vty)
vty_out(vty, " gtp local-ip %s%s",
inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
llist_for_each_entry(gctx, &sgsn->ggsn_list, list) {
if (gctx->id == UINT32_MAX)
continue;
@ -213,10 +275,26 @@ static int config_write_sgsn(struct vty *vty)
for (server = sgsn->ares_servers; server; server = server->next)
vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
if (g_cfg->cipher != GPRS_ALGO_GEA0)
vty_out(vty, " encryption %s%s",
get_value_string(gprs_cipher_names, g_cfg->cipher),
VTY_NEWLINE);
if (g_cfg->gea_encryption_mask != 0) {
vty_out(vty, " encryption gea");
for (i = 0; i < _GPRS_ALGO_NUM; i++)
if (g_cfg->gea_encryption_mask >> i & 1)
vty_out(vty, " %u", i);
vty_out(vty, "%s", VTY_NEWLINE);
}
if (g_cfg->uea_encryption_mask != 0) {
vty_out(vty, " encryption uea");
for (i = 0; i < _OSMO_UTRAN_UEA_NUM; i++)
if (g_cfg->uea_encryption_mask >> i & 1)
vty_out(vty, " %u", i);
vty_out(vty, "%s", VTY_NEWLINE);
}
if (g_cfg->crypt_cipher_plugin_path)
vty_out(vty, " encryption cipher-plugin-path %s%s", g_cfg->crypt_cipher_plugin_path, VTY_NEWLINE);
if (g_cfg->sgsn_ipa_name)
vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
if (g_cfg->gsup_server_addr.sin_addr.s_addr)
@ -245,9 +323,9 @@ static int config_write_sgsn(struct vty *vty)
llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
if (llist_empty(&sgsn_apn_ctxts))
if (llist_empty(&sgsn->apn_list))
vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
llist_for_each_entry(actx, &sgsn->apn_list, list) {
if (strlen(actx->imsi_prefix) > 0)
vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
actx->name, actx->imsi_prefix, actx->ggsn->id,
@ -268,6 +346,7 @@ static int config_write_sgsn(struct vty *vty)
vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
osmo_tdef_vty_write(vty, g_cfg->T_defs_gtp, " timer gtp ");
if (g_cfg->pcomp_rfc1144.active) {
vty_out(vty, " compression rfc1144 active slots %d%s",
@ -297,6 +376,10 @@ static int config_write_sgsn(struct vty *vty)
} else
vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
llist_for_each_entry(mme, &sgsn->mme_list, list) {
config_write_mme(vty, mme, " ");
}
#ifdef BUILD_IU
vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
VTY_NEWLINE);
@ -323,6 +406,11 @@ DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
"Set the directory for the GTP State file\n"
"Local Directory\n")
{
if (mkdir(argv[0], 0755) == -1 && errno != EEXIST) {
vty_out(vty, "%% Failed to create state-dir: %s%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
return CMD_SUCCESS;
@ -351,7 +439,7 @@ DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
"IPv4 Address\n")
{
uint32_t id = atoi(argv[0]);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
inet_aton(argv[1], &ggc->remote_addr);
@ -376,7 +464,7 @@ DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
"Version 0\n" "Version 1\n")
{
uint32_t id = atoi(argv[0]);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
if (atoi(argv[1]))
ggc->gtp_version = 1;
@ -394,7 +482,7 @@ DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
"Interval between echo requests in seconds.\n")
{
uint32_t id = atoi(argv[0]);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
ggc->echo_interval = atoi(argv[1]);
@ -413,7 +501,7 @@ DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
NO_STR "Send an echo request to this static GGSN every interval.\n")
{
uint32_t id = atoi(argv[0]);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
ggc->echo_interval = 0;
sgsn_ggsn_ctx_check_echo_timer(ggc);
@ -454,7 +542,7 @@ static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
struct apn_ctx *actx;
struct sgsn_ggsn_ctx *ggsn;
ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
ggsn = sgsn_ggsn_ctx_by_id(sgsn, ggsn_id);
if (ggsn == NULL) {
vty_out(vty, "%% a GGSN with id %d has not been defined%s",
ggsn_id, VTY_NEWLINE);
@ -518,8 +606,13 @@ static void vty_dump_pdp(struct vty *vty, const char *pfx,
osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
VTY_NEWLINE);
vty_out(vty, "%s PDP Address: %s%s", pfx,
gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, false),
VTY_NEWLINE);
if (pdp->lib->eua.v[1] == PDP_TYPE_N_IETF_IPv4v6) {
vty_out(vty, "%s PDP Address: %s%s", pfx,
gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, true),
VTY_NEWLINE);
}
vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
@ -627,7 +720,7 @@ DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
vty_dump_mmctx(vty, "", mm, (argc > 1) ? 1 : 0);
return CMD_SUCCESS;
}
@ -636,9 +729,8 @@ DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
{
struct sgsn_mm_ctx *mm;
llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
llist_for_each_entry(mm, &sgsn->mm_list, list)
vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
return CMD_SUCCESS;
}
@ -649,7 +741,7 @@ DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
{
struct sgsn_pdp_ctx *pdp;
llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
llist_for_each_entry(pdp, &sgsn->pdp_list, g_list)
vty_dump_pdp(vty, "", pdp);
return CMD_SUCCESS;
@ -695,15 +787,19 @@ DEFUN(imsi_acl, cfg_imsi_acl_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_encrypt, cfg_encrypt_cmd,
DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
"encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
"Set encryption algorithm for SGSN\n"
"Use GEA0 (no encryption)\n"
"Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
{
enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
if (strcmp(argv[0], "gea") == 0)
return CMD_SUCCESS;
if (c != GPRS_ALGO_GEA0) {
if (!gprs_cipher_supported(c)) {
if (gprs_cipher_supported(c) <= 0) {
vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
@ -715,11 +811,73 @@ DEFUN(cfg_encrypt, cfg_encrypt_cmd,
}
}
g_cfg->cipher = c;
g_cfg->gea_encryption_mask |= (1 << c);
return CMD_SUCCESS;
}
#define ENCRYPTION_STR "Set encryption algorithms for SGSN\n"
DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
"encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]",
ENCRYPTION_STR
"GPRS Encryption Algorithm\n"
"GEAn Algorithm Number\n"
"GEAn Algorithm Number\n"
"GEAn Algorithm Number\n"
"GEAn Algorithm Number\n"
"GEAn Algorithm Number\n")
{
int i = 0;
g_cfg->gea_encryption_mask = 0;
for (i = 0; i < argc; i++)
g_cfg->gea_encryption_mask |= (1 << atoi(argv[i]));
for (i = 0; i < _GPRS_ALGO_NUM; i++) {
if (g_cfg->gea_encryption_mask >> i & 1) {
if (i == GPRS_ALGO_GEA0)
continue;
if (gprs_cipher_supported(i) <= 0) {
vty_out(vty, "%% cipher %d is unsupported in current version%s", i, VTY_NEWLINE);
return CMD_ERR_INCOMPLETE;
}
if (!g_cfg->require_authentication) {
vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
argv[i], VTY_NEWLINE);
return CMD_ERR_INCOMPLETE;
}
}
}
return CMD_SUCCESS;
}
DEFUN(cfg_encrypt_cipher_plugin_path, cfg_encrypt_cipher_plugin_path_cmd,
"encryption cipher-plugin-path PATH",
ENCRYPTION_STR
"Path to gprs encryption cipher plugin directory\n"
"Plugin path\n")
{
osmo_talloc_replace_string(sgsn, &sgsn->cfg.crypt_cipher_plugin_path, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_no_encrypt_cipher_plugin_path, cfg_no_encrypt_cipher_plugin_path_cmd,
"no encryption cipher-plugin-path PATH",
NO_STR ENCRYPTION_STR
"Path to gprs encryption cipher plugin directory\n"
"Plugin path\n")
{
TALLOC_FREE(sgsn->cfg.crypt_cipher_plugin_path);
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"
@ -741,6 +899,23 @@ DEFUN(cfg_authentication, cfg_authentication_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_encryption_uea, cfg_encryption_uea_cmd,
"encryption uea <0-2> [<0-2>] [<0-2>]",
ENCRYPTION_STR
"UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2.\n"
"UEAn Algorithm Number\n"
"UEAn Algorithm Number\n"
"UEAn Algorithm Number\n")
{
unsigned int i;
g_cfg->uea_encryption_mask = 0;
for (i = 0; i < argc; i++)
g_cfg->uea_encryption_mask |= (1 << atoi(argv[i]));
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"
@ -822,8 +997,17 @@ static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int
}
llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
pdp->context_id, pdp->pdp_type, pdp->apn_str);
char ip_str[INET6_ADDRSTRLEN] = { 0 };
vty_out(vty, " PDP info: Id: %d, Addr(Org: 0x%02x Type: 0x%02x",
pdp->context_id, pdp->pdp_type_org, pdp->pdp_type_nr);
if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC)
vty_out(vty, " Addr[0]: %s", osmo_sockaddr_ntop(&pdp->pdp_address[0].u.sa, ip_str));
if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC)
vty_out(vty, " Addr[1]: %s", osmo_sockaddr_ntop(&pdp->pdp_address[1].u.sa, ip_str));
vty_out(vty, ") APN: '%s'", pdp->apn_str);
if (pdp->qos_subscribed_len)
vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
@ -870,7 +1054,7 @@ DEFUN_HIDDEN(reset_sgsn_state,
struct gprs_subscr *subscr, *tmp_subscr;
struct sgsn_mm_ctx *mm, *tmp_mm;
llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
llist_for_each_entry_safe(mm, tmp_mm, &sgsn->mm_list, list)
{
gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
}
@ -1134,6 +1318,25 @@ DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
return CMD_SUCCESS;
}
DEFUN(page_subscr, page_subscr_info_cmd,
"page imsi IMSI",
"Send a PS paging request to subscriber\n"
"Use the IMSI to select the subscriber\n"
"The IMSI\n")
{
const char *imsi = argv[0];
struct sgsn_mm_ctx *mm;
mm = sgsn_mm_ctx_by_imsi(imsi);
if (!mm) {
vty_out(vty, "No MM context for IMSI %s%s", imsi, VTY_NEWLINE);
return CMD_WARNING;
}
sgsn_bssgp_page_ps_ra(mm);
return CMD_SUCCESS;
}
DEFUN(cfg_gsup_ipa_name,
cfg_gsup_ipa_name_cmd,
"gsup ipa-name NAME",
@ -1424,13 +1627,165 @@ DEFUN(cfg_sgsn_cs7_instance_iu,
}
#endif
DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,
"mme NAME",
"Configure an MME peer\n"
"Name identifying the MME peer\n")
{
struct sgsn_mme_ctx *mme;
mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);
if (!mme)
return CMD_WARNING;
vty->node = MME_NODE;
vty->index = mme;
return CMD_SUCCESS;
}
DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,
"no mme NAME",
NO_STR "Delete an MME peer configuration\n"
"Name identifying the MME peer\n")
{
struct sgsn_mme_ctx *mme;
mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);
if (!mme) {
vty_out(vty, "%% MME %s doesn't exist.%s",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
sgsn_mme_ctx_free(mme);
return CMD_SUCCESS;
}
#define GTP_STR "Configure GTP connection\n"
DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,
"gtp remote-ip A.B.C.D",
GTP_STR "Set Remote GTP IP address\n" IP_STR)
{
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
inet_aton(argv[0], &mme->remote_addr);
return CMD_SUCCESS;
}
#define RAN_INFO_STR "Configure RAN Information Relay routing\n"
#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"
DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,
"gtp ran-info-relay <0-999> <0-999> <0-65535>",
GTP_STR RAN_INFO_STR TAI_DOC)
{
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
struct sgsn_mme_ctx *mme_tmp;
struct osmo_eutran_tai tai;
const char *mcc = argv[0];
const char *mnc = argv[1];
const char *tac = argv[2];
if (osmo_mcc_from_str(mcc, &tai.mcc)) {
vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
return CMD_WARNING;
}
if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
return CMD_WARNING;
}
tai.tac = atoi(tac);
if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
if (mme_tmp != mme) {
vty_out(vty, "%% Another MME %s already contains this route%s",
mme_tmp->name, VTY_NEWLINE);
return CMD_WARNING;
}
/* else: NO-OP, return */
return CMD_SUCCESS;
}
sgsn_mme_ctx_route_add(mme, &tai);
return CMD_SUCCESS;
}
DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,
"no gtp ran-info-relay <0-999> <0-999> <0-65535>",
NO_STR GTP_STR RAN_INFO_STR TAI_DOC)
{
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
struct sgsn_mme_ctx *mme_tmp;
struct osmo_eutran_tai tai;
const char *mcc = argv[0];
const char *mnc = argv[1];
const char *tac = argv[2];
if (osmo_mcc_from_str(mcc, &tai.mcc)) {
vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
return CMD_WARNING;
}
if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
return CMD_WARNING;
}
tai.tac = atoi(tac);
if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
if (mme_tmp != mme) {
vty_out(vty, "%% Another MME %s contains this route%s",
mme_tmp->name, VTY_NEWLINE);
return CMD_WARNING;
}
sgsn_mme_ctx_route_del(mme, &tai);
return CMD_SUCCESS;
} else {
vty_out(vty, "%% This route doesn't exist in current MME %s%s",
mme->name, VTY_NEWLINE);
return CMD_WARNING;
}
}
DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,
"gtp ran-info-relay default",
GTP_STR RAN_INFO_STR "Set as default route")
{
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
struct sgsn_mme_ctx *default_mme;
if (mme->default_route)
return CMD_SUCCESS; /* NO-OP */
if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {
vty_out(vty, "%% Another MME %s is already set as default route, "
"remove it before setting it here.%s",
default_mme->name, VTY_NEWLINE);
return CMD_WARNING;
}
mme->default_route = true;
return CMD_SUCCESS;
}
DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,
"no gtp ran-info-relay default",
NO_STR GTP_STR RAN_INFO_STR "Set as default route")
{
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
mme->default_route = false;
return CMD_SUCCESS;
}
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);
@ -1438,6 +1793,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element_ve(&show_pdpctx_all_cmd);
install_element_ve(&show_subscr_cache_cmd);
install_element_ve(&show_timer_cmd);
install_element_ve(&show_timer_gtp_cmd);
install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
install_element(ENABLE_NODE, &update_subscr_create_cmd);
@ -1445,6 +1801,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
install_element(ENABLE_NODE, &page_subscr_info_cmd);
install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
install_element(CONFIG_NODE, &cfg_sgsn_cmd);
@ -1459,7 +1816,14 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
install_element(SGSN_NODE, &cfg_auth_policy_cmd);
install_element(SGSN_NODE, &cfg_authentication_cmd);
/* order matters here: ensure we attempt to parse our new command first! */
install_element(SGSN_NODE, &cfg_encrypt2_cmd);
install_element(SGSN_NODE, &cfg_encrypt_cmd);
install_element(SGSN_NODE, &cfg_encryption_uea_cmd);
install_element(SGSN_NODE, &cfg_encrypt_cipher_plugin_path_cmd);
install_element(SGSN_NODE, &cfg_no_encrypt_cipher_plugin_path_cmd);
install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
@ -1479,6 +1843,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
install_element(SGSN_NODE, &cfg_sgsn_timer_gtp_cmd);
install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
@ -1487,6 +1852,15 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);
install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);
install_node(&mme_node, NULL);
install_element(MME_NODE, &cfg_mme_remote_ip_cmd);
install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);
install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);
install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);
install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_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);

View File

@ -17,10 +17,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED.

View File

@ -42,38 +42,38 @@ DISTCLEANFILES = \
$(NULL)
if ENABLE_EXT_TESTS
python-tests: $(BUILT_SOURCES)
python-tests:
$(MAKE) vty-test
$(MAKE) ctrl-python-test
else
python-tests: $(BUILT_SOURCES)
python-tests:
echo "Not running python-based tests (determined at configure-time)"
endif
vty-python-test: $(BUILT_SOURCES)
vty-python-test: $(top_builddir)/src/sgsn/osmo-sgsn
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
rm -f $(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:
vty-transcript-test: $(top_builddir)/src/sgsn/osmo-sgsn
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)/osmo-sgsn*.vty}
rm -f $(builddir)/sms.db $(builddir)/gsn_restart
rm -f $(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)
ctrl-python-test: $(top_builddir)/src/sgsn/osmo-sgsn
$(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
rm -f $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
check-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)

View File

@ -1,9 +1,10 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS)
AM_LDFLAGS = -no-install
EXTRA_DIST = gprs_test.ok
noinst_PROGRAMS = gprs_test
check_PROGRAMS = gprs_test
gprs_test_SOURCES = gprs_test.c $(top_srcdir)/src/gprs/gprs_utils.c

View File

@ -24,7 +24,7 @@ static int nu_is_retransmission(uint16_t nu, uint16_t vur)
return ret;
}
static void test_8_4_2()
static void test_8_4_2(void)
{
printf("Testing gprs_llc_is_retransmit.\n");
@ -48,6 +48,22 @@ static void test_8_4_2()
ASSERT_FALSE(nu_is_retransmission(479, 511)); // wrapped
}
/* GSM 04.08, 10.5.7.3 GPRS Timer */
static int gprs_tmr_to_secs(uint8_t tmr)
{
switch (tmr & GPRS_TMR_UNIT_MASK) {
case GPRS_TMR_2SECONDS:
return 2 * (tmr & GPRS_TMR_FACT_MASK);
default:
case GPRS_TMR_MINUTE:
return 60 * (tmr & GPRS_TMR_FACT_MASK);
case GPRS_TMR_6MINUTE:
return 360 * (tmr & GPRS_TMR_FACT_MASK);
case GPRS_TMR_DEACTIVATED:
return -1;
}
}
static void test_gprs_timer_enc_dec(void)
{
int i, u, secs, tmr;

View File

@ -12,11 +12,13 @@ AM_CFLAGS = \
$(LIBGTP_CFLAGS) \
$(NULL)
AM_LDFLAGS = -no-install
EXTRA_DIST = \
gtphub_test.ok \
$(NULL)
noinst_PROGRAMS = \
check_PROGRAMS = \
gtphub_test \
$(NULL)
@ -28,6 +30,7 @@ gtphub_test_LDFLAGS = \
-Wl,--wrap=gtphub_resolve_ggsn_addr \
-Wl,--wrap=gtphub_ares_init \
-Wl,--wrap=gtphub_write \
$(AM_LDFLAGS) \
$(NULL)
gtphub_test_LDADD = \

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