mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-10-23 00:02:01 +00:00
Compare commits
254 Commits
laforge/li
...
sysmocom/i
Author | SHA1 | Date | |
---|---|---|---|
|
6950d14c5b | ||
|
cf2ca648e9 | ||
|
62ee416d95 | ||
|
e42a2ab158 | ||
|
9336cede84 | ||
|
8c6732909b | ||
|
960d28087e | ||
|
a27b295100 | ||
|
9015d4db52 | ||
|
3cda077541 | ||
|
c3da27fa98 | ||
|
bfc190e0fc | ||
|
f959ad8991 | ||
|
f3bcdd272b | ||
|
1d125c902f | ||
|
35ebbbea7a | ||
|
a95927c1de | ||
|
03ded61060 | ||
|
26d0326157 | ||
|
885a11b33e | ||
|
99f2477653 | ||
|
a9791df3b9 | ||
|
d9202b342c | ||
|
c902bd4032 | ||
|
ad21c3b8e3 | ||
|
28fdbdcd53 | ||
|
903ad2e135 | ||
|
04bfcdd6c2 | ||
|
3a9c52a5dc | ||
|
c6580c5b2c | ||
|
fb845bb1df | ||
|
6f4e83beb0 | ||
|
214302b306 | ||
|
defe78f1e1 | ||
|
061787878c | ||
|
00007897d4 | ||
|
5c4386c692 | ||
|
fc68c83ddb | ||
|
74101106a1 | ||
|
db916bfd8d | ||
|
a54358879f | ||
|
a54b47b048 | ||
|
3b922064a4 | ||
|
5b3fd465d1 | ||
|
0991c684d3 | ||
|
dc4b14b269 | ||
|
687270de3a | ||
|
96f88fda06 | ||
|
2ae1f5b7e0 | ||
|
63b99ced83 | ||
|
0b8e6dd2df | ||
|
9f2eaf8f56 | ||
|
afce55a4bc | ||
|
f3a1ca5d04 | ||
|
c7fcdeb18e | ||
|
3aa8b30bb3 | ||
|
208250558f | ||
|
bdb3f26668 | ||
|
69d3c26e43 | ||
|
3f18cfce85 | ||
|
658d1c3e14 | ||
|
6d1df9ad96 | ||
|
9bc1ddc849 | ||
|
90e2c751e9 | ||
|
15f6c9f1e8 | ||
|
5d5a25bc5a | ||
|
95c9f29634 | ||
|
30753e4a28 | ||
|
8fe0feb21b | ||
|
444a516f18 | ||
|
0f3bce4aef | ||
|
edafdc14f3 | ||
|
54fc3a1318 | ||
|
baefda5d64 | ||
|
8dfe9690c5 | ||
|
fafb074268 | ||
|
a3dfdcb308 | ||
|
bae2594424 | ||
|
5e007d9445 | ||
|
42024336fe | ||
|
bb81326719 | ||
|
276192d27c | ||
|
c4b9b4edbb | ||
|
b70dfa610d | ||
|
4b940126a3 | ||
|
debb0e3868 | ||
|
d025a3cfbb | ||
|
4b3b13e10c | ||
|
fa48a98e71 | ||
|
9fd87ecd11 | ||
|
8e5c63f032 | ||
|
2cd36e87ae | ||
|
0bc6c11cbf | ||
|
182adecb98 | ||
|
3d0a500f2d | ||
|
a5c9cea22c | ||
|
f45dc35321 | ||
|
2f6c4b6479 | ||
|
2385074cba | ||
|
d8b0b61ca8 | ||
|
19f0735752 | ||
|
ffd9968d3a | ||
|
deb227b98e | ||
|
5e611021b0 | ||
|
d04db9d907 | ||
|
3c94c2c597 | ||
|
372a3bd346 | ||
|
51bf76ef47 | ||
|
aa60582036 | ||
|
6b2623d944 | ||
|
8b1272a6d3 | ||
|
080921a551 | ||
|
8e7f4c6f21 | ||
|
4a9b871de5 | ||
|
93f6fa5a81 | ||
|
f1777ee843 | ||
|
9e8e0e6a29 | ||
|
cf3d2a1fad | ||
|
e4baf402cb | ||
|
53d782fc38 | ||
|
33a343858d | ||
|
15b1fce69c | ||
|
2f8117d214 | ||
|
8927bb46d5 | ||
|
d52b1c4342 | ||
|
5d9004bc9b | ||
|
a4198d1922 | ||
|
544a203f67 | ||
|
b40df4c09e | ||
|
5c1c0bad89 | ||
|
1e361301d1 | ||
|
9e8322ca0c | ||
|
9bd121b75b | ||
|
fa029f08c2 | ||
|
db9c064dd4 | ||
|
a0da2dbe9e | ||
|
7df5705251 | ||
|
da7424cc54 | ||
|
8146cfa782 | ||
|
330898afb7 | ||
|
77544a65b5 | ||
|
4e5ddfa91a | ||
|
cba441f3de | ||
|
3acbc817f6 | ||
|
bcb98b1754 | ||
|
2a7426d7cb | ||
|
b9bb2a4f54 | ||
|
098c14800f | ||
|
a46c651a4a | ||
|
4cc1f72cb7 | ||
|
4f143e52b6 | ||
|
e3407f8884 | ||
|
7d1b6b1c79 | ||
|
656d7cd0b4 | ||
|
553d2a8ceb | ||
|
23f22b1183 | ||
|
090aabe052 | ||
|
be37fbd85d | ||
|
3cc0836b1a | ||
|
8cd32937da | ||
|
377a9f5dea | ||
|
b8df4d5318 | ||
|
daa0652d3f | ||
|
f7436b22b3 | ||
|
711333c113 | ||
|
91f04dfe3a | ||
|
4371ff8cce | ||
|
92223cc32e | ||
|
2f5cc8abe0 | ||
|
ba47b525ff | ||
|
cf1707af7f | ||
|
d6d0d8b86f | ||
|
38137e84f7 | ||
|
82724653e7 | ||
|
da8d9bc355 | ||
|
c59e52a6aa | ||
|
24c4af1d82 | ||
|
f918920d65 | ||
|
292f1ce533 | ||
|
23e7f28c5c | ||
|
243c7cb044 | ||
|
cf2591f6fc | ||
|
6a2d8985bf | ||
|
c6794eed1d | ||
|
7a70a4f52a | ||
|
c6172a320b | ||
|
5280ed558c | ||
|
b36b910366 | ||
|
b47e52c958 | ||
|
267f6c7e0d | ||
|
5e47b1a1d3 | ||
|
b9e5403ef4 | ||
|
b6769b99de | ||
|
39daffd7a5 | ||
|
71d1e17e5e | ||
|
2c9e65051c | ||
|
a2ce4aa615 | ||
|
ee1541d504 | ||
|
9dcae17866 | ||
|
c2c5176328 | ||
|
a2c182df6d | ||
|
070f673b12 | ||
|
e2a10dbe35 | ||
|
bf30ec26e5 | ||
|
dcbc852125 | ||
|
48e091ea2b | ||
|
712074cb17 | ||
|
a34aedf7f9 | ||
|
2e5c13129d | ||
|
da5b3fcd32 | ||
|
5291ee5c16 | ||
|
5773987881 | ||
|
836b904e77 | ||
|
444d50b77f | ||
|
b3b8ccfa54 | ||
|
231aa60ce4 | ||
|
8b713f817d | ||
|
ce3b41fdb6 | ||
|
0f93bb80e4 | ||
|
477a054c2c | ||
|
52ddce4378 | ||
|
2945fd4611 | ||
|
2449c0ce58 | ||
|
5d145b5477 | ||
|
45b13244f0 | ||
|
cb91aa7e6c | ||
|
7ef6d9893f | ||
|
6aeee0a0d9 | ||
|
17d061bd8e | ||
|
ef3548c0a1 | ||
|
add0953692 | ||
|
ca3977c8fe | ||
|
a234287d09 | ||
|
8440c9f04b | ||
|
2cb732aeb9 | ||
|
a7551e033e | ||
|
08ed1d73f2 | ||
|
af9bfac58d | ||
|
ac9951e54a | ||
|
75cdeaf1e3 | ||
|
41f8f047bc | ||
|
195d2dc724 | ||
|
315abfd46b | ||
|
648b9db47f | ||
|
8291623054 | ||
|
5331cf8dbd | ||
|
cf8e56cd1e | ||
|
e157174447 | ||
|
493534bf56 | ||
|
342f59d92e | ||
|
aefb0c45e9 | ||
|
692f31446e | ||
|
2cde90e904 | ||
|
f6672ab8b0 |
2
openbsc/.gitignore
vendored
2
openbsc/.gitignore
vendored
@@ -55,6 +55,7 @@ src/gprs/osmo-sgsn
|
||||
src/gprs/osmo-gbproxy
|
||||
src/gprs/osmo-gtphub
|
||||
src/osmo-bsc_nat/osmo-bsc_nat
|
||||
src/osmo-cscn/osmo-cscn
|
||||
|
||||
#tests
|
||||
tests/testsuite.dir
|
||||
@@ -88,7 +89,6 @@ tests/package.m4
|
||||
tests/testsuite
|
||||
tests/testsuite.log
|
||||
|
||||
|
||||
src/openbsc.cfg*
|
||||
writtenconfig/
|
||||
gtphub_restart_count
|
||||
|
@@ -28,6 +28,9 @@ PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.2.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.1)
|
||||
PKG_CHECK_MODULES(LIBCRYPTO, libcrypto >= 0.9.5)
|
||||
PKG_CHECK_MODULES(LIBASN1C, libasn1c)
|
||||
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap)
|
||||
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran)
|
||||
|
||||
# Enabke/disable the NAT?
|
||||
AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])],
|
||||
@@ -47,7 +50,7 @@ fi
|
||||
AM_CONDITIONAL(BUILD_BSC, test "x$osmo_ac_build_bsc" = "xyes")
|
||||
AC_SUBST(osmo_ac_build_bsc)
|
||||
|
||||
# Enable/disable smpp support in the nitb?
|
||||
# Enable/disable smpp support in the cscn?
|
||||
AC_ARG_ENABLE([smpp], [AS_HELP_STRING([--enable-smpp], [Build the SMPP interface])],
|
||||
[osmo_ac_build_smpp="$enableval"],[osmo_ac_build_smpp="no"])
|
||||
if test "$osmo_ac_build_smpp" = "yes" ; then
|
||||
@@ -191,7 +194,9 @@ AC_OUTPUT(
|
||||
src/libmgcp/Makefile
|
||||
src/libcommon/Makefile
|
||||
src/libfilter/Makefile
|
||||
src/osmo-nitb/Makefile
|
||||
src/libiu/Makefile
|
||||
src/libxsc/Makefile
|
||||
src/osmo-cscn/Makefile
|
||||
src/osmo-bsc/Makefile
|
||||
src/osmo-bsc_nat/Makefile
|
||||
src/osmo-bsc_mgcp/Makefile
|
||||
@@ -200,6 +205,7 @@ AC_OUTPUT(
|
||||
src/gprs/Makefile
|
||||
tests/Makefile
|
||||
tests/atlocal
|
||||
tests/libiudummy/Makefile
|
||||
tests/gsm0408/Makefile
|
||||
tests/db/Makefile
|
||||
tests/channel/Makefile
|
||||
|
608
openbsc/doc/call-graphs-MSC-BSC-HNBGW.txt
Normal file
608
openbsc/doc/call-graphs-MSC-BSC-HNBGW.txt
Normal file
@@ -0,0 +1,608 @@
|
||||
gprs_iu_tx
|
||||
|
||||
-- WORK IN PROGRESS --
|
||||
|
||||
This is an incomplete collection of call graphs between MSC and Osmo-BSC,
|
||||
partly including Osmo-BTS. These traces helped understanding the separation of
|
||||
the BSC part from Osmo-NITB. The aim: obtain a clearly separated "A" interface
|
||||
towards the BSC, and have an Iu-CS interface to operate with HNB-GW and hNodeB.
|
||||
The working title for the result is Osmo-CSCN (Circuit Switched Core Network),
|
||||
combining an MSC with various other core network components, but without the
|
||||
BSC parts.
|
||||
|
||||
|
||||
Some Specs and Overview
|
||||
|
||||
0408: Radio interface
|
||||
0411: PP-SMS on Radio interface
|
||||
0802: A Interface MSC<->BSS (BSS = BSC + BTS)
|
||||
0804: A Interface L1 MSC<->BSS
|
||||
0806: A Interface L2 MSC<->BSS
|
||||
0808: A Interface L3 MSC<->BSS
|
||||
0808: Figure 1: A MSC<->BSS
|
||||
0820: RA (Rate Adaption) MSC<->BSS
|
||||
|
||||
0851,0852: A-bis general BSC<->BTS
|
||||
1221: A-bis NM BSC<->BTS
|
||||
1201: Figure 9: A-bis BSC<->BTS
|
||||
|
||||
MS <-> BTS <-> BSC <-> MSC <-> cn
|
||||
| | | | |
|
||||
|<-------0408=DTAP----->| |
|
||||
|<-------0411---------->| |
|
||||
| | |<--0808>| |
|
||||
| | |<BSSMAP>| |
|
||||
| | | | |
|
||||
| Abis | A |
|
||||
|
||||
MS <-> hNodeB <-> HNB-GW <-> MSC <-> cn
|
||||
| | | | |
|
||||
|<-0408->|<--Iu--->|<-Iu-cs->| |
|
||||
|<-0411->| | | |
|
||||
| | | | |
|
||||
|
||||
Entry/Exit points
|
||||
|
||||
Osmo-BSC <--A--> MSC or Osmo-CSCN
|
||||
format: BSSAP/SCCP (where BSSAP = DTAP + BSSMAP)
|
||||
Osmo-BSC
|
||||
read from MSC: sccp_system_incoming_ctx()
|
||||
write to MSC: sccp_connection_write() <-- osmo-bsc/osmo_bsc_sccp.c:bsc_queue_for_msc()
|
||||
MSC:
|
||||
third party
|
||||
Osmo-CSCN:
|
||||
read: does not exist yet
|
||||
write: does not exist yet
|
||||
|
||||
HNB-GW <--Iu-CS--> Osmo-CSCN
|
||||
format: CC+MM/RANAP/SUA
|
||||
HNB-GW:
|
||||
read: does not exist yet
|
||||
write: does not exist yet
|
||||
Osmo-CSCN:
|
||||
read: does not exist yet
|
||||
write: does not exist yet
|
||||
|
||||
Osmo-BTS <-Abis-> Osmo-BSC
|
||||
Osmo-BSC:
|
||||
read: libbsc/abis_rsl.c:abis_rsl_rcvmsg(msg)
|
||||
write: libosmo-abis/src/e1_input.c:abis_sendmsg() (e1inp_sign_link*)msg->dst;
|
||||
|
||||
Osmo-BTS <-Abis-> Osmo-NITB
|
||||
Osmo-NITB:
|
||||
read:
|
||||
osmo_signal_dispatch():
|
||||
from on_dso_load_token() libmsc/token_auth.c
|
||||
SS_SUBSCR: token_subscr_cb() libmsc/token_auth.c
|
||||
SS_SMS: token_sms_cb() libmsc/token_auth.c
|
||||
from subscr_sig_cb() libmsc/rrlp.c
|
||||
SS_SUBSCR: subscr_sig_cb() libmsc/rrlp.c
|
||||
SS_PAGING: paging_sig_cb() libmsc/rrlp.c
|
||||
from on_dso_load_ho_dec() libbsc/handover_decision.c
|
||||
SS_LCHAN: ho_dec_sig_cb() libbsc/handover_decision.c
|
||||
from e1inp_init() libosmo-abis/src/e1_input.c
|
||||
SS_L_GLOBAL: e1i_sig_cb() libosmo-abis/src/e1_input.c
|
||||
|
||||
bts_model_bs11_init();
|
||||
bts_model_rbs2k_init();
|
||||
bts_model_nanobts_init();
|
||||
bts_model_nokia_site_init();
|
||||
bts_model_sysmobts_init();
|
||||
|
||||
bsc_bootstrap_network():
|
||||
osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
|
||||
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
|
||||
|
||||
|
||||
Call Trees
|
||||
|
||||
- A Interface
|
||||
|
||||
Osmo-BSC sends to MSC:
|
||||
|
||||
sccp_connection_write(conn->sccp, msg);
|
||||
^ bsc_queue_for_msc()
|
||||
^
|
||||
| osmo-bsc/osmo_bsc_api.c:
|
||||
| bsc_clear_request()
|
||||
| queue_msg_or_return() osmo-bsc/osmo_bsc_api.c
|
||||
| ^ bsc_sapi_n_reject()
|
||||
| | ^send_sapi_reject()
|
||||
| | ^ gsm0808_submit_dtap() libbsc/bsc_api.c
|
||||
| | | ^ gsm48_conn_sendmsg() libmsc/gsm_04_08.c
|
||||
| | | | ^ gsm48_cc_tx_notify_ss() libmsc/gsm_04_08.c
|
||||
| | | | | mm_tx_identity_req() libmsc/gsm_04_08.c
|
||||
| | | | | gsm48_tx_mm_info() libmsc/gsm_04_08.c
|
||||
| | | | | gsm48_tx_mm_auth_req()
|
||||
| | | | | gsm48_send_rr_app_info()
|
||||
| | | | | gsm48_cc_tx_status()
|
||||
| | | | | gsm48_tx_simple()
|
||||
| | | | | ^ gsm48_tx_mm_auth_rej()
|
||||
| | | | | gsm48_cc_tx_setup()
|
||||
| | | | | gsm48_cc_tx_call_proc()
|
||||
| | | | | gsm48_cc_tx_alerting()
|
||||
| | | | | gsm48_cc_tx_progress()
|
||||
| | | | | gsm48_cc_tx_connect()
|
||||
| | | | | gsm48_cc_tx_connect_ack()
|
||||
| | | | | gsm48_cc_tx_disconnect()
|
||||
| | | | | gsm48_cc_tx_release()
|
||||
| | | | | gsm48_cc_tx_release_compl()
|
||||
| | | | | gsm48_cc_tx_facility()
|
||||
| | | | | gsm48_cc_tx_hold_ack()
|
||||
| | | | | gsm48_cc_tx_hold_rej()
|
||||
| | | | | gsm48_cc_tx_retrieve_ack()
|
||||
| | | | | gsm48_cc_tx_retrieve_rej()
|
||||
| | | | | gsm48_cc_tx_start_dtmf_ack()
|
||||
| | | | | gsm48_cc_tx_start_dtmf_rej()
|
||||
| | | | | gsm48_cc_tx_stop_dtmf_ack()
|
||||
| | | | | gsm48_cc_tx_modify()
|
||||
| | | | | gsm48_cc_tx_modify_complete()
|
||||
| | | | | gsm48_cc_tx_modify_reject()
|
||||
| | | | | gsm48_cc_tx_notify()
|
||||
| | | | | gsm48_cc_tx_userinfo()
|
||||
| | | |
|
||||
| | | | gsm0480_send_ussd_response() libmsc/gsm_04_80.c
|
||||
| | | | gsm0480_send_ussd_reject() libmsc/gsm_04_80.c
|
||||
| | | | gsm0480_send_ussdNotify() libmsc/gsm_04_80.c
|
||||
| | | | ^ bsc_send_ussd_no_srv() osmo-bsc/osmo_bsc_api.c
|
||||
| | | | gsm0480_send_releaseComplete() libmsc/gsm_04_80.c
|
||||
| | | | ^ bsc_send_ussd_no_srv() osmo-bsc/osmo_bsc_api.c
|
||||
| | | |
|
||||
| | | | gsm411_sendmsg() libmsc/gsm_04_11.c
|
||||
| | | |
|
||||
| | | | bsc_maybe_lu_reject() osmo-bsc/osmo_bsc_api.c
|
||||
| | | | ^ complete_layer3()
|
||||
| | | | | bsc_dtap()
|
||||
| | | |
|
||||
| | | | dtap_rcvmsg() osmo-bsc/osmo_bsc_bssap.c
|
||||
| | | |
|
||||
| | | | gsm48_tx_mm_serv_ack() libbsc/gsm_04_08_utils.c
|
||||
| | | | ^ _gsm48_rx_mm_serv_req_sec_cb()
|
||||
| | | | | bsc_send_ussd_no_srv() osmo-bsc/osmo_bsc_api.c
|
||||
| | | |
|
||||
| | | | gsm48_tx_mm_serv_rej() libbsc/gsm_04_08_utils.c
|
||||
| | |
|
||||
| | | bsc_rll_req.cb = rll_ind_cb() from rll_establish() from gsm0808_submit_dtap()
|
||||
| | | ^ complete_rllr() libbsc/bsc_rll.c
|
||||
| | | | ^ timer_cb() libbsc/bsc_rll.c
|
||||
| | | | | rll_indication() libbsc/bsc_rll.c
|
||||
| | | | | rll_lchan_signal() libbsc/bsc_rll.c
|
||||
| |
|
||||
| | bsc_cipher_mode_compl()
|
||||
| | ^ bsc_api.cipher_mode_compl()
|
||||
| | | dispatch_dtap() (2)
|
||||
| | | with GSM48_MT_RR_CIPH_M_COMPL
|
||||
| |
|
||||
| | bsc_dtap()
|
||||
| | ^ cb from osmo-bsc/osmo_bsc_api.c
|
||||
| | bsc_api.dtap()
|
||||
| | ^ libbsc/bsc_api.c:
|
||||
| | | dispatch_dtap() (2)
|
||||
| | | case GSM48_MT_RR_APP_INFO
|
||||
| | | case unknown 04.08 RR
|
||||
| |
|
||||
| | bsc_assign_compl()
|
||||
| | ^ osmo-bsc/osmo_bsc_api.c
|
||||
| | bsc_api.assign_compl()
|
||||
| | ^ libbsc/bsc_api.c:
|
||||
| | | dispatch_dtap() (2)
|
||||
| | | case GSM48_MT_RR_CHAN_MODE_MODIF_ACK
|
||||
| | | handle_ass_compl()
|
||||
| | | ^ dispatch_dtap() (2)
|
||||
| | | | case GSM48_MT_RR_ASS_COMPL
|
||||
| |
|
||||
| | bsc_assign_fail()
|
||||
| |
|
||||
| | bsc_cm_update()
|
||||
|
|
||||
| osmo-bsc/osmo_bsc_bssap.c:
|
||||
| bssmap_handle_clear_command()
|
||||
| bssmap_handle_cipher_mode()
|
||||
| bssmap_handle_assignm_req()
|
||||
|
|
||||
|
||||
|
||||
Osmo-BSC receives from MSC:
|
||||
sccp_system_incoming_ctx() (libosmo-sccp)
|
||||
| L2 type:
|
||||
v SCCP_MSG_TYPE_CR: _sccp_handle_connection_request(msgb, ctx);
|
||||
SCCP_MSG_TYPE_RLSD: _sccp_handle_connection_released(msgb);
|
||||
SCCP_MSG_TYPE_CREF: _sccp_handle_connection_refused(msgb);
|
||||
SCCP_MSG_TYPE_CC: _sccp_handle_connection_confirm(msgb);
|
||||
SCCP_MSG_TYPE_RLC: _sccp_handle_connection_release_complete(msgb);
|
||||
|
||||
SCCP_MSG_TYPE_DT1: _sccp_handle_connection_dt1(msgb);
|
||||
Note: a dt1 target entry was created during one of:
|
||||
- bsc_open_connection() (SCCP connections are established by the BSC, exclusively)
|
||||
sccp_connection_connect()
|
||||
_sccp_send_connection_request()
|
||||
llist_add_tail(&connection->list, &sccp_connections);
|
||||
- sccp_system_incoming_ctx()
|
||||
SCCP_MSG_TYPE_CR:
|
||||
_sccp_handle_connection_request(struct msgb *msgb, void *ctx)
|
||||
cb->accept_cb() = msc_sccp_accept()
|
||||
|
||||
SCCP_MSG_TYPE_UDT: _sccp_handle_read(msgb) --read_cb--> osmo-bsc/osmo_bsc_sccp.c:msc_sccp_read()
|
||||
msc_sccp_read()
|
||||
| bsc_handle_udt() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_bssap.c:494
|
||||
v bssmap_rcvmsg_udt() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_bssap.c:387
|
||||
gsm0808_bssmap_name() ./libosmocore/src/gsm/gsm0808.c:535
|
||||
bssmap_handle_reset_ack() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_bssap.c:91
|
||||
LOGP()
|
||||
bssmap_handle_paging() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_bssap.c:99
|
||||
GSM0808_IE_IMSI
|
||||
GSM0808_IE_CELL_IDENTIFIER_LIST
|
||||
GSM0808_IE_TMSI
|
||||
CELL_IDENT_LAC
|
||||
CELL_IDENT_BSS
|
||||
GSM0808_IE_CHANNEL_NEEDED
|
||||
GSM0808_IE_EMLPP_PRIORITY
|
||||
subscr_get_or_create() ./openbsc/openbsc/src/libcommon/gsm_subscriber_base.c:101
|
||||
subscr_group
|
||||
LOGL_INFO
|
||||
bsc_grace_paging_request() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_grace.c:87
|
||||
normal_paging() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_grace.c:37
|
||||
if (msc->core_lac != -1)
|
||||
paging_request_bts() ./openbsc/openbsc/src/libbsc/paging.c:307
|
||||
trx_is_usable() ./openbsc/openbsc/src/libbsc/chan_alloc.c:49
|
||||
if is_ipaccess_bts() and nm_is_running(): 0
|
||||
else: 1
|
||||
paging_init_if_needed() ./openbsc/openbsc/src/libbsc/paging.c:224
|
||||
LAUNCH TIMER:
|
||||
bts->paging.work_timer.cb = paging_worker;
|
||||
paging_worker() ./openbsc/openbsc/src/libbsc/paging.c:217
|
||||
paging_handle_pending_requests() ./openbsc/openbsc/src/libbsc/paging.c:169 (R):
|
||||
paging_give_credit() ./openbsc/openbsc/src/libbsc/paging.c:107 (R):
|
||||
recurse paging_handle_pending_requests()
|
||||
can_send_pag_req() ./openbsc/openbsc/src/libbsc/paging.c:116
|
||||
page_ms() ./openbsc/openbsc/src/libbsc/paging.c:69
|
||||
gsm0808_page() ./openbsc/openbsc/src/libbsc/bsc_api.c:415
|
||||
rsl_paging_cmd() ./openbsc/openbsc/src/libbsc/abis_rsl.c:751
|
||||
abis_rsl_dchan_hdr
|
||||
RSL_MT_PAGING_CMD
|
||||
RSL_CHAN_PCH_AGCH
|
||||
init_dchan_hdr() ./openbsc/openbsc/src/libbsc/abis_rsl.c:99
|
||||
mdisc_by_msgtype() ./openbsc/openbsc/src/libbsc/abis_rsl.c:80
|
||||
ABIS_RSL_MDISC_RLL
|
||||
ABIS_RSL_MDISC_TRX
|
||||
ABIS_RSL_MDISC_COM_CHAN
|
||||
ABIS_RSL_MDISC_DED_CHAN
|
||||
ABIS_RSL_MDISC_LOC
|
||||
RSL_IE_CHAN_NR
|
||||
RSL_IE_PAGING_GROUP
|
||||
RSL_IE_MS_IDENTITY
|
||||
RSL_IE_CHAN_NEEDED
|
||||
abis_rsl_sendmsg() ./libosmo-abis/src/e1_input.c:258
|
||||
_paging_request() ./openbsc/openbsc/src/libbsc/paging.c:279
|
||||
llist_add_tail(&req->entry, &bts_entry->pending_requests);
|
||||
paging_schedule_if_needed() ./openbsc/openbsc/src/libbsc/paging.c:96
|
||||
if (msc->core_lac == -1)
|
||||
paging_request()
|
||||
gsm_bts_by_lac() ./openbsc/openbsc/src/libcommon/gsm_data.c:135
|
||||
paging_request_bts() ./openbsc/openbsc/src/libbsc/paging.c:307
|
||||
(see above)
|
||||
if err
|
||||
paging_request_stop()
|
||||
(see below)
|
||||
locked_paging() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_grace.c:54
|
||||
paging_request_bts() ./openbsc/openbsc/src/libbsc/paging.c:307
|
||||
(see above)
|
||||
|
||||
|
||||
- A-bis Interface
|
||||
|
||||
Osmo-BSC to BTS:
|
||||
abis_sendmsg()
|
||||
^
|
||||
| libosmo-abis/src/e1_input.c:abis_rsl_sendmsg()
|
||||
| ^
|
||||
| | libbsc/abis_rsl.c: 23 callers
|
||||
| | rsl_bcch_info()
|
||||
| | rsl_sacch_filling()
|
||||
| | rsl_sacch_info_modify()
|
||||
| | rsl_chan_bs_power_ctrl()
|
||||
| | rsl_chan_ms_power_ctrl()
|
||||
| | rsl_chan_activate_lchan()
|
||||
| | rsl_chan_mode_modify_req()
|
||||
| | rsl_encryption_cmd()
|
||||
| | rsl_deact_sacch()
|
||||
| | rsl_rf_chan_release()
|
||||
| | rsl_paging_cmd()
|
||||
| | rsl_imm_assign_cmd()
|
||||
| | rsl_siemens_mrpci()
|
||||
| | rsl_data_request()
|
||||
| | rsl_establish_request()
|
||||
| | rsl_release_request()
|
||||
| | rsl_ipacc_crcx()
|
||||
| | rsl_ipacc_mdcx()
|
||||
| | rsl_ipacc_pdch_activate()
|
||||
| | rsl_sms_cb_command()
|
||||
| | rsl_nokia_si_begin()
|
||||
| | rsl_nokia_si_end()
|
||||
| | rsl_bs_power_control()
|
||||
|
|
||||
| libbsc/bts_nokia_site.c:nokia_abis_nm_queue_send_next()
|
||||
|
|
||||
| libbsc/abis_nm.c:_abis_nm_sendmsg()
|
||||
| ^ abis_nm_sendmsg()
|
||||
| | abis_nm_sendmsg_direct()
|
||||
|
|
||||
| osmo-bts/src/common/abis.c:abis_oml_sendmsg()
|
||||
| osmo-bts/src/common/abis.c:abis_bts_rsl_sendmsg()
|
||||
|
||||
|
||||
|
||||
libbsc/e1_config.c:bts_isdn_e1inp_line_ops.sign_link =
|
||||
libbsc/e1_config.c:bts_isdn_sign_link(struct msgb *msg)
|
||||
case E1INP_SIGN_RSL:
|
||||
libbsc/abis_rsl.c:abis_rsl_rcvmsg(msg) (1)
|
||||
case E1INP_SIGN_OML:
|
||||
ret = bts->model->oml_rcvmsg(msg);
|
||||
|
||||
libbsc/bts_ipaccess_nanobts.c:ipaccess_e1inp_line_ops.sign_link =
|
||||
ipaccess_sign_link(struct msgb *msg)
|
||||
case E1INP_SIGN_RSL:
|
||||
libbsc/abis_rsl.c:abis_rsl_rcvmsg(msg) (1)
|
||||
case E1INP_SIGN_OML:
|
||||
libbsc/abis_nm.c:abis_nm_rcvmsg(msg);
|
||||
|
||||
|
||||
(1)
|
||||
libbsc/abis_rsl.c:abis_rsl_rcvmsg(msg)
|
||||
case ABIS_RSL_MDISC_RLL:
|
||||
libbsc/abis_rsl.c:abis_rsl_rx_rll(msg)
|
||||
case DATA_IND, EST_IND:
|
||||
libbsc/bsc_api.c:gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
|
||||
msg->lchan->ts->trx->bts->network->bsc_api;
|
||||
if (lchan->conn)
|
||||
libbsc/bsc_api.c:dispatch_dtap() (2)
|
||||
else
|
||||
lchan->conn = subscr_con_allocate(msg->lchan);
|
||||
rc = api->compl_l3(lchan->conn, msg, 0); (3)
|
||||
|
||||
case ABIS_RSL_MDISC_DED_CHAN:
|
||||
rc = abis_rsl_rx_dchan(msg);
|
||||
|
||||
case ABIS_RSL_MDISC_COM_CHAN:
|
||||
rc = abis_rsl_rx_cchan(msg);
|
||||
|
||||
case ABIS_RSL_MDISC_TRX:
|
||||
rc = abis_rsl_rx_trx(msg);
|
||||
|
||||
case ABIS_RSL_MDISC_IPACCESS:
|
||||
rc = abis_rsl_rx_ipacc(msg);
|
||||
break;
|
||||
|
||||
case ABIS_RSL_MDISC_LOC:
|
||||
LOGP(DRSL, LOGL_NOTICE, "unimplemented RSL msg disc 0x%02x\n",
|
||||
|
||||
|
||||
(2)
|
||||
libbsc/bsc_api.c:dispatch_dtap()
|
||||
struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
|
||||
|
||||
default:
|
||||
if (api->dtap)
|
||||
api->dtap(conn, link_id, msg); (5)
|
||||
|
||||
case GSM48_PDISC_RR:
|
||||
case GSM48_MT_RR_HANDO_COMPL:
|
||||
handle_rr_ho_compl(msg);
|
||||
|
||||
case GSM48_MT_RR_HANDO_FAIL:
|
||||
handle_rr_ho_fail(msg);
|
||||
|
||||
case GSM48_MT_RR_CIPH_M_COMPL:
|
||||
if (api->cipher_mode_compl)
|
||||
api->cipher_mode_compl(conn, msg, (4)
|
||||
conn->lchan->encr.alg_id);
|
||||
|
||||
case GSM48_MT_RR_ASS_COMPL:
|
||||
handle_ass_compl(conn, msg);
|
||||
|
||||
case GSM48_MT_RR_ASS_FAIL:
|
||||
handle_ass_fail(conn, msg);
|
||||
|
||||
case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
|
||||
rc = gsm48_rx_rr_modif_ack(msg);
|
||||
if (rc < 0) {
|
||||
api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE)
|
||||
else
|
||||
api->assign_compl()
|
||||
|
||||
case GSM48_MT_RR_CLSM_CHG:
|
||||
handle_classmark_chg(conn, msg);
|
||||
|
||||
case GSM48_MT_RR_APP_INFO:
|
||||
if (api->dtap)
|
||||
api->dtap(conn, link_id, msg); (5)
|
||||
|
||||
default:
|
||||
if (api->dtap)
|
||||
api->dtap(conn, link_id, msg); (5)
|
||||
|
||||
case GSM48_MT_RR_GPRS_SUSP_REQ:
|
||||
DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
|
||||
|
||||
case GSM48_MT_RR_STATUS:
|
||||
LOGP(DRR, LOGL_NOTICE, "RR STATUS (cause: %s)\n",
|
||||
|
||||
case GSM48_MT_RR_MEAS_REP:
|
||||
LOGP(DMEAS, LOGL_ERROR, "DIRECT GSM48 MEASUREMENT REPORT ?!? ");
|
||||
|
||||
|
||||
(3)[0]
|
||||
msc_bsc_api().compl_l3 =
|
||||
libmsc/osmo_msc.c: msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
|
||||
libmsc/gsm0408.c: gsm0408_dispatch() (6)
|
||||
|
||||
(3)[1]
|
||||
osmo_bsc_api().compl_l3 =
|
||||
osmo-bsc/osmo_bsc_api.c:bsc_compl_l3()
|
||||
msc = bsc_find_msc(conn, msg);
|
||||
complete_layer3(conn, msg, msc)
|
||||
bsc_filter_initial(msc->network->bsc_data, msc, conn, msg,
|
||||
&imsi, &con_type, &lu_cause);
|
||||
bsc_create_new_connection(conn, msc, send_ping);
|
||||
sccp->state_cb = msc_outgoing_sccp_state()
|
||||
sccp->data_cb = msc_outgoing_sccp_data()
|
||||
bsc_con->send_ping = send_ping()
|
||||
bsc_con->sccp_it_timeout.cb = sccp_it_timeout()
|
||||
bsc_con->sccp_cc_timeout.cb = sccp_cc_timeout()
|
||||
bsc_scan_bts_msg(conn, msg); (7)
|
||||
resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci);
|
||||
|
||||
(5)[0]
|
||||
msc_bsc_api().dtap =
|
||||
libmsc/osmo_msc.c: msc_dtap(conn, link_id, msg)
|
||||
gsm0408_dispatch(conn, msg) (6)
|
||||
|
||||
(5)[1]
|
||||
osmo_bsc_api().dtap =
|
||||
osmo-bsc/osmo_bsc_api.c: bsc_dtap(conn, link_id, msg)
|
||||
if (handle_cc_setup(conn, msg) >= 1) return;
|
||||
if (bsc_filter_data(conn, msg, &lu_cause) < 0)
|
||||
bsc_maybe_lu_reject()
|
||||
return;
|
||||
bsc_scan_bts_msg(conn, msg); (7)
|
||||
resp = gsm0808_create_dtap(msg, link_id);
|
||||
queue_msg_or_return(resp);
|
||||
|
||||
(7)
|
||||
bsc_scan_bts_msg() <osmo-bsc/osmo_bsc_filter.c:212>:
|
||||
if GSM48_PDISC_MM, GSM48_MT_MM_LOC_UPD_REQUEST
|
||||
handle_lu_request() <osmo-bsc/osmo_bsc_filter.c:29>:
|
||||
gsm48_generate_lai()
|
||||
if GSM48_PDISC_RR, GSM48_MT_RR_PAG_RESP
|
||||
handle_page_resp() <osmo-bsc/osmo_bsc_filter.c:97>:
|
||||
extract_sub() <osmo-bsc/osmo_bsc_filter.c:57>
|
||||
paging_request_stop() <libbsc/paging.c:390>:
|
||||
log_set_context()
|
||||
_paging_request_stop() <libbsc/paging.c:359>:
|
||||
paging_init_if_needed() <libbsc/paging.c:224>:
|
||||
paging_worker() <libbsc/paging.c:217>:
|
||||
paging_handle_pending_requests() <libbsc/paging.c:169> (R):
|
||||
cb()
|
||||
paging_give_credit() <libbsc/paging.c:107> (R):
|
||||
paging_handle_pending_requests() <libbsc/paging.c:169> (recursive: see 37)
|
||||
can_send_pag_req() <libbsc/paging.c:116>:
|
||||
page_ms() <libbsc/paging.c:69>:
|
||||
gsm0808_page() <libbsc/bsc_api.c:415>:
|
||||
rsl_paging_cmd() <libbsc/abis_rsl.c:751>:
|
||||
abis_rsl_dchan_hdr = RSL_IE_CHAN_NR
|
||||
mdisc_by_msgtype() <libbsc/abis_rsl.c:80>:
|
||||
ABIS_RSL_MDISC_RLL
|
||||
ABIS_RSL_MDISC_TRX
|
||||
ABIS_RSL_MDISC_COM_CHAN
|
||||
ABIS_RSL_MDISC_DED_CHAN
|
||||
ABIS_RSL_MDISC_LOC
|
||||
msgb_tv_put(msg, RSL_IE_PAGING_GROUP, paging_group);
|
||||
msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len-2, ms_ident+2);
|
||||
msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed);
|
||||
rsl_link
|
||||
abis_rsl_sendmsg()
|
||||
cbfn() (8)
|
||||
paging_remove_request() <libbsc/paging.c:60>:
|
||||
subscr_put() <libcommon/gsm_subscriber_base.c:89>
|
||||
subscr_put() <libcommon/gsm_subscriber_base.c:89>
|
||||
|
||||
(8)[0]
|
||||
libmsc/gsm_04_08.c:mncc_tx_to_cc()
|
||||
req->cbfn =
|
||||
libmsc/gsm_04_08.c:setup_trig_pag_evt
|
||||
|
||||
(8)[1]
|
||||
libmsc/gsm_04_11.c:gsm411_send_sms_subscr()
|
||||
req->cbfn =
|
||||
libmsc/gsm_04_11.c:paging_cb_send_sms
|
||||
|
||||
(9)
|
||||
bsc_scan_msc_msg() ./osmo-bsc/osmo_bsc_filter.c:330
|
||||
gsm48_hdr
|
||||
send_welcome_ussd() ./osmo-bsc/osmo_bsc_filter.c:229
|
||||
LOGP()
|
||||
DMSC
|
||||
LOGL_DEBUG
|
||||
ussd_welcome_txt
|
||||
BSS_SEND_USSD
|
||||
GSM48_MT_MM_INFO
|
||||
bsc_patch_mm_info() ./osmo-bsc/osmo_bsc_filter.c:255
|
||||
uint8_t
|
||||
tzbsd
|
||||
dst
|
||||
tlv_parse()
|
||||
gsm48_mm_att_tlvdef
|
||||
override
|
||||
hr
|
||||
mn
|
||||
TLVP_PRESENT()
|
||||
GSM48_IE_UTC
|
||||
LOGP()
|
||||
DMSC
|
||||
LOGL_DEBUG
|
||||
TLVP_VAL()
|
||||
GSM48_IE_NET_TIME_TZ
|
||||
GSM48_IE_NET_DST
|
||||
|
||||
|
||||
(6)
|
||||
libmsc/gsm0408.c: gsm0408_dispatch() (MSC rx from BSC)
|
||||
if (silent_call_reroute(conn, msg))
|
||||
return silent_call_rx(conn, msg);
|
||||
|
||||
case gsm48_pdisc_cc:
|
||||
rc = gsm0408_rcv_cc(conn, msg);
|
||||
|
||||
case gsm48_pdisc_mm:
|
||||
rc = gsm0408_rcv_mm(conn, msg);
|
||||
|
||||
case gsm48_pdisc_rr:
|
||||
rc = gsm0408_rcv_rr(conn, msg);
|
||||
|
||||
case gsm48_pdisc_sms:
|
||||
rc = gsm0411_rcv_sms(conn, msg);
|
||||
|
||||
case gsm48_pdisc_nc_ss:
|
||||
rc = handle_rcv_ussd(conn, msg);
|
||||
|
||||
case gsm48_pdisc_mm_gprs:
|
||||
case gsm48_pdisc_sm_gprs:
|
||||
logp(drll, logl_notice, "unimplemented "
|
||||
|
||||
msc_bsc_api().assign_compl =
|
||||
msc_assign_compl()
|
||||
nothing
|
||||
|
||||
(4)[0]
|
||||
libmsc/osmo_msc.c:msc_bsc_api().cipher_mode_compl =
|
||||
msc_ciph_m_compl(conn, msg, alg_id)
|
||||
conn->sec_operation->cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_SUCCEEDED,
|
||||
NULL, conn, conn->sec_operation->cb_data)
|
||||
release_security_operation(conn);
|
||||
msc_release_connection(conn)
|
||||
bsc_api.c:gsm0808_clear(conn)
|
||||
libbsc/handover_logic.c:bsc_clear_handover(conn, 1)
|
||||
libbsc/chan_alloc.c:lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END);
|
||||
libbsc/chan_alloc.c:lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END),
|
||||
(conn->lchan, 1, RSL_REL_NORMAL)
|
||||
bsc_api.c:subscr_con_free(conn)
|
||||
libcommon/gsm_subscriber_base.c:subscr_put(conn->subscr);
|
||||
|
||||
(4)[1]
|
||||
osmo-bsc/osmo_bsc_api.c:osmo_bsc_api().cipher_mode_compl =
|
||||
bsc_cipher_mode_compl()
|
||||
queue_msg_or_return() osmo-bsc/osmo_bsc_api.c
|
||||
bsc_queue_for_msc()
|
||||
|
||||
|
||||
libbsc/abis_nm.c:abis_nm_rcvmsg(msg);
|
||||
case ABIS_OM_MDISC_FOM:
|
||||
rc = abis_nm_rcvmsg_fom(msg);
|
||||
|
||||
case ABIS_OM_MDISC_MANUF:
|
||||
rc = abis_nm_rcvmsg_manuf(msg);
|
||||
|
||||
case ABIS_OM_MDISC_MMI:
|
||||
case ABIS_OM_MDISC_TRAU:
|
||||
LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
|
||||
|
36
openbsc/doc/examples/osmo-cscn/osmo-cscn.cfg
Normal file
36
openbsc/doc/examples/osmo-cscn/osmo-cscn.cfg
Normal file
@@ -0,0 +1,36 @@
|
||||
!
|
||||
! OsmoCSCN configuration saved from vty
|
||||
!
|
||||
line vty
|
||||
no login
|
||||
!
|
||||
network
|
||||
network country code 1
|
||||
mobile network code 1
|
||||
short name OsmoCSCN
|
||||
long name OsmoCSCN
|
||||
auth policy closed
|
||||
location updating reject cause 13
|
||||
encryption a5 0
|
||||
rrlp mode none
|
||||
mm info 1
|
||||
handover 0
|
||||
handover window rxlev averaging 10
|
||||
handover window rxqual averaging 1
|
||||
handover window rxlev neighbor averaging 10
|
||||
handover power budget interval 6
|
||||
handover power budget hysteresis 3
|
||||
handover maximum distance 9999
|
||||
timer t3101 10
|
||||
timer t3103 0
|
||||
timer t3105 0
|
||||
timer t3107 0
|
||||
timer t3109 4
|
||||
timer t3111 0
|
||||
timer t3113 60
|
||||
timer t3115 0
|
||||
timer t3117 0
|
||||
timer t3119 0
|
||||
timer t3141 0
|
||||
cscn
|
||||
subscriber-create-on-demand
|
@@ -1,5 +1,7 @@
|
||||
digraph G {
|
||||
net [label="gsm_network"]
|
||||
subconns [label="subscr_conns"]
|
||||
btslist [label="bts_list"]
|
||||
bts [label="gsm_bts"]
|
||||
trx [label="gsm_bts_trx"]
|
||||
ts [label="gsm_bts_trx_ts"]
|
||||
@@ -9,7 +11,8 @@ digraph G {
|
||||
sccpcon [label="osmo_bsc_sccp_con"]
|
||||
subgrp [label="gsm_subscriber_group"]
|
||||
|
||||
net -> bts
|
||||
net -> btslist
|
||||
btslist -> bts [label="llist"]
|
||||
bts -> trx
|
||||
trx -> ts
|
||||
ts -> lchan
|
||||
@@ -21,6 +24,8 @@ digraph G {
|
||||
|
||||
lchan -> subcon
|
||||
|
||||
net -> subconns
|
||||
subconns -> subcon [label="llist"]
|
||||
subcon -> sub
|
||||
subcon -> sccpcon
|
||||
subcon -> lchan
|
15
openbsc/doc/libmsc-data-structures.dot
Normal file
15
openbsc/doc/libmsc-data-structures.dot
Normal file
@@ -0,0 +1,15 @@
|
||||
digraph G {
|
||||
net [label="gsm_network"]
|
||||
subconns [label="subscr_conns"]
|
||||
sub [label="gsm_subscriber"]
|
||||
subcon [label="gsm_subscriber_conn"]
|
||||
subgrp [label="gsm_subscriber_group"]
|
||||
|
||||
net -> subconns
|
||||
subconns -> subcon [label="llist"]
|
||||
subcon -> sub
|
||||
subcon -> net
|
||||
|
||||
sub -> subgrp
|
||||
subgrp -> net
|
||||
}
|
@@ -8,7 +8,7 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
|
||||
vty.h socket.h e1_config.h trau_upqueue.h token_auth.h \
|
||||
handover_decision.h rrlp.h \
|
||||
crc24.h gprs_llc.h gprs_gmm.h \
|
||||
gb_proxy.h gprs_sgsn.h sgsn.h \
|
||||
gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.h \
|
||||
auth.h osmo_msc.h bsc_msc.h bsc_nat.h \
|
||||
osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \
|
||||
osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \
|
||||
@@ -18,7 +18,9 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
|
||||
gprs_gb_parse.h smpp.h meas_feed.h \
|
||||
gprs_gsup_client.h bsc_msg_filter.h \
|
||||
oap.h oap_messages.h \
|
||||
gtphub.h
|
||||
gtphub.h \
|
||||
msc_api.h msc_ifaces.h iu.h iu_cs.h \
|
||||
xsc.h
|
||||
|
||||
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
|
||||
openbscdir = $(includedir)/openbsc
|
||||
|
@@ -52,6 +52,4 @@ int gsm0808_page(struct gsm_bts *bts, unsigned int page_group,
|
||||
unsigned int mi_len, uint8_t *mi, int chan_type);
|
||||
int gsm0808_clear(struct gsm_subscriber_connection *conn);
|
||||
|
||||
struct llist_head *bsc_api_sub_connections(struct gsm_network *net);
|
||||
|
||||
#endif
|
||||
|
@@ -1,11 +1,14 @@
|
||||
#ifndef _BSS_H_
|
||||
#define _BSS_H_
|
||||
|
||||
#include <openbsc/xsc.h>
|
||||
|
||||
struct gsm_network;
|
||||
struct msgb;
|
||||
|
||||
/* start and stop network */
|
||||
extern int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *), const char *cfg_file);
|
||||
extern int bsc_network_init(mncc_recv_cb_t mncc_recv);
|
||||
extern int bsc_network_configure(const char *cfg_file);
|
||||
extern int bsc_shutdown_net(struct gsm_network *net);
|
||||
|
||||
/* register all supported BTS */
|
||||
|
@@ -34,6 +34,9 @@ enum {
|
||||
DSMPP,
|
||||
DFILTER,
|
||||
DGTPHUB,
|
||||
DSUA,
|
||||
DRANAP,
|
||||
DIUCS,
|
||||
Debug_LastEntry,
|
||||
};
|
||||
|
||||
|
@@ -10,7 +10,9 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
|
||||
int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);
|
||||
int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);
|
||||
|
||||
int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme);
|
||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme);
|
||||
int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
|
||||
uint16_t *sai);
|
||||
int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);
|
||||
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg);
|
||||
void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *mmctx);
|
||||
|
@@ -23,7 +23,7 @@ struct gsm_subscriber;
|
||||
enum gsm48_gsm_cause;
|
||||
|
||||
/* TS 04.08 4.1.3.3 GMM mobility management states on the network side */
|
||||
enum gprs_mm_state {
|
||||
enum gprs_gmm_state {
|
||||
GMM_DEREGISTERED, /* 4.1.3.3.1.1 */
|
||||
GMM_COMMON_PROC_INIT, /* 4.1.3.3.1.2 */
|
||||
GMM_REGISTERED_NORMAL, /* 4.1.3.3.2.1 */
|
||||
@@ -31,6 +31,16 @@ enum gprs_mm_state {
|
||||
GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */
|
||||
};
|
||||
|
||||
/* TS 23.060 6.1.1 and 6.1.2 Mobility management states A/Gb and Iu mode */
|
||||
enum gprs_pmm_state {
|
||||
PMM_DETACHED,
|
||||
PMM_CONNECTED,
|
||||
PMM_IDLE,
|
||||
MM_IDLE = PMM_DETACHED,
|
||||
MM_READY = PMM_CONNECTED,
|
||||
MM_STANDBY = PMM_IDLE,
|
||||
};
|
||||
|
||||
enum gprs_mm_ctr {
|
||||
GMM_CTR_PKTS_SIG_IN,
|
||||
GMM_CTR_PKTS_SIG_OUT,
|
||||
@@ -92,13 +102,32 @@ struct sgsn_ggsn_lookup {
|
||||
uint8_t ti;
|
||||
};
|
||||
|
||||
enum sgsn_ran_type {
|
||||
/* GPRS/EDGE via Gb */
|
||||
MM_CTX_T_GERAN_Gb,
|
||||
/* UMTS via Iu */
|
||||
MM_CTX_T_UTRAN_Iu,
|
||||
/* GPRS/EDGE via Iu */
|
||||
MM_CTX_T_GERAN_Iu,
|
||||
};
|
||||
|
||||
struct service_info {
|
||||
uint8_t type;
|
||||
uint16_t pdp_status;
|
||||
};
|
||||
|
||||
struct ue_conn_ctx;
|
||||
|
||||
/* 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 {
|
||||
struct llist_head list;
|
||||
|
||||
enum sgsn_ran_type ran_type;
|
||||
|
||||
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
enum gprs_mm_state mm_state;
|
||||
enum gprs_gmm_state mm_state;
|
||||
enum gprs_pmm_state pmm_state;
|
||||
uint32_t p_tmsi;
|
||||
uint32_t p_tmsi_old; /* old P-TMSI before new is confirmed */
|
||||
uint32_t p_tmsi_sig;
|
||||
@@ -106,10 +135,32 @@ struct sgsn_mm_ctx {
|
||||
/* Opt: Software Version Numbber / TS 23.195 */
|
||||
char msisdn[GSM_EXTENSION_LENGTH];
|
||||
struct gprs_ra_id ra;
|
||||
uint16_t cell_id;
|
||||
uint32_t cell_id_age;
|
||||
uint16_t sac; /* Iu: Service Area Code */
|
||||
uint32_t sac_age;/* Iu: Service Area Code age */
|
||||
struct {
|
||||
uint16_t cell_id; /* Gb only */
|
||||
uint32_t cell_id_age; /* Gb only */
|
||||
uint8_t radio_prio_sms;
|
||||
|
||||
/* Additional bits not present in the GSM TS */
|
||||
uint16_t nsei;
|
||||
uint16_t bvci;
|
||||
struct gprs_llc_llme *llme;
|
||||
uint32_t tlli;
|
||||
uint32_t tlli_new;
|
||||
} gb;
|
||||
struct {
|
||||
int new_key;
|
||||
uint16_t sac; /* Iu: Service Area Code */
|
||||
uint32_t sac_age; /* Iu: Service Area Code age */
|
||||
/* CSG ID */
|
||||
/* CSG Membership */
|
||||
/* Access Mode */
|
||||
/* Seelected CN Operator ID (TS 23.251) */
|
||||
/* CSG Subscription Data */
|
||||
/* LIPA Allowed */
|
||||
/* Voice Support Match Indicator */
|
||||
struct ue_conn_ctx *ue_ctx;
|
||||
struct service_info service;
|
||||
} iu;
|
||||
/* VLR number */
|
||||
uint32_t new_sgsn_addr;
|
||||
/* Authentication Triplet */
|
||||
@@ -118,30 +169,38 @@ struct sgsn_mm_ctx {
|
||||
/* Iu: CK, IK, KSI */
|
||||
/* CKSN */
|
||||
enum gprs_ciph_algo ciph_algo;
|
||||
|
||||
struct {
|
||||
uint8_t len;
|
||||
uint8_t buf[50]; /* GSM 04.08 10.5.5.12a, extended in TS 24.008 */
|
||||
} ms_radio_access_capa;
|
||||
/* Supported Codecs (SRVCC) */
|
||||
struct {
|
||||
uint8_t len;
|
||||
uint8_t buf[8]; /* GSM 04.08 10.5.5.12, extended in TS 24.008 */
|
||||
} ms_network_capa;
|
||||
/* UE Netowrk Capability (E-UTRAN) */
|
||||
uint16_t drx_parms;
|
||||
/* Active Time value for PSM */
|
||||
int mnrg; /* MS reported to HLR? */
|
||||
int ngaf; /* MS reported to MSC/VLR? */
|
||||
int ppf; /* paging for GPRS + non-GPRS? */
|
||||
/* Subscribed Charging Characteristics */
|
||||
/* Trace Reference */
|
||||
/* Trace Type */
|
||||
/* Trigger ID */
|
||||
/* OMC Identity */
|
||||
/* SMS Parameters */
|
||||
int recovery;
|
||||
uint8_t radio_prio_sms;
|
||||
/* Access Restriction */
|
||||
/* GPRS CSI (CAMEL) */
|
||||
/* MG-CSI (CAMEL) */
|
||||
/* Subscribed UE-AMBR */
|
||||
/* UE-AMBR */
|
||||
/* APN Subscribed */
|
||||
|
||||
struct llist_head pdp_list;
|
||||
|
||||
/* Additional bits not present in the GSM TS */
|
||||
struct gprs_llc_llme *llme;
|
||||
uint32_t tlli;
|
||||
uint32_t tlli_new;
|
||||
uint16_t nsei;
|
||||
uint16_t bvci;
|
||||
struct rate_ctr_group *ctrg;
|
||||
struct osmo_timer_list timer;
|
||||
unsigned int T; /* Txxxx number */
|
||||
@@ -176,6 +235,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
|
||||
const struct gprs_ra_id *raid);
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi);
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi);
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx);
|
||||
|
||||
/* look-up by matching TLLI and P-TMSI (think twice before using this) */
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
|
||||
@@ -184,6 +244,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
|
||||
/* Allocate a new SGSN MM context */
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
|
||||
const struct gprs_ra_id *raid);
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx);
|
||||
|
||||
void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx);
|
||||
|
||||
struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
|
||||
|
@@ -77,6 +77,8 @@ int decode_bcd_number(char *output, int output_len, const uint8_t *bcd_lv,
|
||||
int send_siemens_mrpci(struct gsm_lchan *lchan, uint8_t *classmark2_lv);
|
||||
int gsm48_extract_mi(uint8_t *classmark2, int length, char *mi_string, uint8_t *mi_type);
|
||||
int gsm48_paging_extract_mi(struct gsm48_pag_resp *pag, int length, char *mi_string, uint8_t *mi_type);
|
||||
|
||||
/* TODO MSCSPLIT remove gsm48_handle_paging_resp() */
|
||||
int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn, struct msgb *msg, struct gsm_subscriber *subscr);
|
||||
|
||||
int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t lchan_mode);
|
||||
|
21
openbsc/include/openbsc/gsm_04_08_gprs.h
Normal file
21
openbsc/include/openbsc/gsm_04_08_gprs.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
|
||||
/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */
|
||||
|
||||
/* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */
|
||||
#define GSM48_MT_GMM_SERVICE_REQ 0x0c
|
||||
#define GSM48_MT_GMM_SERVICE_ACK 0x0d
|
||||
#define GSM48_MT_GMM_SERVICE_REJ 0x0e
|
||||
|
||||
/* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */
|
||||
enum gsm48_gmm_service_type {
|
||||
GPRS_SERVICE_T_SIGNALLING = 0x00,
|
||||
GPRS_SERVICE_T_DATA = 0x01,
|
||||
GPRS_SERVICE_T_PAGING_RESP = 0x02,
|
||||
GPRS_SERVICE_T_MBMS_MC_SERV = 0x03,
|
||||
GPRS_SERVICE_T_MBMS_BC_SERV = 0x04,
|
||||
};
|
||||
|
||||
extern const struct value_string *gprs_service_t_strs;
|
@@ -38,5 +38,5 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn,
|
||||
struct gsm_sms *sms);
|
||||
void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn);
|
||||
|
||||
uint8_t sms_next_rp_msg_ref(struct gsm_subscriber_connection *conn);
|
||||
uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref);
|
||||
#endif
|
||||
|
@@ -14,6 +14,9 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
|
||||
const struct msgb *msg,
|
||||
const struct ussd_request *request);
|
||||
|
||||
struct msgb *gsm0480_gen_ussdNotify(int level, const char *text);
|
||||
struct msgb *gsm0480_gen_releaseComplete(void);
|
||||
|
||||
int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text);
|
||||
int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn);
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <osmocom/crypt/auth.h>
|
||||
|
||||
#include <openbsc/rest_octets.h>
|
||||
#include <openbsc/xsc.h>
|
||||
|
||||
/** annotations for msgb ownership */
|
||||
#define __uses
|
||||
@@ -97,7 +98,19 @@ struct neigh_meas_proc {
|
||||
uint8_t last_seen_nr;
|
||||
};
|
||||
|
||||
/* the per subscriber data for lchan */
|
||||
enum interface_type {
|
||||
IFACE_UNKNOWN = -1,
|
||||
IFACE_A = 0, /* A-interface for 2G */
|
||||
IFACE_IU = 1 /* Iu-interface for UMTS aka 3G (IuCS or IuPS) */
|
||||
};
|
||||
|
||||
enum integrity_protection_state {
|
||||
INTEGRITY_PROTECTION_NONE = 0,
|
||||
INTEGRITY_PROTECTION_IK = 1,
|
||||
INTEGRITY_PROTECTION_IK_CK = 2,
|
||||
};
|
||||
|
||||
/* mobile subscriber data */
|
||||
struct gsm_subscriber_connection {
|
||||
struct llist_head entry;
|
||||
|
||||
@@ -124,18 +137,40 @@ struct gsm_subscriber_connection {
|
||||
int mncc_rtp_create_pending;
|
||||
int mncc_rtp_connect_pending;
|
||||
|
||||
/* bsc structures */
|
||||
struct osmo_bsc_sccp_con *sccp_con;
|
||||
|
||||
/* back pointers */
|
||||
struct gsm_network *network;
|
||||
|
||||
/* The BSC used to be an integral part of OsmoNITB. In OsmoCSCN, the
|
||||
* BSC and/or RNC is a separate entity, and no back pointers to the bts
|
||||
* and lchan structures are available. To facilitate separation of the
|
||||
* code paths, I'm explicitly excluding the unavailable structures from
|
||||
* the build. Once separated, this split may become unnecessary. */
|
||||
#if COMPILING_LIBMSC
|
||||
int in_release;
|
||||
uint16_t lac;
|
||||
struct gsm_encr encr;
|
||||
|
||||
/* 2G or 3G? See enum interface_type */
|
||||
int via_iface;
|
||||
|
||||
/* which Iu-CS connection, if any. */
|
||||
struct {
|
||||
struct ue_conn_ctx *ue_ctx;
|
||||
int integrity_protection;
|
||||
} iu;
|
||||
|
||||
#else
|
||||
struct gsm_bts *bts;
|
||||
struct gsm_lchan *lchan;
|
||||
struct gsm_lchan *ho_lchan;
|
||||
struct gsm_bts *bts;
|
||||
|
||||
/* bsc structures */
|
||||
struct osmo_bsc_sccp_con *sccp_con;
|
||||
|
||||
/* for assignment handling */
|
||||
struct osmo_timer_list T10;
|
||||
struct gsm_lchan *secondary_lchan;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
@@ -207,7 +242,20 @@ enum gsm_auth_policy {
|
||||
#define GSM_T3113_DEFAULT 60
|
||||
#define GSM_T3122_DEFAULT 10
|
||||
|
||||
struct gsm_tz {
|
||||
int override; /* if 0, use system's time zone instead. */
|
||||
int hr; /* hour */
|
||||
int mn; /* minute */
|
||||
int dst; /* daylight savings */
|
||||
};
|
||||
|
||||
struct gsm_network {
|
||||
/* TODO MSCSPLIT the gsm_network struct is basically a kitchen sink for
|
||||
* global settings and variables, "madly" mixing BSC and MSC stuff. Split
|
||||
* this in e.g. struct osmo_bsc and struct osmo_msc, with the things
|
||||
* these have in common, like country and network code, put in yet
|
||||
* separate structs and placed as members in osmo_bsc and osmo_msc. */
|
||||
|
||||
/* global parameters */
|
||||
uint16_t country_code;
|
||||
uint16_t network_code;
|
||||
@@ -290,6 +338,19 @@ struct gsm_network {
|
||||
|
||||
/* control interface */
|
||||
struct ctrl_handle *ctrl;
|
||||
|
||||
/* all active subscriber connections. */
|
||||
struct llist_head subscr_conns;
|
||||
|
||||
/* if override is nonzero, this timezone data is used for all MM
|
||||
* contexts. */
|
||||
/* TODO: in OsmoNITB, tz-override used to be BTS-specific. To enable
|
||||
* BTS|RNC specific timezone overrides for multi-tz networks in
|
||||
* OsmoCSCN, this should be tied to the location area code (LAC). */
|
||||
struct gsm_tz tz;
|
||||
|
||||
/* Periodic location update default value */
|
||||
uint8_t t3212;
|
||||
};
|
||||
|
||||
struct osmo_esme;
|
||||
@@ -336,13 +397,12 @@ struct gsm_sms {
|
||||
char text[SMS_TEXT_SIZE];
|
||||
};
|
||||
|
||||
struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_code,
|
||||
int (*mncc_recv)(struct gsm_network *, struct msgb *));
|
||||
int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
|
||||
struct gsm_network *gsm_network_init(void *ctx,
|
||||
uint16_t country_code,
|
||||
uint16_t network_code,
|
||||
mncc_recv_cb_t mncc_recv);
|
||||
|
||||
/* Get reference to a neighbor cell on a given BCCH ARFCN */
|
||||
struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
|
||||
uint16_t arfcn, uint8_t bsic);
|
||||
int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
|
||||
|
||||
enum gsm_bts_type parse_btstype(const char *arg);
|
||||
const char *btstype2str(enum gsm_bts_type type);
|
||||
@@ -426,13 +486,15 @@ int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode);
|
||||
|
||||
int gsm48_ra_id_by_bts(uint8_t *buf, struct gsm_bts *bts);
|
||||
void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
|
||||
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan);
|
||||
|
||||
int gsm_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features feat);
|
||||
int gsm_bts_model_register(struct gsm_bts_model *model);
|
||||
|
||||
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan);
|
||||
void subscr_con_free(struct gsm_subscriber_connection *conn);
|
||||
struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lchan);
|
||||
void bsc_subscr_con_free(struct gsm_subscriber_connection *conn);
|
||||
|
||||
struct gsm_subscriber_connection *msc_subscr_con_allocate(struct gsm_network *network);
|
||||
void msc_subscr_con_free(struct gsm_subscriber_connection *conn);
|
||||
|
||||
struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net,
|
||||
enum gsm_bts_type type,
|
||||
|
@@ -24,6 +24,8 @@
|
||||
#include <osmocom/gsm/lapdm.h>
|
||||
#endif
|
||||
|
||||
#include <openbsc/xsc.h>
|
||||
|
||||
struct osmo_bsc_data;
|
||||
|
||||
struct osmo_bsc_sccp_con;
|
||||
@@ -100,7 +102,6 @@ struct gsm_abis_mo {
|
||||
struct gsm_bts *bts;
|
||||
};
|
||||
|
||||
#define MAX_A5_KEY_LEN (128/8)
|
||||
#define A38_XOR_MIN_KEY_LEN 12
|
||||
#define A38_XOR_MAX_KEY_LEN 16
|
||||
#define A38_COMP128_KEY_LEN 16
|
||||
@@ -202,11 +203,7 @@ struct gsm_lchan {
|
||||
uint8_t bs_power;
|
||||
uint8_t ms_power;
|
||||
/* Encryption information */
|
||||
struct {
|
||||
uint8_t alg_id;
|
||||
uint8_t key_len;
|
||||
uint8_t key[MAX_A5_KEY_LEN];
|
||||
} encr;
|
||||
struct gsm_encr encr;
|
||||
|
||||
/* AMR bits */
|
||||
uint8_t mr_ms_lv[7];
|
||||
@@ -351,7 +348,7 @@ struct gsm_bts_trx_ts {
|
||||
struct gsm_lchan lchan[TS_MAX_LCHAN];
|
||||
};
|
||||
|
||||
/* One TRX in a BTS */
|
||||
/* One TRX (transceiver) in a BTS */
|
||||
struct gsm_bts_trx {
|
||||
/* list header in bts->trx_list */
|
||||
struct llist_head list;
|
||||
@@ -609,14 +606,6 @@ struct gsm_bts {
|
||||
/* buffers where we put the pre-computed SI */
|
||||
sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE];
|
||||
|
||||
/* TimeZone hours, mins, and bts specific */
|
||||
struct {
|
||||
int hr;
|
||||
int mn;
|
||||
int override;
|
||||
int dst;
|
||||
} tz;
|
||||
|
||||
/* ip.accesss Unit ID's have Site/BTS/TRX layout */
|
||||
union {
|
||||
struct {
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#ifndef _GSM_SUBSCR_H
|
||||
#define _GSM_SUBSCR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gsm_data.h"
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
@@ -68,6 +70,7 @@ struct gsm_subscriber {
|
||||
|
||||
/* pending requests */
|
||||
int is_paging;
|
||||
struct osmo_timer_list paging_timeout;
|
||||
struct llist_head requests;
|
||||
|
||||
/* GPRS/SGSN related fields */
|
||||
@@ -87,6 +90,20 @@ enum gsm_subscriber_update_reason {
|
||||
GSM_SUBSCRIBER_UPDATE_EQUIPMENT,
|
||||
};
|
||||
|
||||
/*
|
||||
* Struct for pending channel requests. This is managed in the
|
||||
* llist_head requests of each subscriber. The reference counting
|
||||
* should work in such a way that a subscriber with a pending request
|
||||
* remains in memory.
|
||||
*/
|
||||
struct subscr_request {
|
||||
struct llist_head entry;
|
||||
|
||||
/* the callback data */
|
||||
gsm_cbfn *cbfn;
|
||||
void *param;
|
||||
};
|
||||
|
||||
struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr);
|
||||
struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr);
|
||||
struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
|
||||
@@ -101,7 +118,8 @@ struct gsm_subscriber *subscr_get_by_id(struct gsm_subscriber_group *sgrp,
|
||||
unsigned long long id);
|
||||
struct gsm_subscriber *subscr_get_or_create(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi);
|
||||
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
|
||||
int subscr_update(struct gsm_network *network, struct gsm_subscriber *s,
|
||||
uint16_t lac, int reason);
|
||||
struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_subscriber_group *sgrp,
|
||||
uint32_t tmsi);
|
||||
struct gsm_subscriber *subscr_active_by_imsi(struct gsm_subscriber_group *sgrp,
|
||||
@@ -112,14 +130,18 @@ char *subscr_name(struct gsm_subscriber *subscr);
|
||||
int subscr_purge_inactive(struct gsm_subscriber_group *sgrp);
|
||||
void subscr_update_from_db(struct gsm_subscriber *subscr);
|
||||
void subscr_expire(struct gsm_subscriber_group *sgrp);
|
||||
int subscr_update_expire_lu(struct gsm_subscriber *subscr, struct gsm_bts *bts);
|
||||
int subscr_update_expire_lu(struct gsm_network *network, struct gsm_subscriber *subscr);
|
||||
|
||||
bool subscr_authorized(struct gsm_subscriber *subsc);
|
||||
|
||||
/*
|
||||
* Paging handling with authentication
|
||||
*/
|
||||
struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
|
||||
int type, gsm_cbfn *cbfn, void *param);
|
||||
struct subscr_request *subscr_request_conn(struct gsm_subscriber *subscr,
|
||||
gsm_cbfn *cbfn, void *param);
|
||||
void subscr_remove_request(struct subscr_request *req);
|
||||
int subscr_rx_paging_response(struct msgb *msg,
|
||||
struct gsm_subscriber_connection *conn);
|
||||
|
||||
/* internal */
|
||||
struct gsm_subscriber *subscr_alloc(void);
|
||||
|
61
openbsc/include/openbsc/iu.h
Normal file
61
openbsc/include/openbsc/iu.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct sgsn_pdp_ctx;
|
||||
struct msgb;
|
||||
struct gprs_ra_id;
|
||||
|
||||
struct RANAP_RAB_SetupOrModifiedItemIEs_s;
|
||||
struct RANAP_GlobalRNC_ID;
|
||||
|
||||
struct ue_conn_ctx {
|
||||
struct llist_head list;
|
||||
struct osmo_sua_link *link;
|
||||
uint32_t conn_id;
|
||||
int integrity_active;
|
||||
struct gprs_ra_id ra_id;
|
||||
};
|
||||
|
||||
enum iu_event_type {
|
||||
IU_EVENT_RAB_ASSIGN,
|
||||
IU_EVENT_SECURITY_MODE_COMPLETE,
|
||||
IU_EVENT_IU_RELEASE, /* An actual Iu Release message was received */
|
||||
IU_EVENT_LINK_INVALIDATED, /* A SUA link was lost or closed down */
|
||||
/* FIXME: maybe IU_EVENT_IU_RELEASE and IU_EVENT_LINK_INVALIDATED
|
||||
* should be combined to one generic event that simply means the
|
||||
* ue_conn_ctx should no longer be used, for whatever reason. */
|
||||
};
|
||||
|
||||
extern const struct value_string iu_event_type_names[];
|
||||
static inline const char *iu_event_type_str(enum iu_event_type e)
|
||||
{
|
||||
return get_value_string(iu_event_type_names, e);
|
||||
}
|
||||
|
||||
/* Implementations of iu_recv_cb_t shall find the ue_conn_ctx in msg->dst. */
|
||||
typedef int (* iu_recv_cb_t )(struct msgb *msg, struct gprs_ra_id *ra_id,
|
||||
/* TODO "gprs_" in generic CS+PS domain ^ */
|
||||
uint16_t *sai);
|
||||
|
||||
typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx,
|
||||
enum iu_event_type type, void *data);
|
||||
|
||||
typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id,
|
||||
struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies);
|
||||
|
||||
int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port,
|
||||
iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb);
|
||||
|
||||
void iu_link_del(struct osmo_sua_link *link);
|
||||
|
||||
int iu_tx(struct msgb *msg, uint8_t sapi);
|
||||
|
||||
int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac);
|
||||
int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac);
|
||||
|
||||
int iu_rab_act_cs(struct ue_conn_ctx *ue_ctx, uint32_t rtp_ip, uint16_t rtp_port);
|
||||
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap);
|
||||
int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id);
|
||||
int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp,
|
||||
int send_ck, int new_key);
|
7
openbsc/include/openbsc/iu_cs.h
Normal file
7
openbsc/include/openbsc/iu_cs.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
|
||||
uint16_t *lac);
|
||||
|
||||
struct gsm_subscriber_connection *subscr_conn_lookup_iu(struct gsm_network *network,
|
||||
struct ue_conn_ctx *ue);
|
29
openbsc/include/openbsc/msc_api.h
Normal file
29
openbsc/include/openbsc/msc_api.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
/* These functions receive or send MM|CC|... messages from/to the BSC|RNC
|
||||
* direction, while they are not concerned with which particular external
|
||||
* interface is actually involved (A or IuCS).
|
||||
*
|
||||
* For the interface specific decisions see msc_iface.[hc]
|
||||
*/
|
||||
|
||||
/* MSCSPLIT WIP: this will gradually replace the role that the bsc_api.h had in
|
||||
* OsmoNITB. Actually, osmo_msc.[hc] has the same role as this file, but having
|
||||
* separate files helps me to keep track of how far I've gotten yet. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct gsm_subscriber_connection;
|
||||
struct msgb;
|
||||
|
||||
enum {
|
||||
MSC_CONN_ACCEPT = 0,
|
||||
MSC_CONN_REJECT = 1,
|
||||
};
|
||||
|
||||
/* receive a Level 3 Complete message and return MSC_CONN_ACCEPT or
|
||||
* MSC_CONN_REJECT */
|
||||
int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
|
||||
uint16_t chosen_channel);
|
||||
/* TODO: is chosen_channel BSC land == NITB legacy? */
|
||||
|
40
openbsc/include/openbsc/msc_ifaces.h
Normal file
40
openbsc/include/openbsc/msc_ifaces.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
|
||||
/* These are the interfaces of the MSC layer towards (from?) the BSC and RNC,
|
||||
* i.e. in the direction towards the mobile device (MS aka UE).
|
||||
*
|
||||
* 2G will use the A-interface,
|
||||
* 3G aka UMTS will use the Iu-interface (for the MSC, it's IuCS).
|
||||
*
|
||||
* To allow linking parts of the MSC code without having to include entire
|
||||
* infrastructures of external libraries, the core transmitting and receiving
|
||||
* functions are left unimplemented. For example, a unit test does not need to
|
||||
* link against external ASN1 libraries if it is never going to encode actual
|
||||
* outgoing messages. It is up to each building scope to implement real world
|
||||
* functions or to plug mere dummy implementations.
|
||||
*
|
||||
* For example, msc_tx_dtap(conn, msg), depending on conn->via_iface, will call
|
||||
* either iu_tx() or a_tx() [note: at time of writing, the A-interface is not
|
||||
* yet implemented]. When you try to link against libmsc, you will find that
|
||||
* the compiler complains about an undefined reference to iu_tx(). If you,
|
||||
* however, link against libiu as well as the osmo-iuh libs (etc.), iu_tx() is
|
||||
* available. A unit test may instead simply implement a dummy iu_tx() function
|
||||
* and not link against osmo-iuh.
|
||||
*/
|
||||
|
||||
/* Each main linkage must implement this function (see comment above). */
|
||||
extern int iu_tx(struct msgb *msg, uint8_t sapi);
|
||||
|
||||
/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface
|
||||
* gets implemented, it should be in a separate lib (like libiu), this function
|
||||
* should move there, and the following comment should remain here: "
|
||||
* Each main linkage must implement this function (see comment above).
|
||||
* " */
|
||||
extern int a_tx(struct msgb *msg);
|
||||
|
||||
int msc_tx_dtap(struct gsm_subscriber_connection *conn,
|
||||
struct msgb *msg);
|
||||
|
@@ -142,7 +142,6 @@ struct gsm_subscriber;
|
||||
|
||||
struct paging_signal_data {
|
||||
struct gsm_subscriber *subscr;
|
||||
struct gsm_bts *bts;
|
||||
|
||||
int paging_result;
|
||||
|
||||
|
@@ -32,18 +32,22 @@ enum bsc_vty_node {
|
||||
TRUNK_NODE,
|
||||
PGROUP_NODE,
|
||||
MNCC_INT_NODE,
|
||||
NITB_NODE,
|
||||
BSC_NODE,
|
||||
SMPP_NODE,
|
||||
SMPP_ESME_NODE,
|
||||
GTPHUB_NODE,
|
||||
CSCN_NODE,
|
||||
};
|
||||
|
||||
extern int bsc_vty_is_config_node(struct vty *vty, int node);
|
||||
extern void bsc_replace_string(void *ctx, char **dst, const char *newstr);
|
||||
|
||||
struct log_info;
|
||||
int bsc_vty_init(const struct log_info *cat);
|
||||
int bsc_vty_init(const struct log_info *cat, struct gsm_network *network);
|
||||
int bsc_vty_init_extra(void);
|
||||
|
||||
void cscn_vty_init(void);
|
||||
|
||||
struct gsm_network *gsmnet_from_vty(struct vty *vty);
|
||||
|
||||
#endif
|
||||
|
23
openbsc/include/openbsc/xsc.h
Normal file
23
openbsc/include/openbsc/xsc.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct msgb;
|
||||
struct gsm_network;
|
||||
struct log_info;
|
||||
struct ctrl_handle;
|
||||
|
||||
typedef int (*mncc_recv_cb_t)(struct gsm_network *, struct msgb *);
|
||||
|
||||
#define MAX_A5_KEY_LEN (128/8)
|
||||
|
||||
struct gsm_encr {
|
||||
uint8_t alg_id;
|
||||
uint8_t key_len;
|
||||
uint8_t key[MAX_A5_KEY_LEN];
|
||||
};
|
||||
|
||||
extern struct gsm_network *vty_global_gsm_network;
|
||||
|
||||
int xsc_vty_init(struct gsm_network *network);
|
||||
|
@@ -2,7 +2,7 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
|
||||
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
|
||||
|
||||
SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs
|
||||
SUBDIRS = libcommon libmgcp libbsc libiu libmsc libtrau libfilter libxsc osmo-cscn osmo-bsc_mgcp utils ipaccess gprs
|
||||
|
||||
# Conditional modules
|
||||
if BUILD_NAT
|
||||
|
@@ -2,9 +2,11 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOCTRL_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) $(LIBOSMOGB_CFLAGS) $(COVERAGE_CFLAGS) \
|
||||
$(LIBCARES_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBGTP_CFLAGS)
|
||||
$(LIBCARES_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBGTP_CFLAGS) \
|
||||
$(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS)
|
||||
|
||||
OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS)
|
||||
$(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) -ltalloc -lm
|
||||
|
||||
noinst_HEADERS = gprs_sndcp.h
|
||||
|
||||
@@ -16,6 +18,8 @@ bin_PROGRAMS += osmo-sgsn osmo-gtphub
|
||||
endif
|
||||
endif
|
||||
|
||||
IUHDIR = $(top_srcdir)/../../osmo-iuh
|
||||
|
||||
osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \
|
||||
gb_proxy_patch.c gb_proxy_tlli.c gb_proxy_peer.c \
|
||||
gprs_gb_parse.c gprs_llc_parse.c crc24.c gprs_utils.c
|
||||
@@ -27,12 +31,15 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
|
||||
gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \
|
||||
sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \
|
||||
gprs_utils.c gprs_gsup_client.c \
|
||||
sgsn_cdr.c sgsn_ares.c \
|
||||
gsm_04_08_gprs.c sgsn_cdr.c sgsn_ares.c \
|
||||
oap.c oap_messages.c
|
||||
|
||||
osmo_sgsn_LDADD = \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(top_builddir)/src/libiu/libiu.a \
|
||||
-lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \
|
||||
$(LIBCRYPTO_LIBS) -lrt
|
||||
$(LIBCRYPTO_LIBS) -lrt \
|
||||
$(LIBOSMOSIGTRAN_LIBS) $(LIBOSMORANAP_LIBS) $(LIBASN1C_LIBS)
|
||||
|
||||
osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \
|
||||
gtphub_vty.c sgsn_ares.c gprs_utils.c
|
||||
|
@@ -31,6 +31,8 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include <openbsc/db.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/gsm/tlv.h>
|
||||
@@ -38,15 +40,17 @@
|
||||
#include <osmocom/core/signal.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/crypt/auth.h>
|
||||
#include <osmocom/gsm/apn.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
#include <osmocom/ranap/ranap_ies_defs.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/gsm_04_08_gprs.h>
|
||||
#include <openbsc/paging.h>
|
||||
#include <openbsc/transaction.h>
|
||||
#include <openbsc/gprs_llc.h>
|
||||
@@ -55,6 +59,7 @@
|
||||
#include <openbsc/gprs_utils.h>
|
||||
#include <openbsc/sgsn.h>
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/iu.h>
|
||||
|
||||
#include <pdp.h>
|
||||
|
||||
@@ -95,6 +100,46 @@ static const struct tlv_definition gsm48_sm_att_tlvdef = {
|
||||
|
||||
static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx);
|
||||
|
||||
int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies);
|
||||
int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data)
|
||||
{
|
||||
struct sgsn_mm_ctx *mm;
|
||||
int rc = -1;
|
||||
|
||||
mm = sgsn_mm_ctx_by_ue_ctx(ctx);
|
||||
if (!mm) {
|
||||
LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %i!\n", type);
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case IU_EVENT_RAB_ASSIGN:
|
||||
rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data);
|
||||
break;
|
||||
case IU_EVENT_IU_RELEASE:
|
||||
/* fall thru */
|
||||
case IU_EVENT_LINK_INVALIDATED:
|
||||
/* Clean up ue_conn_ctx here */
|
||||
LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
|
||||
if (mm->pmm_state == PMM_CONNECTED)
|
||||
mm->pmm_state = PMM_IDLE;
|
||||
|
||||
rc = 0;
|
||||
break;
|
||||
case IU_EVENT_SECURITY_MODE_COMPLETE:
|
||||
/* Continue authentication here */
|
||||
mm->iu.ue_ctx->integrity_active = 1;
|
||||
rc = gsm48_gmm_authorize(mm);
|
||||
break;
|
||||
default:
|
||||
LOGP(DRANAP, LOGL_NOTICE, "Unknown event received: %i\n", type);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Our implementation, should be kept in SGSN */
|
||||
|
||||
static void mmctx_timer_cb(void *_mm);
|
||||
@@ -135,6 +180,9 @@ static int gsm48_gmm_sendmsg(struct msgb *msg, int command,
|
||||
if (mm)
|
||||
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
|
||||
|
||||
if (msg->dst)
|
||||
return iu_tx(msg, GPRS_SAPI_GMM);
|
||||
|
||||
/* caller needs to provide TLLI, BVCI and NSEI */
|
||||
return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm);
|
||||
}
|
||||
@@ -146,21 +194,24 @@ static void gmm_copy_id(struct msgb *msg, const struct msgb *old)
|
||||
msgb_tlli(msg) = msgb_tlli(old);
|
||||
msgb_bvci(msg) = msgb_bvci(old);
|
||||
msgb_nsei(msg) = msgb_nsei(old);
|
||||
msg->dst = old->dst;
|
||||
}
|
||||
|
||||
/* Store BVCI/NSEI in MM context */
|
||||
static void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg)
|
||||
{
|
||||
mm->bvci = msgb_bvci(msg);
|
||||
mm->nsei = msgb_nsei(msg);
|
||||
mm->gb.bvci = msgb_bvci(msg);
|
||||
mm->gb.nsei = msgb_nsei(msg);
|
||||
mm->iu.ue_ctx = msg->dst;
|
||||
}
|
||||
|
||||
/* Store BVCI/NSEI in MM context */
|
||||
static void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm)
|
||||
{
|
||||
msgb_tlli(msg) = mm->tlli;
|
||||
msgb_bvci(msg) = mm->bvci;
|
||||
msgb_nsei(msg) = mm->nsei;
|
||||
msgb_tlli(msg) = mm->gb.tlli;
|
||||
msgb_bvci(msg) = mm->gb.bvci;
|
||||
msgb_nsei(msg) = mm->gb.nsei;
|
||||
msg->dst = mm->iu.ue_ctx;
|
||||
}
|
||||
|
||||
static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
|
||||
@@ -169,6 +220,7 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
|
||||
|
||||
/* Mark MM state as deregistered */
|
||||
ctx->mm_state = GMM_DEREGISTERED;
|
||||
ctx->pmm_state = PMM_DETACHED;
|
||||
|
||||
sgsn_mm_ctx_cleanup_free(ctx);
|
||||
}
|
||||
@@ -524,10 +576,15 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
|
||||
|
||||
ctx->is_authenticated = 1;
|
||||
|
||||
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu)
|
||||
ctx->iu.new_key = 1;
|
||||
|
||||
/* FIXME: enable LLC cipheirng */
|
||||
|
||||
/* Check if we can let the mobile station enter */
|
||||
return gsm48_gmm_authorize(ctx);
|
||||
rc = gsm48_gmm_authorize(ctx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void extract_subscr_msisdn(struct sgsn_mm_ctx *ctx)
|
||||
@@ -599,9 +656,72 @@ static void extract_subscr_hlr(struct sgsn_mm_ctx *ctx)
|
||||
strncpy(&ctx->hlr[0], called.number, sizeof(ctx->hlr) - 1);
|
||||
}
|
||||
|
||||
/* Chapter 9.4.21: Service accept */
|
||||
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);
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_MM_GPRS;
|
||||
gh->msg_type = GSM48_MT_GMM_SERVICE_ACK;
|
||||
|
||||
/* Optional: PDP context status */
|
||||
/* Optional: MBMS context status */
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0, mm);
|
||||
}
|
||||
|
||||
/* Chapter 9.4.22: Service reject */
|
||||
static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause,
|
||||
const struct sgsn_mm_ctx *mm)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gmm_cause));
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
gh->proto_discr = GSM48_PDISC_MM_GPRS;
|
||||
gh->msg_type = GSM48_MT_GMM_SERVICE_REJ;
|
||||
gh->data[0] = gmm_cause;
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0, NULL);
|
||||
}
|
||||
static int gsm48_tx_gmm_service_rej_oldmsg(const struct msgb *old_msg,
|
||||
uint8_t gmm_cause)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ OLD");
|
||||
gmm_copy_id(msg, old_msg);
|
||||
return _tx_gmm_service_rej(msg, gmm_cause, NULL);
|
||||
}
|
||||
static int gsm48_tx_gmm_service_rej(struct sgsn_mm_ctx *mm,
|
||||
uint8_t gmm_cause)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ");
|
||||
mmctx2msgid(msg, mm);
|
||||
return _tx_gmm_service_rej(msg, gmm_cause, mm);
|
||||
}
|
||||
|
||||
static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm);
|
||||
|
||||
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
|
||||
{
|
||||
/* Send RAB activation requests for all PDP contexts */
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
llist_for_each_entry(pdp, &ctx->pdp_list, list) {
|
||||
iu_rab_act_ps(pdp->nsapi, pdp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we can already authorize a subscriber */
|
||||
static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
|
||||
{
|
||||
int rc;
|
||||
#ifndef PTMSI_ALLOC
|
||||
struct sgsn_signal_data sig_data;
|
||||
#endif
|
||||
@@ -656,6 +776,11 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
|
||||
}
|
||||
|
||||
/* The MS is authorized */
|
||||
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) {
|
||||
rc = iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet, 0, ctx->iu.new_key);
|
||||
ctx->iu.new_key = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (ctx->pending_req) {
|
||||
case 0:
|
||||
@@ -663,6 +788,7 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
|
||||
"no pending request, authorization completed\n");
|
||||
break;
|
||||
case GSM48_MT_GMM_ATTACH_REQ:
|
||||
ctx->pending_req = 0;
|
||||
|
||||
extract_subscr_msisdn(ctx);
|
||||
extract_subscr_hlr(ctx);
|
||||
@@ -678,6 +804,22 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
|
||||
#endif
|
||||
|
||||
return gsm48_tx_gmm_att_ack(ctx);
|
||||
case GSM48_MT_GMM_SERVICE_REQ:
|
||||
/* TODO: PMM State transition */
|
||||
ctx->pending_req = 0;
|
||||
ctx->pmm_state = PMM_CONNECTED;
|
||||
rc = gsm48_tx_gmm_service_ack(ctx);
|
||||
|
||||
if (ctx->iu.service.type == 1) {
|
||||
activate_pdp_rabs(ctx);
|
||||
}
|
||||
|
||||
return rc;
|
||||
case GSM48_MT_GMM_RA_UPD_REQ:
|
||||
ctx->pending_req = 0;
|
||||
/* Send RA UPDATE ACCEPT */
|
||||
return gsm48_tx_gmm_ra_upd_ack(ctx);
|
||||
|
||||
default:
|
||||
LOGMMCTXP(LOGL_ERROR, ctx,
|
||||
"only Attach Request is supported yet, "
|
||||
@@ -834,7 +976,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
uint32_t tmsi;
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
struct gprs_ra_id ra_id;
|
||||
uint16_t cid;
|
||||
uint16_t cid = 0;
|
||||
enum gsm48_gmm_cause reject_cause;
|
||||
int rc;
|
||||
|
||||
@@ -844,7 +986,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
* with a foreign TLLI (P-TMSI that was allocated to the MS before),
|
||||
* or with random TLLI. */
|
||||
|
||||
cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
|
||||
if (!msg->dst)
|
||||
cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
|
||||
|
||||
/* MS network capability 10.5.5.12 */
|
||||
msnc_len = *cur++;
|
||||
@@ -853,8 +996,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
goto err_inval;
|
||||
cur += msnc_len;
|
||||
|
||||
/* TODO: In iu mode - handle follow-on request */
|
||||
|
||||
/* aTTACH Type 10.5.5.2 */
|
||||
att_type = *cur++ & 0x0f;
|
||||
att_type = *cur++ & 0x07;
|
||||
|
||||
/* DRX parameter 10.5.5.6 */
|
||||
drx_par = *cur++ << 8;
|
||||
@@ -896,7 +1041,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
#if 0
|
||||
return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN);
|
||||
#else
|
||||
ctx = sgsn_mm_ctx_alloc(0, &ra_id);
|
||||
if (msg->dst)
|
||||
ctx = sgsn_mm_ctx_alloc_iu(msg->dst);
|
||||
else
|
||||
ctx = sgsn_mm_ctx_alloc(0, &ra_id);
|
||||
if (!ctx) {
|
||||
reject_cause = GMM_CAUSE_NET_FAIL;
|
||||
goto rejected;
|
||||
@@ -904,8 +1052,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi) - 1);
|
||||
#endif
|
||||
}
|
||||
ctx->tlli = msgb_tlli(msg);
|
||||
ctx->llme = llme;
|
||||
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
ctx->gb.tlli = msgb_tlli(msg);
|
||||
ctx->gb.llme = llme;
|
||||
}
|
||||
msgid2mmctx(ctx, msg);
|
||||
break;
|
||||
case GSM_MI_TYPE_TMSI:
|
||||
@@ -917,11 +1067,16 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
if (!ctx) {
|
||||
/* Allocate a context as most of our code expects one.
|
||||
* Context will not have an IMSI ultil ID RESP is received */
|
||||
ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id);
|
||||
if (msg->dst)
|
||||
ctx = sgsn_mm_ctx_alloc_iu(msg->dst);
|
||||
else
|
||||
ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id);
|
||||
ctx->p_tmsi = tmsi;
|
||||
}
|
||||
ctx->tlli = msgb_tlli(msg);
|
||||
ctx->llme = llme;
|
||||
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
ctx->gb.tlli = msgb_tlli(msg);
|
||||
ctx->gb.llme = llme;
|
||||
}
|
||||
msgid2mmctx(ctx, msg);
|
||||
break;
|
||||
default:
|
||||
@@ -932,7 +1087,32 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
}
|
||||
/* Update MM Context with currient RA and Cell ID */
|
||||
ctx->ra = ra_id;
|
||||
ctx->cell_id = cid;
|
||||
if (ctx->ran_type == MM_CTX_T_GERAN_Gb)
|
||||
ctx->gb.cell_id = cid;
|
||||
else if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) {
|
||||
unsigned char tmp_rand[16];
|
||||
/* Ki 000102030405060708090a0b0c0d0e0f */
|
||||
struct osmo_sub_auth_data auth = {
|
||||
.type = OSMO_AUTH_TYPE_GSM,
|
||||
.algo = OSMO_AUTH_ALG_COMP128v1,
|
||||
.u.gsm.ki = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f
|
||||
},
|
||||
};
|
||||
//ctx->iu.sac = sac;
|
||||
/* XXX: Hack to make 3G auth work with special SIM card */
|
||||
ctx->auth_state = SGSN_AUTH_AUTHENTICATE;
|
||||
|
||||
RAND_bytes(tmp_rand, 16);
|
||||
|
||||
memset(&ctx->auth_triplet.vec, 0, sizeof(ctx->auth_triplet.vec));
|
||||
osmo_auth_gen_vec(&ctx->auth_triplet.vec, &auth, tmp_rand);
|
||||
|
||||
ctx->auth_triplet.key_seq = 0;
|
||||
}
|
||||
|
||||
/* Update MM Context with other data */
|
||||
ctx->drx_parms = drx_par;
|
||||
ctx->ms_radio_access_capa.len = ms_ra_acc_cap_len;
|
||||
@@ -950,13 +1130,16 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
}
|
||||
ctx->mm_state = GMM_COMMON_PROC_INIT;
|
||||
#endif
|
||||
/* Even if there is no P-TMSI allocated, the MS will switch from
|
||||
* foreign TLLI to local TLLI */
|
||||
ctx->tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
|
||||
|
||||
/* Inform LLC layer about new TLLI but keep old active */
|
||||
gprs_llgmm_assign(ctx->llme, ctx->tlli, ctx->tlli_new,
|
||||
GPRS_ALGO_GEA0, NULL);
|
||||
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Even if there is no P-TMSI allocated, the MS will
|
||||
* switch from foreign TLLI to local TLLI */
|
||||
ctx->gb.tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
|
||||
|
||||
/* Inform LLC layer about new TLLI but keep old active */
|
||||
gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new,
|
||||
GPRS_ALGO_GEA0, NULL);
|
||||
}
|
||||
|
||||
ctx->pending_req = GSM48_MT_GMM_ATTACH_REQ;
|
||||
return gsm48_gmm_authorize(ctx);
|
||||
@@ -1131,8 +1314,10 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
enum gsm48_gmm_cause reject_cause;
|
||||
int rc;
|
||||
|
||||
/* TODO: In iu mode - handle follow-on request */
|
||||
|
||||
/* Update Type 10.5.5.18 */
|
||||
upd_type = *cur++ & 0x0f;
|
||||
upd_type = *cur++ & 0x07;
|
||||
|
||||
LOGP(DMM, LOGL_INFO, "-> GMM RA UPDATE REQUEST type=\"%s\"\n",
|
||||
get_value_string(gprs_upd_t_strs, upd_type));
|
||||
@@ -1165,6 +1350,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
break;
|
||||
}
|
||||
|
||||
#warning "Differentiate look-up between Iu and Gb"
|
||||
if (!mmctx) {
|
||||
/* BSSGP doesn't give us an mmctx */
|
||||
|
||||
@@ -1174,7 +1360,24 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
* is an optimization to avoid the RA reject (impl detached)
|
||||
* below, which will cause a new attach cycle. */
|
||||
/* Look-up the MM context based on old RA-ID and TLLI */
|
||||
mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id);
|
||||
if (!msg->dst) {
|
||||
mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id);
|
||||
} else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {
|
||||
/* In Iu mode search only for ptmsi */
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
|
||||
uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
|
||||
uint8_t mi_type = *mi & GSM_MI_TYPE_MASK;
|
||||
uint32_t tmsi;
|
||||
|
||||
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
|
||||
|
||||
if (mi_type == GSM_MI_TYPE_TMSI) {
|
||||
memcpy(&tmsi, mi+1, 4);
|
||||
tmsi = ntohl(tmsi);
|
||||
mmctx = sgsn_mm_ctx_by_ptmsi(tmsi);
|
||||
}
|
||||
}
|
||||
if (mmctx) {
|
||||
LOGMMCTXP(LOGL_INFO, mmctx,
|
||||
"Looked up by matching TLLI and P_TMSI. "
|
||||
@@ -1182,7 +1385,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
"TLLI: %08x (%08x), RA: %d-%d-%d-%d\n",
|
||||
msgb_tlli(msg),
|
||||
mmctx->p_tmsi, mmctx->p_tmsi_old,
|
||||
mmctx->tlli, mmctx->tlli_new,
|
||||
mmctx->gb.tlli, mmctx->gb.tlli_new,
|
||||
mmctx->ra.mcc, mmctx->ra.mnc,
|
||||
mmctx->ra.lac, mmctx->ra.rac);
|
||||
|
||||
@@ -1200,10 +1403,12 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
}
|
||||
|
||||
if (!mmctx) {
|
||||
/* send a XID reset to re-set all LLC sequence numbers
|
||||
* in the MS */
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx, "LLC XID RESET\n");
|
||||
gprs_llgmm_reset(llme);
|
||||
if (llme) {
|
||||
/* send a XID reset to re-set all LLC sequence numbers
|
||||
* in the MS */
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx, "LLC XID RESET\n");
|
||||
gprs_llgmm_reset(llme);
|
||||
}
|
||||
/* The MS has to perform GPRS attach */
|
||||
/* Device is still IMSI attached for CS but initiate GPRS ATTACH,
|
||||
* see GSM 04.08, 4.7.5.1.4 and G.6 */
|
||||
@@ -1217,9 +1422,12 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||
|
||||
/* Update the MM context with the new RA-ID */
|
||||
bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
|
||||
/* Update the MM context with the new (i.e. foreign) TLLI */
|
||||
mmctx->tlli = msgb_tlli(msg);
|
||||
#warning "how to obtain RA_ID in Iu case?"
|
||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
|
||||
/* Update the MM context with the new (i.e. foreign) TLLI */
|
||||
mmctx->gb.tlli = msgb_tlli(msg);
|
||||
}
|
||||
/* FIXME: Update the MM context with the MS radio acc capabilities */
|
||||
/* FIXME: Update the MM context with the MS network capabilities */
|
||||
|
||||
@@ -1244,13 +1452,16 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
sig_data.mm = mmctx;
|
||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_UPDATE, &sig_data);
|
||||
#endif
|
||||
/* Even if there is no P-TMSI allocated, the MS will switch from
|
||||
* foreign TLLI to local TLLI */
|
||||
mmctx->tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL);
|
||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Even if there is no P-TMSI allocated, the MS will switch from
|
||||
* foreign TLLI to local TLLI */
|
||||
mmctx->gb.tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL);
|
||||
|
||||
/* Inform LLC layer about new TLLI but keep old active */
|
||||
gprs_llgmm_assign(mmctx->llme, mmctx->tlli, mmctx->tlli_new,
|
||||
GPRS_ALGO_GEA0, NULL);
|
||||
/* Inform LLC layer about new TLLI but keep old active */
|
||||
gprs_llgmm_assign(mmctx->gb.llme, mmctx->gb.tlli,
|
||||
mmctx->gb.tlli_new, GPRS_ALGO_GEA0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Look at PDP Context Status IE and see if MS's view of
|
||||
* activated/deactivated NSAPIs agrees with our view */
|
||||
@@ -1259,8 +1470,9 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
process_ms_ctx_status(mmctx, pdp_status);
|
||||
}
|
||||
|
||||
mmctx->pending_req = GSM48_MT_GMM_RA_UPD_REQ;
|
||||
/* Send RA UPDATE ACCEPT */
|
||||
return gsm48_tx_gmm_ra_upd_ack(mmctx);
|
||||
return gsm48_gmm_authorize(mmctx);
|
||||
|
||||
rejected:
|
||||
/* Send RA UPDATE REJECT */
|
||||
@@ -1270,14 +1482,126 @@ rejected:
|
||||
rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause);
|
||||
if (mmctx)
|
||||
mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ");
|
||||
else
|
||||
/* TLLI unassignment */
|
||||
gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0,
|
||||
NULL);
|
||||
else {
|
||||
if (llme) {
|
||||
/* TLLI unassignment */
|
||||
gprs_llgmm_assign(llme, llme->tlli, 0xffffffff,
|
||||
GPRS_ALGO_GEA0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 Section 9.4.20 Service request */
|
||||
static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
uint8_t *cur = gh->data, *mi;
|
||||
uint8_t ciph_seq_nr, service_type, mi_len, mi_type;
|
||||
uint32_t tmsi;
|
||||
struct tlv_parsed tp;
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
uint16_t cid = 0;
|
||||
enum gsm48_gmm_cause reject_cause;
|
||||
int rc;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM SERVICE REQUEST ");
|
||||
|
||||
/* This message is only valid in Iu mode */
|
||||
if (!msg->dst) {
|
||||
LOGPC(DMM, LOGL_INFO, "Invalid if not in Iu mode\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Skip Ciphering key sequence number 10.5.1.2 */
|
||||
ciph_seq_nr = *cur & 0x07;
|
||||
|
||||
/* Service type 10.5.5.20 */
|
||||
service_type = (*cur++ >> 4) & 0x07;
|
||||
|
||||
/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
|
||||
mi_len = *cur++;
|
||||
mi = cur;
|
||||
if (mi_len > 8)
|
||||
goto err_inval;
|
||||
mi_type = *mi & GSM_MI_TYPE_MASK;
|
||||
cur += mi_len;
|
||||
|
||||
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
|
||||
|
||||
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
|
||||
get_value_string(gprs_service_t_strs, service_type));
|
||||
|
||||
LOGPC(DMM, LOGL_INFO, "\n");
|
||||
|
||||
/* Optional: PDP context status, MBMS context status, Uplink data status, Device properties */
|
||||
tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur, (msg->data + msg->len) - cur, 0, 0);
|
||||
|
||||
switch (mi_type) {
|
||||
case GSM_MI_TYPE_IMSI:
|
||||
/* Try to find MM context based on IMSI */
|
||||
if (!ctx)
|
||||
ctx = sgsn_mm_ctx_by_imsi(mi_string);
|
||||
if (!ctx) {
|
||||
/* FIXME: We need to have a context for service request? */
|
||||
reject_cause = GMM_CAUSE_NET_FAIL;
|
||||
goto rejected;
|
||||
}
|
||||
msgid2mmctx(ctx, msg);
|
||||
break;
|
||||
case GSM_MI_TYPE_TMSI:
|
||||
memcpy(&tmsi, mi+1, 4);
|
||||
tmsi = ntohl(tmsi);
|
||||
/* Try to find MM context based on P-TMSI */
|
||||
if (!ctx)
|
||||
ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
|
||||
if (!ctx) {
|
||||
/* FIXME: We need to have a context for service request? */
|
||||
reject_cause = GMM_CAUSE_NET_FAIL;
|
||||
goto rejected;
|
||||
}
|
||||
msgid2mmctx(ctx, msg);
|
||||
break;
|
||||
default:
|
||||
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with "
|
||||
"MI type %s\n", gsm48_mi_type_name(mi_type));
|
||||
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
|
||||
goto rejected;
|
||||
}
|
||||
|
||||
ctx->mm_state = GMM_COMMON_PROC_INIT;
|
||||
|
||||
ctx->iu.service.type = service_type;
|
||||
|
||||
/* TODO: Handle those only in case of accept? */
|
||||
/* Look at PDP Context Status IE and see if MS's view of
|
||||
* activated/deactivated NSAPIs agrees with our view */
|
||||
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
|
||||
const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
|
||||
process_ms_ctx_status(ctx, pdp_status);
|
||||
}
|
||||
|
||||
|
||||
ctx->pending_req = GSM48_MT_GMM_SERVICE_REQ;
|
||||
return gsm48_gmm_authorize(ctx);
|
||||
|
||||
err_inval:
|
||||
LOGPC(DMM, LOGL_INFO, "\n");
|
||||
reject_cause = GMM_CAUSE_SEM_INCORR_MSG;
|
||||
|
||||
rejected:
|
||||
/* Send SERVICE REJECT */
|
||||
LOGMMCTXP(LOGL_NOTICE, ctx,
|
||||
"Rejecting Service Request with cause '%s' (%d)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
|
||||
rc = gsm48_tx_gmm_service_rej_oldmsg(msg, reject_cause);
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
@@ -1298,7 +1622,7 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
|
||||
/* MMCTX can be NULL when called */
|
||||
|
||||
if (!mmctx &&
|
||||
if (llme && !mmctx &&
|
||||
gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
|
||||
gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) {
|
||||
LOGP(DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
|
||||
@@ -1346,7 +1670,20 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
case GSM48_MT_GMM_ATTACH_REQ:
|
||||
rc = gsm48_rx_gmm_att_req(mmctx, msg, llme);
|
||||
break;
|
||||
case GSM48_MT_GMM_SERVICE_REQ:
|
||||
rc = gsm48_rx_gmm_service_req(mmctx, msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* For all the following types mmctx can not be NULL */
|
||||
if (!mmctx) {
|
||||
/* FIXME: return some error? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (gh->msg_type) {
|
||||
case GSM48_MT_GMM_ID_RESP:
|
||||
rc = gsm48_rx_gmm_id_resp(mmctx, msg);
|
||||
break;
|
||||
@@ -1368,11 +1705,15 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
|
||||
mmctx->p_tmsi_old = 0;
|
||||
mmctx->pending_req = 0;
|
||||
/* Unassign the old TLLI */
|
||||
mmctx->tlli = mmctx->tlli_new;
|
||||
gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new,
|
||||
GPRS_ALGO_GEA0, NULL);
|
||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Unassign the old TLLI */
|
||||
mmctx->gb.tlli = mmctx->gb.tlli_new;
|
||||
gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff,
|
||||
mmctx->gb.tlli_new,
|
||||
GPRS_ALGO_GEA0, NULL);
|
||||
}
|
||||
mmctx->mm_state = GMM_REGISTERED_NORMAL;
|
||||
mmctx->pmm_state = PMM_CONNECTED;
|
||||
rc = 0;
|
||||
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
@@ -1386,11 +1727,15 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
|
||||
mmctx->p_tmsi_old = 0;
|
||||
mmctx->pending_req = 0;
|
||||
/* Unassign the old TLLI */
|
||||
mmctx->tlli = mmctx->tlli_new;
|
||||
gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new,
|
||||
GPRS_ALGO_GEA0, NULL);
|
||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Unassign the old TLLI */
|
||||
mmctx->gb.tlli = mmctx->gb.tlli_new;
|
||||
gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, mmctx->gb.tlli_new,
|
||||
GPRS_ALGO_GEA0, NULL);
|
||||
}
|
||||
mmctx->mm_state = GMM_REGISTERED_NORMAL;
|
||||
mmctx->pmm_state = PMM_CONNECTED;
|
||||
activate_pdp_rabs(mmctx);
|
||||
rc = 0;
|
||||
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
@@ -1403,9 +1748,11 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
||||
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
|
||||
mmctx->p_tmsi_old = 0;
|
||||
mmctx->pending_req = 0;
|
||||
/* Unassign the old TLLI */
|
||||
mmctx->tlli = mmctx->tlli_new;
|
||||
//gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, GPRS_ALGO_GEA0, NULL);
|
||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Unassign the old TLLI */
|
||||
mmctx->gb.tlli = mmctx->gb.tlli_new;
|
||||
//gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, mmctx->gb.tlli_new, GPRS_ALGO_GEA0, NULL);
|
||||
}
|
||||
rc = 0;
|
||||
break;
|
||||
case GSM48_MT_GMM_AUTH_CIPH_RESP:
|
||||
@@ -2077,7 +2424,8 @@ int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg)
|
||||
int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx)
|
||||
{
|
||||
int rc;
|
||||
gprs_llgmm_reset(mmctx->llme);
|
||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
|
||||
gprs_llgmm_reset(mmctx->gb.llme);
|
||||
|
||||
rc = gsm48_tx_gmm_detach_req(
|
||||
mmctx, GPRS_DET_T_MT_REATT_REQ, GMM_CAUSE_IMPL_DETACHED);
|
||||
@@ -2087,8 +2435,50 @@ int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Main entry point for incoming 04.08 GPRS messages */
|
||||
int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme)
|
||||
/* Main entry point for incoming 04.08 GPRS messages from Iu */
|
||||
int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
|
||||
uint16_t *sai)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
uint8_t pdisc = gsm48_hdr_pdisc(gh);
|
||||
struct sgsn_mm_ctx *mmctx;
|
||||
int rc = -EINVAL;
|
||||
|
||||
DEBUGP(DMM, "grps_rcvmsg_iu(%s)\n", osmo_hexdump(msgb_gmmh(msg), msgb_l3len(msg)));
|
||||
|
||||
mmctx = sgsn_mm_ctx_by_ue_ctx(msg->dst);
|
||||
if (mmctx) {
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||
if (ra_id)
|
||||
memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra));
|
||||
//if (sai)
|
||||
//mmctx->iu.sai = *sai;
|
||||
}
|
||||
|
||||
/* MMCTX can be NULL */
|
||||
|
||||
switch (pdisc) {
|
||||
case GSM48_PDISC_MM_GPRS:
|
||||
rc = gsm0408_rcv_gmm(mmctx, msg, NULL);
|
||||
break;
|
||||
case GSM48_PDISC_SM_GPRS:
|
||||
rc = gsm0408_rcv_gsm(mmctx, msg, NULL);
|
||||
break;
|
||||
default:
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx,
|
||||
"Unknown GSM 04.08 discriminator 0x%02x: %s\n",
|
||||
pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
|
||||
/* FIXME: return status message */
|
||||
break;
|
||||
}
|
||||
|
||||
/* MMCTX can be invalid */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Main entry point for incoming 04.08 GPRS messages from Gb */
|
||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
uint8_t pdisc = gsm48_hdr_pdisc(gh);
|
||||
@@ -2101,7 +2491,7 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme)
|
||||
if (mmctx) {
|
||||
msgid2mmctx(mmctx, msg);
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||
mmctx->llme = llme;
|
||||
mmctx->gb.llme = llme;
|
||||
}
|
||||
|
||||
/* MMCTX can be NULL */
|
||||
|
@@ -56,8 +56,8 @@ static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
|
||||
dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
|
||||
|
||||
/* make sure we only send it to the right llme */
|
||||
OSMO_ASSERT(msgb_tlli(msg) == mmctx->llme->tlli
|
||||
|| msgb_tlli(msg) == mmctx->llme->old_tlli);
|
||||
OSMO_ASSERT(msgb_tlli(msg) == mmctx->gb.llme->tlli
|
||||
|| msgb_tlli(msg) == mmctx->gb.llme->old_tlli);
|
||||
}
|
||||
memcpy(&dup.qos_profile, qos_profile_default,
|
||||
sizeof(qos_profile_default));
|
||||
@@ -663,7 +663,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
|
||||
switch (llhp.sapi) {
|
||||
case GPRS_SAPI_GMM:
|
||||
/* send LL_UNITDATA_IND to GMM */
|
||||
rc = gsm0408_gprs_rcvmsg(msg, lle->llme);
|
||||
rc = gsm0408_gprs_rcvmsg_gb(msg, lle->llme);
|
||||
break;
|
||||
case GPRS_SAPI_SNDCP3:
|
||||
case GPRS_SAPI_SNDCP5:
|
||||
|
@@ -39,6 +39,9 @@
|
||||
#include <openbsc/gprs_utils.h>
|
||||
#include <openbsc/signal.h>
|
||||
#include "openbsc/gprs_llc.h"
|
||||
#include <openbsc/iu.h>
|
||||
|
||||
#include <pdp.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -90,6 +93,19 @@ static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
|
||||
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
|
||||
};
|
||||
|
||||
/* look-up a SGSN MM context based on TLLI + RAI */
|
||||
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) {
|
||||
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && uectx == ctx->iu.ue_ctx)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* look-up a SGSN MM context based on TLLI + RAI */
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
|
||||
const struct gprs_ra_id *raid)
|
||||
@@ -97,7 +113,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) {
|
||||
if ((tlli == ctx->tlli || tlli == ctx->tlli_new) &&
|
||||
if ((tlli == ctx->gb.tlli || tlli == ctx->gb.tlli_new) &&
|
||||
gprs_ra_id_equals(raid, &ctx->ra))
|
||||
return ctx;
|
||||
}
|
||||
@@ -165,7 +181,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
|
||||
return NULL;
|
||||
|
||||
memcpy(&ctx->ra, raid, sizeof(ctx->ra));
|
||||
ctx->tlli = tlli;
|
||||
ctx->ran_type = MM_CTX_T_GERAN_Gb;
|
||||
ctx->gb.tlli = tlli;
|
||||
ctx->mm_state = GMM_DEREGISTERED;
|
||||
ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
|
||||
ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli);
|
||||
@@ -176,6 +193,34 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/* Allocate a new SGSN MM context */
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
|
||||
{
|
||||
struct sgsn_mm_ctx *ctx;
|
||||
|
||||
ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->ran_type = MM_CTX_T_UTRAN_Iu;
|
||||
ctx->iu.ue_ctx = uectx;
|
||||
ctx->iu.new_key = 1;
|
||||
ctx->mm_state = GMM_DEREGISTERED;
|
||||
ctx->pmm_state = PMM_DETACHED;
|
||||
ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
|
||||
ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0);
|
||||
|
||||
/* Need to get RAID from IU conn */
|
||||
ctx->ra = ctx->iu.ue_ctx->ra_id;
|
||||
|
||||
INIT_LLIST_HEAD(&ctx->pdp_list);
|
||||
|
||||
llist_add(&ctx->list, &sgsn_mm_ctxts);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
/* this is a hard _free_ function, it doesn't clean up the PDP contexts
|
||||
* in libgtp! */
|
||||
static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
|
||||
@@ -196,10 +241,11 @@ static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
|
||||
|
||||
void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
|
||||
{
|
||||
struct gprs_llc_llme *llme = mm->llme;
|
||||
uint32_t tlli = mm->tlli;
|
||||
struct gprs_llc_llme *llme = mm->gb.llme;
|
||||
uint32_t tlli = mm->gb.tlli;
|
||||
struct sgsn_pdp_ctx *pdp, *pdp2;
|
||||
struct sgsn_signal_data sig_data;
|
||||
enum sgsn_ran_type ran_type;
|
||||
|
||||
/* Forget about ongoing look-ups */
|
||||
if (mm->ggsn_lookup) {
|
||||
@@ -233,11 +279,15 @@ void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
|
||||
subscr_put(subscr);
|
||||
}
|
||||
|
||||
ran_type = mm->ran_type;
|
||||
|
||||
sgsn_mm_ctx_free(mm);
|
||||
mm = NULL;
|
||||
|
||||
/* TLLI unassignment, must be called after sgsn_mm_ctx_free */
|
||||
gprs_llgmm_assign(llme, tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
|
||||
if (ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* TLLI unassignment, must be called after sgsn_mm_ctx_free */
|
||||
gprs_llgmm_assign(llme, tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -290,7 +340,6 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
|
||||
return pdp;
|
||||
}
|
||||
|
||||
#include <pdp.h>
|
||||
/*
|
||||
* 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
|
||||
@@ -307,8 +356,10 @@ void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
|
||||
|
||||
LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n");
|
||||
|
||||
/* Force the deactivation of the SNDCP layer */
|
||||
sndcp_sm_deactivate_ind(&pdp->mm->llme->lle[pdp->sapi], pdp->nsapi);
|
||||
if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Force the deactivation of the SNDCP layer */
|
||||
sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
|
||||
}
|
||||
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
sig_data.pdp = pdp;
|
||||
@@ -751,7 +802,7 @@ 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->llme) {
|
||||
if (llme == mmctx->gb.llme) {
|
||||
gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
|
||||
return;
|
||||
}
|
||||
|
37
openbsc/src/gprs/gsm_04_08_gprs.c
Normal file
37
openbsc/src/gprs/gsm_04_08_gprs.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2010 by On-Waves
|
||||
* (C) 2014-2015 by Sysmocom s.f.m.c. GmbH
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */
|
||||
|
||||
#include <openbsc/gsm_04_08_gprs.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
const struct value_string gprs_service_t_strs_[] = {
|
||||
{ GPRS_SERVICE_T_SIGNALLING, "signalling" },
|
||||
{ GPRS_SERVICE_T_DATA, "data" },
|
||||
{ GPRS_SERVICE_T_PAGING_RESP, "paging response" },
|
||||
{ GPRS_SERVICE_T_MBMS_MC_SERV, "MBMS multicast service" },
|
||||
{ GPRS_SERVICE_T_MBMS_BC_SERV, "MBMS broadcast service" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string *gprs_service_t_strs = gprs_service_t_strs_;
|
@@ -1,14 +1,38 @@
|
||||
!
|
||||
! Osmocom SGSN (0.9.0.474-0ede2) configuration saved from vty
|
||||
! OsmoSGSN (0.15.0.145-a710-dirty) configuration saved from vty
|
||||
!!
|
||||
!
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print category 0
|
||||
logging timestamp 0
|
||||
logging level all everything
|
||||
logging level mm debug
|
||||
logging level pag notice
|
||||
logging level meas notice
|
||||
logging level ref notice
|
||||
logging level gprs debug
|
||||
logging level ns info
|
||||
logging level bssgp debug
|
||||
logging level llc debug
|
||||
logging level sndcp debug
|
||||
logging level lglobal notice
|
||||
logging level llapd notice
|
||||
logging level linp notice
|
||||
logging level lmux notice
|
||||
logging level lmi notice
|
||||
logging level lmib notice
|
||||
logging level lsms notice
|
||||
logging level lctrl notice
|
||||
logging level lgtp notice
|
||||
logging level lstats notice
|
||||
!
|
||||
stats interval 5
|
||||
!
|
||||
line vty
|
||||
no login
|
||||
!
|
||||
sgsn
|
||||
gtp local-ip 192.168.100.11
|
||||
ggsn 0 remote-ip 192.168.100.239
|
||||
ggsn 0 gtp-version 1
|
||||
ns
|
||||
timer tns-block 3
|
||||
timer tns-block-retries 3
|
||||
@@ -17,7 +41,30 @@ ns
|
||||
timer tns-test 30
|
||||
timer tns-alive 3
|
||||
timer tns-alive-retries 10
|
||||
encapsulation udp local-ip 192.168.100.11
|
||||
encapsulation udp local-ip 192.168.0.51
|
||||
encapsulation udp local-port 23000
|
||||
encapsulation framerelay-gre enabled 0
|
||||
bssgp
|
||||
sgsn
|
||||
gtp local-ip 127.0.0.2
|
||||
ggsn 0 remote-ip 192.168.0.51
|
||||
ggsn 0 gtp-version 1
|
||||
auth-policy closed
|
||||
gsup oap-id 0
|
||||
imsi-acl add 262032312854076
|
||||
imsi-acl add 262778026147135
|
||||
! apn * ggsn 0
|
||||
no cdr filename
|
||||
cdr interval 600
|
||||
timer t3312 600
|
||||
timer t3322 6
|
||||
timer t3350 6
|
||||
timer t3360 6
|
||||
timer t3370 6
|
||||
timer t3313 30
|
||||
timer t3314 44
|
||||
timer t3316 44
|
||||
timer t3385 8
|
||||
timer t3386 8
|
||||
timer t3395 8
|
||||
timer t3397 8
|
||||
|
@@ -94,7 +94,7 @@ static void cdr_log_mm(struct sgsn_instance *inst, const char *ev,
|
||||
mmctx->imsi,
|
||||
mmctx->imei,
|
||||
mmctx->msisdn,
|
||||
mmctx->cell_id,
|
||||
mmctx->gb.cell_id,
|
||||
mmctx->ra.lac,
|
||||
mmctx->hlr,
|
||||
ev);
|
||||
@@ -179,7 +179,7 @@ static void cdr_log_pdp(struct sgsn_instance *inst, const char *ev,
|
||||
pdp->mm ? pdp->mm->imsi : "N/A",
|
||||
pdp->mm ? pdp->mm->imei : "N/A",
|
||||
pdp->mm ? pdp->mm->msisdn : "N/A",
|
||||
pdp->mm ? pdp->mm->cell_id : -1,
|
||||
pdp->mm ? pdp->mm->gb.cell_id : -1,
|
||||
pdp->mm ? pdp->mm->ra.lac : -1,
|
||||
pdp->mm ? pdp->mm->hlr : "N/A",
|
||||
ev,
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/crypt/auth.h>
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
|
||||
@@ -47,6 +48,11 @@
|
||||
#include <openbsc/gprs_sgsn.h>
|
||||
#include <openbsc/gprs_gmm.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/iu.h>
|
||||
|
||||
#include <osmocom/ranap/ranap_ies_defs.h>
|
||||
|
||||
#include <asn1c/asn1helpers.h>
|
||||
|
||||
#include <gtp.h>
|
||||
#include <pdp.h>
|
||||
@@ -218,7 +224,10 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
||||
memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
|
||||
sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
|
||||
|
||||
/* SGSN address for user plane */
|
||||
/* SGSN address for user plane
|
||||
* Default to the control plane addr for now. If we are connected to a
|
||||
* hnbgw via IuPS we'll need to send a PDP context update with the
|
||||
* correct IP address after the RAB Assignment is complete */
|
||||
pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr);
|
||||
memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
|
||||
sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
|
||||
@@ -239,7 +248,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
||||
pdp->userloc_given = 1;
|
||||
pdp->userloc.l = 8;
|
||||
pdp->userloc.v[0] = 0; /* CGI for GERAN */
|
||||
bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->cell_id);
|
||||
bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->gb.cell_id);
|
||||
|
||||
/* include the IMEI(SV) */
|
||||
pdp->imeisv_given = 1;
|
||||
@@ -304,6 +313,19 @@ static const struct cause_map gtp2sm_cause_map[] = {
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx)
|
||||
{
|
||||
struct sgsn_signal_data sig_data;
|
||||
|
||||
/* Inform others about it */
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
sig_data.pdp = pctx;
|
||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data);
|
||||
|
||||
/* Send PDP CTX ACT to MS */
|
||||
return gsm48_tx_gsm_act_pdp_acc(pctx);
|
||||
}
|
||||
|
||||
/* The GGSN has confirmed the creation of a PDP Context */
|
||||
static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
{
|
||||
@@ -340,16 +362,17 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
goto reject;
|
||||
}
|
||||
|
||||
/* Activate the SNDCP layer */
|
||||
sndcp_sm_activate_ind(&pctx->mm->llme->lle[pctx->sapi], pctx->nsapi);
|
||||
if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Activate the SNDCP layer */
|
||||
sndcp_sm_activate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi);
|
||||
|
||||
/* Inform others about it */
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
sig_data.pdp = pctx;
|
||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data);
|
||||
|
||||
/* Send PDP CTX ACT to MS */
|
||||
return gsm48_tx_gsm_act_pdp_acc(pctx);
|
||||
return send_act_pdp_cont_acc(pctx);
|
||||
} else {
|
||||
/* Activate a radio bearer */
|
||||
iu_rab_act_ps(pdp->nsapi, pctx, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
reject:
|
||||
/*
|
||||
@@ -372,6 +395,70 @@ reject:
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Callback for RAB assignment response */
|
||||
int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
|
||||
{
|
||||
uint8_t rab_id;
|
||||
bool require_pdp_update = false;
|
||||
struct sgsn_pdp_ctx *pdp = NULL;
|
||||
RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
|
||||
|
||||
rab_id = item->rAB_ID.buf[0];
|
||||
|
||||
pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id);
|
||||
if (!pdp) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (item->transportLayerAddress) {
|
||||
LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf,
|
||||
item->transportLayerAddress->size));
|
||||
switch (item->transportLayerAddress->size) {
|
||||
case 7:
|
||||
/* It must be IPv4 inside a X213 NSAP */
|
||||
memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4);
|
||||
break;
|
||||
case 4:
|
||||
/* It must be a raw IPv4 address */
|
||||
memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4);
|
||||
break;
|
||||
case 16:
|
||||
/* TODO: It must be a raw IPv6 address */
|
||||
case 19:
|
||||
/* TODO: It must be IPv6 inside a X213 NSAP */
|
||||
default:
|
||||
LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown "
|
||||
"transport layer address size %u\n",
|
||||
item->transportLayerAddress->size);
|
||||
return -1;
|
||||
}
|
||||
require_pdp_update = true;
|
||||
}
|
||||
|
||||
/* The TEI on the RNC side might have changed, too */
|
||||
if (item->iuTransportAssociation &&
|
||||
item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI &&
|
||||
item->iuTransportAssociation->choice.gTP_TEI.buf &&
|
||||
item->iuTransportAssociation->choice.gTP_TEI.size >= 4) {
|
||||
uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf);
|
||||
LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n",
|
||||
pdp->lib->teid_own, tei);
|
||||
pdp->lib->teid_own = tei;
|
||||
require_pdp_update = true;
|
||||
}
|
||||
|
||||
if (require_pdp_update)
|
||||
gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0);
|
||||
|
||||
if (pdp->state != PDP_STATE_CR_CONF) {
|
||||
send_act_pdp_cont_acc(pdp);
|
||||
pdp->state = PDP_STATE_CR_CONF;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Confirmation of a PDP Context Delete */
|
||||
static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
{
|
||||
@@ -387,8 +474,13 @@ static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_DEACT, &sig_data);
|
||||
|
||||
if (pctx->mm) {
|
||||
/* Deactivate the SNDCP layer */
|
||||
sndcp_sm_deactivate_ind(&pctx->mm->llme->lle[pctx->sapi], pctx->nsapi);
|
||||
if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Deactivate the SNDCP layer */
|
||||
sndcp_sm_deactivate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi);
|
||||
} else {
|
||||
/* Dectivate a radio bearer */
|
||||
iu_rab_deact(pctx->mm->iu.ue_ctx, 1);
|
||||
}
|
||||
|
||||
/* Confirm deactivation of PDP context to MS */
|
||||
rc = gsm48_tx_gsm_deact_pdp_acc(pctx);
|
||||
@@ -521,9 +613,9 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
||||
ud = msgb_put(msg, len);
|
||||
memcpy(ud, packet, len);
|
||||
|
||||
msgb_tlli(msg) = mm->tlli;
|
||||
msgb_bvci(msg) = mm->bvci;
|
||||
msgb_nsei(msg) = mm->nsei;
|
||||
msgb_tlli(msg) = mm->gb.tlli;
|
||||
msgb_bvci(msg) = mm->gb.bvci;
|
||||
msgb_nsei(msg) = mm->gb.nsei;
|
||||
|
||||
switch (mm->mm_state) {
|
||||
case GMM_REGISTERED_SUSPENDED:
|
||||
@@ -531,12 +623,12 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
||||
memset(&pinfo, 0, sizeof(pinfo));
|
||||
pinfo.mode = BSSGP_PAGING_PS;
|
||||
pinfo.scope = BSSGP_PAGING_BVCI;
|
||||
pinfo.bvci = mm->bvci;
|
||||
pinfo.bvci = mm->gb.bvci;
|
||||
pinfo.imsi = mm->imsi;
|
||||
pinfo.ptmsi = &mm->p_tmsi;
|
||||
pinfo.drx_params = mm->drx_parms;
|
||||
pinfo.qos[0] = 0; // FIXME
|
||||
bssgp_tx_paging(mm->nsei, 0, &pinfo);
|
||||
bssgp_tx_paging(mm->gb.nsei, 0, &pinfo);
|
||||
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PAGING_PS]);
|
||||
/* FIXME: queue the packet we received from GTP */
|
||||
break;
|
||||
@@ -544,7 +636,7 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
||||
break;
|
||||
default:
|
||||
LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state "
|
||||
"%u\n", mm->tlli, mm->mm_state);
|
||||
"%u\n", mm->gb.tlli, mm->mm_state);
|
||||
msgb_free(msg);
|
||||
return -1;
|
||||
}
|
||||
@@ -557,7 +649,7 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
||||
/* It is easier to have a global count */
|
||||
pdp->cdr_bytes_out += len;
|
||||
|
||||
return sndcp_unitdata_req(msg, &mm->llme->lle[pdp->sapi],
|
||||
return sndcp_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
|
||||
pdp->nsapi, mm);
|
||||
}
|
||||
|
||||
|
@@ -55,6 +55,8 @@
|
||||
#include <openbsc/sgsn.h>
|
||||
#include <openbsc/gprs_llc.h>
|
||||
#include <openbsc/gprs_gmm.h>
|
||||
#include <openbsc/iu.h>
|
||||
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/ctrl/ports.h>
|
||||
|
||||
@@ -232,6 +234,8 @@ static void handle_options(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
extern int asn_debug;
|
||||
|
||||
/* default categories */
|
||||
static struct log_info_cat gprs_categories[] = {
|
||||
[DMM] = {
|
||||
@@ -281,6 +285,16 @@ static struct log_info_cat gprs_categories[] = {
|
||||
.description = "GPRS Sub-Network Dependent Control Protocol (SNDCP)",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DSUA] = {
|
||||
.name = "DSUA",
|
||||
.description = "SCCP User Adaptation (SUA)",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DRANAP] = {
|
||||
.name = "DRANAP",
|
||||
.description = "RAN Application Part (RANAP)",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct log_info gprs_log_info = {
|
||||
@@ -289,6 +303,9 @@ static const struct log_info gprs_log_info = {
|
||||
.num_cat = ARRAY_SIZE(gprs_categories),
|
||||
};
|
||||
|
||||
int asn_debug;
|
||||
|
||||
int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@@ -404,6 +421,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
asn_debug = 0;
|
||||
iu_init(tall_bsc_ctx, "127.0.0.2", 14001, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event);
|
||||
|
||||
if (daemonize) {
|
||||
rc = osmo_daemonize();
|
||||
if (rc < 0) {
|
||||
|
@@ -431,12 +431,12 @@ static void vty_dump_mmctx(struct vty *vty, const char *pfx,
|
||||
vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
|
||||
pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
|
||||
vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
|
||||
pfx, mm->msisdn, mm->tlli, mm->hlr, VTY_NEWLINE);
|
||||
pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
|
||||
vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
|
||||
"Cell ID: %u%s", pfx,
|
||||
get_value_string(gprs_mm_st_strs, mm->mm_state),
|
||||
mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
|
||||
mm->cell_id, VTY_NEWLINE);
|
||||
mm->gb.cell_id, VTY_NEWLINE);
|
||||
|
||||
vty_out_rate_ctr_group(vty, " ", mm->ctrg);
|
||||
|
||||
|
@@ -6,8 +6,7 @@ OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS)
|
||||
bin_PROGRAMS = abisip-find ipaccess-config ipaccess-proxy
|
||||
|
||||
abisip_find_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libmsc/libmsc.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libxsc/libxsc.a \
|
||||
$(top_builddir)/src/libtrau/libtrau.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(OSMO_LIBS)
|
||||
@@ -17,15 +16,14 @@ ipaccess_config_SOURCES = ipaccess-config.c ipaccess-firmware.c network_listen.c
|
||||
|
||||
# FIXME: resolve the bogus dependencies patched around here:
|
||||
ipaccess_config_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libxsc/libxsc.a \
|
||||
$(top_builddir)/src/libtrau/libtrau.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(LIBCRYPT) $(OSMO_LIBS)
|
||||
|
||||
ipaccess_proxy_SOURCES = ipaccess-proxy.c
|
||||
ipaccess_proxy_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libmsc/libmsc.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libxsc/libxsc.a \
|
||||
$(top_builddir)/src/libtrau/libtrau.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(OSMO_LIBS)
|
||||
|
@@ -983,7 +983,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
libosmo_abis_init(tall_ctx_config);
|
||||
|
||||
bsc_gsmnet = gsm_network_init(1, 1, NULL);
|
||||
bsc_gsmnet = gsm_network_init(tall_bsc_ctx, 1, 1, NULL);
|
||||
if (!bsc_gsmnet)
|
||||
exit(1);
|
||||
|
||||
|
@@ -20,6 +20,7 @@ libbsc_a_SOURCES = abis_nm.c abis_nm_vty.c \
|
||||
e1_config.c \
|
||||
bsc_api.c bsc_msc.c bsc_vty.c \
|
||||
gsm_04_08_utils.c \
|
||||
gsm_04_80_utils.c \
|
||||
bsc_init.c bts_init.c bsc_rf_ctrl.c \
|
||||
arfcn_range_encode.c bsc_ctrl_commands.c \
|
||||
bsc_ctrl_lookup.c \
|
||||
|
@@ -94,7 +94,7 @@ DEFUN(oml_class_inst, oml_class_inst_cmd,
|
||||
struct oml_node_state *oms;
|
||||
int bts_nr = atoi(argv[0]);
|
||||
|
||||
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
|
||||
bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -128,7 +128,7 @@ DEFUN(oml_classnum_inst, oml_classnum_inst_cmd,
|
||||
struct oml_node_state *oms;
|
||||
int bts_nr = atoi(argv[0]);
|
||||
|
||||
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
|
||||
bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
|
@@ -82,7 +82,7 @@ DEFUN(om2k_class_inst, om2k_class_inst_cmd,
|
||||
struct oml_node_state *oms;
|
||||
int bts_nr = atoi(argv[0]);
|
||||
|
||||
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
|
||||
bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -122,7 +122,7 @@ DEFUN(om2k_classnum_inst, om2k_classnum_inst_cmd,
|
||||
struct oml_node_state *oms;
|
||||
int bts_nr = atoi(argv[0]);
|
||||
|
||||
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
|
||||
bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
|
@@ -1048,7 +1048,7 @@ static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
|
||||
int i;
|
||||
char *name = "";
|
||||
|
||||
if (lchan && lchan->conn && lchan->conn->subscr)
|
||||
if (lchan && lchan->conn)
|
||||
name = subscr_name(lchan->conn->subscr);
|
||||
|
||||
DEBUGP(DMEAS, "[%s] MEASUREMENT RESULT NR=%d ", name, mr->nr);
|
||||
@@ -1087,6 +1087,19 @@ static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
|
||||
}
|
||||
}
|
||||
|
||||
static struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct gsm_meas_rep *meas_rep;
|
||||
|
||||
meas_rep = &lchan->meas_rep[lchan->meas_rep_idx];
|
||||
memset(meas_rep, 0, sizeof(*meas_rep));
|
||||
meas_rep->lchan = lchan;
|
||||
lchan->meas_rep_idx = (lchan->meas_rep_idx + 1)
|
||||
% ARRAY_SIZE(lchan->meas_rep);
|
||||
|
||||
return meas_rep;
|
||||
}
|
||||
|
||||
static int rsl_rx_meas_res(struct msgb *msg)
|
||||
{
|
||||
struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
|
||||
|
@@ -39,7 +39,7 @@
|
||||
|
||||
#define GSM0808_T10_VALUE 6, 0
|
||||
|
||||
static LLIST_HEAD(sub_connections);
|
||||
static LLIST_HEAD(sub_connections); /* FIXME move to libmsc */
|
||||
|
||||
static void rll_ind_cb(struct gsm_lchan *, uint8_t, void *, enum bsc_rllr_ind);
|
||||
static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id);
|
||||
@@ -147,7 +147,7 @@ static void assignment_t10_timeout(void *_conn)
|
||||
conn->secondary_lchan = NULL;
|
||||
|
||||
/* inform them about the failure */
|
||||
api = conn->bts->network->bsc_api;
|
||||
api = conn->network->bsc_api;
|
||||
api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ static void handle_mr_config(struct gsm_subscriber_connection *conn,
|
||||
struct gsm_lchan *lchan, int full_rate)
|
||||
{
|
||||
struct bsc_api *api;
|
||||
api = conn->bts->network->bsc_api;
|
||||
api = conn->network->bsc_api;
|
||||
struct amr_multirate_conf *mr;
|
||||
struct gsm48_multi_rate_conf *mr_conf;
|
||||
|
||||
@@ -204,7 +204,8 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha
|
||||
|
||||
chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H;
|
||||
|
||||
new_lchan = lchan_alloc(conn->bts, chan_type, 0);
|
||||
struct gsm_bts *bts = conn->lchan->ts->trx->bts; // MSCPLIT ??
|
||||
new_lchan = lchan_alloc(bts, chan_type, 0);
|
||||
|
||||
if (!new_lchan) {
|
||||
LOGP(DMSC, LOGL_NOTICE, "No free channel.\n");
|
||||
@@ -239,24 +240,25 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
|
||||
struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn;
|
||||
struct gsm_network *network = lchan->ts->trx->bts->network;
|
||||
|
||||
conn = talloc_zero(lchan->ts->trx->bts->network, struct gsm_subscriber_connection);
|
||||
conn = talloc_zero(network, struct gsm_subscriber_connection);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
|
||||
/* Configure the time and start it so it will be closed */
|
||||
/* FIXME: above comment is weird in at least two ways */
|
||||
conn->network = network;
|
||||
conn->lchan = lchan;
|
||||
conn->bts = lchan->ts->trx->bts;
|
||||
lchan->conn = conn;
|
||||
llist_add_tail(&conn->entry, &sub_connections);
|
||||
llist_add_tail(&conn->entry, &network->subscr_conns);
|
||||
return conn;
|
||||
}
|
||||
|
||||
/* TODO: move subscriber put here... */
|
||||
void subscr_con_free(struct gsm_subscriber_connection *conn)
|
||||
void bsc_subscr_con_free(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return;
|
||||
@@ -387,7 +389,7 @@ static int chan_compat_with_mode(struct gsm_lchan *lchan, int chan_mode, int ful
|
||||
int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate)
|
||||
{
|
||||
struct bsc_api *api;
|
||||
api = conn->bts->network->bsc_api;
|
||||
api = conn->network->bsc_api;
|
||||
|
||||
if (!chan_compat_with_mode(conn->lchan, chan_mode, full_rate)) {
|
||||
if (handle_new_assignment(conn, chan_mode, full_rate) != 0)
|
||||
@@ -424,7 +426,7 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
|
||||
struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
struct bsc_api *api = conn->bts->network->bsc_api;
|
||||
struct bsc_api *api = conn->network->bsc_api;
|
||||
|
||||
if (conn->secondary_lchan != msg->lchan) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Assignment Compl should occur on second lchan.\n");
|
||||
@@ -439,8 +441,13 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
|
||||
}
|
||||
|
||||
/* switch TRAU muxer for E1 based BTS from one channel to another */
|
||||
#if BEFORE_MSCSPLIT
|
||||
if (is_e1_bts(conn->bts))
|
||||
switch_trau_mux(conn->lchan, conn->secondary_lchan);
|
||||
#else
|
||||
if (is_e1_bts(conn->lchan->ts->trx->bts))
|
||||
switch_trau_mux(conn->lchan, conn->secondary_lchan);
|
||||
#endif
|
||||
|
||||
/* swap channels */
|
||||
osmo_timer_del(&conn->T10);
|
||||
@@ -449,7 +456,7 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
|
||||
conn->lchan = conn->secondary_lchan;
|
||||
conn->secondary_lchan = NULL;
|
||||
|
||||
if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
|
||||
if (is_ipaccess_bts(conn->lchan->ts->trx->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
|
||||
rsl_ipacc_crcx(conn->lchan);
|
||||
|
||||
api->assign_compl(conn, gh->data[0],
|
||||
@@ -461,7 +468,7 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
|
||||
static void handle_ass_fail(struct gsm_subscriber_connection *conn,
|
||||
struct msgb *msg)
|
||||
{
|
||||
struct bsc_api *api = conn->bts->network->bsc_api;
|
||||
struct bsc_api *api = conn->network->bsc_api;
|
||||
uint8_t *rr_failure;
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
@@ -656,7 +663,8 @@ static void dispatch_dtap(struct gsm_subscriber_connection *conn,
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief RSL has received a DATA INDICATION with L3 from MS */
|
||||
/*! \brief RSL has received a DATA INDICATION with L3 from MS.
|
||||
* (for Iu-CS see gsm0408_rcvmsg_iucs()) */
|
||||
int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
|
||||
{
|
||||
int rc;
|
||||
@@ -678,7 +686,7 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
|
||||
} else {
|
||||
/* allocate a new connection */
|
||||
rc = BSC_API_CONN_POL_REJECT;
|
||||
lchan->conn = subscr_con_allocate(msg->lchan);
|
||||
lchan->conn = bsc_subscr_con_allocate(msg->lchan);
|
||||
if (!lchan->conn) {
|
||||
lchan_release(lchan, 1, RSL_REL_NORMAL);
|
||||
return -1;
|
||||
@@ -689,7 +697,7 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
|
||||
|
||||
if (rc != BSC_API_CONN_POL_ACCEPT) {
|
||||
lchan->conn->lchan = NULL;
|
||||
subscr_con_free(lchan->conn);
|
||||
bsc_subscr_con_free(lchan->conn);
|
||||
lchan_release(lchan, 1, RSL_REL_NORMAL);
|
||||
}
|
||||
}
|
||||
@@ -737,7 +745,6 @@ int gsm0808_clear(struct gsm_subscriber_connection *conn)
|
||||
conn->lchan = NULL;
|
||||
conn->secondary_lchan = NULL;
|
||||
conn->ho_lchan = NULL;
|
||||
conn->bts = NULL;
|
||||
|
||||
osmo_timer_del(&conn->T10);
|
||||
|
||||
@@ -751,7 +758,7 @@ static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
api = conn->bts->network->bsc_api;
|
||||
api = conn->network->bsc_api;
|
||||
if (!api || !api->sapi_n_reject)
|
||||
return;
|
||||
|
||||
@@ -848,7 +855,7 @@ static void handle_release(struct gsm_subscriber_connection *conn,
|
||||
gsm0808_clear(conn);
|
||||
|
||||
if (destruct)
|
||||
subscr_con_free(conn);
|
||||
bsc_subscr_con_free(conn);
|
||||
}
|
||||
|
||||
static void handle_chan_ack(struct gsm_subscriber_connection *conn,
|
||||
@@ -877,7 +884,3 @@ static __attribute__((constructor)) void on_dso_load_bsc(void)
|
||||
osmo_signal_register_handler(SS_LCHAN, bsc_handle_lchan_signal, NULL);
|
||||
}
|
||||
|
||||
struct llist_head *bsc_api_sub_connections(struct gsm_network *net)
|
||||
{
|
||||
return &sub_connections;
|
||||
}
|
||||
|
@@ -476,24 +476,24 @@ static int bootstrap_bts(struct gsm_bts *bts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *),
|
||||
const char *config_file)
|
||||
int bsc_network_init(mncc_recv_cb_t mncc_recv)
|
||||
{
|
||||
struct telnet_connection dummy_conn;
|
||||
struct gsm_bts *bts;
|
||||
int rc;
|
||||
|
||||
/* initialize our data structures */
|
||||
bsc_gsmnet = gsm_network_init(1, 1, mncc_recv);
|
||||
bsc_gsmnet = gsm_network_init(tall_bsc_ctx, 1, 1, mncc_recv);
|
||||
if (!bsc_gsmnet)
|
||||
return -ENOMEM;
|
||||
|
||||
bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC");
|
||||
bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC");
|
||||
|
||||
/* our vty command code expects vty->priv to point to a telnet_connection */
|
||||
dummy_conn.priv = bsc_gsmnet;
|
||||
rc = vty_read_config_file(config_file, &dummy_conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bsc_network_configure(const char *config_file)
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
int rc;
|
||||
|
||||
rc = vty_read_config_file(config_file, NULL);
|
||||
if (rc < 0) {
|
||||
LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file);
|
||||
return rc;
|
||||
|
@@ -53,15 +53,13 @@
|
||||
#include <openbsc/osmo_msc_data.h>
|
||||
#include <openbsc/osmo_bsc_rf.h>
|
||||
|
||||
#include <openbsc/xsc.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
|
||||
|
||||
#define NETWORK_STR "Configure the GSM network\n"
|
||||
#define CODE_CMD_STR "Code commands\n"
|
||||
#define NAME_CMD_STR "Name Commands\n"
|
||||
#define NAME_STR "Name to use\n"
|
||||
#define LCHAN_NR_STR "Logical Channel Number\n"
|
||||
|
||||
|
||||
@@ -106,12 +104,6 @@ const struct value_string bts_loc_fix_names[] = {
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
struct cmd_node net_node = {
|
||||
GSMNET_NODE,
|
||||
"%s(config-net)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
struct cmd_node bts_node = {
|
||||
BTS_NODE,
|
||||
"%s(config-net-bts)# ",
|
||||
@@ -130,21 +122,6 @@ struct cmd_node ts_node = {
|
||||
1,
|
||||
};
|
||||
|
||||
extern struct gsm_network *bsc_gsmnet;
|
||||
|
||||
struct gsm_network *gsmnet_from_vty(struct vty *v)
|
||||
{
|
||||
/* In case we read from the config file, the vty->priv cannot
|
||||
* point to a struct telnet_connection, and thus conn->priv
|
||||
* will not point to the gsm_network structure */
|
||||
#if 0
|
||||
struct telnet_connection *conn = v->priv;
|
||||
return (struct gsm_network *) conn->priv;
|
||||
#else
|
||||
return bsc_gsmnet;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dummy_config_write(struct vty *v)
|
||||
{
|
||||
return CMD_SUCCESS;
|
||||
@@ -178,57 +155,6 @@ static void dump_pchan_load_vty(struct vty *vty, char *prefix,
|
||||
}
|
||||
}
|
||||
|
||||
static void net_dump_vty(struct vty *vty, struct gsm_network *net)
|
||||
{
|
||||
struct pchan_load pl;
|
||||
|
||||
vty_out(vty, "BSC is on Country Code %u, Network Code %u "
|
||||
"and has %u BTS%s", net->country_code, net->network_code,
|
||||
net->num_bts, VTY_NEWLINE);
|
||||
vty_out(vty, " Long network name: '%s'%s",
|
||||
net->name_long, VTY_NEWLINE);
|
||||
vty_out(vty, " Short network name: '%s'%s",
|
||||
net->name_short, VTY_NEWLINE);
|
||||
vty_out(vty, " Authentication policy: %s%s",
|
||||
gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE);
|
||||
vty_out(vty, " Location updating reject cause: %u%s",
|
||||
net->reject_cause, VTY_NEWLINE);
|
||||
vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " NECI (TCH/H): %u%s", net->neci,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " Use TCH for Paging any: %d%s", net->pag_any_tch,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off",
|
||||
VTY_NEWLINE);
|
||||
network_chan_load(&pl, net);
|
||||
vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
|
||||
dump_pchan_load_vty(vty, " ", &pl);
|
||||
|
||||
/* show rf */
|
||||
if (net->bsc_data)
|
||||
vty_out(vty, " Last RF Command: %s%s",
|
||||
net->bsc_data->rf_ctrl->last_state_command,
|
||||
VTY_NEWLINE);
|
||||
if (net->bsc_data)
|
||||
vty_out(vty, " Last RF Lock Command: %s%s",
|
||||
net->bsc_data->rf_ctrl->last_rf_lock_ctrl_command,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_net, show_net_cmd, "show network",
|
||||
SHOW_STR "Display information about a GSM NETWORK\n")
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
net_dump_vty(vty, net);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l)
|
||||
{
|
||||
struct e1inp_line *line;
|
||||
@@ -550,14 +476,6 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
|
||||
vty_out(vty, " location_area_code %u%s", bts->location_area_code,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
|
||||
if (bts->tz.override != 0) {
|
||||
if (bts->tz.dst)
|
||||
vty_out(vty, " timezone %d %d %d%s",
|
||||
bts->tz.hr, bts->tz.mn, bts->tz.dst, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " timezone %d %d%s",
|
||||
bts->tz.hr, bts->tz.mn, VTY_NEWLINE);
|
||||
}
|
||||
vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
|
||||
vty_out(vty, " cell reselection hysteresis %u%s",
|
||||
bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
|
||||
@@ -591,13 +509,6 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
|
||||
(sp->penalty_time*20)+20, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
/* Is periodic LU enabled or disabled? */
|
||||
if (bts->si_common.chan_desc.t3212 == 0)
|
||||
vty_out(vty, " no periodic location update%s", VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " periodic location update %u%s",
|
||||
bts->si_common.chan_desc.t3212 * 6, VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " radio-link-timeout %d%s",
|
||||
get_radio_link_timeout(&bts->si_common.cell_options),
|
||||
VTY_NEWLINE);
|
||||
@@ -766,56 +677,6 @@ static int config_write_bts(struct vty *v)
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_write_net(struct vty *vty)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
vty_out(vty, "network%s", VTY_NEWLINE);
|
||||
vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
|
||||
vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
|
||||
vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
|
||||
vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
|
||||
vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
|
||||
vty_out(vty, " location updating reject cause %u%s",
|
||||
gsmnet->reject_cause, VTY_NEWLINE);
|
||||
vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
|
||||
vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
|
||||
vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
|
||||
vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE);
|
||||
vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE);
|
||||
vty_out(vty, " handover window rxlev averaging %u%s",
|
||||
gsmnet->handover.win_rxlev_avg, VTY_NEWLINE);
|
||||
vty_out(vty, " handover window rxqual averaging %u%s",
|
||||
gsmnet->handover.win_rxqual_avg, VTY_NEWLINE);
|
||||
vty_out(vty, " handover window rxlev neighbor averaging %u%s",
|
||||
gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE);
|
||||
vty_out(vty, " handover power budget interval %u%s",
|
||||
gsmnet->handover.pwr_interval, VTY_NEWLINE);
|
||||
vty_out(vty, " handover power budget hysteresis %u%s",
|
||||
gsmnet->handover.pwr_hysteresis, VTY_NEWLINE);
|
||||
vty_out(vty, " handover maximum distance %u%s",
|
||||
gsmnet->handover.max_distance, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3107 %u%s", gsmnet->T3107, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3109 %u%s", gsmnet->T3109, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3111 %u%s", gsmnet->T3111, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3113 %u%s", gsmnet->T3113, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3115 %u%s", gsmnet->T3115, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3122 %u%s", gsmnet->T3122, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
|
||||
vty_out(vty, " dtx-used %u%s", gsmnet->dtx_enabled, VTY_NEWLINE);
|
||||
vty_out(vty, " subscriber-keep-in-ram %d%s",
|
||||
gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
|
||||
{
|
||||
vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
|
||||
@@ -1320,321 +1181,6 @@ DEFUN(show_paging_group,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net,
|
||||
cfg_net_cmd,
|
||||
"network", NETWORK_STR)
|
||||
{
|
||||
vty->index = gsmnet_from_vty(vty);
|
||||
vty->node = GSMNET_NODE;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ncc,
|
||||
cfg_net_ncc_cmd,
|
||||
"network country code <1-999>",
|
||||
"Set the GSM network country code\n"
|
||||
"Country commands\n"
|
||||
CODE_CMD_STR
|
||||
"Network Country Code to use\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->country_code = atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_mnc,
|
||||
cfg_net_mnc_cmd,
|
||||
"mobile network code <0-999>",
|
||||
"Set the GSM mobile network code\n"
|
||||
"Network Commands\n"
|
||||
CODE_CMD_STR
|
||||
"Mobile Network Code to use\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->network_code = atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_name_short,
|
||||
cfg_net_name_short_cmd,
|
||||
"short name NAME",
|
||||
"Set the short GSM network name\n" NAME_CMD_STR NAME_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
bsc_replace_string(gsmnet, &gsmnet->name_short, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_name_long,
|
||||
cfg_net_name_long_cmd,
|
||||
"long name NAME",
|
||||
"Set the long GSM network name\n" NAME_CMD_STR NAME_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
bsc_replace_string(gsmnet, &gsmnet->name_long, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_auth_policy,
|
||||
cfg_net_auth_policy_cmd,
|
||||
"auth policy (closed|accept-all|token)",
|
||||
"Authentication (not cryptographic)\n"
|
||||
"Set the GSM network authentication policy\n"
|
||||
"Require the MS to be activated in HLR\n"
|
||||
"Accept all MS, whether in HLR or not\n"
|
||||
"Use SMS-token based authentication\n")
|
||||
{
|
||||
enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->auth_policy = policy;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_reject_cause,
|
||||
cfg_net_reject_cause_cmd,
|
||||
"location updating reject cause <2-111>",
|
||||
"Set the reject cause of location updating reject\n"
|
||||
"Set the reject cause of location updating reject\n"
|
||||
"Set the reject cause of location updating reject\n"
|
||||
"Set the reject cause of location updating reject\n"
|
||||
"Cause Value as Per GSM TS 04.08\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->reject_cause = atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_encryption,
|
||||
cfg_net_encryption_cmd,
|
||||
"encryption a5 (0|1|2|3)",
|
||||
"Encryption options\n"
|
||||
"A5 encryption\n" "A5/0: No encryption\n"
|
||||
"A5/1: Encryption\n" "A5/2: Export-grade Encryption\n"
|
||||
"A5/3: 'New' Secure Encryption\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->a5_encryption= atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_neci,
|
||||
cfg_net_neci_cmd,
|
||||
"neci (0|1)",
|
||||
"New Establish Cause Indication\n"
|
||||
"Don't set the NECI bit\n" "Set the NECI bit\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->neci = atoi(argv[0]);
|
||||
gsm_net_update_ctype(gsmnet);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
|
||||
"rrlp mode (none|ms-based|ms-preferred|ass-preferred)",
|
||||
"Radio Resource Location Protocol\n"
|
||||
"Set the Radio Resource Location Protocol Mode\n"
|
||||
"Don't send RRLP request\n"
|
||||
"Request MS-based location\n"
|
||||
"Request any location, prefer MS-based\n"
|
||||
"Request any location, prefer MS-assisted\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd,
|
||||
"mm info (0|1)",
|
||||
"Mobility Management\n"
|
||||
"Send MM INFO after LOC UPD ACCEPT\n"
|
||||
"Disable\n" "Enable\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->send_mm_info = atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define HANDOVER_STR "Handover Options\n"
|
||||
|
||||
DEFUN(cfg_net_handover, cfg_net_handover_cmd,
|
||||
"handover (0|1)",
|
||||
HANDOVER_STR
|
||||
"Don't perform in-call handover\n"
|
||||
"Perform in-call handover\n")
|
||||
{
|
||||
int enable = atoi(argv[0]);
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
if (enable && ipacc_rtp_direct) {
|
||||
vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
|
||||
"is enabled by using the -P command line option%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
gsmnet->handover.active = enable;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define HO_WIN_STR HANDOVER_STR "Measurement Window\n"
|
||||
#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
|
||||
#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
|
||||
#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
|
||||
#define HO_AVG_COUNT_STR "Amount to use for Averaging\n"
|
||||
|
||||
DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
|
||||
"handover window rxlev averaging <1-10>",
|
||||
HO_WIN_RXLEV_STR
|
||||
"How many RxLev measurements are used for averaging\n"
|
||||
HO_AVG_COUNT_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
|
||||
"handover window rxqual averaging <1-10>",
|
||||
HO_WIN_RXQUAL_STR
|
||||
"How many RxQual measurements are used for averaging\n"
|
||||
HO_AVG_COUNT_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
|
||||
"handover window rxlev neighbor averaging <1-10>",
|
||||
HO_WIN_RXLEV_STR "Neighbor\n"
|
||||
"How many RxQual measurements are used for averaging\n"
|
||||
HO_AVG_COUNT_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
|
||||
"handover power budget interval <1-99>",
|
||||
HO_PBUDGET_STR
|
||||
"How often to check if we have a better cell (SACCH frames)\n"
|
||||
"Interval\n" "Number\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.pwr_interval = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
|
||||
"handover power budget hysteresis <0-999>",
|
||||
HO_PBUDGET_STR
|
||||
"How many dB does a neighbor to be stronger to become a HO candidate\n"
|
||||
"Hysteresis\n" "Number\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
|
||||
"handover maximum distance <0-9999>",
|
||||
HANDOVER_STR
|
||||
"How big is the maximum timing advance before HO is forced\n"
|
||||
"Distance\n" "Number\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.max_distance = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_pag_any_tch,
|
||||
cfg_net_pag_any_tch_cmd,
|
||||
"paging any use tch (0|1)",
|
||||
"Assign a TCH when receiving a Paging Any request\n"
|
||||
"Any Channel\n" "Use\n" "TCH\n"
|
||||
"Do not use TCH for Paging Request Any\n"
|
||||
"Do use TCH for Paging Request Any\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->pag_any_tch = atoi(argv[0]);
|
||||
gsm_net_update_ctype(gsmnet);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define DECLARE_TIMER(number, doc) \
|
||||
DEFUN(cfg_net_T##number, \
|
||||
cfg_net_T##number##_cmd, \
|
||||
"timer t" #number " <0-65535>", \
|
||||
"Configure GSM Timers\n" \
|
||||
doc "Timer Value in seconds\n") \
|
||||
{ \
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty); \
|
||||
int value = atoi(argv[0]); \
|
||||
\
|
||||
if (value < 0 || value > 65535) { \
|
||||
vty_out(vty, "Timer value %s out of range.%s", \
|
||||
argv[0], VTY_NEWLINE); \
|
||||
return CMD_WARNING; \
|
||||
} \
|
||||
\
|
||||
gsmnet->T##number = value; \
|
||||
return CMD_SUCCESS; \
|
||||
}
|
||||
|
||||
DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.\n")
|
||||
DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n")
|
||||
DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION.\n")
|
||||
DECLARE_TIMER(3107, "Currently not used.\n")
|
||||
DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout.\n")
|
||||
DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n")
|
||||
DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n")
|
||||
DECLARE_TIMER(3115, "Currently not used.\n")
|
||||
DECLARE_TIMER(3117, "Currently not used.\n")
|
||||
DECLARE_TIMER(3119, "Currently not used.\n")
|
||||
DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT\n")
|
||||
DECLARE_TIMER(3141, "Currently not used.\n")
|
||||
|
||||
DEFUN(cfg_net_dtx,
|
||||
cfg_net_dtx_cmd,
|
||||
"dtx-used (0|1)",
|
||||
"Enable the usage of DTX.\n"
|
||||
"DTX is disabled\n" "DTX is enabled\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->dtx_enabled = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_subscr_keep,
|
||||
cfg_net_subscr_keep_cmd,
|
||||
"subscriber-keep-in-ram (0|1)",
|
||||
"Keep unused subscribers in RAM.\n"
|
||||
"Delete unused subscribers\n" "Keep unused subscribers\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->subscr_group->keep_subscr = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* per-BTS configuration */
|
||||
DEFUN(cfg_bts,
|
||||
cfg_bts_cmd,
|
||||
@@ -1776,67 +1322,6 @@ DEFUN(cfg_bts_bsic,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_timezone,
|
||||
cfg_bts_timezone_cmd,
|
||||
"timezone <-19-19> (0|15|30|45)",
|
||||
"Set the Timezone Offset of this BTS\n"
|
||||
"Timezone offset (hours)\n"
|
||||
"Timezone offset (00 minutes)\n"
|
||||
"Timezone offset (15 minutes)\n"
|
||||
"Timezone offset (30 minutes)\n"
|
||||
"Timezone offset (45 minutes)\n"
|
||||
)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
int tzhr = atoi(argv[0]);
|
||||
int tzmn = atoi(argv[1]);
|
||||
|
||||
bts->tz.hr = tzhr;
|
||||
bts->tz.mn = tzmn;
|
||||
bts->tz.dst = 0;
|
||||
bts->tz.override = 1;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_timezone_dst,
|
||||
cfg_bts_timezone_dst_cmd,
|
||||
"timezone <-19-19> (0|15|30|45) <0-2>",
|
||||
"Set the Timezone Offset of this BTS\n"
|
||||
"Timezone offset (hours)\n"
|
||||
"Timezone offset (00 minutes)\n"
|
||||
"Timezone offset (15 minutes)\n"
|
||||
"Timezone offset (30 minutes)\n"
|
||||
"Timezone offset (45 minutes)\n"
|
||||
"DST offset (hours)\n"
|
||||
)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
int tzhr = atoi(argv[0]);
|
||||
int tzmn = atoi(argv[1]);
|
||||
int tzdst = atoi(argv[2]);
|
||||
|
||||
bts->tz.hr = tzhr;
|
||||
bts->tz.mn = tzmn;
|
||||
bts->tz.dst = tzdst;
|
||||
bts->tz.override = 1;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_no_timezone,
|
||||
cfg_bts_no_timezone_cmd,
|
||||
"no timezone",
|
||||
NO_STR
|
||||
"Disable BTS specific timezone\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
bts->tz.override = 0;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_unit_id,
|
||||
cfg_bts_unit_id_cmd,
|
||||
"ip.access unit_id <0-65534> <0-255>",
|
||||
@@ -2332,30 +1817,67 @@ DEFUN(cfg_bts_penalty_time_rsvd, cfg_bts_penalty_time_rsvd_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd,
|
||||
DEFUN(cfg_net_pag_any_tch,
|
||||
cfg_net_pag_any_tch_cmd,
|
||||
"paging any use tch (0|1)",
|
||||
"Assign a TCH when receiving a Paging Any request\n"
|
||||
"Any Channel\n" "Use\n" "TCH\n"
|
||||
"Do not use TCH for Paging Request Any\n"
|
||||
"Do use TCH for Paging Request Any\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->pag_any_tch = atoi(argv[0]);
|
||||
gsm_net_update_ctype(gsmnet);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_neci,
|
||||
cfg_net_neci_cmd,
|
||||
"neci (0|1)",
|
||||
"New Establish Cause Indication\n"
|
||||
"Don't set the NECI bit\n" "Set the NECI bit\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->neci = atoi(argv[0]);
|
||||
gsm_net_update_ctype(gsmnet);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_per_loc_upd, cfg_net_per_loc_upd_cmd,
|
||||
"periodic location update <6-1530>",
|
||||
"Periodic Location Updating Interval\n"
|
||||
"Periodic Location Updating Interval\n"
|
||||
"Periodic Location Updating Interval\n"
|
||||
"Periodic Location Updating Interval in Minutes\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct gsm_network *net = vty->index;
|
||||
struct gsm_bts *bts;
|
||||
|
||||
bts->si_common.chan_desc.t3212 = atoi(argv[0]) / 6;
|
||||
net->t3212 = atoi(argv[0]) / 6;
|
||||
|
||||
llist_for_each_entry(bts, &net->bts_list, list) {
|
||||
bts->si_common.chan_desc.t3212 = net->t3212;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_no_per_loc_upd, cfg_bts_no_per_loc_upd_cmd,
|
||||
DEFUN(cfg_net_no_per_loc_upd, cfg_net_no_per_loc_upd_cmd,
|
||||
"no periodic location update",
|
||||
NO_STR
|
||||
"Periodic Location Updating Interval\n"
|
||||
"Periodic Location Updating Interval\n"
|
||||
"Periodic Location Updating Interval\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct gsm_network *net = vty->index;
|
||||
struct gsm_bts *bts;
|
||||
|
||||
bts->si_common.chan_desc.t3212 = 0;
|
||||
net->t3212 = 0;
|
||||
|
||||
llist_for_each_entry(bts, &net->bts_list, list) {
|
||||
bts->si_common.chan_desc.t3212 = net->t3212;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -3776,7 +3298,7 @@ DEFUN(smscb_cmd, smscb_cmd_cmd,
|
||||
uint8_t buf[88];
|
||||
int rc;
|
||||
|
||||
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
|
||||
bts = gsm_bts_num(vty_global_gsm_network, bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -3827,7 +3349,7 @@ DEFUN(pdch_act, pdch_act_cmd,
|
||||
int ts_nr = atoi(argv[2]);
|
||||
int activate;
|
||||
|
||||
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
|
||||
bts = gsm_bts_num(vty_global_gsm_network, bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -3864,9 +3386,8 @@ DEFUN(pdch_act, pdch_act_cmd,
|
||||
}
|
||||
|
||||
extern int bsc_vty_init_extra(void);
|
||||
extern const char *openbsc_copyright;
|
||||
|
||||
int bsc_vty_init(const struct log_info *cat)
|
||||
int bsc_vty_init(const struct log_info *cat, struct gsm_network *network)
|
||||
{
|
||||
cfg_ts_pchan_cmd.string =
|
||||
vty_cmd_string_from_valstr(tall_bsc_ctx,
|
||||
@@ -3890,8 +3411,16 @@ int bsc_vty_init(const struct log_info *cat)
|
||||
"BTS Vendor/Type\n",
|
||||
"\n", "", 0);
|
||||
|
||||
logging_vty_add_cmds(cat);
|
||||
xsc_vty_init(network);
|
||||
|
||||
install_element(GSMNET_NODE, &cfg_net_neci_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_per_loc_upd_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_no_per_loc_upd_cmd);
|
||||
|
||||
gsm_net_update_ctype(network);
|
||||
|
||||
install_element_ve(&show_net_cmd);
|
||||
install_element_ve(&show_bts_cmd);
|
||||
install_element_ve(&show_trx_cmd);
|
||||
install_element_ve(&show_ts_cmd);
|
||||
@@ -3901,45 +3430,6 @@ int bsc_vty_init(const struct log_info *cat)
|
||||
install_element_ve(&show_paging_cmd);
|
||||
install_element_ve(&show_paging_group_cmd);
|
||||
|
||||
logging_vty_add_cmds(cat);
|
||||
osmo_stats_vty_add_cmds();
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_net_cmd);
|
||||
install_node(&net_node, config_write_net);
|
||||
vty_install_default(GSMNET_NODE);
|
||||
install_element(GSMNET_NODE, &cfg_net_ncc_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_mnc_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_neci_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_mm_info_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_handover_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3101_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3103_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3105_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3107_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3109_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3111_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3113_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3115_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3117_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3119_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3122_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3141_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_dtx_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
|
||||
|
||||
install_element(GSMNET_NODE, &cfg_bts_cmd);
|
||||
install_node(&bts_node, config_write_bts);
|
||||
vty_install_default(BTS_NODE);
|
||||
@@ -3953,9 +3443,6 @@ int bsc_vty_init(const struct log_info *cat)
|
||||
install_element(BTS_NODE, &cfg_bts_bsic_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rsl_ip_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_timezone_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_timezone_dst_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_no_timezone_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_nokia_site_no_loc_rel_cnf_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_nokia_site_bts_reset_timer_cnf_cmd);
|
||||
@@ -3974,8 +3461,6 @@ int bsc_vty_init(const struct log_info *cat)
|
||||
install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rach_ac_class_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_no_per_loc_upd_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_cell_bar_qualify_cmd);
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include <osmocom/abis/ipaccess.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <openbsc/ipaccess.h>
|
||||
#include <openbsc/vty.h>
|
||||
|
||||
extern struct gsm_network *bsc_gsmnet;
|
||||
|
||||
|
@@ -329,39 +329,6 @@ int lchan_release(struct gsm_lchan *lchan, int sacch_deact, enum rsl_rel_mode mo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
|
||||
struct gsm_bts_trx *trx;
|
||||
int ts_no, lchan_no;
|
||||
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
for (ts_no = 0; ts_no < 8; ++ts_no) {
|
||||
for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
|
||||
struct gsm_lchan *lchan =
|
||||
&trx->ts[ts_no].lchan[lchan_no];
|
||||
if (lchan->conn && subscr == lchan->conn->subscr)
|
||||
return lchan;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr)
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
struct gsm_network *net = subscr->group->net;
|
||||
struct gsm_lchan *lchan;
|
||||
|
||||
llist_for_each_entry(bts, &net->bts_list, list) {
|
||||
lchan = lchan_find(bts, subscr);
|
||||
if (lchan)
|
||||
return lchan->conn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
|
||||
{
|
||||
struct gsm_bts_trx *trx;
|
||||
|
@@ -258,30 +258,7 @@ int send_siemens_mrpci(struct gsm_lchan *lchan,
|
||||
return rsl_siemens_mrpci(lchan, &mrpci);
|
||||
}
|
||||
|
||||
int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
|
||||
{
|
||||
/* Check the size for the classmark */
|
||||
if (length < 1 + *classmark2_lv)
|
||||
return -1;
|
||||
|
||||
uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
|
||||
if (length < 2 + *classmark2_lv + mi_lv[0])
|
||||
return -2;
|
||||
|
||||
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
|
||||
return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
|
||||
}
|
||||
|
||||
int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
|
||||
char *mi_string, uint8_t *mi_type)
|
||||
{
|
||||
static const uint32_t classmark_offset =
|
||||
offsetof(struct gsm48_pag_resp, classmark2);
|
||||
uint8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
|
||||
return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
|
||||
mi_string, mi_type);
|
||||
}
|
||||
|
||||
/* TODO MSCSPLIT remove gsm48_handle_paging_resp() */
|
||||
int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn,
|
||||
struct msgb *msg, struct gsm_subscriber *subscr)
|
||||
{
|
||||
@@ -634,39 +611,6 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
msg = gsm48_msgb_alloc_name("GSM 04.08 SERV REJ");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
gh->proto_discr = GSM48_PDISC_MM;
|
||||
gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
|
||||
gh->data[0] = value;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *gsm48_create_loc_upd_rej(uint8_t cause)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
struct msgb *msg;
|
||||
|
||||
msg = gsm48_msgb_alloc_name("GSM 04.08 LOC UPD REJ");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
gh->proto_discr = GSM48_PDISC_MM;
|
||||
gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
|
||||
gh->data[0] = cause;
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* 9.2.5 CM service accept */
|
||||
int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* Helpers for SMS/GSM 04.11 */
|
||||
/*
|
||||
* (C) 2014 by Holger Hans Peter Freyther
|
||||
/* OpenBSC utility functions for 3GPP TS 04.80 */
|
||||
|
||||
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
@@ -19,19 +19,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/gsm_04_11.h>
|
||||
#include <openbsc/gsm_04_80.h>
|
||||
#include <openbsc/bsc_api.h>
|
||||
|
||||
uint8_t sms_next_rp_msg_ref(struct gsm_subscriber_connection *conn)
|
||||
int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text)
|
||||
{
|
||||
const uint8_t rp_msg_ref = conn->next_rp_ref;
|
||||
/*
|
||||
* This should wrap as the valid range is 0 to 255. We only
|
||||
* transfer one SMS at a time so we don't need to check if
|
||||
* the id has been already assigned.
|
||||
*/
|
||||
conn->next_rp_ref += 1;
|
||||
|
||||
return rp_msg_ref;
|
||||
struct msgb *msg = gsm0480_gen_ussdNotify(level, text);
|
||||
if (!msg)
|
||||
return -1;
|
||||
return gsm0808_submit_dtap(conn, msg, 0, 0);
|
||||
}
|
||||
|
||||
int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct msgb *msg = gsm0480_gen_releaseComplete();
|
||||
if (!msg)
|
||||
return -1;
|
||||
return gsm0808_submit_dtap(conn, msg, 0, 0);
|
||||
}
|
@@ -33,6 +33,27 @@
|
||||
#include <openbsc/handover.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
|
||||
/* Get reference to a neighbor cell on a given BCCH ARFCN */
|
||||
static struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
|
||||
uint16_t arfcn, uint8_t bsic)
|
||||
{
|
||||
struct gsm_bts *neigh;
|
||||
/* FIXME: use some better heuristics here to determine which cell
|
||||
* using this ARFCN really is closest to the target cell. For
|
||||
* now we simply assume that each ARFCN will only be used by one
|
||||
* cell */
|
||||
|
||||
llist_for_each_entry(neigh, &bts->network->bts_list, list) {
|
||||
/* FIXME: this is probably returning the same bts again!? */
|
||||
if (neigh->c0->arfcn == arfcn &&
|
||||
neigh->bsic == bsic)
|
||||
return neigh;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* issue handover to a cell identified by ARFCN and BSIC */
|
||||
static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
|
||||
uint16_t arfcn, uint8_t bsic)
|
||||
|
@@ -269,9 +269,14 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
|
||||
|
||||
osmo_timer_del(&ho->T3103);
|
||||
|
||||
#if BEFORE_MSCSPLIT
|
||||
/* switch TRAU muxer for E1 based BTS from one channel to another */
|
||||
if (is_e1_bts(new_lchan->conn->bts))
|
||||
switch_trau_mux(ho->old_lchan, new_lchan);
|
||||
#else
|
||||
if (is_e1_bts(new_lchan->ts->trx->bts))
|
||||
switch_trau_mux(ho->old_lchan, new_lchan);
|
||||
#endif
|
||||
|
||||
/* Replace the ho lchan with the primary one */
|
||||
if (ho->old_lchan != new_lchan->conn->lchan)
|
||||
|
@@ -17,96 +17,3 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/osmo_msc_data.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
|
||||
struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_code,
|
||||
int (*mncc_recv)(struct gsm_network *, struct msgb *))
|
||||
{
|
||||
struct gsm_network *net;
|
||||
|
||||
net = talloc_zero(tall_bsc_ctx, struct gsm_network);
|
||||
if (!net)
|
||||
return NULL;
|
||||
|
||||
net->bsc_data = talloc_zero(net, struct osmo_bsc_data);
|
||||
if (!net->bsc_data) {
|
||||
talloc_free(net);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
net->subscr_group = talloc_zero(net, struct gsm_subscriber_group);
|
||||
if (!net->subscr_group) {
|
||||
talloc_free(net);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Init back pointer */
|
||||
net->bsc_data->auto_off_timeout = -1;
|
||||
net->bsc_data->network = net;
|
||||
INIT_LLIST_HEAD(&net->bsc_data->mscs);
|
||||
|
||||
net->subscr_group->net = net;
|
||||
net->create_subscriber = 1;
|
||||
|
||||
net->country_code = country_code;
|
||||
net->network_code = network_code;
|
||||
net->num_bts = 0;
|
||||
net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED;
|
||||
net->T3101 = GSM_T3101_DEFAULT;
|
||||
net->T3105 = GSM_T3105_DEFAULT;
|
||||
net->T3113 = GSM_T3113_DEFAULT;
|
||||
net->T3122 = GSM_T3122_DEFAULT;
|
||||
/* FIXME: initialize all other timers! */
|
||||
|
||||
/* default set of handover parameters */
|
||||
net->handover.win_rxlev_avg = 10;
|
||||
net->handover.win_rxqual_avg = 1;
|
||||
net->handover.win_rxlev_avg_neigh = 10;
|
||||
net->handover.pwr_interval = 6;
|
||||
net->handover.pwr_hysteresis = 3;
|
||||
net->handover.max_distance = 9999;
|
||||
|
||||
INIT_LLIST_HEAD(&net->trans_list);
|
||||
INIT_LLIST_HEAD(&net->upqueue);
|
||||
INIT_LLIST_HEAD(&net->bts_list);
|
||||
|
||||
net->stats.chreq.total = osmo_counter_alloc("net.chreq.total");
|
||||
net->stats.chreq.no_channel = osmo_counter_alloc("net.chreq.no_channel");
|
||||
net->stats.handover.attempted = osmo_counter_alloc("net.handover.attempted");
|
||||
net->stats.handover.no_channel = osmo_counter_alloc("net.handover.no_channel");
|
||||
net->stats.handover.timeout = osmo_counter_alloc("net.handover.timeout");
|
||||
net->stats.handover.completed = osmo_counter_alloc("net.handover.completed");
|
||||
net->stats.handover.failed = osmo_counter_alloc("net.handover.failed");
|
||||
net->stats.loc_upd_type.attach = osmo_counter_alloc("net.loc_upd_type.attach");
|
||||
net->stats.loc_upd_type.normal = osmo_counter_alloc("net.loc_upd_type.normal");
|
||||
net->stats.loc_upd_type.periodic = osmo_counter_alloc("net.loc_upd_type.periodic");
|
||||
net->stats.loc_upd_type.detach = osmo_counter_alloc("net.imsi_detach.count");
|
||||
net->stats.loc_upd_resp.reject = osmo_counter_alloc("net.loc_upd_resp.reject");
|
||||
net->stats.loc_upd_resp.accept = osmo_counter_alloc("net.loc_upd_resp.accept");
|
||||
net->stats.paging.attempted = osmo_counter_alloc("net.paging.attempted");
|
||||
net->stats.paging.detached = osmo_counter_alloc("net.paging.detached");
|
||||
net->stats.paging.completed = osmo_counter_alloc("net.paging.completed");
|
||||
net->stats.paging.expired = osmo_counter_alloc("net.paging.expired");
|
||||
net->stats.sms.submitted = osmo_counter_alloc("net.sms.submitted");
|
||||
net->stats.sms.no_receiver = osmo_counter_alloc("net.sms.no_receiver");
|
||||
net->stats.sms.delivered = osmo_counter_alloc("net.sms.delivered");
|
||||
net->stats.sms.rp_err_mem = osmo_counter_alloc("net.sms.rp_err_mem");
|
||||
net->stats.sms.rp_err_other = osmo_counter_alloc("net.sms.rp_err_other");
|
||||
net->stats.call.mo_setup = osmo_counter_alloc("net.call.mo_setup");
|
||||
net->stats.call.mo_connect_ack = osmo_counter_alloc("net.call.mo_connect_ack");
|
||||
net->stats.call.mt_setup = osmo_counter_alloc("net.call.mt_setup");
|
||||
net->stats.call.mt_connect = osmo_counter_alloc("net.call.mt_connect");
|
||||
net->stats.chan.rf_fail = osmo_counter_alloc("net.chan.rf_fail");
|
||||
net->stats.chan.rll_err = osmo_counter_alloc("net.chan.rll_err");
|
||||
net->stats.bts.oml_fail = osmo_counter_alloc("net.bts.oml_fail");
|
||||
net->stats.bts.rsl_fail = osmo_counter_alloc("net.bts.rsl_fail");
|
||||
|
||||
net->mncc_recv = mncc_recv;
|
||||
|
||||
gsm_net_update_ctype(net);
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
|
@@ -54,6 +54,12 @@ void *tall_paging_ctx;
|
||||
|
||||
#define PAGING_TIMER 0, 500000
|
||||
|
||||
/*
|
||||
* TODO MSCSPLIT: the paging in libbsc is closely tied to MSC land in that the
|
||||
* MSC realm callback functions used to be invoked from the BSC/BTS level. So
|
||||
* this entire file needs to be rewired for use with an A interface.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Kill one paging request update the internal list...
|
||||
*/
|
||||
|
@@ -42,6 +42,7 @@ int bsc_vty_go_parent(struct vty *vty)
|
||||
vty->node = CONFIG_NODE;
|
||||
vty->index = NULL;
|
||||
break;
|
||||
#ifdef ROLE_BSC
|
||||
case BTS_NODE:
|
||||
vty->node = GSMNET_NODE;
|
||||
{
|
||||
@@ -69,6 +70,7 @@ int bsc_vty_go_parent(struct vty *vty)
|
||||
vty->index_sub = &ts->trx->description;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case OML_NODE:
|
||||
case OM2K_NODE:
|
||||
vty->node = ENABLE_NODE;
|
||||
@@ -106,7 +108,7 @@ int bsc_vty_go_parent(struct vty *vty)
|
||||
case BSC_NODE:
|
||||
case MSC_NODE:
|
||||
case MNCC_INT_NODE:
|
||||
case NITB_NODE:
|
||||
case CSCN_NODE:
|
||||
default:
|
||||
if (bsc_vty_is_config_node(vty, vty->node))
|
||||
vty->node = CONFIG_NODE;
|
||||
|
@@ -41,74 +41,74 @@ static const struct log_info_cat default_categories[] = {
|
||||
.name = "DRLL",
|
||||
.description = "A-bis Radio Link Layer (RLL)",
|
||||
.color = "\033[1;31m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DCC] = {
|
||||
.name = "DCC",
|
||||
.description = "Layer3 Call Control (CC)",
|
||||
.color = "\033[1;32m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DMM] = {
|
||||
.name = "DMM",
|
||||
.description = "Layer3 Mobility Management (MM)",
|
||||
.color = "\033[1;33m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DRR] = {
|
||||
.name = "DRR",
|
||||
.description = "Layer3 Radio Resource (RR)",
|
||||
.color = "\033[1;34m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DRSL] = {
|
||||
.name = "DRSL",
|
||||
.description = "A-bis Radio Siganlling Link (RSL)",
|
||||
.color = "\033[1;35m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DNM] = {
|
||||
.name = "DNM",
|
||||
.description = "A-bis Network Management / O&M (NM/OML)",
|
||||
.color = "\033[1;36m",
|
||||
.enabled = 1, .loglevel = LOGL_INFO,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DMNCC] = {
|
||||
.name = "DMNCC",
|
||||
.description = "MNCC API for Call Control application",
|
||||
.color = "\033[1;39m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DPAG] = {
|
||||
.name = "DPAG",
|
||||
.description = "Paging Subsystem",
|
||||
.color = "\033[1;38m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DMEAS] = {
|
||||
.name = "DMEAS",
|
||||
.description = "Radio Measurement Processing",
|
||||
.enabled = 0, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 0, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DSCCP] = {
|
||||
.name = "DSCCP",
|
||||
.description = "SCCP Protocol",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DMSC] = {
|
||||
.name = "DMSC",
|
||||
.description = "Mobile Switching Center",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DMGCP] = {
|
||||
.name = "DMGCP",
|
||||
.description = "Media Gateway Control Protocol",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DHO] = {
|
||||
.name = "DHO",
|
||||
.description = "Hand-Over",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DDB] = {
|
||||
.name = "DDB",
|
||||
@@ -118,7 +118,7 @@ static const struct log_info_cat default_categories[] = {
|
||||
[DREF] = {
|
||||
.name = "DREF",
|
||||
.description = "Reference Counting",
|
||||
.enabled = 0, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 0, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DGPRS] = {
|
||||
.name = "DGPRS",
|
||||
@@ -128,7 +128,7 @@ static const struct log_info_cat default_categories[] = {
|
||||
[DNS] = {
|
||||
.name = "DNS",
|
||||
.description = "GPRS Network Service (NS)",
|
||||
.enabled = 1, .loglevel = LOGL_INFO,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DBSSGP] = {
|
||||
.name = "DBSSGP",
|
||||
@@ -148,12 +148,12 @@ static const struct log_info_cat default_categories[] = {
|
||||
[DNAT] = {
|
||||
.name = "DNAT",
|
||||
.description = "GSM 08.08 NAT/Multiplexer",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DCTRL] = {
|
||||
.name = "DCTRL",
|
||||
.description = "Control interface",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DSMPP] = {
|
||||
.name = "DSMPP",
|
||||
@@ -165,6 +165,21 @@ static const struct log_info_cat default_categories[] = {
|
||||
.description = "BSC/NAT IMSI based filtering",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DRANAP] = {
|
||||
.name = "DRANAP",
|
||||
.description = "Radio Access Network Application Part Protocol",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DIUCS] = {
|
||||
.name = "DIUCS",
|
||||
.description = "Iu-CS Protocol",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DSUA] = {
|
||||
.name = "DSUA",
|
||||
.description = "SCCP User Adaptation Protocol",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
};
|
||||
|
||||
enum log_filter {
|
||||
|
@@ -70,25 +70,6 @@ int gsm_bts_model_register(struct gsm_bts_model *model)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get reference to a neighbor cell on a given BCCH ARFCN */
|
||||
struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
|
||||
uint16_t arfcn, uint8_t bsic)
|
||||
{
|
||||
struct gsm_bts *neigh;
|
||||
/* FIXME: use some better heuristics here to determine which cell
|
||||
* using this ARFCN really is closest to the target cell. For
|
||||
* now we simply assume that each ARFCN will only be used by one
|
||||
* cell */
|
||||
|
||||
llist_for_each_entry(neigh, &bts->network->bts_list, list) {
|
||||
if (neigh->c0->arfcn == arfcn &&
|
||||
neigh->bsic == bsic)
|
||||
return neigh;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct value_string bts_type_names[_NUM_GSM_BTS_TYPE+1] = {
|
||||
{ GSM_BTS_TYPE_UNKNOWN, "unknown" },
|
||||
{ GSM_BTS_TYPE_BS11, "bs11" },
|
||||
@@ -228,19 +209,6 @@ int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct gsm_meas_rep *meas_rep;
|
||||
|
||||
meas_rep = &lchan->meas_rep[lchan->meas_rep_idx];
|
||||
memset(meas_rep, 0, sizeof(*meas_rep));
|
||||
meas_rep->lchan = lchan;
|
||||
lchan->meas_rep_idx = (lchan->meas_rep_idx + 1)
|
||||
% ARRAY_SIZE(lchan->meas_rep);
|
||||
|
||||
return meas_rep;
|
||||
}
|
||||
|
||||
int gsm_btsmodel_set_feature(struct gsm_bts_model *bts, enum gsm_bts_features feat)
|
||||
{
|
||||
return bitvec_set_bit_pos(&bts->features, feat, 1);
|
||||
@@ -336,7 +304,7 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ
|
||||
bts->si_common.chan_desc.att = 1; /* attachment required */
|
||||
bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; /* paging frames */
|
||||
bts->si_common.chan_desc.bs_ag_blks_res = 1; /* reserved AGCH blocks */
|
||||
bts->si_common.chan_desc.t3212 = 5; /* Use 30 min periodic update interval as sane default */
|
||||
bts->si_common.chan_desc.t3212 = net->t3212; /* Use network's current value */
|
||||
set_radio_link_timeout(&bts->si_common.cell_options, 32);
|
||||
/* Use RADIO LINK TIMEOUT of 32 seconds */
|
||||
|
||||
|
@@ -43,6 +43,9 @@ struct llist_head *subscr_bsc_active_subscribers(void)
|
||||
|
||||
char *subscr_name(struct gsm_subscriber *subscr)
|
||||
{
|
||||
if (!subscr)
|
||||
return "unknown";
|
||||
|
||||
if (strlen(subscr->name))
|
||||
return subscr->name;
|
||||
|
||||
|
@@ -17,22 +17,22 @@ extern void *tall_map_ctx;
|
||||
extern void *tall_upq_ctx;
|
||||
extern void *tall_ctr_ctx;
|
||||
|
||||
void talloc_ctx_init(void)
|
||||
void talloc_ctx_init(void *ctx_root)
|
||||
{
|
||||
tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
|
||||
tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0,
|
||||
tall_msgb_ctx = talloc_named_const(ctx_root, 0, "msgb");
|
||||
tall_fle_ctx = talloc_named_const(ctx_root, 0,
|
||||
"bs11_file_list_entry");
|
||||
tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 0, "loc_updating_oper");
|
||||
tall_authciphop_ctx = talloc_named_const(tall_bsc_ctx, 0, "auth_ciph_oper");
|
||||
tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 0, "sms");
|
||||
tall_subscr_ctx = talloc_named_const(tall_bsc_ctx, 0, "subscriber");
|
||||
tall_sub_req_ctx = talloc_named_const(tall_bsc_ctx, 0, "subscr_request");
|
||||
tall_call_ctx = talloc_named_const(tall_bsc_ctx, 0, "gsm_call");
|
||||
tall_paging_ctx = talloc_named_const(tall_bsc_ctx, 0, "paging_request");
|
||||
tall_sigh_ctx = talloc_named_const(tall_bsc_ctx, 0, "signal_handler");
|
||||
tall_tqe_ctx = talloc_named_const(tall_bsc_ctx, 0, "subch_txq_entry");
|
||||
tall_trans_ctx = talloc_named_const(tall_bsc_ctx, 0, "transaction");
|
||||
tall_map_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_map_entry");
|
||||
tall_upq_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_upq_entry");
|
||||
tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
|
||||
tall_locop_ctx = talloc_named_const(ctx_root, 0, "loc_updating_oper");
|
||||
tall_authciphop_ctx = talloc_named_const(ctx_root, 0, "auth_ciph_oper");
|
||||
tall_gsms_ctx = talloc_named_const(ctx_root, 0, "sms");
|
||||
tall_subscr_ctx = talloc_named_const(ctx_root, 0, "subscriber");
|
||||
tall_sub_req_ctx = talloc_named_const(ctx_root, 0, "subscr_request");
|
||||
tall_call_ctx = talloc_named_const(ctx_root, 0, "gsm_call");
|
||||
tall_paging_ctx = talloc_named_const(ctx_root, 0, "paging_request");
|
||||
tall_sigh_ctx = talloc_named_const(ctx_root, 0, "signal_handler");
|
||||
tall_tqe_ctx = talloc_named_const(ctx_root, 0, "subch_txq_entry");
|
||||
tall_trans_ctx = talloc_named_const(ctx_root, 0, "transaction");
|
||||
tall_map_ctx = talloc_named_const(ctx_root, 0, "trau_map_entry");
|
||||
tall_upq_ctx = talloc_named_const(ctx_root, 0, "trau_upq_entry");
|
||||
tall_ctr_ctx = talloc_named_const(ctx_root, 0, "counter");
|
||||
}
|
||||
|
10
openbsc/src/libiu/Makefile.am
Normal file
10
openbsc/src/libiu/Makefile.am
Normal file
@@ -0,0 +1,10 @@
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \
|
||||
$(LIBASN1C_CFLAGS) \
|
||||
$(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS)
|
||||
|
||||
noinst_LIBRARIES = libiu.a
|
||||
|
||||
libiu_a_SOURCES = iu.c
|
||||
|
771
openbsc/src/libiu/iu.c
Normal file
771
openbsc/src/libiu/iu.c
Normal file
@@ -0,0 +1,771 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/prim.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/vty/logging.h>
|
||||
|
||||
#include <osmocom/gsm/gsm48.h>
|
||||
#include <osmocom/gprs/gprs_msgb.h>
|
||||
|
||||
#include <osmocom/sigtran/sua.h>
|
||||
#include <osmocom/sigtran/sccp_sap.h>
|
||||
#include <osmocom/sigtran/sccp_helpers.h>
|
||||
|
||||
#include <openbsc/gprs_sgsn.h>
|
||||
#include <openbsc/iu.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <pdp.h>
|
||||
|
||||
#include <osmocom/ranap/ranap_ies_defs.h>
|
||||
#include <osmocom/ranap/ranap_common.h>
|
||||
#include <osmocom/ranap/ranap_common_cn.h>
|
||||
#include <osmocom/ranap/ranap_msg_factory.h>
|
||||
|
||||
#include <asn1c/asn1helpers.h>
|
||||
|
||||
/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the
|
||||
* PLMN identity is a BCD representation of the MCC and MNC.
|
||||
* See iu_grnc_id_parse(). */
|
||||
struct iu_grnc_id {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint16_t rnc_id;
|
||||
};
|
||||
|
||||
/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has
|
||||
* called us and is currently reachable at the given osmo_sua_link. So, when we
|
||||
* know a LAC for a subscriber, we can page it at the RNC matching that LAC or
|
||||
* RAC. An HNB-GW typically presents itself as if it were a single RNC, even
|
||||
* though it may have several RNCs in hNodeBs connected to it. Those will then
|
||||
* share the same RNC id, which they actually receive and adopt from the HNB-GW
|
||||
* in the HNBAP HNB REGISTER ACCEPT message. */
|
||||
struct iu_rnc {
|
||||
struct llist_head entry;
|
||||
|
||||
uint16_t rnc_id;
|
||||
uint16_t lac; /* Location Area Code (used for CS and PS) */
|
||||
uint8_t rac; /* Routing Area Code (used for PS only) */
|
||||
struct osmo_sua_link *link;
|
||||
};
|
||||
|
||||
void *talloc_iu_ctx;
|
||||
|
||||
int asn1_xer_print = 1;
|
||||
void *talloc_asn1_ctx;
|
||||
|
||||
iu_recv_cb_t global_iu_recv_cb = NULL;
|
||||
iu_event_cb_t global_iu_event_cb = NULL;
|
||||
|
||||
static LLIST_HEAD(ue_conn_ctx_list);
|
||||
static LLIST_HEAD(rnc_list);
|
||||
|
||||
const struct value_string iu_event_type_names[] = {
|
||||
#define IU_EVT_STR(X) { X, #X }
|
||||
IU_EVT_STR(IU_EVENT_RAB_ASSIGN),
|
||||
IU_EVT_STR(IU_EVENT_SECURITY_MODE_COMPLETE),
|
||||
IU_EVT_STR(IU_EVENT_IU_RELEASE),
|
||||
IU_EVT_STR(IU_EVENT_LINK_INVALIDATED),
|
||||
#undef IU_EVT_STR
|
||||
};
|
||||
|
||||
struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sua_link *link, uint32_t conn_id)
|
||||
{
|
||||
struct ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ue_conn_ctx);
|
||||
|
||||
ctx->link = link;
|
||||
ctx->conn_id = conn_id;
|
||||
llist_add(&ctx->list, &ue_conn_ctx_list);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sua_link *link,
|
||||
uint32_t conn_id)
|
||||
{
|
||||
struct ue_conn_ctx *ctx;
|
||||
|
||||
llist_for_each_entry(ctx, &ue_conn_ctx_list, list) {
|
||||
if (ctx->link == link && ctx->conn_id == conn_id)
|
||||
return ctx;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac,
|
||||
struct osmo_sua_link *link)
|
||||
{
|
||||
struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc);
|
||||
|
||||
rnc->rnc_id = rnc_id;
|
||||
rnc->lac = lac;
|
||||
rnc->rac = rac;
|
||||
rnc->link = link;
|
||||
llist_add(&rnc->entry, &rnc_list);
|
||||
|
||||
LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n",
|
||||
rnc->rnc_id, rnc->lac, rnc->rac);
|
||||
|
||||
return rnc;
|
||||
}
|
||||
|
||||
static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac,
|
||||
uint8_t rac, struct osmo_sua_link *link)
|
||||
{
|
||||
struct iu_rnc *rnc;
|
||||
llist_for_each_entry(rnc, &rnc_list, entry) {
|
||||
if (rnc->rnc_id != rnc_id)
|
||||
continue;
|
||||
|
||||
/* We have this RNC Id registered already. Make sure that the
|
||||
* details match. */
|
||||
|
||||
/* TODO should a mismatch be an error? */
|
||||
if (rnc->lac != lac || rnc->rac != rac)
|
||||
LOGP(DRANAP, LOGL_NOTICE, "RNC %d changes its details:"
|
||||
" LAC=%d RAC=%d --> LAC=%d RAC=%d\n",
|
||||
rnc->rnc_id, rnc->lac, rnc->rac,
|
||||
lac, rac);
|
||||
rnc->lac = lac;
|
||||
rnc->rac = rac;
|
||||
|
||||
if (link && rnc->link != link)
|
||||
LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link"
|
||||
" (LAC=%d RAC=%d)\n",
|
||||
rnc->rnc_id, rnc->lac, rnc->rac);
|
||||
rnc->link = link;
|
||||
return rnc;
|
||||
}
|
||||
|
||||
/* Not found, make a new one. */
|
||||
return iu_rnc_alloc(rnc_id, lac, rac, link);
|
||||
}
|
||||
|
||||
/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the
|
||||
* given link, since this link is invalid and about to be deallocated. For
|
||||
* each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED.
|
||||
*/
|
||||
void iu_link_del(struct osmo_sua_link *link)
|
||||
{
|
||||
struct iu_rnc *rnc, *rnc_next;
|
||||
llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) {
|
||||
if (!rnc->link)
|
||||
continue;
|
||||
if (rnc->link != link)
|
||||
continue;
|
||||
rnc->link = NULL;
|
||||
llist_del(&rnc->entry);
|
||||
talloc_free(rnc);
|
||||
}
|
||||
|
||||
struct ue_conn_ctx *uec, *uec_next;
|
||||
llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) {
|
||||
if (uec->link != link)
|
||||
continue;
|
||||
uec->link = NULL;
|
||||
global_iu_event_cb(uec, IU_EVENT_LINK_INVALIDATED, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* RANAP handling
|
||||
***********************************************************************/
|
||||
|
||||
static int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg)
|
||||
{
|
||||
struct osmo_scu_prim *prim;
|
||||
|
||||
/* wrap RANAP message in SCCP N-DATA.req */
|
||||
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
|
||||
prim->u.data.conn_id = ue_ctx->conn_id;
|
||||
osmo_prim_init(&prim->oph,
|
||||
SCCP_SAP_USER,
|
||||
OSMO_SCU_PRIM_N_DATA,
|
||||
PRIM_OP_REQUEST,
|
||||
msg);
|
||||
return osmo_sua_user_link_down(ue_ctx->link, &prim->oph);
|
||||
}
|
||||
|
||||
int iu_rab_act_cs(struct ue_conn_ctx *ue_ctx, uint32_t rtp_ip, uint16_t rtp_port)
|
||||
{
|
||||
struct msgb *msg;
|
||||
|
||||
/* FIXME: Generate unique RAB ID per UE */
|
||||
msg = ranap_new_msg_rab_assign_voice(1, rtp_ip, rtp_port);
|
||||
msg->l2h = msg->data;
|
||||
return iu_rab_act(ue_ctx, msg);
|
||||
}
|
||||
|
||||
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct sgsn_mm_ctx *mm = pdp->mm;
|
||||
struct ue_conn_ctx *uectx;
|
||||
uint32_t ggsn_ip;
|
||||
|
||||
uectx = mm->iu.ue_ctx;
|
||||
|
||||
/* Get the IP address for ggsn user plane */
|
||||
memcpy(&ggsn_ip, pdp->lib->gsnru.v, pdp->lib->gsnru.l);
|
||||
ggsn_ip = htonl(ggsn_ip);
|
||||
|
||||
LOGP(DRANAP, LOGL_DEBUG, "Assigning RAB: rab_id=%d, ggsn_ip=%x,"
|
||||
" teid_gn=%x, use_x213_nsap=%d\n",
|
||||
rab_id, ggsn_ip, pdp->lib->teid_gn, use_x213_nsap);
|
||||
|
||||
msg = ranap_new_msg_rab_assign_data(rab_id, ggsn_ip,
|
||||
pdp->lib->teid_gn, use_x213_nsap);
|
||||
msg->l2h = msg->data;
|
||||
return iu_rab_act(uectx, msg);
|
||||
}
|
||||
|
||||
int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id)
|
||||
{
|
||||
/* FIXME */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp,
|
||||
int send_ck, int new_key)
|
||||
{
|
||||
struct osmo_scu_prim *prim;
|
||||
struct msgb *msg;
|
||||
uint8_t ik[16];
|
||||
uint8_t ck[16];
|
||||
unsigned int i;
|
||||
|
||||
/* C5 function to derive IK from Kc */
|
||||
for (i = 0; i < 4; i++)
|
||||
ik[i] = tp->vec.kc[i] ^ tp->vec.kc[i+4];
|
||||
memcpy(ik+4, tp->vec.kc, 8);
|
||||
for (i = 12; i < 16; i++)
|
||||
ik[i] = ik[i-12];
|
||||
|
||||
if (send_ck) {
|
||||
/* C4 function to derive CK from Kc */
|
||||
memcpy(ck, tp->vec.kc, 8);
|
||||
memcpy(ck+8, tp->vec.kc, 8);
|
||||
}
|
||||
|
||||
/* create RANAP message */
|
||||
msg = ranap_new_msg_sec_mod_cmd(ik, send_ck? ck : NULL, new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old);
|
||||
msg->l2h = msg->data;
|
||||
/* wrap RANAP message in SCCP N-DATA.req */
|
||||
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
|
||||
prim->u.data.conn_id = uectx->conn_id;
|
||||
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
|
||||
OSMO_SCU_PRIM_N_DATA,
|
||||
PRIM_OP_REQUEST, msg);
|
||||
osmo_sua_user_link_down(uectx->link, &prim->oph);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iu_grnc_id_parse(struct iu_grnc_id *dst,
|
||||
struct RANAP_GlobalRNC_ID *src)
|
||||
{
|
||||
/* The size is coming from arbitrary sender, check it gracefully */
|
||||
if (src->pLMNidentity.size != 3) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "Invalid PLMN Identity size:"
|
||||
" should be 3, is %d\n", src->pLMNidentity.size);
|
||||
return -1;
|
||||
}
|
||||
gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0],
|
||||
&dst->mcc, &dst->mnc);
|
||||
dst->rnc_id = (uint16_t)src->rNC_ID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
-- not used at present --
|
||||
static int iu_grnc_id_compose(struct iu_grnc_id *src,
|
||||
struct RANAP_GlobalRNC_ID *dst)
|
||||
{
|
||||
/* The caller must ensure proper size */
|
||||
OSMO_ASSERT(dst->pLMNidentity.size == 3);
|
||||
gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0],
|
||||
src->mcc, src->mnc);
|
||||
dst->rNC_ID = src->rnc_id;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies)
|
||||
{
|
||||
struct ue_conn_ctx *ue_conn = ctx;
|
||||
struct gprs_ra_id ra_id;
|
||||
struct iu_grnc_id grnc_id;
|
||||
uint16_t sai;
|
||||
struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
|
||||
|
||||
if (ranap_parse_lai(&ra_id, &ies->lai) != 0) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) {
|
||||
ra_id.rac = asn1str_to_u8(&ies->rac);
|
||||
}
|
||||
|
||||
if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) {
|
||||
LOGP(DRANAP, LOGL_ERROR,
|
||||
"Failed to parse RANAP Global-RNC-ID IE\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sai = asn1str_to_u16(&ies->sai.sAC);
|
||||
msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
|
||||
memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
|
||||
|
||||
/* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */
|
||||
iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link);
|
||||
ue_conn->ra_id = ra_id;
|
||||
|
||||
/* Feed into the MM layer */
|
||||
msg->dst = ctx;
|
||||
global_iu_recv_cb(msg, &ra_id, &sai);
|
||||
|
||||
msgb_free(msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies)
|
||||
{
|
||||
struct gprs_ra_id _ra_id, *ra_id = NULL;
|
||||
uint16_t _sai, *sai = NULL;
|
||||
struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
|
||||
|
||||
if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) {
|
||||
if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
|
||||
return -1;
|
||||
}
|
||||
ra_id = &_ra_id;
|
||||
if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) {
|
||||
_ra_id.rac = asn1str_to_u8(&ies->rac);
|
||||
}
|
||||
if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) {
|
||||
_sai = asn1str_to_u16(&ies->sai.sAC);
|
||||
sai = &_sai;
|
||||
}
|
||||
}
|
||||
|
||||
msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
|
||||
memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
|
||||
|
||||
/* Feed into the MM/CC/SMS-CP layer */
|
||||
msg->dst = ctx;
|
||||
global_iu_recv_cb(msg, ra_id, sai);
|
||||
|
||||
msgb_free(msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies)
|
||||
{
|
||||
if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT)
|
||||
LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n",
|
||||
ranap_cause_str(&ies->cause));
|
||||
else
|
||||
LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iu_tx(struct msgb *msg_nas, uint8_t sapi)
|
||||
{
|
||||
struct ue_conn_ctx *uectx = msg_nas->dst;
|
||||
struct msgb *msg;
|
||||
struct osmo_scu_prim *prim;
|
||||
|
||||
LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SUA link %p conn_id %u)\n",
|
||||
uectx->link, uectx->conn_id);
|
||||
|
||||
msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas));
|
||||
msgb_free(msg_nas);
|
||||
msg->l2h = msg->data;
|
||||
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
|
||||
prim->u.data.conn_id = uectx->conn_id;
|
||||
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
|
||||
OSMO_SCU_PRIM_N_DATA,
|
||||
PRIM_OP_REQUEST, msg);
|
||||
osmo_sua_user_link_down(uectx->link, &prim->oph);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ranap_handle_co_iu_rel_req(struct ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmo_scu_prim *prim;
|
||||
|
||||
LOGP(DRANAP, LOGL_INFO, "Received Iu Release Request, Sending Release Command\n");
|
||||
msg = ranap_new_msg_iu_rel_cmd(&ies->cause);
|
||||
msg->l2h = msg->data;
|
||||
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
|
||||
prim->u.data.conn_id = ctx->conn_id;
|
||||
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
|
||||
OSMO_SCU_PRIM_N_DATA,
|
||||
PRIM_OP_REQUEST, msg);
|
||||
osmo_sua_user_link_down(ctx->link, &prim->oph);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ranap_handle_co_rab_ass_resp(struct ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
LOGP(DRANAP, LOGL_INFO, "RAB Asignment Response:");
|
||||
if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) {
|
||||
/* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */
|
||||
RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0];
|
||||
RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies;
|
||||
|
||||
rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value);
|
||||
if (rc) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = global_iu_event_cb(ctx, IU_EVENT_RAB_ASSIGN, &setup_ies);
|
||||
|
||||
ranap_free_rab_setupormodifieditemies(&setup_ies);
|
||||
}
|
||||
|
||||
LOGPC(DRANAP, LOGL_INFO, "\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Entry point for connection-oriented RANAP message */
|
||||
static void cn_ranap_handle_co(void *ctx, ranap_message *message)
|
||||
{
|
||||
int rc;
|
||||
|
||||
LOGP(DRANAP, LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode);
|
||||
|
||||
switch (message->direction) {
|
||||
case RANAP_RANAP_PDU_PR_initiatingMessage:
|
||||
switch (message->procedureCode) {
|
||||
case RANAP_ProcedureCode_id_InitialUE_Message:
|
||||
rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs);
|
||||
break;
|
||||
case RANAP_ProcedureCode_id_DirectTransfer:
|
||||
rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs);
|
||||
break;
|
||||
case RANAP_ProcedureCode_id_ErrorIndication:
|
||||
rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs);
|
||||
break;
|
||||
case RANAP_ProcedureCode_id_Iu_ReleaseRequest:
|
||||
/* Iu Release Request */
|
||||
rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs);
|
||||
break;
|
||||
default:
|
||||
LOGP(DRANAP, LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n",
|
||||
message->procedureCode);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RANAP_RANAP_PDU_PR_successfulOutcome:
|
||||
switch (message->procedureCode) {
|
||||
case RANAP_ProcedureCode_id_SecurityModeControl:
|
||||
/* Security Mode Complete */
|
||||
rc = global_iu_event_cb(ctx, IU_EVENT_SECURITY_MODE_COMPLETE, NULL);
|
||||
break;
|
||||
case RANAP_ProcedureCode_id_Iu_Release:
|
||||
/* Iu Release Complete */
|
||||
rc = global_iu_event_cb(ctx, IU_EVENT_IU_RELEASE, NULL);
|
||||
if (rc) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n",
|
||||
rc);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGP(DRANAP, LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n",
|
||||
message->procedureCode);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RANAP_RANAP_PDU_PR_outcome:
|
||||
switch (message->procedureCode) {
|
||||
case RANAP_ProcedureCode_id_RAB_Assignment:
|
||||
/* RAB Assignment Response */
|
||||
rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs);
|
||||
break;
|
||||
default:
|
||||
LOGP(DRANAP, LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n",
|
||||
message->procedureCode);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
|
||||
default:
|
||||
LOGP(DRANAP, LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n",
|
||||
message->procedureCode);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_co (%d)\n",
|
||||
rc);
|
||||
/* TODO handling of the error? */
|
||||
}
|
||||
}
|
||||
|
||||
static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies)
|
||||
{
|
||||
/* FIXME: send reset response */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies)
|
||||
{
|
||||
if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT)
|
||||
LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n",
|
||||
ranap_cause_str(&ies->cause));
|
||||
else
|
||||
LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Entry point for connection-less RANAP message */
|
||||
static void cn_ranap_handle_cl(void *ctx, ranap_message *message)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (message->direction) {
|
||||
case RANAP_RANAP_PDU_PR_initiatingMessage:
|
||||
switch (message->procedureCode) {
|
||||
case RANAP_ProcedureCode_id_Reset:
|
||||
/* received reset.req, send reset.resp */
|
||||
rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs);
|
||||
break;
|
||||
case RANAP_ProcedureCode_id_ErrorIndication:
|
||||
rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs);
|
||||
break;
|
||||
default:
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RANAP_RANAP_PDU_PR_successfulOutcome:
|
||||
case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
|
||||
case RANAP_RANAP_PDU_PR_outcome:
|
||||
default:
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_cl (%d)\n",
|
||||
rc);
|
||||
/* TODO handling of the error? */
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Paging
|
||||
***********************************************************************/
|
||||
|
||||
/* Send a paging command down a given SUA link. tmsi and paging_cause are
|
||||
* optional and may be passed NULL and 0, respectively, to disable their use.
|
||||
* See enum RANAP_PagingCause.
|
||||
*
|
||||
* If TMSI is given, the IMSI is not sent over the air interface. Nevertheless,
|
||||
* the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */
|
||||
static int iu_tx_paging_cmd(struct osmo_sua_link *link,
|
||||
const char *imsi, const uint32_t *tmsi,
|
||||
bool is_ps, uint32_t paging_cause)
|
||||
{
|
||||
struct msgb *msg;
|
||||
msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause);
|
||||
msg->l2h = msg->data;
|
||||
return osmo_sccp_tx_unitdata_ranap(link, 1, 2, msg->data,
|
||||
msgb_length(msg));
|
||||
}
|
||||
|
||||
static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi,
|
||||
uint16_t lac, uint8_t rac, bool is_ps)
|
||||
{
|
||||
struct iu_rnc *rnc;
|
||||
int pagings_sent = 0;
|
||||
|
||||
if (tmsi_or_ptimsi) {
|
||||
LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s"
|
||||
" (paging will use %s %x)\n",
|
||||
is_ps? "IuPS" : "IuCS",
|
||||
imsi,
|
||||
is_ps? "PTMSI" : "TMSI",
|
||||
*tmsi_or_ptimsi);
|
||||
} else {
|
||||
LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s"
|
||||
" (paging will use IMSI)\n",
|
||||
is_ps? "IuPS" : "IuCS",
|
||||
imsi
|
||||
);
|
||||
}
|
||||
|
||||
llist_for_each_entry(rnc, &rnc_list, entry) {
|
||||
if (!rnc->link) {
|
||||
/* Not actually connected, don't count it. */
|
||||
continue;
|
||||
}
|
||||
if (rnc->lac != lac)
|
||||
continue;
|
||||
if (is_ps && rnc->rac != rac)
|
||||
continue;
|
||||
|
||||
/* Found a match! */
|
||||
if (iu_tx_paging_cmd(rnc->link, imsi, tmsi_or_ptimsi, is_ps, 0)
|
||||
== 0) {
|
||||
LOGP(DRANAP, LOGL_DEBUG,
|
||||
"%s: Paged for IMSI %s on RNC %d, on SUA link %p\n",
|
||||
is_ps? "IuPS" : "IuCS",
|
||||
imsi, rnc->rnc_id, rnc->link);
|
||||
pagings_sent ++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Some logging... */
|
||||
if (pagings_sent > 0) {
|
||||
LOGP(DRANAP, LOGL_DEBUG,
|
||||
"%s: %d RNCs were paged for IMSI %s.\n",
|
||||
is_ps? "IuPS" : "IuCS",
|
||||
pagings_sent, imsi);
|
||||
}
|
||||
else {
|
||||
if (is_ps) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "IuPS: Found no RNC to page for"
|
||||
" LAC %d RAC %d (would have paged IMSI %s)\n",
|
||||
lac, rac, imsi);
|
||||
}
|
||||
else {
|
||||
LOGP(DRANAP, LOGL_ERROR, "IuCS: Found no RNC to page for"
|
||||
" LAC %d (would have paged IMSI %s)\n",
|
||||
lac, imsi);
|
||||
}
|
||||
}
|
||||
|
||||
return pagings_sent;
|
||||
}
|
||||
|
||||
int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac)
|
||||
{
|
||||
return iu_page(imsi, tmsi, lac, 0, false);
|
||||
}
|
||||
|
||||
int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac)
|
||||
{
|
||||
return iu_page(imsi, ptmsi, lac, rac, true);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
int tx_unitdata(struct osmo_sua_link *link);
|
||||
int tx_conn_req(struct osmo_sua_link *link, uint32_t conn_id);
|
||||
|
||||
struct osmo_prim_hdr *make_conn_req(uint32_t conn_id);
|
||||
struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len);
|
||||
|
||||
struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc(1024, "conn_resp");
|
||||
struct osmo_scu_prim *prim;
|
||||
|
||||
prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim));
|
||||
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
|
||||
OSMO_SCU_PRIM_N_CONNECT,
|
||||
PRIM_OP_RESPONSE, msg);
|
||||
memcpy(&prim->u.connect, param, sizeof(prim->u.connect));
|
||||
return &prim->oph;
|
||||
}
|
||||
|
||||
static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link)
|
||||
{
|
||||
struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;
|
||||
struct osmo_prim_hdr *resp = NULL;
|
||||
int rc;
|
||||
struct ue_conn_ctx *ue;
|
||||
|
||||
printf("sccp_sap_up(%s)\n", osmo_scu_prim_name(oph));
|
||||
|
||||
switch (OSMO_PRIM_HDR(oph)) {
|
||||
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
|
||||
/* confirmation of outbound connection */
|
||||
rc = -1;
|
||||
break;
|
||||
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):
|
||||
/* indication of new inbound connection request*/
|
||||
printf("N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id);
|
||||
if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */
|
||||
!msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) {
|
||||
LOGP(DGPRS, LOGL_NOTICE, "Received invalid N-CONNECT.ind\n");
|
||||
return 0;
|
||||
}
|
||||
ue = ue_conn_ctx_alloc(link, prim->u.connect.conn_id);
|
||||
/* first ensure the local SUA/SCCP socket is ACTIVE */
|
||||
resp = make_conn_resp(&prim->u.connect);
|
||||
osmo_sua_user_link_down(link, resp);
|
||||
/* then handle the RANAP payload */
|
||||
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
|
||||
break;
|
||||
case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
|
||||
/* indication of disconnect */
|
||||
printf("N-DISCONNECT.ind(%u)\n", prim->u.disconnect.conn_id);
|
||||
ue = ue_conn_ctx_find(link, prim->u.disconnect.conn_id);
|
||||
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
|
||||
break;
|
||||
case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
|
||||
/* connection-oriented data received */
|
||||
printf("N-DATA.ind(%u, %s)\n", prim->u.data.conn_id,
|
||||
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
|
||||
/* resolve UE context */
|
||||
ue = ue_conn_ctx_find(link, prim->u.data.conn_id);
|
||||
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
|
||||
break;
|
||||
case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
|
||||
/* connection-less data received */
|
||||
printf("N-UNITDATA.ind(%s)\n",
|
||||
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
|
||||
rc = ranap_cn_rx_cl(cn_ranap_handle_cl, link, msgb_l2(oph->msg), msgb_l2len(oph->msg));
|
||||
break;
|
||||
default:
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
msgb_free(oph->msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port,
|
||||
iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb)
|
||||
{
|
||||
struct osmo_sua_user *user;
|
||||
talloc_iu_ctx = talloc_named_const(ctx, 1, "iu");
|
||||
talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1");
|
||||
|
||||
global_iu_recv_cb = iu_recv_cb;
|
||||
global_iu_event_cb = iu_event_cb;
|
||||
osmo_sua_set_log_area(DSUA);
|
||||
user = osmo_sua_user_create(talloc_iu_ctx, sccp_sap_up, talloc_iu_ctx);
|
||||
return osmo_sua_server_listen(user, listen_addr, listen_port);
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) \
|
||||
-DCOMPILING_LIBMSC=1
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBSMPP34_CFLAGS)
|
||||
|
||||
@@ -8,7 +9,7 @@ noinst_LIBRARIES = libmsc.a
|
||||
|
||||
libmsc_a_SOURCES = auth.c \
|
||||
db.c \
|
||||
gsm_04_08.c gsm_04_11.c gsm_04_11_helper.c \
|
||||
gsm_04_08.c gsm_04_11.c \
|
||||
gsm_04_80.c \
|
||||
gsm_subscriber.c \
|
||||
mncc.c mncc_builtin.c mncc_sock.c \
|
||||
@@ -18,8 +19,11 @@ libmsc_a_SOURCES = auth.c \
|
||||
token_auth.c \
|
||||
ussd.c \
|
||||
vty_interface_layer3.c \
|
||||
cscn_vty.c \
|
||||
transaction.c \
|
||||
osmo_msc.c ctrl_commands.c meas_feed.c
|
||||
osmo_msc.c ctrl_commands.c meas_feed.c \
|
||||
msc_api.c msc_ifaces.c iu_cs.c \
|
||||
a_iface.c
|
||||
|
||||
if BUILD_SMPP
|
||||
noinst_HEADERS += smpp_smsc.h
|
||||
|
77
openbsc/src/libmsc/a_iface.c
Normal file
77
openbsc/src/libmsc/a_iface.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/* A-interface implementation, from MSC to BSC */
|
||||
|
||||
/* (C) 2016 by sysmocom s.m.f.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/msgb.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/msc_ifaces.h>
|
||||
|
||||
int a_tx(struct msgb *msg)
|
||||
{
|
||||
LOGP(DMSC, LOGL_ERROR, "message to be sent to BSC, but A-interface"
|
||||
" not implemented.\n%s\n", osmo_hexdump(msg->data, msg->len));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
|
||||
const uint8_t *key, int len, int include_imeisv)
|
||||
{
|
||||
/* TODO generalize for A- and Iu interfaces, don't name after 08.08 */
|
||||
LOGP(DMSC, LOGL_ERROR, "gsm0808_cipher_mode(): message to be sent to"
|
||||
" BSC, but A interface not yet implemented.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* from gsm_04_08_utils.c *****/
|
||||
|
||||
/* 9.2.5 CM service accept */
|
||||
int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC");
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
|
||||
gh->proto_discr = GSM48_PDISC_MM;
|
||||
gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
|
||||
|
||||
DEBUGP(DMM, "-> CM SERVICE ACCEPT\n");
|
||||
|
||||
return msc_tx_dtap(conn, msg);
|
||||
}
|
||||
|
||||
/* 9.2.6 CM service reject */
|
||||
int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
|
||||
enum gsm48_reject_value value)
|
||||
{
|
||||
struct msgb *msg;
|
||||
|
||||
msg = gsm48_create_mm_serv_rej(value);
|
||||
if (!msg) {
|
||||
LOGP(DMM, LOGL_ERROR, "Failed to allocate CM Service Reject.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
|
||||
|
||||
return msc_tx_dtap(conn, msg);
|
||||
}
|
@@ -91,8 +91,6 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
/* Get subscriber info (if any) */
|
||||
rc = db_get_authinfo_for_subscr(&ainfo, subscr);
|
||||
if (rc < 0) {
|
||||
LOGP(DMM, LOGL_NOTICE,
|
||||
"No retrievable Ki for subscriber, skipping auth\n");
|
||||
return rc == -ENOENT ? AUTH_NOT_AVAIL : AUTH_ERROR;
|
||||
}
|
||||
|
||||
@@ -134,11 +132,13 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
|
||||
case AUTH_ALGO_XOR:
|
||||
if (_use_xor(&ainfo, atuple))
|
||||
/* non-zero return value means failure */
|
||||
return AUTH_NOT_AVAIL;
|
||||
break;
|
||||
|
||||
case AUTH_ALGO_COMP128v1:
|
||||
if (_use_comp128_v1(&ainfo, atuple))
|
||||
/* non-zero return value means failure */
|
||||
return AUTH_NOT_AVAIL;
|
||||
break;
|
||||
|
||||
|
100
openbsc/src/libmsc/cscn_vty.c
Normal file
100
openbsc/src/libmsc/cscn_vty.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/* MSC interface to quagga VTY */
|
||||
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
|
||||
* Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
|
||||
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2009-2011 by Holger Hans Peter Freyther
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* NOTE: I would have liked to call this the MSC_NODE instead of the CSCN_NODE,
|
||||
* but MSC_NODE already exists to configure a remote MSC for osmo-bsc. */
|
||||
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <openbsc/vty.h>
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
|
||||
static struct cmd_node cscn_node = {
|
||||
CSCN_NODE,
|
||||
"%s(config-cscn)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(cfg_cscn, cfg_cscn_cmd,
|
||||
"cscn", "Configure CSCN options")
|
||||
{
|
||||
vty->node = CSCN_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_cscn_subscr_create, cfg_cscn_subscr_create_cmd,
|
||||
"subscriber-create-on-demand",
|
||||
"Make a new record when a subscriber is first seen.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->create_subscriber = 1;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_cscn_no_subscr_create, cfg_cscn_no_subscr_create_cmd,
|
||||
"no subscriber-create-on-demand",
|
||||
NO_STR "Make a new record when a subscriber is first seen.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->create_subscriber = 0;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_cscn_assign_tmsi, cfg_cscn_assign_tmsi_cmd,
|
||||
"assign-tmsi",
|
||||
"Assign TMSI during Location Updating.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->avoid_tmsi = 0;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_cscn_no_assign_tmsi, cfg_cscn_no_assign_tmsi_cmd,
|
||||
"no assign-tmsi",
|
||||
NO_STR "Assign TMSI during Location Updating.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->avoid_tmsi = 1;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_write_cscn(struct vty *vty)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
vty_out(vty, "cscn%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %ssubscriber-create-on-demand%s",
|
||||
gsmnet->create_subscriber ? "" : "no ", VTY_NEWLINE);
|
||||
vty_out(vty, " %sassign-tmsi%s",
|
||||
gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void cscn_vty_init(void)
|
||||
{
|
||||
install_element(CONFIG_NODE, &cfg_cscn_cmd);
|
||||
install_node(&cscn_node, config_write_cscn);
|
||||
install_element(CSCN_NODE, &cfg_cscn_subscr_create_cmd);
|
||||
install_element(CSCN_NODE, &cfg_cscn_no_subscr_create_cmd);
|
||||
install_element(CSCN_NODE, &cfg_cscn_assign_tmsi_cmd);
|
||||
install_element(CSCN_NODE, &cfg_cscn_no_assign_tmsi_cmd);
|
||||
}
|
@@ -891,7 +891,7 @@ struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
|
||||
subscr->id = dbi_result_get_ulonglong(result, "id");
|
||||
|
||||
db_set_from_query(subscr, result);
|
||||
DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n",
|
||||
DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %x, EXTEN '%s', LAC %hu, AUTH %u\n",
|
||||
subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
|
||||
subscr->lac, subscr->authorized);
|
||||
dbi_result_free(result);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -53,7 +53,7 @@
|
||||
#include <openbsc/paging.h>
|
||||
#include <openbsc/bsc_rll.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <openbsc/bsc_api.h>
|
||||
#include <openbsc/msc_ifaces.h>
|
||||
|
||||
#ifdef BUILD_SMPP
|
||||
#include "smpp_smsc.h"
|
||||
@@ -124,7 +124,7 @@ static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *m
|
||||
{
|
||||
DEBUGP(DLSMS, "GSM4.11 TX %s\n", osmo_hexdump(msg->data, msg->len));
|
||||
msg->l3h = msg->data;
|
||||
return gsm0808_submit_dtap(conn, msg, UM_SAPI_SMS, 1);
|
||||
return msc_tx_dtap(conn, msg);
|
||||
}
|
||||
|
||||
/* Prefix msg with a 04.08/04.11 CP header */
|
||||
@@ -304,7 +304,7 @@ try_local:
|
||||
#endif
|
||||
|
||||
/* determine gsms->receiver based on dialled number */
|
||||
gsms->receiver = subscr_get_by_extension(conn->bts->network->subscr_group,
|
||||
gsms->receiver = subscr_get_by_extension(conn->network->subscr_group,
|
||||
gsms->dst.addr);
|
||||
if (!gsms->receiver) {
|
||||
#ifdef BUILD_SMPP
|
||||
@@ -315,14 +315,14 @@ try_local:
|
||||
rc = smpp_try_deliver(gsms, conn);
|
||||
if (rc == 1) {
|
||||
rc = 1; /* cause 1: unknown subscriber */
|
||||
osmo_counter_inc(conn->bts->network->stats.sms.no_receiver);
|
||||
osmo_counter_inc(conn->network->stats.sms.no_receiver);
|
||||
} else if (rc < 0) {
|
||||
rc = 21; /* cause 21: short message transfer rejected */
|
||||
/* FIXME: handle the error somehow? */
|
||||
}
|
||||
#else
|
||||
rc = 1; /* cause 1: unknown subscriber */
|
||||
osmo_counter_inc(conn->bts->network->stats.sms.no_receiver);
|
||||
osmo_counter_inc(conn->network->stats.sms.no_receiver);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
@@ -363,7 +363,7 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
|
||||
uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
|
||||
int rc = 0;
|
||||
|
||||
osmo_counter_inc(conn->bts->network->stats.sms.submitted);
|
||||
osmo_counter_inc(conn->network->stats.sms.submitted);
|
||||
|
||||
gsms = sms_alloc();
|
||||
if (!gsms)
|
||||
@@ -605,7 +605,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
|
||||
static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
|
||||
struct gsm411_rp_hdr *rph)
|
||||
{
|
||||
struct gsm_network *net = trans->conn->bts->network;
|
||||
struct gsm_network *net = trans->conn->network;
|
||||
struct gsm_sms *sms = trans->sms.sms;
|
||||
uint8_t cause_len = rph->data[0];
|
||||
uint8_t cause = rph->data[1];
|
||||
@@ -805,7 +805,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
|
||||
|
||||
if (!trans) {
|
||||
DEBUGP(DLSMS, " -> (new transaction)\n");
|
||||
trans = trans_alloc(conn->bts->network, conn->subscr,
|
||||
trans = trans_alloc(conn->network, conn->subscr,
|
||||
GSM48_PDISC_SMS,
|
||||
transaction_id, new_callref++);
|
||||
if (!trans) {
|
||||
@@ -855,19 +855,19 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
|
||||
}
|
||||
|
||||
/* Take a SMS in gsm_sms structure and send it through an already
|
||||
* existing lchan. We also assume that the caller ensured this lchan already
|
||||
* existing conn. We also assume that the caller ensured this conn already
|
||||
* has a SAPI3 RLL connection! */
|
||||
int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
|
||||
{
|
||||
struct msgb *msg = gsm411_msgb_alloc();
|
||||
struct gsm_trans *trans;
|
||||
uint8_t *data, *rp_ud_len;
|
||||
uint8_t msg_ref = sms_next_rp_msg_ref(conn);
|
||||
uint8_t msg_ref = sms_next_rp_msg_ref(&conn->next_rp_ref);
|
||||
int transaction_id;
|
||||
int rc;
|
||||
|
||||
transaction_id =
|
||||
trans_assign_trans_id(conn->bts->network, conn->subscr,
|
||||
trans_assign_trans_id(conn->network, conn->subscr,
|
||||
GSM48_PDISC_SMS, 0);
|
||||
if (transaction_id == -1) {
|
||||
LOGP(DLSMS, LOGL_ERROR, "No available transaction ids\n");
|
||||
@@ -877,10 +877,10 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
DEBUGP(DLSMS, "send_sms_lchan()\n");
|
||||
DEBUGP(DLSMS, "gsm411_send_sms()\n");
|
||||
|
||||
/* FIXME: allocate transaction with message reference */
|
||||
trans = trans_alloc(conn->bts->network, conn->subscr,
|
||||
trans = trans_alloc(conn->network, conn->subscr,
|
||||
GSM48_PDISC_SMS,
|
||||
transaction_id, new_callref++);
|
||||
if (!trans) {
|
||||
@@ -932,7 +932,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
|
||||
|
||||
DEBUGP(DLSMS, "TX: SMS DELIVER\n");
|
||||
|
||||
osmo_counter_inc(conn->bts->network->stats.sms.delivered);
|
||||
osmo_counter_inc(conn->network->stats.sms.delivered);
|
||||
db_sms_inc_deliver_attempts(trans->sms.sms);
|
||||
|
||||
return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg,
|
||||
@@ -981,16 +981,19 @@ int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
|
||||
struct gsm_subscriber_connection *conn;
|
||||
void *res;
|
||||
|
||||
/* check if we already have an open lchan to the subscriber.
|
||||
/* check if we already have an open conn to the subscriber.
|
||||
* if yes, send the SMS this way */
|
||||
conn = connection_for_subscr(subscr);
|
||||
if (conn) {
|
||||
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS via already open connection %p to %s\n",
|
||||
conn, subscr_name(subscr));
|
||||
return gsm411_send_sms(conn, sms);
|
||||
}
|
||||
|
||||
/* if not, we have to start paging */
|
||||
res = subscr_request_channel(subscr, RSL_CHANNEED_SDCCH,
|
||||
paging_cb_send_sms, sms);
|
||||
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n",
|
||||
subscr_name(subscr));
|
||||
res = subscr_request_conn(subscr, paging_cb_send_sms, sms);
|
||||
if (!res) {
|
||||
send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY);
|
||||
sms_free(sms);
|
||||
@@ -1022,7 +1025,7 @@ void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn)
|
||||
struct gsm_network *net;
|
||||
struct gsm_trans *trans, *tmp;
|
||||
|
||||
net = conn->bts->network;
|
||||
net = conn->network;
|
||||
|
||||
llist_for_each_entry_safe(trans, tmp, &net->trans_list, entry) {
|
||||
struct gsm_sms *sms;
|
||||
|
@@ -32,7 +32,7 @@
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/gsm_04_80.h>
|
||||
#include <openbsc/bsc_api.h>
|
||||
#include <openbsc/msc_ifaces.h>
|
||||
|
||||
#include <osmocom/gsm/gsm0480.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
@@ -106,7 +106,7 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
|
||||
| (1<<7); /* TI direction = 1 */
|
||||
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
|
||||
|
||||
return gsm0808_submit_dtap(conn, msg, 0, 0);
|
||||
return msc_tx_dtap(conn, msg);
|
||||
}
|
||||
|
||||
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
|
||||
@@ -135,41 +135,21 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
|
||||
gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */
|
||||
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
|
||||
|
||||
return gsm0808_submit_dtap(conn, msg, 0, 0);
|
||||
return msc_tx_dtap(conn, msg);
|
||||
}
|
||||
|
||||
int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
struct msgb *msg;
|
||||
|
||||
msg = gsm0480_create_unstructuredSS_Notify(level, text);
|
||||
struct msgb *msg = gsm0480_gen_ussdNotify(level, text);
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
gsm0480_wrap_invoke(msg, GSM0480_OP_CODE_USS_NOTIFY, 0);
|
||||
gsm0480_wrap_facility(msg);
|
||||
|
||||
/* And finally pre-pend the L3 header */
|
||||
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_NC_SS;
|
||||
gh->msg_type = GSM0480_MTYPE_REGISTER;
|
||||
|
||||
return gsm0808_submit_dtap(conn, msg, 0, 0);
|
||||
return msc_tx_dtap(conn, msg);
|
||||
}
|
||||
|
||||
int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
struct msgb *msg;
|
||||
|
||||
msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REL COMPL");
|
||||
struct msgb *msg = gsm0480_gen_releaseComplete();
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_NC_SS;
|
||||
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
|
||||
|
||||
return gsm0808_submit_dtap(conn, msg, 0, 0);
|
||||
return msc_tx_dtap(conn, msg);
|
||||
}
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <openbsc/iu.h>
|
||||
|
||||
void *tall_sub_req_ctx;
|
||||
|
||||
@@ -47,20 +48,6 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
|
||||
gsm_cbfn *cb, void *cb_data);
|
||||
|
||||
|
||||
/*
|
||||
* Struct for pending channel requests. This is managed in the
|
||||
* llist_head requests of each subscriber. The reference counting
|
||||
* should work in such a way that a subscriber with a pending request
|
||||
* remains in memory.
|
||||
*/
|
||||
struct subscr_request {
|
||||
struct llist_head entry;
|
||||
|
||||
/* the callback data */
|
||||
gsm_cbfn *cbfn;
|
||||
void *param;
|
||||
};
|
||||
|
||||
static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
|
||||
int type, const char *ident)
|
||||
{
|
||||
@@ -70,31 +57,32 @@ static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
|
||||
return subscr;
|
||||
}
|
||||
|
||||
/*
|
||||
* We got the channel assigned and can now hand this channel
|
||||
* over to one of our callbacks.
|
||||
*/
|
||||
/* A connection is established and the paging callbacks may run now. */
|
||||
static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
|
||||
struct msgb *msg, void *data, void *param)
|
||||
struct msgb *msg, void *data, void *param)
|
||||
{
|
||||
struct subscr_request *request, *tmp;
|
||||
struct gsm_subscriber_connection *conn = data;
|
||||
struct gsm_subscriber *subscr = param;
|
||||
struct paging_signal_data sig_data;
|
||||
|
||||
OSMO_ASSERT(subscr->is_paging);
|
||||
OSMO_ASSERT(hooknum == GSM_HOOK_RR_PAGING);
|
||||
OSMO_ASSERT(subscr);
|
||||
OSMO_ASSERT(!(conn && (conn->subscr != subscr)));
|
||||
OSMO_ASSERT(!((event == GSM_PAGING_SUCCEEDED) && !conn));
|
||||
|
||||
/*
|
||||
* Stop paging on all other BTS. E.g. if this is
|
||||
* the first timeout on a BTS then the others will
|
||||
* timeout soon as well. Let's just stop everything
|
||||
* and forget we wanted to page.
|
||||
*/
|
||||
paging_request_stop(NULL, subscr, NULL, NULL);
|
||||
LOGP(DPAG, LOGL_DEBUG, "Paging %s for %s (event=%d)\n",
|
||||
event == GSM_PAGING_SUCCEEDED ? "success" : "failure",
|
||||
subscr_name(subscr), event);
|
||||
|
||||
if (!subscr->is_paging) {
|
||||
LOGP(DPAG, LOGL_NOTICE,
|
||||
"Paging Response received for subscriber"
|
||||
" that is not paging.\n");
|
||||
}
|
||||
|
||||
/* Inform parts of the system we don't know */
|
||||
sig_data.subscr = subscr;
|
||||
sig_data.bts = conn ? conn->bts : NULL;
|
||||
sig_data.conn = conn;
|
||||
sig_data.paging_result = event;
|
||||
osmo_signal_dispatch(
|
||||
@@ -106,83 +94,143 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
|
||||
|
||||
llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) {
|
||||
llist_del(&request->entry);
|
||||
request->cbfn(hooknum, event, msg, data, request->param);
|
||||
if (request->cbfn) {
|
||||
LOGP(DPAG, LOGL_DEBUG, "Calling paging cbfn.\n");
|
||||
request->cbfn(hooknum, event, msg, data, request->param);
|
||||
} else
|
||||
LOGP(DPAG, LOGL_DEBUG, "Paging without action.\n");
|
||||
talloc_free(request);
|
||||
}
|
||||
|
||||
/* balanced with the moment we start paging */
|
||||
subscr->is_paging = 0;
|
||||
|
||||
/* balanced with the moment we receive a paging response */
|
||||
subscr_put(subscr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void paging_timeout_release(struct gsm_subscriber *subscr)
|
||||
{
|
||||
DEBUGP(DPAG, "Paging timeout released for %s\n", subscr_name(subscr));
|
||||
osmo_timer_del(&subscr->paging_timeout);
|
||||
}
|
||||
|
||||
static void paging_timeout(void *data)
|
||||
{
|
||||
struct gsm_subscriber *subscr = data;
|
||||
DEBUGP(DPAG, "Paging timeout reached for %s\n", subscr_name(subscr));
|
||||
paging_timeout_release(subscr);
|
||||
subscr_paging_dispatch(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
|
||||
NULL, NULL, subscr);
|
||||
}
|
||||
|
||||
static void paging_timeout_start(struct gsm_subscriber *subscr)
|
||||
{
|
||||
DEBUGP(DPAG, "Starting paging timeout for %s\n", subscr_name(subscr));
|
||||
subscr->paging_timeout.data = subscr;
|
||||
subscr->paging_timeout.cb = paging_timeout;
|
||||
osmo_timer_schedule(&subscr->paging_timeout, 10, 0);
|
||||
/* TODO: configurable timeout duration? */
|
||||
}
|
||||
|
||||
|
||||
static int subscr_paging_sec_cb(unsigned int hooknum, unsigned int event,
|
||||
struct msgb *msg, void *data, void *param)
|
||||
{
|
||||
int rc;
|
||||
struct gsm_subscriber_connection *conn = data;
|
||||
OSMO_ASSERT(conn);
|
||||
|
||||
switch (event) {
|
||||
case GSM_SECURITY_AUTH_FAILED:
|
||||
/* Dispatch as paging failure */
|
||||
LOGP(DPAG, LOGL_ERROR,
|
||||
"Dropping Paging Response:"
|
||||
" authorization failed for subscriber %s\n",
|
||||
subscr_name(conn->subscr));
|
||||
rc = subscr_paging_dispatch(
|
||||
GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
|
||||
msg, data, param);
|
||||
msg, conn, conn->subscr);
|
||||
break;
|
||||
|
||||
case GSM_SECURITY_NOAVAIL:
|
||||
case GSM_SECURITY_SUCCEEDED:
|
||||
/* Dispatch as paging failure */
|
||||
rc = subscr_paging_dispatch(
|
||||
GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
|
||||
msg, data, param);
|
||||
msg, conn, conn->subscr);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGP(DPAG, LOGL_FATAL,
|
||||
"Invalid authorization event: %d\n", event);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
|
||||
struct msgb *msg, void *data, void *param)
|
||||
int subscr_rx_paging_response(struct msgb *msg,
|
||||
struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn = data;
|
||||
struct gsm48_hdr *gh;
|
||||
struct gsm48_pag_resp *pr;
|
||||
|
||||
/* Other cases mean problem, dispatch direclty */
|
||||
if (event != GSM_PAGING_SUCCEEDED)
|
||||
return subscr_paging_dispatch(hooknum, event, msg, data, param);
|
||||
|
||||
/* Get paging response */
|
||||
/* Get key_seq from Paging Response headers */
|
||||
gh = msgb_l3(msg);
|
||||
pr = (struct gsm48_pag_resp *)gh->data;
|
||||
|
||||
/* We _really_ have a channel, secure it now ! */
|
||||
return gsm48_secure_channel(conn, pr->key_seq, subscr_paging_sec_cb, param);
|
||||
paging_timeout_release(conn->subscr);
|
||||
|
||||
/* Secure the connection */
|
||||
if (subscr_authorized(conn->subscr))
|
||||
return gsm48_secure_channel(conn, pr->key_seq,
|
||||
subscr_paging_sec_cb, NULL);
|
||||
|
||||
/* Not authorized. Failure. */
|
||||
subscr_paging_sec_cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED,
|
||||
msg, conn, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
|
||||
int channel_type, gsm_cbfn *cbfn, void *param)
|
||||
static int msc_paging_request(struct gsm_subscriber *subscr)
|
||||
{
|
||||
/* The subscriber was last seen in subscr->lac. Find out which
|
||||
* BSCs/RNCs are responsible and send them a paging request via open
|
||||
* SCCP connections (if any). */
|
||||
/* TODO Implementing only RNC paging, since this is code on the iu branch.
|
||||
* Need to add BSC paging at some point. */
|
||||
return iu_page_cs(subscr->imsi,
|
||||
subscr->tmsi == GSM_RESERVED_TMSI?
|
||||
NULL : &subscr->tmsi,
|
||||
subscr->lac);
|
||||
}
|
||||
|
||||
struct subscr_request *subscr_request_conn(struct gsm_subscriber *subscr,
|
||||
gsm_cbfn *cbfn, void *param)
|
||||
{
|
||||
int rc;
|
||||
struct subscr_request *request;
|
||||
|
||||
/* Start paging.. we know it is async so we can do it before */
|
||||
if (!subscr->is_paging) {
|
||||
LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
|
||||
LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet, start paging.\n",
|
||||
subscr_name(subscr));
|
||||
rc = paging_request(subscr->group->net, subscr, channel_type,
|
||||
subscr_paging_cb, subscr);
|
||||
rc = msc_paging_request(subscr);
|
||||
if (rc <= 0) {
|
||||
LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
|
||||
subscr_name(subscr), rc);
|
||||
return NULL;
|
||||
}
|
||||
/* reduced on the first paging callback */
|
||||
/* reduced in subscr_rx_paging_response() */
|
||||
subscr_get(subscr);
|
||||
subscr->is_paging = 1;
|
||||
LOGP(DMM, LOGL_DEBUG, "Paged subscriber %s.\n",
|
||||
subscr_name(subscr));
|
||||
paging_timeout_start(subscr);
|
||||
}
|
||||
else {
|
||||
LOGP(DMM, LOGL_DEBUG, "Subscriber %s already paged.\n",
|
||||
subscr_name(subscr));
|
||||
}
|
||||
|
||||
/* TODO: Stop paging in case of memory allocation failure */
|
||||
@@ -268,7 +316,7 @@ struct gsm_subscriber *subscr_get_by_id(struct gsm_subscriber_group *sgrp,
|
||||
return get_subscriber(sgrp, GSM_SUBSCRIBER_ID, buf);
|
||||
}
|
||||
|
||||
int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts)
|
||||
int subscr_update_expire_lu(struct gsm_network *network, struct gsm_subscriber *s)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -279,27 +327,27 @@ int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts)
|
||||
* Timeout is twice the t3212 value plus one minute */
|
||||
|
||||
/* Is expiration handling enabled? */
|
||||
if (bts->si_common.chan_desc.t3212 == 0)
|
||||
if (network->t3212 == 0)
|
||||
s->expire_lu = GSM_SUBSCRIBER_NO_EXPIRATION;
|
||||
else
|
||||
s->expire_lu = time(NULL) +
|
||||
(bts->si_common.chan_desc.t3212 * 60 * 6 * 2) + 60;
|
||||
s->expire_lu = time(NULL) + (network->t3212 * 60 * 6 * 2) + 60;
|
||||
|
||||
rc = db_sync_subscriber(s);
|
||||
db_subscriber_update(s);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
|
||||
int subscr_update(struct gsm_network *network, struct gsm_subscriber *s,
|
||||
uint16_t lac, int reason)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* FIXME: Migrate pending requests from one BSC to another */
|
||||
switch (reason) {
|
||||
case GSM_SUBSCRIBER_UPDATE_ATTACHED:
|
||||
s->group = bts->network->subscr_group;
|
||||
s->group = network->subscr_group;
|
||||
/* Indicate "attached to LAC" */
|
||||
s->lac = bts->location_area_code;
|
||||
s->lac = lac;
|
||||
|
||||
LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n",
|
||||
subscr_name(s), s->lac);
|
||||
@@ -308,12 +356,12 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
|
||||
* The below will set a new expire_lu but as a side-effect
|
||||
* the new lac will be saved in the database.
|
||||
*/
|
||||
rc = subscr_update_expire_lu(s, bts);
|
||||
rc = subscr_update_expire_lu(network, s);
|
||||
osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_ATTACHED, s);
|
||||
break;
|
||||
case GSM_SUBSCRIBER_UPDATE_DETACHED:
|
||||
/* Only detach if we are currently in this area */
|
||||
if (bts->location_area_code == s->lac)
|
||||
if (lac == s->lac)
|
||||
s->lac = GSM_LAC_RESERVED_DETACHED;
|
||||
LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", subscr_name(s));
|
||||
rc = db_sync_subscriber(s);
|
||||
@@ -352,7 +400,7 @@ static void subscr_expire_callback(void *data, long long unsigned int id)
|
||||
if (conn && conn->expire_timer_stopped) {
|
||||
LOGP(DMM, LOGL_DEBUG, "Not expiring subscriber %s (ID %llu)\n",
|
||||
subscr_name(s), id);
|
||||
subscr_update_expire_lu(s, conn->bts);
|
||||
subscr_update_expire_lu(conn->network, s);
|
||||
subscr_put(s);
|
||||
return;
|
||||
}
|
||||
@@ -370,3 +418,30 @@ void subscr_expire(struct gsm_subscriber_group *sgrp)
|
||||
{
|
||||
db_subscriber_expire(sgrp->net, subscr_expire_callback);
|
||||
}
|
||||
|
||||
bool subscr_authorized(struct gsm_subscriber *subscriber)
|
||||
{
|
||||
switch (subscriber->group->net->auth_policy) {
|
||||
case GSM_AUTH_POLICY_CLOSED:
|
||||
LOGP(DMM, LOGL_DEBUG, "subscriber %s authorized = %d\n",
|
||||
subscr_name(subscriber), subscriber->authorized);
|
||||
return subscriber->authorized ? true : false;
|
||||
case GSM_AUTH_POLICY_TOKEN:
|
||||
if (subscriber->authorized) {
|
||||
LOGP(DMM, LOGL_DEBUG,
|
||||
"subscriber %s authorized = %d\n",
|
||||
subscr_name(subscriber), subscriber->authorized);
|
||||
return subscriber->authorized;
|
||||
}
|
||||
LOGP(DMM, LOGL_DEBUG, "subscriber %s first contact = %d\n",
|
||||
subscr_name(subscriber),
|
||||
(int)(subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT));
|
||||
return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT);
|
||||
case GSM_AUTH_POLICY_ACCEPT_ALL:
|
||||
return true;
|
||||
default:
|
||||
LOGP(DMM, LOGL_DEBUG, "unknown auth_policy, rejecting"
|
||||
" subscriber %s\n", subscr_name(subscriber));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
173
openbsc/src/libmsc/iu_cs.c
Normal file
173
openbsc/src/libmsc/iu_cs.c
Normal file
@@ -0,0 +1,173 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/msc_api.h>
|
||||
#include <openbsc/iu.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
|
||||
/* For A-interface see libbsc/bsc_api.c subscr_con_allocate() */
|
||||
static struct gsm_subscriber_connection *subscr_conn_allocate_iu(struct gsm_network *network,
|
||||
struct ue_conn_ctx *ue,
|
||||
uint16_t lac)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
DEBUGP(DIUCS, "Allocating IuCS subscriber conn: lac %d, link_id %p, conn_id %" PRIx32 "\n",
|
||||
lac, ue->link, ue->conn_id);
|
||||
|
||||
conn = talloc_zero(network, struct gsm_subscriber_connection);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
|
||||
conn->network = network;
|
||||
conn->via_iface = IFACE_IU;
|
||||
conn->iu.ue_ctx = ue;
|
||||
conn->lac = lac;
|
||||
|
||||
llist_add_tail(&conn->entry, &network->subscr_conns);
|
||||
return conn;
|
||||
}
|
||||
|
||||
static int same_ue_conn(struct ue_conn_ctx *a, struct ue_conn_ctx *b)
|
||||
{
|
||||
if (a == b)
|
||||
return 1;
|
||||
return (a->link == b->link)
|
||||
&& (a->conn_id == b->conn_id);
|
||||
}
|
||||
|
||||
static inline void log_subscribers(struct gsm_network *network)
|
||||
{
|
||||
if (!log_check_level(DIUCS, LOGL_DEBUG))
|
||||
return;
|
||||
|
||||
struct gsm_subscriber_connection *conn;
|
||||
int i = 0;
|
||||
llist_for_each_entry(conn, &network->subscr_conns, entry) {
|
||||
DEBUGP(DIUCS, "%3d: %s", i, subscr_name(conn->subscr));
|
||||
switch (conn->via_iface) {
|
||||
case IFACE_IU:
|
||||
DEBUGPC(DIUCS, " Iu");
|
||||
if (conn->iu.ue_ctx) {
|
||||
DEBUGPC(DIUCS, " link %p, conn_id %d",
|
||||
conn->iu.ue_ctx->link,
|
||||
conn->iu.ue_ctx->conn_id
|
||||
);
|
||||
}
|
||||
break;
|
||||
case IFACE_A:
|
||||
DEBUGPC(DIUCS, " A");
|
||||
/* TODO log A-interface connection details */
|
||||
break;
|
||||
case IFACE_UNKNOWN:
|
||||
DEBUGPC(DIUCS, " ?");
|
||||
break;
|
||||
default:
|
||||
DEBUGPC(DIUCS, " invalid");
|
||||
break;
|
||||
}
|
||||
DEBUGPC(DIUCS, "\n");
|
||||
i++;
|
||||
}
|
||||
DEBUGP(DIUCS, "subscribers registered: %d\n", i);
|
||||
}
|
||||
|
||||
/* Return an existing IuCS subscriber connection record for the given link and
|
||||
* connection IDs, or return NULL if not found. */
|
||||
struct gsm_subscriber_connection *subscr_conn_lookup_iu(
|
||||
struct gsm_network *network,
|
||||
struct ue_conn_ctx *ue)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
DEBUGP(DIUCS, "Looking for IuCS subscriber: link_id %p, conn_id %" PRIx32 "\n",
|
||||
ue->link, ue->conn_id);
|
||||
log_subscribers(network);
|
||||
|
||||
llist_for_each_entry(conn, &network->subscr_conns, entry) {
|
||||
if (conn->via_iface != IFACE_IU)
|
||||
continue;
|
||||
if (!same_ue_conn(conn->iu.ue_ctx, ue))
|
||||
continue;
|
||||
DEBUGP(DIUCS, "Found IuCS subscriber for link_id %p, conn_id %" PRIx32 "\n",
|
||||
ue->link, ue->conn_id);
|
||||
return conn;
|
||||
}
|
||||
DEBUGP(DIUCS, "No IuCS subscriber found for link_id %p, conn_id %" PRIx32 "\n",
|
||||
ue->link, ue->conn_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Receive MM/CC/... message from IuCS (SCCP user SAP).
|
||||
* msg->dst must reference a struct ue_conn_ctx, which identifies the peer that
|
||||
* sent the msg.
|
||||
*
|
||||
* For A-interface see libbsc/bsc_api.c gsm0408_rcvmsg(). */
|
||||
int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
|
||||
uint16_t *lac)
|
||||
{
|
||||
int rc;
|
||||
struct ue_conn_ctx *ue_ctx;
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
ue_ctx = (struct ue_conn_ctx*)msg->dst;
|
||||
|
||||
/* TODO: are there message types that could allow us to skip this
|
||||
* search? */
|
||||
conn = subscr_conn_lookup_iu(network, ue_ctx);
|
||||
|
||||
if (conn && lac && (conn->lac != *lac)) {
|
||||
LOGP(DIUCS, LOGL_ERROR, "IuCS subscriber has changed LAC"
|
||||
" within the same connection, discarding connection:"
|
||||
" %s from LAC %d to %d\n",
|
||||
subscr_name(conn->subscr), conn->lac, *lac);
|
||||
/* Deallocate conn with previous LAC */
|
||||
gsm0408_clear_request(conn, 0);
|
||||
/* At this point we could be tolerant and allocate a new
|
||||
* connection, but changing the LAC within the same connection
|
||||
* is shifty. Rather cancel everything. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn) {
|
||||
/* if we already have a connection, handle DTAP.
|
||||
gsm0408_dispatch() is aka msc_dtap() */
|
||||
|
||||
/* Make sure we don't receive RR over IuCS; otherwise all
|
||||
* messages handled by gsm0408_dispatch() are of interest (CC,
|
||||
* MM, SMS, NS_SS, maybe even MM_GPRS and SM_GPRS). */
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
uint8_t pdisc = gh->proto_discr & 0x0f;
|
||||
OSMO_ASSERT(pdisc != GSM48_PDISC_RR);
|
||||
|
||||
rc = gsm0408_dispatch(conn, msg);
|
||||
} else {
|
||||
/* allocate a new connection */
|
||||
|
||||
if (!lac) {
|
||||
LOGP(DIUCS, LOGL_ERROR, "New IuCS subscriber"
|
||||
" but no LAC available. Expecting an InitialUE"
|
||||
" message containing a LAI IE."
|
||||
" Dropping connection.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
conn = subscr_conn_allocate_iu(network, ue_ctx, *lac);
|
||||
if (!conn)
|
||||
abort();
|
||||
|
||||
rc = msc_compl_l3(conn, msg, 0);
|
||||
if (rc != MSC_CONN_ACCEPT) {
|
||||
gsm0408_clear_request(conn, 0);
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@@ -207,9 +207,11 @@ static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
|
||||
bridge.callref[1] = call->remote_ref;
|
||||
DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
|
||||
|
||||
#if BEFORE_MSCSPLIT
|
||||
/* in direct mode, we always have to bridge the channels */
|
||||
if (ipacc_rtp_direct)
|
||||
return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge);
|
||||
#endif
|
||||
|
||||
/* proxy mode */
|
||||
if (!net->handover.active) {
|
||||
@@ -293,11 +295,16 @@ static int mncc_rcv_data(struct gsm_call *call, int msg_type,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#if BEFORE_MSCSPLIT
|
||||
/* RTP socket of remote end has meanwhile died */
|
||||
if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
|
||||
return -EIO;
|
||||
|
||||
return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
|
||||
#else
|
||||
/* not implemented yet! */
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
56
openbsc/src/libmsc/msc_api.c
Normal file
56
openbsc/src/libmsc/msc_api.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Implementations for receiving or sending MM|CC|... messages from/to the
|
||||
* BSC|RNC direction, regardless of which particular external interface is
|
||||
* actually involved (A or IuCS). */
|
||||
|
||||
/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de>
|
||||
*
|
||||
* Based on parts of osmo_msc.c:
|
||||
* (C) 2010,2013 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2010 by On-Waves
|
||||
*
|
||||
* 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/logging.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <openbsc/msc_api.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/transaction.h>
|
||||
|
||||
int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
|
||||
uint16_t chosen_channel)
|
||||
{
|
||||
gsm0408_new_conn(conn);
|
||||
gsm0408_dispatch(conn, msg);
|
||||
|
||||
/*
|
||||
* If this is a silent call we want the channel to remain open as long as
|
||||
* possible and this is why we accept this connection regardless of any
|
||||
* pending transaction or ongoing operation.
|
||||
*/
|
||||
if (conn->silent_call)
|
||||
return MSC_CONN_ACCEPT;
|
||||
if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
|
||||
return MSC_CONN_ACCEPT;
|
||||
if (trans_has_conn(conn))
|
||||
return MSC_CONN_ACCEPT;
|
||||
|
||||
LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n");
|
||||
return MSC_CONN_REJECT;
|
||||
}
|
||||
|
52
openbsc/src/libmsc/msc_ifaces.c
Normal file
52
openbsc/src/libmsc/msc_ifaces.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/* Implementation for MSC decisions which interface to send messages out on. */
|
||||
|
||||
/* (C) 2016 by sysmocom s.m.f.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/logging.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/msc_ifaces.h>
|
||||
|
||||
static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg)
|
||||
{
|
||||
switch (conn->via_iface) {
|
||||
case IFACE_A:
|
||||
msg->dst = conn;
|
||||
return a_tx(msg);
|
||||
|
||||
case IFACE_IU:
|
||||
msg->dst = conn->iu.ue_ctx;
|
||||
return iu_tx(msg, 0);
|
||||
|
||||
default:
|
||||
LOGP(DMSC, LOGL_ERROR,
|
||||
"msc_tx(): conn->via_iface invalid (%d)\n",
|
||||
conn->via_iface);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int msc_tx_dtap(struct gsm_subscriber_connection *conn,
|
||||
struct msgb *msg)
|
||||
{
|
||||
return msc_tx(conn, msg);
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <openbsc/transaction.h>
|
||||
#include <openbsc/db.h>
|
||||
|
||||
#include <openbsc/msc_api.h>
|
||||
#include <openbsc/gsm_04_11.h>
|
||||
|
||||
static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
|
||||
@@ -42,28 +43,6 @@ static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t ca
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
|
||||
uint16_t chosen_channel)
|
||||
{
|
||||
gsm0408_new_conn(conn);
|
||||
gsm0408_dispatch(conn, msg);
|
||||
|
||||
/*
|
||||
* If this is a silent call we want the channel to remain open as long as
|
||||
* possible and this is why we accept this connection regardless of any
|
||||
* pending transaction or ongoing operation.
|
||||
*/
|
||||
if (conn->silent_call)
|
||||
return BSC_API_CONN_POL_ACCEPT;
|
||||
if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
|
||||
return BSC_API_CONN_POL_ACCEPT;
|
||||
if (trans_has_conn(conn))
|
||||
return BSC_API_CONN_POL_ACCEPT;
|
||||
|
||||
LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n");
|
||||
return BSC_API_CONN_POL_REJECT;
|
||||
}
|
||||
|
||||
static void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
|
||||
{
|
||||
gsm0408_dispatch(conn, msg);
|
||||
@@ -143,7 +122,7 @@ struct bsc_api *msc_bsc_api() {
|
||||
return &msc_handler;
|
||||
}
|
||||
|
||||
/* lchan release handling */
|
||||
/* conn release handling */
|
||||
void msc_release_connection(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
/* skip when we are in release, e.g. due an error */
|
||||
@@ -169,9 +148,8 @@ void msc_release_connection(struct gsm_subscriber_connection *conn)
|
||||
* to restarting the timer. Set the new expiration time.
|
||||
*/
|
||||
if (conn->expire_timer_stopped)
|
||||
subscr_update_expire_lu(conn->subscr, conn->bts);
|
||||
subscr_update_expire_lu(conn->network, conn->subscr);
|
||||
|
||||
conn->in_release = 1;
|
||||
gsm0808_clear(conn);
|
||||
subscr_con_free(conn);
|
||||
msc_subscr_con_free(conn);
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ static const uint8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 };
|
||||
|
||||
static int send_rrlp_req(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm_network *net = conn->bts->network;
|
||||
struct gsm_network *net = conn->network;
|
||||
const uint8_t *req;
|
||||
|
||||
switch (net->rrlp.mode) {
|
||||
|
@@ -52,8 +52,10 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
|
||||
|
||||
switch (event) {
|
||||
case GSM_PAGING_SUCCEEDED:
|
||||
#if BEFORE_MSCSPLIT
|
||||
DEBUGPC(DLSMS, "success, using Timeslot %u on ARFCN %u\n",
|
||||
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
|
||||
#endif
|
||||
conn->silent_call = 1;
|
||||
/* increment lchan reference count */
|
||||
osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
|
||||
@@ -121,7 +123,10 @@ int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type)
|
||||
{
|
||||
struct subscr_request *req;
|
||||
|
||||
req = subscr_request_channel(subscr, type, paging_cb_silent, data);
|
||||
/* FIXME the VTY command allows selecting a silent call channel type.
|
||||
* This doesn't apply to the situation after MSCSPLIT with an
|
||||
* A-interface. */
|
||||
req = subscr_request_conn(subscr, paging_cb_silent, data);
|
||||
return req != NULL;
|
||||
}
|
||||
|
||||
@@ -138,8 +143,10 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr)
|
||||
if (!conn->silent_call)
|
||||
return -EINVAL;
|
||||
|
||||
#if BEFORE_MSCSPLIT
|
||||
DEBUGPC(DLSMS, "Stopping silent call using Timeslot %u on ARFCN %u\n",
|
||||
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
|
||||
#endif
|
||||
|
||||
conn->silent_call = 0;
|
||||
msc_release_connection(conn);
|
||||
|
@@ -420,6 +420,7 @@ void append_tlv_u16(tlv_t **req_tlv, uint16_t tag, uint16_t val)
|
||||
build_tlv(req_tlv, &tlv);
|
||||
}
|
||||
|
||||
#if BEFORE_MSCSPLIT
|
||||
/* Append the Osmocom vendor-specific additional TLVs to a SMPP msg */
|
||||
static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
|
||||
{
|
||||
@@ -458,6 +459,7 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
|
||||
(uint8_t *)subscr->equipment.imei, imei_len+1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
|
||||
struct gsm_subscriber_connection *conn)
|
||||
@@ -533,8 +535,10 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
|
||||
memcpy(deliver.short_message, sms->user_data, deliver.sm_length);
|
||||
}
|
||||
|
||||
#if BEFORE_MSCSPLIT
|
||||
if (esme->acl && esme->acl->osmocom_ext && conn->lchan)
|
||||
append_osmo_tlvs(&deliver.tlv, conn->lchan);
|
||||
#endif
|
||||
|
||||
return smpp_tx_deliver(esme, &deliver);
|
||||
}
|
||||
|
@@ -225,10 +225,14 @@ static void sms_submit_pending(void *_data)
|
||||
|
||||
|
||||
sms = take_next_sms(smsq);
|
||||
if (!sms)
|
||||
if (!sms) {
|
||||
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (%d attempted)\n",
|
||||
attempted);
|
||||
break;
|
||||
}
|
||||
|
||||
rounds += 1;
|
||||
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS round %d\n", rounds);
|
||||
|
||||
/*
|
||||
* This code needs to detect a loop. It assumes that no SMS
|
||||
@@ -243,6 +247,8 @@ static void sms_submit_pending(void *_data)
|
||||
first_sub = sms->receiver->id;
|
||||
initialized = 1;
|
||||
} else if (first_sub == sms->receiver->id) {
|
||||
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (loop) (%d attempted)\n",
|
||||
attempted);
|
||||
sms_free(sms);
|
||||
break;
|
||||
}
|
||||
@@ -324,6 +330,7 @@ no_pending_sms:
|
||||
*/
|
||||
int sms_queue_trigger(struct gsm_sms_queue *smsq)
|
||||
{
|
||||
LOGP(DLSMS, LOGL_DEBUG, "Triggering SMS queue\n");
|
||||
if (osmo_timer_pending(&smsq->push_queue))
|
||||
return 0;
|
||||
|
||||
|
@@ -37,7 +37,7 @@ struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
|
||||
uint8_t proto, uint8_t trans_id)
|
||||
{
|
||||
struct gsm_trans *trans;
|
||||
struct gsm_network *net = conn->bts->network;
|
||||
struct gsm_network *net = conn->network;
|
||||
struct gsm_subscriber *subscr = conn->subscr;
|
||||
|
||||
llist_for_each_entry(trans, &net->trans_list, entry) {
|
||||
@@ -155,7 +155,7 @@ int trans_has_conn(const struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm_trans *trans;
|
||||
|
||||
llist_for_each_entry(trans, &conn->bts->network->trans_list, entry)
|
||||
llist_for_each_entry(trans, &conn->network->trans_list, entry)
|
||||
if (trans->conn == conn)
|
||||
return 1;
|
||||
|
||||
|
@@ -53,8 +53,6 @@
|
||||
|
||||
#include "meas_feed.h"
|
||||
|
||||
extern struct gsm_network *gsmnet_from_vty(struct vty *v);
|
||||
|
||||
static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
|
||||
{
|
||||
int rc;
|
||||
@@ -139,7 +137,7 @@ DEFUN(show_subscr_cache,
|
||||
DEFUN(sms_send_pend,
|
||||
sms_send_pend_cmd,
|
||||
"sms send pending",
|
||||
"SMS related comamnds\n" "SMS Sending related commands\n"
|
||||
"SMS related commands\n" "SMS Sending related commands\n"
|
||||
"Send all pending SMS")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
@@ -174,6 +172,7 @@ static int _send_sms_str(struct gsm_subscriber *receiver,
|
||||
sms_free(sms);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
LOGP(DLSMS, LOGL_DEBUG, "SMS stored in DB\n");
|
||||
|
||||
sms_free(sms);
|
||||
sms_queue_trigger(receiver->group->net->sms_queue);
|
||||
@@ -197,10 +196,10 @@ static struct gsm_subscriber *get_subscr_by_argv(struct gsm_network *gsmnet,
|
||||
}
|
||||
#define SUBSCR_TYPES "(extension|imsi|tmsi|id)"
|
||||
#define SUBSCR_HELP "Operations on a Subscriber\n" \
|
||||
"Identify subscriber by his extension (phone number)\n" \
|
||||
"Identify subscriber by his IMSI\n" \
|
||||
"Identify subscriber by his TMSI\n" \
|
||||
"Identify subscriber by his database ID\n" \
|
||||
"Identify subscriber by extension (phone number)\n" \
|
||||
"Identify subscriber by IMSI\n" \
|
||||
"Identify subscriber by TMSI\n" \
|
||||
"Identify subscriber by database ID\n" \
|
||||
"Identifier for the subscriber\n"
|
||||
|
||||
DEFUN(show_subscr,
|
||||
@@ -611,6 +610,7 @@ DEFUN(ena_subscr_handover,
|
||||
SUBSCR_HELP "Handover the active connection\n"
|
||||
"Number of the BTS to handover to\n")
|
||||
{
|
||||
#if BEFORE_MSCSPLIT
|
||||
int ret;
|
||||
struct gsm_subscriber_connection *conn;
|
||||
struct gsm_bts *bts;
|
||||
@@ -654,6 +654,10 @@ DEFUN(ena_subscr_handover,
|
||||
|
||||
subscr_put(subscr);
|
||||
return CMD_SUCCESS;
|
||||
#else
|
||||
vty_out(vty, "%% Not implemented!%s", VTY_NEWLINE);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define A3A8_ALG_TYPES "(none|xor|comp128v1)"
|
||||
@@ -768,6 +772,7 @@ DEFUN(subscriber_update,
|
||||
static int scall_cbfn(unsigned int subsys, unsigned int signal,
|
||||
void *handler_data, void *signal_data)
|
||||
{
|
||||
#if BEFORE_MSCSPLIT
|
||||
struct scall_signal_data *sigdata = signal_data;
|
||||
struct vty *vty = sigdata->data;
|
||||
|
||||
@@ -782,6 +787,10 @@ static int scall_cbfn(unsigned int subsys, unsigned int signal,
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
/* not implemented yet! */
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFUN(show_stats,
|
||||
@@ -791,7 +800,6 @@ DEFUN(show_stats,
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
|
||||
openbsc_vty_print_statistics(vty, net);
|
||||
vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s",
|
||||
osmo_counter_get(net->stats.loc_upd_type.attach),
|
||||
osmo_counter_get(net->stats.loc_upd_type.normal),
|
||||
@@ -1018,66 +1026,6 @@ DEFUN(logging_fltr_imsi,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static struct cmd_node nitb_node = {
|
||||
NITB_NODE,
|
||||
"%s(config-nitb)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(cfg_nitb, cfg_nitb_cmd,
|
||||
"nitb", "Configure NITB options")
|
||||
{
|
||||
vty->node = NITB_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
|
||||
"subscriber-create-on-demand",
|
||||
"Make a new record when a subscriber is first seen.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->create_subscriber = 1;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nitb_no_subscr_create, cfg_nitb_no_subscr_create_cmd,
|
||||
"no subscriber-create-on-demand",
|
||||
NO_STR "Make a new record when a subscriber is first seen.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->create_subscriber = 0;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nitb_assign_tmsi, cfg_nitb_assign_tmsi_cmd,
|
||||
"assign-tmsi",
|
||||
"Assign TMSI during Location Updating.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->avoid_tmsi = 0;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nitb_no_assign_tmsi, cfg_nitb_no_assign_tmsi_cmd,
|
||||
"no assign-tmsi",
|
||||
NO_STR "Assign TMSI during Location Updating.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->avoid_tmsi = 1;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_write_nitb(struct vty *vty)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
vty_out(vty, "nitb%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %ssubscriber-create-on-demand%s",
|
||||
gsmnet->create_subscriber ? "" : "no ", VTY_NEWLINE);
|
||||
vty_out(vty, " %sassign-tmsi%s",
|
||||
gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int bsc_vty_init_extra(void)
|
||||
{
|
||||
osmo_signal_register_handler(SS_SCALL, scall_cbfn, NULL);
|
||||
@@ -1123,13 +1071,5 @@ int bsc_vty_init_extra(void)
|
||||
install_element(CFG_LOG_NODE, &log_level_sms_cmd);
|
||||
install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);
|
||||
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_nitb_cmd);
|
||||
install_node(&nitb_node, config_write_nitb);
|
||||
install_element(NITB_NODE, &cfg_nitb_subscr_create_cmd);
|
||||
install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd);
|
||||
install_element(NITB_NODE, &cfg_nitb_assign_tmsi_cmd);
|
||||
install_element(NITB_NODE, &cfg_nitb_no_assign_tmsi_cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -172,7 +172,7 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
|
||||
/* always allocate for the maximum possible size to avoid
|
||||
* fragmentation */
|
||||
new_msg = msgb_alloc(sizeof(struct gsm_data_frame) +
|
||||
MAX_RTP_PAYLOAD_LEN, "GSM-DATA (TCH)");
|
||||
MAX_RTP_PAYLOAD_LEN+1, "GSM-DATA (TCH)");
|
||||
|
||||
if (!new_msg)
|
||||
return -ENOMEM;
|
||||
|
7
openbsc/src/libxsc/Makefile.am
Normal file
7
openbsc/src/libxsc/Makefile.am
Normal file
@@ -0,0 +1,7 @@
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
|
||||
|
||||
noinst_LIBRARIES = libxsc.a
|
||||
|
||||
libxsc_a_SOURCES = xsc.c xsc_vty.c
|
260
openbsc/src/libxsc/xsc.c
Normal file
260
openbsc/src/libxsc/xsc.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/* Code used by both libbsc and libmsc (xsc means "BSC or MSC").
|
||||
*
|
||||
* (C) 2016 by sysmocom s.m.f.c. <info@sysmocom.de>
|
||||
* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2014 by Holger Hans Peter Freyther
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* TODO: this file was created during the MSCSPLIT, separating the BSC from the
|
||||
* NITB to create a standalone MSC. Things from libbsc that are needed from
|
||||
* libmsc have been moved here, probably taking along some stuff not actually
|
||||
* needed by the MSC. It may make sense to move things to more appropriate
|
||||
* places or implement things differently when they become more obvious. I'm
|
||||
* taking that as an excuse to make a mess of this file in the sense of keeping
|
||||
* #includes close to their use, and not caring much about mixing things. */
|
||||
|
||||
/* FIXME parts of the gsm_network are BSC specific and don't belong here. */
|
||||
|
||||
#include <osmocom/gsm/gsm0480.h>
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/osmo_msc_data.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
|
||||
struct gsm_network *gsm_network_init(void *ctx,
|
||||
uint16_t country_code,
|
||||
uint16_t network_code,
|
||||
mncc_recv_cb_t mncc_recv)
|
||||
{
|
||||
struct gsm_network *net;
|
||||
|
||||
net = talloc_zero(ctx, struct gsm_network);
|
||||
if (!net)
|
||||
return NULL;
|
||||
|
||||
net->bsc_data = talloc_zero(net, struct osmo_bsc_data);
|
||||
if (!net->bsc_data) {
|
||||
talloc_free(net);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
net->subscr_group = talloc_zero(net, struct gsm_subscriber_group);
|
||||
if (!net->subscr_group) {
|
||||
talloc_free(net);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Init back pointer */
|
||||
net->bsc_data->auto_off_timeout = -1;
|
||||
net->bsc_data->network = net;
|
||||
INIT_LLIST_HEAD(&net->bsc_data->mscs);
|
||||
|
||||
net->subscr_group->net = net;
|
||||
net->create_subscriber = 1;
|
||||
|
||||
net->country_code = country_code;
|
||||
net->network_code = network_code;
|
||||
net->num_bts = 0;
|
||||
net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED;
|
||||
net->T3101 = GSM_T3101_DEFAULT;
|
||||
net->T3105 = GSM_T3105_DEFAULT;
|
||||
net->T3113 = GSM_T3113_DEFAULT;
|
||||
net->T3122 = GSM_T3122_DEFAULT;
|
||||
/* FIXME: initialize all other timers! */
|
||||
|
||||
/* default set of handover parameters */
|
||||
net->handover.win_rxlev_avg = 10;
|
||||
net->handover.win_rxqual_avg = 1;
|
||||
net->handover.win_rxlev_avg_neigh = 10;
|
||||
net->handover.pwr_interval = 6;
|
||||
net->handover.pwr_hysteresis = 3;
|
||||
net->handover.max_distance = 9999;
|
||||
|
||||
/* Use 30 min periodic update interval as sane default */
|
||||
net->t3212 = 5;
|
||||
|
||||
INIT_LLIST_HEAD(&net->trans_list);
|
||||
INIT_LLIST_HEAD(&net->upqueue);
|
||||
INIT_LLIST_HEAD(&net->bts_list);
|
||||
INIT_LLIST_HEAD(&net->subscr_conns);
|
||||
|
||||
net->stats.chreq.total = osmo_counter_alloc("net.chreq.total");
|
||||
net->stats.chreq.no_channel = osmo_counter_alloc("net.chreq.no_channel");
|
||||
net->stats.handover.attempted = osmo_counter_alloc("net.handover.attempted");
|
||||
net->stats.handover.no_channel = osmo_counter_alloc("net.handover.no_channel");
|
||||
net->stats.handover.timeout = osmo_counter_alloc("net.handover.timeout");
|
||||
net->stats.handover.completed = osmo_counter_alloc("net.handover.completed");
|
||||
net->stats.handover.failed = osmo_counter_alloc("net.handover.failed");
|
||||
net->stats.loc_upd_type.attach = osmo_counter_alloc("net.loc_upd_type.attach");
|
||||
net->stats.loc_upd_type.normal = osmo_counter_alloc("net.loc_upd_type.normal");
|
||||
net->stats.loc_upd_type.periodic = osmo_counter_alloc("net.loc_upd_type.periodic");
|
||||
net->stats.loc_upd_type.detach = osmo_counter_alloc("net.imsi_detach.count");
|
||||
net->stats.loc_upd_resp.reject = osmo_counter_alloc("net.loc_upd_resp.reject");
|
||||
net->stats.loc_upd_resp.accept = osmo_counter_alloc("net.loc_upd_resp.accept");
|
||||
net->stats.paging.attempted = osmo_counter_alloc("net.paging.attempted");
|
||||
net->stats.paging.detached = osmo_counter_alloc("net.paging.detached");
|
||||
net->stats.paging.completed = osmo_counter_alloc("net.paging.completed");
|
||||
net->stats.paging.expired = osmo_counter_alloc("net.paging.expired");
|
||||
net->stats.sms.submitted = osmo_counter_alloc("net.sms.submitted");
|
||||
net->stats.sms.no_receiver = osmo_counter_alloc("net.sms.no_receiver");
|
||||
net->stats.sms.delivered = osmo_counter_alloc("net.sms.delivered");
|
||||
net->stats.sms.rp_err_mem = osmo_counter_alloc("net.sms.rp_err_mem");
|
||||
net->stats.sms.rp_err_other = osmo_counter_alloc("net.sms.rp_err_other");
|
||||
net->stats.call.mo_setup = osmo_counter_alloc("net.call.mo_setup");
|
||||
net->stats.call.mo_connect_ack = osmo_counter_alloc("net.call.mo_connect_ack");
|
||||
net->stats.call.mt_setup = osmo_counter_alloc("net.call.mt_setup");
|
||||
net->stats.call.mt_connect = osmo_counter_alloc("net.call.mt_connect");
|
||||
net->stats.chan.rf_fail = osmo_counter_alloc("net.chan.rf_fail");
|
||||
net->stats.chan.rll_err = osmo_counter_alloc("net.chan.rll_err");
|
||||
net->stats.bts.oml_fail = osmo_counter_alloc("net.bts.oml_fail");
|
||||
net->stats.bts.rsl_fail = osmo_counter_alloc("net.bts.rsl_fail");
|
||||
|
||||
net->mncc_recv = mncc_recv;
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr)
|
||||
{
|
||||
/* FIXME: replace this with a backpointer in gsm_subscriber? */
|
||||
struct gsm_network *net = subscr->group->net;
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
llist_for_each_entry(conn, &net->subscr_conns, entry) {
|
||||
if (conn->subscr == subscr)
|
||||
return conn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* from gsm_04_08_utils.c *****/
|
||||
|
||||
struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
msg = gsm48_msgb_alloc_name("GSM 04.08 SERV REJ");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
gh->proto_discr = GSM48_PDISC_MM;
|
||||
gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
|
||||
gh->data[0] = value;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *gsm48_create_loc_upd_rej(uint8_t cause)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
struct msgb *msg;
|
||||
|
||||
msg = gsm48_msgb_alloc_name("GSM 04.08 LOC UPD REJ");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
gh->proto_discr = GSM48_PDISC_MM;
|
||||
gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
|
||||
gh->data[0] = cause;
|
||||
return msg;
|
||||
}
|
||||
|
||||
int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
|
||||
{
|
||||
/* Check the size for the classmark */
|
||||
if (length < 1 + *classmark2_lv)
|
||||
return -1;
|
||||
|
||||
uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
|
||||
if (length < 2 + *classmark2_lv + mi_lv[0])
|
||||
return -2;
|
||||
|
||||
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
|
||||
return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
|
||||
}
|
||||
|
||||
int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
|
||||
char *mi_string, uint8_t *mi_type)
|
||||
{
|
||||
static const uint32_t classmark_offset =
|
||||
offsetof(struct gsm48_pag_resp, classmark2);
|
||||
uint8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
|
||||
return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
|
||||
mi_string, mi_type);
|
||||
}
|
||||
|
||||
|
||||
struct msgb *gsm0480_gen_ussdNotify(int level, const char *text)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
struct msgb *msg;
|
||||
|
||||
msg = gsm0480_create_unstructuredSS_Notify(level, text);
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
gsm0480_wrap_invoke(msg, GSM0480_OP_CODE_USS_NOTIFY, 0);
|
||||
gsm0480_wrap_facility(msg);
|
||||
|
||||
/* And finally pre-pend the L3 header */
|
||||
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_NC_SS;
|
||||
gh->msg_type = GSM0480_MTYPE_REGISTER;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *gsm0480_gen_releaseComplete(void)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
struct msgb *msg;
|
||||
|
||||
msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REL COMPL");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_NC_SS;
|
||||
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
/* Helpers for SMS/GSM 04.11 */
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/gsm_04_11.h>
|
||||
|
||||
uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref)
|
||||
{
|
||||
const uint8_t rp_msg_ref = *next_rp_ref;
|
||||
/*
|
||||
* This should wrap as the valid range is 0 to 255. We only
|
||||
* transfer one SMS at a time so we don't need to check if
|
||||
* the id has been already assigned.
|
||||
*/
|
||||
*next_rp_ref += 1;
|
||||
|
||||
return rp_msg_ref;
|
||||
}
|
||||
|
587
openbsc/src/libxsc/xsc_vty.c
Normal file
587
openbsc/src/libxsc/xsc_vty.c
Normal file
@@ -0,0 +1,587 @@
|
||||
/* Code used by both libbsc and libmsc (xsc means "BSC or MSC").
|
||||
*
|
||||
* (C) 2016 by sysmocom s.m.f.c. <info@sysmocom.de>
|
||||
* (C) 2008-2010 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* FIXME parts of the gsm_network VTY commands are BSC specific and don't
|
||||
* belong here. */
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/logging.h>
|
||||
#include <osmocom/vty/stats.h>
|
||||
|
||||
#include <openbsc/vty.h>
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
|
||||
struct cmd_node net_node = {
|
||||
GSMNET_NODE,
|
||||
"%s(config-net)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
struct gsm_network *vty_global_gsm_network = 0;
|
||||
|
||||
struct gsm_network *gsmnet_from_vty(struct vty *v)
|
||||
{
|
||||
/* In case we read from the config file, the vty->priv cannot
|
||||
* point to a struct telnet_connection, and thus conn->priv
|
||||
* will not point to the gsm_network structure.
|
||||
* It can't hurt to force callers to continue to pass the vty instance
|
||||
* to this function, in case we'd like to retrieve the global
|
||||
* gsm_network instance from the vty at some point in the future. But
|
||||
* until then, just return the global pointer, which should have been
|
||||
* initialized by bsc_vty_init().
|
||||
*/
|
||||
OSMO_ASSERT(vty_global_gsm_network);
|
||||
return vty_global_gsm_network;
|
||||
}
|
||||
|
||||
static void net_dump_vty(struct vty *vty, struct gsm_network *net)
|
||||
{
|
||||
vty_out(vty, "BSC is on Country Code %u, Network Code %u "
|
||||
"and has %u BTS%s", net->country_code, net->network_code,
|
||||
net->num_bts, VTY_NEWLINE);
|
||||
vty_out(vty, " Long network name: '%s'%s",
|
||||
net->name_long, VTY_NEWLINE);
|
||||
vty_out(vty, " Short network name: '%s'%s",
|
||||
net->name_short, VTY_NEWLINE);
|
||||
vty_out(vty, " Authentication policy: %s%s",
|
||||
gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE);
|
||||
vty_out(vty, " Location updating reject cause: %u%s",
|
||||
net->reject_cause, VTY_NEWLINE);
|
||||
vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " NECI (TCH/H): %u%s", net->neci,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " Use TCH for Paging any: %d%s", net->pag_any_tch,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off",
|
||||
VTY_NEWLINE);
|
||||
#if BEFORE_MSCSPLIT
|
||||
struct pchan_load pl;
|
||||
network_chan_load(&pl, net);
|
||||
vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
|
||||
dump_pchan_load_vty(vty, " ", &pl);
|
||||
|
||||
/* show rf */
|
||||
if (net->bsc_data)
|
||||
vty_out(vty, " Last RF Command: %s%s",
|
||||
net->bsc_data->rf_ctrl->last_state_command,
|
||||
VTY_NEWLINE);
|
||||
if (net->bsc_data)
|
||||
vty_out(vty, " Last RF Lock Command: %s%s",
|
||||
net->bsc_data->rf_ctrl->last_rf_lock_ctrl_command,
|
||||
VTY_NEWLINE);
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFUN(show_net, show_net_cmd, "show network",
|
||||
SHOW_STR "Display information about a GSM NETWORK\n")
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
net_dump_vty(vty, net);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_write_net(struct vty *vty)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
vty_out(vty, "network%s", VTY_NEWLINE);
|
||||
vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
|
||||
vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
|
||||
vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
|
||||
vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
|
||||
vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
|
||||
vty_out(vty, " location updating reject cause %u%s",
|
||||
gsmnet->reject_cause, VTY_NEWLINE);
|
||||
vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
|
||||
vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
|
||||
vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
|
||||
vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE);
|
||||
vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE);
|
||||
vty_out(vty, " handover window rxlev averaging %u%s",
|
||||
gsmnet->handover.win_rxlev_avg, VTY_NEWLINE);
|
||||
vty_out(vty, " handover window rxqual averaging %u%s",
|
||||
gsmnet->handover.win_rxqual_avg, VTY_NEWLINE);
|
||||
vty_out(vty, " handover window rxlev neighbor averaging %u%s",
|
||||
gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE);
|
||||
vty_out(vty, " handover power budget interval %u%s",
|
||||
gsmnet->handover.pwr_interval, VTY_NEWLINE);
|
||||
vty_out(vty, " handover power budget hysteresis %u%s",
|
||||
gsmnet->handover.pwr_hysteresis, VTY_NEWLINE);
|
||||
vty_out(vty, " handover maximum distance %u%s",
|
||||
gsmnet->handover.max_distance, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3107 %u%s", gsmnet->T3107, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3109 %u%s", gsmnet->T3109, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3111 %u%s", gsmnet->T3111, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3113 %u%s", gsmnet->T3113, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3115 %u%s", gsmnet->T3115, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3122 %u%s", gsmnet->T3122, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
|
||||
vty_out(vty, " dtx-used %u%s", gsmnet->dtx_enabled, VTY_NEWLINE);
|
||||
vty_out(vty, " subscriber-keep-in-ram %d%s",
|
||||
gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
|
||||
if (gsmnet->tz.override != 0) {
|
||||
if (gsmnet->tz.dst)
|
||||
vty_out(vty, " timezone %d %d %d%s",
|
||||
gsmnet->tz.hr, gsmnet->tz.mn, gsmnet->tz.dst,
|
||||
VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " timezone %d %d%s",
|
||||
gsmnet->tz.hr, gsmnet->tz.mn, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (gsmnet->t3212 == 0)
|
||||
vty_out(vty, " no periodic location update%s", VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " periodic location update %u%s",
|
||||
gsmnet->t3212 * 6, VTY_NEWLINE);
|
||||
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define NETWORK_STR "Configure the GSM network\n"
|
||||
#define CODE_CMD_STR "Code commands\n"
|
||||
#define NAME_CMD_STR "Name Commands\n"
|
||||
#define NAME_STR "Name to use\n"
|
||||
|
||||
DEFUN(cfg_net,
|
||||
cfg_net_cmd,
|
||||
"network", NETWORK_STR)
|
||||
{
|
||||
vty->index = gsmnet_from_vty(vty);
|
||||
vty->node = GSMNET_NODE;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ncc,
|
||||
cfg_net_ncc_cmd,
|
||||
"network country code <1-999>",
|
||||
"Set the GSM network country code\n"
|
||||
"Country commands\n"
|
||||
CODE_CMD_STR
|
||||
"Network Country Code to use\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->country_code = atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_mnc,
|
||||
cfg_net_mnc_cmd,
|
||||
"mobile network code <0-999>",
|
||||
"Set the GSM mobile network code\n"
|
||||
"Network Commands\n"
|
||||
CODE_CMD_STR
|
||||
"Mobile Network Code to use\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->network_code = atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_name_short,
|
||||
cfg_net_name_short_cmd,
|
||||
"short name NAME",
|
||||
"Set the short GSM network name\n" NAME_CMD_STR NAME_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
bsc_replace_string(gsmnet, &gsmnet->name_short, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_name_long,
|
||||
cfg_net_name_long_cmd,
|
||||
"long name NAME",
|
||||
"Set the long GSM network name\n" NAME_CMD_STR NAME_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
bsc_replace_string(gsmnet, &gsmnet->name_long, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_auth_policy,
|
||||
cfg_net_auth_policy_cmd,
|
||||
"auth policy (closed|accept-all|token)",
|
||||
"Authentication (not cryptographic)\n"
|
||||
"Set the GSM network authentication policy\n"
|
||||
"Require the MS to be activated in HLR\n"
|
||||
"Accept all MS, whether in HLR or not\n"
|
||||
"Use SMS-token based authentication\n")
|
||||
{
|
||||
enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->auth_policy = policy;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_reject_cause,
|
||||
cfg_net_reject_cause_cmd,
|
||||
"location updating reject cause <2-111>",
|
||||
"Set the reject cause of location updating reject\n"
|
||||
"Set the reject cause of location updating reject\n"
|
||||
"Set the reject cause of location updating reject\n"
|
||||
"Set the reject cause of location updating reject\n"
|
||||
"Cause Value as Per GSM TS 04.08\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->reject_cause = atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_encryption,
|
||||
cfg_net_encryption_cmd,
|
||||
"encryption a5 (0|1|2|3)",
|
||||
"Encryption options\n"
|
||||
"A5 encryption\n" "A5/0: No encryption\n"
|
||||
"A5/1: Encryption\n" "A5/2: Export-grade Encryption\n"
|
||||
"A5/3: 'New' Secure Encryption\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->a5_encryption= atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
|
||||
"rrlp mode (none|ms-based|ms-preferred|ass-preferred)",
|
||||
"Radio Resource Location Protocol\n"
|
||||
"Set the Radio Resource Location Protocol Mode\n"
|
||||
"Don't send RRLP request\n"
|
||||
"Request MS-based location\n"
|
||||
"Request any location, prefer MS-based\n"
|
||||
"Request any location, prefer MS-assisted\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd,
|
||||
"mm info (0|1)",
|
||||
"Mobility Management\n"
|
||||
"Send MM INFO after LOC UPD ACCEPT\n"
|
||||
"Disable\n" "Enable\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->send_mm_info = atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define HANDOVER_STR "Handover Options\n"
|
||||
|
||||
DEFUN(cfg_net_handover, cfg_net_handover_cmd,
|
||||
"handover (0|1)",
|
||||
HANDOVER_STR
|
||||
"Don't perform in-call handover\n"
|
||||
"Perform in-call handover\n")
|
||||
{
|
||||
int enable = atoi(argv[0]);
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
#if BEFORE_MSCSPLIT
|
||||
if (enable && ipacc_rtp_direct) {
|
||||
vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
|
||||
"is enabled by using the -P command line option%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
#endif
|
||||
gsmnet->handover.active = enable;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define HO_WIN_STR HANDOVER_STR "Measurement Window\n"
|
||||
#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
|
||||
#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
|
||||
#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
|
||||
#define HO_AVG_COUNT_STR "Amount to use for Averaging\n"
|
||||
|
||||
DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
|
||||
"handover window rxlev averaging <1-10>",
|
||||
HO_WIN_RXLEV_STR
|
||||
"How many RxLev measurements are used for averaging\n"
|
||||
HO_AVG_COUNT_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
|
||||
"handover window rxqual averaging <1-10>",
|
||||
HO_WIN_RXQUAL_STR
|
||||
"How many RxQual measurements are used for averaging\n"
|
||||
HO_AVG_COUNT_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
|
||||
"handover window rxlev neighbor averaging <1-10>",
|
||||
HO_WIN_RXLEV_STR "Neighbor\n"
|
||||
"How many RxQual measurements are used for averaging\n"
|
||||
HO_AVG_COUNT_STR)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
|
||||
"handover power budget interval <1-99>",
|
||||
HO_PBUDGET_STR
|
||||
"How often to check if we have a better cell (SACCH frames)\n"
|
||||
"Interval\n" "Number\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.pwr_interval = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
|
||||
"handover power budget hysteresis <0-999>",
|
||||
HO_PBUDGET_STR
|
||||
"How many dB does a neighbor to be stronger to become a HO candidate\n"
|
||||
"Hysteresis\n" "Number\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
|
||||
"handover maximum distance <0-9999>",
|
||||
HANDOVER_STR
|
||||
"How big is the maximum timing advance before HO is forced\n"
|
||||
"Distance\n" "Number\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->handover.max_distance = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define DECLARE_TIMER(number, doc) \
|
||||
DEFUN(cfg_net_T##number, \
|
||||
cfg_net_T##number##_cmd, \
|
||||
"timer t" #number " <0-65535>", \
|
||||
"Configure GSM Timers\n" \
|
||||
doc "Timer Value in seconds\n") \
|
||||
{ \
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty); \
|
||||
int value = atoi(argv[0]); \
|
||||
\
|
||||
if (value < 0 || value > 65535) { \
|
||||
vty_out(vty, "Timer value %s out of range.%s", \
|
||||
argv[0], VTY_NEWLINE); \
|
||||
return CMD_WARNING; \
|
||||
} \
|
||||
\
|
||||
gsmnet->T##number = value; \
|
||||
return CMD_SUCCESS; \
|
||||
}
|
||||
|
||||
DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.\n")
|
||||
DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n")
|
||||
DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION.\n")
|
||||
DECLARE_TIMER(3107, "Currently not used.\n")
|
||||
DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout.\n")
|
||||
DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n")
|
||||
DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n")
|
||||
DECLARE_TIMER(3115, "Currently not used.\n")
|
||||
DECLARE_TIMER(3117, "Currently not used.\n")
|
||||
DECLARE_TIMER(3119, "Currently not used.\n")
|
||||
DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT\n")
|
||||
DECLARE_TIMER(3141, "Currently not used.\n")
|
||||
|
||||
DEFUN(cfg_net_dtx,
|
||||
cfg_net_dtx_cmd,
|
||||
"dtx-used (0|1)",
|
||||
"Enable the usage of DTX.\n"
|
||||
"DTX is disabled\n" "DTX is enabled\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->dtx_enabled = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_subscr_keep,
|
||||
cfg_net_subscr_keep_cmd,
|
||||
"subscriber-keep-in-ram (0|1)",
|
||||
"Keep unused subscribers in RAM.\n"
|
||||
"Delete unused subscribers\n" "Keep unused subscribers\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->subscr_group->keep_subscr = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_timezone,
|
||||
cfg_net_timezone_cmd,
|
||||
"timezone <-19-19> (0|15|30|45)",
|
||||
"Set the Timezone Offset of the network\n"
|
||||
"Timezone offset (hours)\n"
|
||||
"Timezone offset (00 minutes)\n"
|
||||
"Timezone offset (15 minutes)\n"
|
||||
"Timezone offset (30 minutes)\n"
|
||||
"Timezone offset (45 minutes)\n"
|
||||
)
|
||||
{
|
||||
struct gsm_network *net = vty->index;
|
||||
int tzhr = atoi(argv[0]);
|
||||
int tzmn = atoi(argv[1]);
|
||||
|
||||
net->tz.hr = tzhr;
|
||||
net->tz.mn = tzmn;
|
||||
net->tz.dst = 0;
|
||||
net->tz.override = 1;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_timezone_dst,
|
||||
cfg_net_timezone_dst_cmd,
|
||||
"timezone <-19-19> (0|15|30|45) <0-2>",
|
||||
"Set the Timezone Offset of the network\n"
|
||||
"Timezone offset (hours)\n"
|
||||
"Timezone offset (00 minutes)\n"
|
||||
"Timezone offset (15 minutes)\n"
|
||||
"Timezone offset (30 minutes)\n"
|
||||
"Timezone offset (45 minutes)\n"
|
||||
"DST offset (hours)\n"
|
||||
)
|
||||
{
|
||||
struct gsm_network *net = vty->index;
|
||||
int tzhr = atoi(argv[0]);
|
||||
int tzmn = atoi(argv[1]);
|
||||
int tzdst = atoi(argv[2]);
|
||||
|
||||
net->tz.hr = tzhr;
|
||||
net->tz.mn = tzmn;
|
||||
net->tz.dst = tzdst;
|
||||
net->tz.override = 1;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_no_timezone,
|
||||
cfg_net_no_timezone_cmd,
|
||||
"no timezone",
|
||||
NO_STR
|
||||
"Disable network timezone override, use system tz\n")
|
||||
{
|
||||
struct gsm_network *net = vty->index;
|
||||
|
||||
net->tz.override = 0;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int gsmnet_vty_init(struct gsm_network *network)
|
||||
{
|
||||
vty_global_gsm_network = network;
|
||||
|
||||
install_element_ve(&show_net_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_net_cmd);
|
||||
install_node(&net_node, config_write_net);
|
||||
vty_install_default(GSMNET_NODE);
|
||||
install_element(GSMNET_NODE, &cfg_net_ncc_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_mnc_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_mm_info_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_handover_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3101_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3103_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3105_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3107_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3109_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3111_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3113_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3115_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3117_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3119_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3122_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_T3141_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_dtx_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_timezone_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_timezone_dst_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_no_timezone_cmd);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* VTY elements used in both BSC and MSC */
|
||||
int xsc_vty_init(struct gsm_network *network)
|
||||
{
|
||||
osmo_stats_vty_add_cmds();
|
||||
|
||||
gsmnet_vty_init(network);
|
||||
return CMD_SUCCESS;
|
||||
}
|
@@ -12,11 +12,9 @@ osmo_bsc_SOURCES = osmo_bsc_main.c osmo_bsc_vty.c osmo_bsc_api.c \
|
||||
osmo_bsc_LDADD = \
|
||||
$(top_builddir)/src/libfilter/libfilter.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libmsc/libmsc.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libxsc/libxsc.a \
|
||||
$(top_builddir)/src/libtrau/libtrau.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(LIBOSMOSCCP_LIBS) $(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCTRL_LIBS) \
|
||||
$(COVERAGE_LDFLAGS) $(LIBOSMOABIS_LIBS)
|
||||
|
@@ -330,7 +330,7 @@ static int move_to_msc(struct gsm_subscriber_connection *_conn,
|
||||
_conn->sccp_con = NULL;
|
||||
if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) {
|
||||
gsm0808_clear(_conn);
|
||||
subscr_con_free(_conn);
|
||||
bsc_subscr_con_free(_conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -185,7 +185,7 @@ static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
|
||||
if (conn->conn) {
|
||||
LOGP(DMSC, LOGL_INFO, "Releasing all transactions on %p\n", conn);
|
||||
gsm0808_clear(conn->conn);
|
||||
subscr_con_free(conn->conn);
|
||||
bsc_subscr_con_free(conn->conn);
|
||||
conn->conn = NULL;
|
||||
}
|
||||
|
||||
|
@@ -371,9 +371,10 @@ static int get_bts_timezone(struct ctrl_cmd *cmd, void *data)
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (bts->tz.override)
|
||||
struct gsm_tz *tz = &bts->network->tz;
|
||||
if (tz->override)
|
||||
cmd->reply = talloc_asprintf(cmd, "%d,%d,%d",
|
||||
bts->tz.hr, bts->tz.mn, bts->tz.dst);
|
||||
tz->hr, tz->mn, tz->dst);
|
||||
else
|
||||
cmd->reply = talloc_asprintf(cmd, "off");
|
||||
|
||||
@@ -385,8 +386,19 @@ static int get_bts_timezone(struct ctrl_cmd *cmd, void *data)
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
/* Note: it may appear that set_bts_timezone() is never used, but is in in fact
|
||||
* used by CTRL_CMD_DEFINE(bts_timezone, "timezone"); above. */
|
||||
static int set_bts_timezone(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
/* FIXME: in the course of MSCSPLIT, the osmo CN no longer has access
|
||||
* to the BTS structs, and hence the timezone override was moved to the
|
||||
* network level. It does of course still make sense to allow adjusting
|
||||
* the timezone per BTS in osmo-bsc. This function currently modifies
|
||||
* the global timezone data on network level, thus having an effect on
|
||||
* all other BTSs at the same time. I'm doing it this way because I'm
|
||||
* focusing on IuCS and the MSCSPLIT and hope to do this properly
|
||||
* at a later time. Sorry about that... ~Neels */
|
||||
|
||||
char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0;
|
||||
int override;
|
||||
struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
|
||||
@@ -409,12 +421,13 @@ static int set_bts_timezone(struct ctrl_cmd *cmd, void *data)
|
||||
if (hourstr != NULL)
|
||||
override = strcasecmp(hourstr, "off") != 0;
|
||||
|
||||
bts->tz.override = override;
|
||||
struct gsm_tz *tz = &bts->network->tz;
|
||||
tz->override = override;
|
||||
|
||||
if (override) {
|
||||
bts->tz.hr = hourstr ? atol(hourstr) : 0;
|
||||
bts->tz.mn = minstr ? atol(minstr) : 0;
|
||||
bts->tz.dst = dststr ? atol(dststr) : 0;
|
||||
tz->hr = hourstr ? atol(hourstr) : 0;
|
||||
tz->mn = minstr ? atol(minstr) : 0;
|
||||
tz->dst = dststr ? atol(dststr) : 0;
|
||||
}
|
||||
|
||||
talloc_free(tmp);
|
||||
@@ -583,7 +596,7 @@ static int set_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
|
||||
alert = atoi(alert_str);
|
||||
|
||||
net = cmd->node;
|
||||
llist_for_each_entry(conn, bsc_api_sub_connections(net), entry) {
|
||||
llist_for_each_entry(conn, &net->subscr_conns, entry) {
|
||||
if (!conn->sccp_con)
|
||||
continue;
|
||||
|
||||
|
@@ -270,23 +270,24 @@ static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn,
|
||||
return 0;
|
||||
|
||||
/* Is TZ patching enabled? */
|
||||
if (!bts->tz.override)
|
||||
struct gsm_tz *tz = &bts->network->tz;
|
||||
if (!tz->override)
|
||||
return 0;
|
||||
|
||||
/* Convert tz.hr and tz.mn to units */
|
||||
if (bts->tz.hr < 0) {
|
||||
tzunits = -bts->tz.hr*4;
|
||||
if (tz->hr < 0) {
|
||||
tzunits = -tz->hr*4;
|
||||
tzbsd |= 0x08;
|
||||
} else
|
||||
tzunits = bts->tz.hr*4;
|
||||
tzunits = tz->hr*4;
|
||||
|
||||
tzunits = tzunits + (bts->tz.mn/15);
|
||||
tzunits = tzunits + (tz->mn/15);
|
||||
|
||||
tzbsd |= (tzunits % 10)*0x10 + (tzunits / 10);
|
||||
|
||||
/* Convert DST value */
|
||||
if (bts->tz.dst >= 0 && bts->tz.dst <= 2)
|
||||
dst = bts->tz.dst;
|
||||
if (tz->dst >= 0 && tz->dst <= 2)
|
||||
dst = tz->dst;
|
||||
|
||||
if (TLVP_PRESENT(&tp, GSM48_IE_UTC)) {
|
||||
LOGP(DMSC, LOGL_DEBUG,
|
||||
|
@@ -204,7 +204,7 @@ int main(int argc, char **argv)
|
||||
/* This needs to precede handle_options() */
|
||||
vty_info.copyright = openbsc_copyright;
|
||||
vty_init(&vty_info);
|
||||
bsc_vty_init(&log_info);
|
||||
bsc_vty_init(&log_info, bsc_gsmnet);
|
||||
bsc_msg_lst_vty_init(tall_bsc_ctx, &access_lists, BSC_NODE);
|
||||
ctrl_vty_init(tall_bsc_ctx);
|
||||
|
||||
@@ -219,8 +219,12 @@ int main(int argc, char **argv)
|
||||
/* initialize SCCP */
|
||||
sccp_set_log_area(DSCCP);
|
||||
|
||||
|
||||
rc = bsc_bootstrap_network(NULL, config_file);
|
||||
rc = bsc_network_init(NULL);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Allocation failed. exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
rc = bsc_network_configure(config_file);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Bootstrapping the network failed. exiting.\n");
|
||||
exit(1);
|
||||
|
@@ -84,7 +84,7 @@ static void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
|
||||
LOGP(DMSC, LOGL_ERROR,
|
||||
"ERROR: The lchan is still associated.\n");
|
||||
gsm0808_clear(con_data->conn);
|
||||
subscr_con_free(con_data->conn);
|
||||
bsc_subscr_con_free(con_data->conn);
|
||||
con_data->conn = NULL;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ static void bsc_sccp_force_free(struct osmo_bsc_sccp_con *data)
|
||||
{
|
||||
if (data->conn) {
|
||||
gsm0808_clear(data->conn);
|
||||
subscr_con_free(data->conn);
|
||||
bsc_subscr_con_free(data->conn);
|
||||
data->conn = NULL;
|
||||
}
|
||||
|
||||
|
@@ -11,6 +11,7 @@ osmo_bsc_nat_SOURCES = bsc_filter.c bsc_mgcp_utils.c bsc_nat.c bsc_nat_utils.c \
|
||||
osmo_bsc_nat_LDADD = \
|
||||
$(top_builddir)/src/libmgcp/libmgcp.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libxsc/libxsc.a \
|
||||
$(top_builddir)/src/libtrau/libtrau.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(top_builddir)/src/libfilter/libfilter.a \
|
||||
|
@@ -1329,7 +1329,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
|
||||
|
||||
|
||||
/* called by the telnet interface... we have our own init above */
|
||||
int bsc_vty_init(const struct log_info *cat)
|
||||
int bsc_vty_init(const struct log_info *cat, struct gsm_network *network)
|
||||
{
|
||||
logging_vty_add_cmds(cat);
|
||||
return 0;
|
||||
|
@@ -1,19 +1,25 @@
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) \
|
||||
-DCOMPILING_LIBMSC=1
|
||||
AM_CFLAGS=-Wall $(COVERAGE_CFLAGS) \
|
||||
$(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBSMPP34_CFLAGS)
|
||||
$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBSMPP34_CFLAGS) \
|
||||
$(LIBOSMORANAP_CFLAGS) $(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS)
|
||||
|
||||
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
|
||||
|
||||
bin_PROGRAMS = osmo-nitb
|
||||
bin_PROGRAMS = osmo-cscn
|
||||
|
||||
osmo_nitb_SOURCES = bsc_hack.c
|
||||
osmo_nitb_LDADD = \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
noinst_HEADERS = iucs_ranap.h
|
||||
|
||||
osmo_cscn_SOURCES = cscn_main.c iucs_ranap.c
|
||||
|
||||
osmo_cscn_LDADD = \
|
||||
$(top_builddir)/src/libiu/libiu.a \
|
||||
$(top_builddir)/src/libmsc/libmsc.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libtrau/libtrau.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(top_builddir)/src/libxsc/libxsc.a \
|
||||
-ldbi $(LIBCRYPT) \
|
||||
$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS) $(LIBSMPP34_LIBS) $(LIBCRYPTO_LIBS)
|
||||
$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS) $(LIBSMPP34_LIBS) $(LIBCRYPTO_LIBS) \
|
||||
$(LIBOSMORANAP_LIBS) $(LIBASN1C_LIBS) $(LIBOSMOSIGTRAN_LIBS)
|
@@ -1,6 +1,11 @@
|
||||
/* A hackish minimal BSC (+MSC +HLR) implementation */
|
||||
/* OsmoCSCN - Circuit-Switched Core Network (MSC+VLR+HLR+SMSC) implementation
|
||||
*/
|
||||
|
||||
/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
|
||||
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Based on OsmoNITB:
|
||||
* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
@@ -29,6 +34,9 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
|
||||
/* build switches from the configure script */
|
||||
#include "../../bscconfig.h"
|
||||
|
||||
#include <openbsc/db.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/select.h>
|
||||
@@ -41,6 +49,9 @@
|
||||
#include <openbsc/osmo_msc.h>
|
||||
#include <openbsc/osmo_msc_data.h>
|
||||
#include <openbsc/sms_queue.h>
|
||||
#include <osmocom/vty/telnet_interface.h>
|
||||
#include <osmocom/vty/ports.h>
|
||||
#include <osmocom/vty/logging.h>
|
||||
#include <openbsc/vty.h>
|
||||
#include <openbsc/bss.h>
|
||||
#include <openbsc/mncc.h>
|
||||
@@ -48,23 +59,55 @@
|
||||
#include <openbsc/handover_decision.h>
|
||||
#include <openbsc/rrlp.h>
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/ctrl/ports.h>
|
||||
#include <osmocom/ctrl/control_vty.h>
|
||||
#include <osmocom/ctrl/ports.h>
|
||||
#include <openbsc/ctrl.h>
|
||||
#include <openbsc/osmo_bsc_rf.h>
|
||||
#include <openbsc/smpp.h>
|
||||
#include <osmocom/sigtran/sccp_sap.h>
|
||||
#include <osmocom/sigtran/sua.h>
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
#include <openbsc/msc_ifaces.h>
|
||||
#include <openbsc/iu.h>
|
||||
#include <openbsc/iu_cs.h>
|
||||
|
||||
/* MCC and MNC for the Location Area Identifier */
|
||||
struct gsm_network *bsc_gsmnet = 0;
|
||||
static const char *database_name = "hlr.sqlite3";
|
||||
static const char *config_file = "openbsc.cfg";
|
||||
static const char *rf_ctrl_path = NULL;
|
||||
extern const char *openbsc_copyright;
|
||||
static int daemonize = 0;
|
||||
static const char *mncc_sock_path = NULL;
|
||||
static int use_db_counter = 1;
|
||||
#include "iucs_ranap.h"
|
||||
|
||||
static const char * const osmocscn_copyright =
|
||||
"OsmoCSCN - Osmocom Circuit-Switched Core Network implementation\r\n"
|
||||
"Copyright (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
|
||||
"Based on OsmoNITB:\r\n"
|
||||
" (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>\r\n"
|
||||
" (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>\r\n"
|
||||
"Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\r\n"
|
||||
"Dieter Spaar, Andreas Eversberg, Sylvain Munaut, Neels Hofmeyr\r\n\r\n"
|
||||
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
||||
"This is free software: you are free to change and redistribute it.\r\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
||||
|
||||
void *tall_cscn_ctx = NULL;
|
||||
|
||||
/* satisfy deps from libbsc legacy.
|
||||
TODO double check these */
|
||||
void *tall_fle_ctx = NULL;
|
||||
void *tall_paging_ctx = NULL;
|
||||
void *tall_map_ctx = NULL;
|
||||
void *tall_upq_ctx = NULL;
|
||||
/* end deps from libbsc legacy. */
|
||||
|
||||
static struct {
|
||||
const char *database_name;
|
||||
const char *config_file;
|
||||
int daemonize;
|
||||
const char *mncc_sock_path;
|
||||
int use_db_counter;
|
||||
} cscn_cmdline_config = {
|
||||
"hlr.sqlite3",
|
||||
"osmo-cscn.cfg",
|
||||
0,
|
||||
0,
|
||||
1
|
||||
};
|
||||
|
||||
/* timer to store statistics */
|
||||
#define DB_SYNC_INTERVAL 60, 0
|
||||
@@ -104,10 +147,8 @@ static void print_help()
|
||||
printf(" -V --version Print the version of OpenBSC.\n");
|
||||
printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC.\n");
|
||||
printf(" -e --log-level number Set a global loglevel.\n");
|
||||
printf(" -M --mncc-sock-path PATH Disable built-in MNCC handler and offer socket.\n");
|
||||
printf(" -m --mncc-sock Same as `-M /tmp/bsc_mncc' (deprecated).\n");
|
||||
printf(" -m --mncc-sock Disable built-in MNCC handler and offer socket.\n");
|
||||
printf(" -C --no-dbcounter Disable regular syncing of counters to database.\n");
|
||||
printf(" -r --rf-ctl PATH A unix domain socket to listen for cmds.\n");
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char **argv)
|
||||
@@ -130,7 +171,6 @@ static void handle_options(int argc, char **argv)
|
||||
{"mncc-sock", 0, 0, 'm'},
|
||||
{"mncc-sock-path", 1, 0, 'M'},
|
||||
{"no-dbcounter", 0, 0, 'C'},
|
||||
{"rf-ctl", 1, 0, 'r'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -151,13 +191,13 @@ static void handle_options(int argc, char **argv)
|
||||
log_parse_category_mask(osmo_stderr_target, optarg);
|
||||
break;
|
||||
case 'D':
|
||||
daemonize = 1;
|
||||
cscn_cmdline_config.daemonize = 1;
|
||||
break;
|
||||
case 'l':
|
||||
database_name = optarg;
|
||||
cscn_cmdline_config.database_name = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
config_file = optarg;
|
||||
cscn_cmdline_config.config_file = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
create_pcap_file(optarg);
|
||||
@@ -165,37 +205,58 @@ static void handle_options(int argc, char **argv)
|
||||
case 'T':
|
||||
log_set_print_timestamp(osmo_stderr_target, 1);
|
||||
break;
|
||||
#if BEFORE_MSCSPLIT
|
||||
case 'P':
|
||||
ipacc_rtp_direct = 0;
|
||||
break;
|
||||
#endif
|
||||
case 'e':
|
||||
log_set_log_level(osmo_stderr_target, atoi(optarg));
|
||||
break;
|
||||
case 'M':
|
||||
mncc_sock_path = optarg;
|
||||
cscn_cmdline_config.mncc_sock_path = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
mncc_sock_path = "/tmp/bsc_mncc";
|
||||
cscn_cmdline_config.mncc_sock_path = "/tmp/bsc_mncc";
|
||||
break;
|
||||
case 'C':
|
||||
use_db_counter = 0;
|
||||
cscn_cmdline_config.use_db_counter = 0;
|
||||
break;
|
||||
case 'V':
|
||||
print_version(1);
|
||||
exit(0);
|
||||
break;
|
||||
case 'r':
|
||||
rf_ctrl_path = optarg;
|
||||
break;
|
||||
default:
|
||||
/* catch unknown options *as well as* missing arguments. */
|
||||
fprintf(stderr, "Error in command line options. Exiting.\n");
|
||||
exit(-1);
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct gsm_network *cscn_network_init(void *ctx,
|
||||
mncc_recv_cb_t mncc_recv)
|
||||
{
|
||||
struct gsm_network *net = gsm_network_init(ctx, 1, 1, mncc_recv);
|
||||
if (!net)
|
||||
return NULL;
|
||||
|
||||
net->name_long = talloc_strdup(net, "OsmoCSCN");
|
||||
net->name_short = talloc_strdup(net, "OsmoCSCN");
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
void cscn_network_shutdown(struct gsm_network *net)
|
||||
{
|
||||
/* nothing here yet */
|
||||
}
|
||||
|
||||
static struct gsm_network *cscn_network = NULL;
|
||||
|
||||
/* TODO this is here to satisfy linking during intermediate development. Once
|
||||
* libbsc is not linked to osmo-cscn, this should go away. */
|
||||
struct gsm_network *bsc_gsmnet = NULL;
|
||||
|
||||
extern void *tall_vty_ctx;
|
||||
static void signal_handler(int signal)
|
||||
{
|
||||
@@ -203,7 +264,7 @@ static void signal_handler(int signal)
|
||||
|
||||
switch (signal) {
|
||||
case SIGINT:
|
||||
bsc_shutdown_net(bsc_gsmnet);
|
||||
cscn_network_shutdown(cscn_network);
|
||||
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
|
||||
sleep(3);
|
||||
exit(0);
|
||||
@@ -213,7 +274,7 @@ static void signal_handler(int signal)
|
||||
* and then return to the caller, who will abort the process */
|
||||
case SIGUSR1:
|
||||
talloc_report(tall_vty_ctx, stderr);
|
||||
talloc_report_full(tall_bsc_ctx, stderr);
|
||||
talloc_report_full(tall_cscn_ctx, stderr);
|
||||
break;
|
||||
case SIGUSR2:
|
||||
talloc_report_full(tall_vty_ctx, stderr);
|
||||
@@ -238,119 +299,186 @@ static void db_sync_timer_cb(void *data)
|
||||
|
||||
static void subscr_expire_cb(void *data)
|
||||
{
|
||||
subscr_expire(bsc_gsmnet->subscr_group);
|
||||
osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
|
||||
subscr_expire(cscn_network->subscr_group);
|
||||
osmo_timer_schedule(&cscn_network->subscr_expire_timer, EXPIRE_INTERVAL);
|
||||
}
|
||||
|
||||
void talloc_ctx_init(void);
|
||||
void talloc_ctx_init(void *ctx_root);
|
||||
|
||||
extern int bsc_vty_go_parent(struct vty *vty);
|
||||
|
||||
static struct vty_app_info vty_info = {
|
||||
.name = "OpenBSC",
|
||||
static struct vty_app_info cscn_vty_info = {
|
||||
.name = "OsmoCSCN",
|
||||
.version = PACKAGE_VERSION,
|
||||
.go_parent_cb = bsc_vty_go_parent,
|
||||
.is_config_node = bsc_vty_is_config_node,
|
||||
};
|
||||
|
||||
static int rcvmsg_iu_cs(struct msgb *msg, struct gprs_ra_id *ra_id, /* FIXME gprs_ in CS code */
|
||||
uint16_t *sai)
|
||||
{
|
||||
DEBUGP(DIUCS, "got IuCS message"
|
||||
" %d bytes: %s\n",
|
||||
msg->len, osmo_hexdump(msg->data, msg->len));
|
||||
if (ra_id) {
|
||||
DEBUGP(DIUCS, "got IuCS message on"
|
||||
" MNC %d MCC %d LAC %d RAC %d\n",
|
||||
ra_id->mnc, ra_id->mcc, ra_id->lac, ra_id->rac);
|
||||
}
|
||||
|
||||
return gsm0408_rcvmsg_iucs(cscn_network, msg, ra_id? &ra_id->lac : NULL);
|
||||
}
|
||||
|
||||
static int rx_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type,
|
||||
void *data)
|
||||
{
|
||||
DEBUGP(DIUCS, "got IuCS event %u: %s\n", type,
|
||||
iu_event_type_str(type));
|
||||
|
||||
return iucs_rx_ranap_event(cscn_network, ctx, type, data);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
vty_info.copyright = openbsc_copyright;
|
||||
cscn_vty_info.copyright = osmocscn_copyright;
|
||||
|
||||
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
|
||||
talloc_ctx_init();
|
||||
on_dso_load_token();
|
||||
on_dso_load_rrlp();
|
||||
on_dso_load_ho_dec();
|
||||
tall_cscn_ctx = talloc_named_const(NULL, 1, "osmo_cscn");
|
||||
talloc_ctx_init(tall_cscn_ctx);
|
||||
|
||||
libosmo_abis_init(tall_bsc_ctx);
|
||||
osmo_init_logging(&log_info);
|
||||
osmo_stats_init(tall_bsc_ctx);
|
||||
bts_init();
|
||||
osmo_stats_init(tall_cscn_ctx);
|
||||
|
||||
/* This needs to precede handle_options() */
|
||||
vty_init(&vty_info);
|
||||
bsc_vty_init(&log_info);
|
||||
ctrl_vty_init(tall_bsc_ctx);
|
||||
handle_options(argc, argv);
|
||||
|
||||
cscn_network = cscn_network_init(tall_cscn_ctx,
|
||||
cscn_cmdline_config.mncc_sock_path?
|
||||
mncc_sock_from_cc
|
||||
: int_mncc_recv);
|
||||
if (!cscn_network)
|
||||
return -ENOMEM;
|
||||
|
||||
vty_init(&cscn_vty_info);
|
||||
ctrl_vty_init(tall_cscn_ctx);
|
||||
logging_vty_add_cmds(&log_info);
|
||||
xsc_vty_init(cscn_network);
|
||||
cscn_vty_init();
|
||||
bsc_vty_init_extra();
|
||||
|
||||
#ifdef BUILD_SMPP
|
||||
if (smpp_openbsc_alloc_init(tall_bsc_ctx) < 0)
|
||||
if (smpp_openbsc_alloc_init(tall_cscn_ctx) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
/* parse options */
|
||||
handle_options(argc, argv);
|
||||
rc = vty_read_config_file(cscn_cmdline_config.config_file, NULL);
|
||||
if (rc < 0) {
|
||||
LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n",
|
||||
cscn_cmdline_config.config_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* internal MNCC handler or MNCC socket? */
|
||||
if (mncc_sock_path) {
|
||||
rc = bsc_bootstrap_network(mncc_sock_from_cc, config_file);
|
||||
if (rc >= 0)
|
||||
mncc_sock_init(bsc_gsmnet, mncc_sock_path);
|
||||
if (cscn_cmdline_config.mncc_sock_path) {
|
||||
rc = mncc_sock_init(cscn_network,
|
||||
cscn_cmdline_config.mncc_sock_path);
|
||||
if (rc < 0)
|
||||
exit(1);
|
||||
} else {
|
||||
DEBUGP(DMNCC, "Using internal MNCC handler.\n");
|
||||
rc = bsc_bootstrap_network(int_mncc_recv, config_file);
|
||||
}
|
||||
|
||||
/* start telnet after reading config for vty_get_bind_addr() */
|
||||
LOGP(DGPRS, LOGL_NOTICE, "VTY at %s %d\n",
|
||||
vty_get_bind_addr(), OSMO_VTY_PORT_CSCN);
|
||||
rc = telnet_init_dynif(tall_cscn_ctx, &cscn_network,
|
||||
vty_get_bind_addr(), OSMO_VTY_PORT_CSCN);
|
||||
if (rc < 0)
|
||||
exit(1);
|
||||
#ifdef BUILD_SMPP
|
||||
smpp_openbsc_start(bsc_gsmnet);
|
||||
return 2;
|
||||
|
||||
/* BSC stuff is to be split behind an A-interface to be used with
|
||||
* OsmoBSC, but there is no need to remove it yet. Most of the
|
||||
* following code until iu_init() is legacy. */
|
||||
|
||||
#if 0
|
||||
on_dso_load_token();
|
||||
on_dso_load_rrlp();
|
||||
on_dso_load_ho_dec();
|
||||
libosmo_abis_init(tall_cscn_ctx);
|
||||
|
||||
bts_init();
|
||||
#endif
|
||||
bsc_api_init(bsc_gsmnet, msc_bsc_api());
|
||||
|
||||
#ifdef BUILD_SMPP
|
||||
smpp_openbsc_start(cscn_network);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
bsc_api_init(cscn_network, msc_bsc_api()); // pobably not.
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
the bsc_ctrl_node_lookup() only returns BSC specific ctrl nodes
|
||||
|
||||
/* start control interface after reading config for
|
||||
* ctrl_vty_get_bind_addr() */
|
||||
LOGP(DNM, LOGL_NOTICE, "CTRL at %s %d\n",
|
||||
ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_NITB_BSC);
|
||||
bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet,
|
||||
ctrl_vty_get_bind_addr(),
|
||||
OSMO_CTRL_PORT_NITB_BSC);
|
||||
if (!bsc_gsmnet->ctrl) {
|
||||
ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_CSCN);
|
||||
cscn_network->ctrl = bsc_controlif_setup(cscn_network,
|
||||
ctrl_vty_get_bind_addr(),
|
||||
OSMO_CTRL_PORT_CSCN);
|
||||
if (!cscn_network->ctrl) {
|
||||
printf("Failed to initialize control interface. Exiting.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_install().
|
||||
if (bsc_base_ctrl_cmds_install() != 0) {
|
||||
printf("Failed to initialize the BSC control commands.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (msc_ctrl_cmds_install() != 0) {
|
||||
printf("Failed to initialize the MSC control commands.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* seed the PRNG */
|
||||
srand(time(NULL));
|
||||
/* TODO: is this used for crypto?? Improve randomness, at least we
|
||||
* should try to use the nanoseconds part of the current time. */
|
||||
|
||||
bsc_gsmnet->bsc_data->rf_ctrl = osmo_bsc_rf_create(rf_ctrl_path, bsc_gsmnet);
|
||||
if (!bsc_gsmnet->bsc_data->rf_ctrl) {
|
||||
#if 0
|
||||
cscn_network->bsc_data->rf_ctrl = osmo_bsc_rf_create(rf_ctrl_name, cscn_network);
|
||||
if (!cscn_network->bsc_data->rf_ctrl) {
|
||||
fprintf(stderr, "Failed to create the RF service.\n");
|
||||
exit(1);
|
||||
return 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (db_init(database_name)) {
|
||||
printf("DB: Failed to init database. Please check the option settings.\n");
|
||||
return -1;
|
||||
if (db_init(cscn_cmdline_config.database_name)) {
|
||||
printf("DB: Failed to init database: %s\n",
|
||||
cscn_cmdline_config.database_name);
|
||||
return 4;
|
||||
}
|
||||
printf("DB: Database initialized.\n");
|
||||
|
||||
if (db_prepare()) {
|
||||
printf("DB: Failed to prepare database.\n");
|
||||
return -1;
|
||||
return 5;
|
||||
}
|
||||
printf("DB: Database prepared.\n");
|
||||
|
||||
/* setup the timer */
|
||||
db_sync_timer.cb = db_sync_timer_cb;
|
||||
db_sync_timer.data = NULL;
|
||||
if (use_db_counter)
|
||||
if (cscn_cmdline_config.use_db_counter)
|
||||
osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL);
|
||||
|
||||
bsc_gsmnet->subscr_expire_timer.cb = subscr_expire_cb;
|
||||
bsc_gsmnet->subscr_expire_timer.data = NULL;
|
||||
osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
|
||||
cscn_network->subscr_expire_timer.cb = subscr_expire_cb;
|
||||
cscn_network->subscr_expire_timer.data = NULL;
|
||||
osmo_timer_schedule(&cscn_network->subscr_expire_timer, EXPIRE_INTERVAL);
|
||||
|
||||
signal(SIGINT, &signal_handler);
|
||||
signal(SIGABRT, &signal_handler);
|
||||
@@ -359,14 +487,20 @@ int main(int argc, char **argv)
|
||||
osmo_init_ignore_signals();
|
||||
|
||||
/* start the SMS queue */
|
||||
if (sms_queue_start(bsc_gsmnet, 20) != 0)
|
||||
if (sms_queue_start(cscn_network, 20) != 0)
|
||||
return -1;
|
||||
|
||||
if (daemonize) {
|
||||
/* Set up A-Interface */
|
||||
/* TODO: implement A-Interface and remove above legacy stuff. */
|
||||
|
||||
/* Set up IuCS */
|
||||
iu_init(tall_cscn_ctx, "127.0.0.1", 14001, rcvmsg_iu_cs, rx_iu_event);
|
||||
|
||||
if (cscn_cmdline_config.daemonize) {
|
||||
rc = osmo_daemonize();
|
||||
if (rc < 0) {
|
||||
perror("Error during daemonize");
|
||||
exit(1);
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
120
openbsc/src/osmo-cscn/iucs_ranap.c
Normal file
120
openbsc/src/osmo-cscn/iucs_ranap.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/* Implementation of RANAP messages to/from an MSC via an Iu-CS interface.
|
||||
* This keeps direct RANAP dependencies out of libmsc. */
|
||||
|
||||
/* (C) 2016 by sysmocom s.m.f.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/logging.h>
|
||||
|
||||
#include <osmocom/ranap/ranap_ies_defs.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/iu.h>
|
||||
#include <openbsc/iu_cs.h>
|
||||
|
||||
#include "iucs_ranap.h"
|
||||
|
||||
/* To continue authorization after a Security Mode Complete */
|
||||
int gsm0408_authorize(struct gsm_subscriber_connection *conn);
|
||||
|
||||
static int iucs_rx_rab_assign(struct gsm_subscriber_connection *conn,
|
||||
RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
|
||||
{
|
||||
uint8_t rab_id;
|
||||
RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
|
||||
|
||||
rab_id = item->rAB_ID.buf[0];
|
||||
|
||||
LOGP(DIUCS, LOGL_NOTICE, "Received RAB assignment event for %s"
|
||||
" rab_id=%hhd\n", subscr_name(conn->subscr), rab_id);
|
||||
/* TODO do stuff like in sgsn_ranap_rab_ass_resp() */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iucs_rx_sec_mode_compl(struct gsm_subscriber_connection *conn,
|
||||
RANAP_SecurityModeCompleteIEs_t *ies)
|
||||
{
|
||||
gsm_cbfn *cb;
|
||||
|
||||
OSMO_ASSERT(conn->via_iface == IFACE_IU);
|
||||
|
||||
if (!conn->sec_operation) {
|
||||
LOGP(DIUCS, LOGL_ERROR,
|
||||
"Received Security Mode Complete message, but no"
|
||||
" authentication/cipher operation in progress"
|
||||
" for subscr %s\n", subscr_name(conn->subscr));
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO evalute ies */
|
||||
|
||||
if (conn->iu.integrity_protection)
|
||||
LOGP(DIUCS, LOGL_NOTICE, "Integrity Protection"
|
||||
" was already enabled for %s\n",
|
||||
subscr_name(conn->subscr));
|
||||
|
||||
conn->iu.integrity_protection = INTEGRITY_PROTECTION_IK;
|
||||
|
||||
cb = conn->sec_operation->cb;
|
||||
if (cb)
|
||||
cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_SUCCEEDED, NULL,
|
||||
conn, conn->sec_operation->cb_data);
|
||||
release_security_operation(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iucs_rx_ranap_event(struct gsm_network *network,
|
||||
struct ue_conn_ctx *ue_ctx, int type, void *data)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
conn = subscr_conn_lookup_iu(network, ue_ctx);
|
||||
|
||||
if (!conn) {
|
||||
LOGP(DRANAP, LOGL_ERROR, "Cannot find subscriber for IU event %u\n", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case IU_EVENT_IU_RELEASE:
|
||||
case IU_EVENT_LINK_INVALIDATED:
|
||||
LOGP(DIUCS, LOGL_INFO, "IuCS release for %s\n",
|
||||
subscr_name(conn->subscr));
|
||||
gsm0408_clear_request(conn, 0);
|
||||
return 0;
|
||||
|
||||
case IU_EVENT_SECURITY_MODE_COMPLETE:
|
||||
LOGP(DIUCS, LOGL_INFO, "IuCS security mode complete for %s\n",
|
||||
subscr_name(conn->subscr));
|
||||
return iucs_rx_sec_mode_compl(conn,
|
||||
(RANAP_SecurityModeCompleteIEs_t*)data);
|
||||
case IU_EVENT_RAB_ASSIGN:
|
||||
return iucs_rx_rab_assign(conn,
|
||||
(RANAP_RAB_SetupOrModifiedItemIEs_t*)data);
|
||||
default:
|
||||
LOGP(DIUCS, LOGL_NOTICE, "Unknown message received:"
|
||||
" RANAP event: %i\n", type);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
7
openbsc/src/osmo-cscn/iucs_ranap.h
Normal file
7
openbsc/src/osmo-cscn/iucs_ranap.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
struct ue_conn_ctx;
|
||||
|
||||
int iucs_rx_ranap_event(struct gsm_network *network,
|
||||
struct ue_conn_ctx *ue_ctx, int type, void *data);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(SQLITE3_CFLAGS) \
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(SQLITE3_CFLAGS) \
|
||||
$(LIBSMPP34_CFLAGS)
|
||||
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
|
||||
|
||||
@@ -21,6 +21,7 @@ bs11_config_SOURCES = bs11_config.c
|
||||
bs11_config_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libtrau/libtrau.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(top_builddir)/src/libxsc/libxsc.a \
|
||||
$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS)
|
||||
|
||||
isdnsync_SOURCES = isdnsync.c
|
||||
|
@@ -893,7 +893,7 @@ int main(int argc, char **argv)
|
||||
handle_options(argc, argv);
|
||||
bts_model_bs11_init();
|
||||
|
||||
gsmnet = gsm_network_init(1, 1, NULL);
|
||||
gsmnet = gsm_network_init(tall_bsc_ctx, 1, 1, NULL);
|
||||
if (!gsmnet) {
|
||||
fprintf(stderr, "Unable to allocate gsm network\n");
|
||||
exit(1);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user