mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-bts.git
synced 2025-11-16 20:01:56 +00:00
Compare commits
221 Commits
keith/dtx-
...
jolly/lapd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dd42b4024 | ||
|
|
17225a09b5 | ||
|
|
90f6ebcd3b | ||
|
|
17fe7d6841 | ||
|
|
1013ca3b8b | ||
|
|
647b8d0978 | ||
|
|
bc6cc67115 | ||
|
|
bc4ca18a31 | ||
|
|
4a6a2fdf7e | ||
|
|
28b8759465 | ||
|
|
25aae40e17 | ||
|
|
dc3b78da01 | ||
|
|
7c76630024 | ||
|
|
bcb9875176 | ||
|
|
863d4d933e | ||
|
|
791d121bd9 | ||
|
|
771e9f2838 | ||
|
|
e5d8a469d2 | ||
|
|
8fafc1a74c | ||
|
|
d88cc624ed | ||
|
|
bd777b0276 | ||
|
|
3bd97d839e | ||
|
|
6ed4a9a1eb | ||
|
|
d265ce68b2 | ||
|
|
586e897eea | ||
|
|
955b7dc637 | ||
|
|
695080745c | ||
|
|
fe005cb76e | ||
|
|
b960c7558a | ||
|
|
b8a185cc12 | ||
|
|
08f058789f | ||
|
|
8bff3b6898 | ||
|
|
aaa1f26e52 | ||
|
|
40ba43a2e8 | ||
|
|
c6211a8bec | ||
|
|
aa06f97326 | ||
|
|
188f76275a | ||
|
|
ddc15996dd | ||
|
|
f5c1cd3889 | ||
|
|
0978d1df71 | ||
|
|
852b2cbadc | ||
|
|
c4e836838d | ||
|
|
9aaaacc7aa | ||
|
|
9d9d9e2f27 | ||
|
|
fbd8aa8a77 | ||
|
|
e8518ae375 | ||
|
|
fd4654e1b8 | ||
|
|
e97834f2db | ||
|
|
8a1f740dfc | ||
|
|
1d53d231da | ||
|
|
d2d938c261 | ||
|
|
f20e13d160 | ||
|
|
55a21dc1c3 | ||
|
|
b33502a39b | ||
|
|
183c088864 | ||
|
|
37e639cb8f | ||
|
|
7e5a62e9f3 | ||
|
|
9171e37aff | ||
|
|
086b46a77f | ||
|
|
ff085f63c9 | ||
|
|
bbb3a1ed17 | ||
|
|
88de4d6789 | ||
|
|
66eae187b9 | ||
|
|
8ae829cabc | ||
|
|
007e72d5bc | ||
|
|
ca418643b3 | ||
|
|
d1f8f3429c | ||
|
|
97d3bd3e62 | ||
|
|
467d63e387 | ||
|
|
be93b87a64 | ||
|
|
ba5d2e4a5f | ||
|
|
0a2b0a20b3 | ||
|
|
290085787a | ||
|
|
6fa1dfce61 | ||
|
|
65c8f0de94 | ||
|
|
98e5d6f7c6 | ||
|
|
29fcae8632 | ||
|
|
fa90ff3e67 | ||
|
|
15330e2368 | ||
|
|
cdbd83affd | ||
|
|
2ae45aba3f | ||
|
|
6c83527e62 | ||
|
|
d04e3e708b | ||
|
|
4344f323f2 | ||
|
|
17087a08c7 | ||
|
|
f2c902c2af | ||
|
|
bb596dddc7 | ||
|
|
4bbfb904b8 | ||
|
|
deef79ffae | ||
|
|
95407f3f63 | ||
|
|
f3a63758d1 | ||
|
|
34077236f2 | ||
|
|
d53a084fd6 | ||
|
|
2bdb2201f6 | ||
|
|
84d220abc1 | ||
|
|
34838ee4e9 | ||
|
|
44c94fdeae | ||
|
|
f0510b6207 | ||
|
|
3480a2ab4c | ||
|
|
ad15414fd9 | ||
|
|
f98a55b713 | ||
|
|
1f5fdf8c8d | ||
|
|
d78968422f | ||
|
|
c860309aea | ||
|
|
5c1401d6f3 | ||
|
|
477fb3d9a4 | ||
|
|
e5c2bc346b | ||
|
|
c938a95e25 | ||
|
|
4c3b4e2868 | ||
|
|
676e9e5804 | ||
|
|
f0f91fc66c | ||
|
|
805340cb9c | ||
|
|
81ebfb34b4 | ||
|
|
07c3d86356 | ||
|
|
34ab6f1470 | ||
|
|
235d2bfbc4 | ||
|
|
fd544caae1 | ||
|
|
3f9e507d77 | ||
|
|
b2c6b68a10 | ||
|
|
c9a8eca543 | ||
|
|
9b5721b3fb | ||
|
|
194d1e8bc2 | ||
|
|
282c87ab2d | ||
|
|
785e731def | ||
|
|
592030eee7 | ||
|
|
3302d4adfe | ||
|
|
405368b697 | ||
|
|
1dd710944f | ||
|
|
a84b9a0261 | ||
|
|
d9de1a5b28 | ||
|
|
a0770250bc | ||
|
|
c18f9f256c | ||
|
|
44d47b2cdd | ||
|
|
4b945ec327 | ||
|
|
1160cabefb | ||
|
|
208127986e | ||
|
|
05b4629166 | ||
|
|
9cc85c1a6a | ||
|
|
2c511d5755 | ||
|
|
0eb90a0a98 | ||
|
|
7f03444d8b | ||
|
|
81cfbb10cb | ||
|
|
e38618f7cc | ||
|
|
5755946beb | ||
|
|
8b306b6f93 | ||
|
|
267c2606ad | ||
|
|
04a373cf6a | ||
|
|
3f5a343098 | ||
|
|
2a60cc3087 | ||
|
|
acaf6c563b | ||
|
|
dfd6224484 | ||
|
|
8b535ee77a | ||
|
|
cf8736e916 | ||
|
|
204cd4d7e3 | ||
|
|
1d7133e936 | ||
|
|
a4a9c28f15 | ||
|
|
f729ff970a | ||
|
|
bbdb10ee48 | ||
|
|
ac1eb71d78 | ||
|
|
11ec99d419 | ||
|
|
fad8986f06 | ||
|
|
b96d975f7d | ||
|
|
30601ccaf4 | ||
|
|
a1927f32f7 | ||
|
|
be18d2b275 | ||
|
|
cb0c0dfa15 | ||
|
|
8a21e7c27a | ||
|
|
4c56bed4d7 | ||
|
|
31c759165a | ||
|
|
38491d813b | ||
|
|
1dc9e3f2f8 | ||
|
|
b07e19d185 | ||
|
|
c3e059ce04 | ||
|
|
36ef885a6c | ||
|
|
7cd45a7cfe | ||
|
|
6be13437b7 | ||
|
|
3481dd40b3 | ||
|
|
66543fe422 | ||
|
|
c3d839be9e | ||
|
|
5b75e5dc8d | ||
|
|
9c4b472179 | ||
|
|
10d5499d03 | ||
|
|
d50d239914 | ||
|
|
989d99ca00 | ||
|
|
633bbf174a | ||
|
|
4190537d7d | ||
|
|
cea6c230ad | ||
|
|
92d1d1582b | ||
|
|
f4505f6caf | ||
|
|
91a1295a5a | ||
|
|
8894fe6f4c | ||
|
|
aebd2a21b5 | ||
|
|
8c397da917 | ||
|
|
c4a17d35ec | ||
|
|
c12bc93db8 | ||
|
|
7a646f963b | ||
|
|
914e55caf3 | ||
|
|
0350824203 | ||
|
|
4ff6888a81 | ||
|
|
5f556af232 | ||
|
|
909d943fe8 | ||
|
|
1266c068d7 | ||
|
|
61e7fdbb3f | ||
|
|
50710f4e8e | ||
|
|
acf0f0f0bb | ||
|
|
f06b959c7d | ||
|
|
2551882c1c | ||
|
|
96263aa908 | ||
|
|
362f2e50c2 | ||
|
|
3d2c107922 | ||
|
|
9584980ea2 | ||
|
|
80c605dd0b | ||
|
|
c29ca5eb7d | ||
|
|
32682c63f6 | ||
|
|
e1e204fae3 | ||
|
|
ac23ce2e03 | ||
|
|
c17697d337 | ||
|
|
bb3ed23e71 | ||
|
|
a563640f86 | ||
|
|
61b005193c | ||
|
|
d47d288630 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -55,6 +55,7 @@ src/osmo-bts-oc2g/misc/.dirstamp
|
||||
tests/atconfig
|
||||
tests/package.m4
|
||||
tests/amr/amr_test
|
||||
tests/csd/csd_test
|
||||
tests/agch/agch_test
|
||||
tests/paging/paging_test
|
||||
tests/cipher/cipher_test
|
||||
@@ -105,3 +106,7 @@ doc/manuals/common
|
||||
doc/manuals/build
|
||||
|
||||
contrib/osmo-bts.spec
|
||||
contrib/ber/rtp_ber
|
||||
contrib/ber/rtp_gen_map
|
||||
|
||||
arm-poky-linux-gnueabi-libtool
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
# If any interfaces have been added since the last public release: c:r:a + 1.
|
||||
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
||||
#library what description / commit summary line
|
||||
libosmogsm >1.8.0 <osmocom/gsm/protocol/gsm_44_060.h> added
|
||||
libosmogsm >1.9.0 added new PRIM_INFO to include/osmocom/gsm/l1sap.h
|
||||
|
||||
20
configure.ac
20
configure.ac
@@ -69,15 +69,15 @@ then
|
||||
fi
|
||||
|
||||
dnl checks for libraries
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.4.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.4.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.3.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.4.0)
|
||||
|
||||
AC_MSG_CHECKING([whether to enable support for sysmobts calibration tool])
|
||||
AC_ARG_ENABLE(sysmobts-calib,
|
||||
@@ -445,10 +445,12 @@ AC_OUTPUT(
|
||||
tests/power/Makefile
|
||||
tests/meas/Makefile
|
||||
tests/amr/Makefile
|
||||
tests/csd/Makefile
|
||||
doc/Makefile
|
||||
doc/examples/Makefile
|
||||
doc/manuals/Makefile
|
||||
contrib/Makefile
|
||||
contrib/ber/Makefile
|
||||
contrib/systemd/Makefile
|
||||
contrib/osmo-bts.spec
|
||||
Makefile)
|
||||
|
||||
@@ -1 +1 @@
|
||||
SUBDIRS = systemd
|
||||
SUBDIRS = systemd ber
|
||||
|
||||
28
contrib/ber/Makefile.am
Normal file
28
contrib/ber/Makefile.am
Normal file
@@ -0,0 +1,28 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_builddir)/include \
|
||||
-I$(builddir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOTRAU_CFLAGS) \
|
||||
$(LIBOSMOCODEC_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
LDADD = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOTRAU_LIBS) \
|
||||
$(LIBOSMOCODEC_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = rtp_ber rtp_gen_map
|
||||
|
||||
rtp_ber_SOURCES = rtp_ber.c codec_bit_class.h
|
||||
|
||||
rtp_gen_map_SOURCES = rtp_gen_map.c
|
||||
|
||||
update_codec_bit_class_h: rtp_gen_map
|
||||
$(AM_V_GEN)./$< > $(top_srcdir)/contrib/ber/codec_bit_class.h
|
||||
26
contrib/ber/README
Normal file
26
contrib/ber/README
Normal file
@@ -0,0 +1,26 @@
|
||||
BER testing tool
|
||||
----------------
|
||||
|
||||
* Check all configs (MSC/BSC/BTS) for proper codec support
|
||||
- FR enabled
|
||||
- EFR enabled
|
||||
- AMR 12.2 enabled (and all other modes disabled !)
|
||||
- Use `amr-payload octet-aligned` in BSC config
|
||||
|
||||
* Check BTS config
|
||||
- Disable jitter buffer : `bts N / rtp jitter-buffer 0`
|
||||
|
||||
* Check BSC config
|
||||
- Disable radio timeout : `network / bts n / radio-link-timeout infinite`
|
||||
|
||||
* Start BER testing tool
|
||||
- `./rtp_ber 4000`
|
||||
|
||||
* On the MSC CLI, start a silent-call, then request GSM to test loop
|
||||
- `subscriber imsi <XXX> silent-call start tch/f speech-amr`
|
||||
- `subscriber imsi <XXX> ms-test close-loop b`
|
||||
|
||||
Don't forget to terminate the loop and terminate the silent call !
|
||||
|
||||
- `subscriber imsi <XXX> ms-test open-loop`
|
||||
- `subscriber imsi <XXX> silent-call stop`
|
||||
59
contrib/ber/codec_bit_class.h
Normal file
59
contrib/ber/codec_bit_class.h
Normal file
@@ -0,0 +1,59 @@
|
||||
static const int gsm_fr_bitclass[] = {
|
||||
-1, -1, -1, -1, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 2, 2,
|
||||
0, 0, 1, 2, 2, 0, 0, 1, 2, 2, 0, 1, 1, 2, 0, 1,
|
||||
2, 2, 0, 1, 2, 1, 2, 2, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1,
|
||||
1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1,
|
||||
2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2,
|
||||
1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1,
|
||||
1, 2, 1, 1, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1,
|
||||
1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1,
|
||||
2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2,
|
||||
1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1,
|
||||
2, 2, 1, 2, 2, 1, 2, 2,
|
||||
};
|
||||
|
||||
static const int gsm_efr_bitclass[] = {
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
|
||||
1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
|
||||
1, 1, 1, 1, 2, 2, 1, 2,
|
||||
};
|
||||
|
||||
static const int gsm_amr_12_2_bitclass[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
483
contrib/ber/rtp_ber.c
Normal file
483
contrib/ber/rtp_ber.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/* RTP based GSM BER testing for osmo-bts, implementing ideas described in
|
||||
* https://osmocom.org/projects/osmobts/wiki/BER_Testing
|
||||
*
|
||||
* In short: The command transmits a PRBS sequence encapsulated in RTP frames, which are sent
|
||||
* to the BTS, which transmits that data in the (unimpaired) downlink. The mobile station
|
||||
* receives the data and is instructed to loop it back in the (possibly impaired) uplink.
|
||||
* The BTS receives that uplink, puts in in RTP frames which end up being received back by this
|
||||
* very tool. By correlating the received RTP with the PRBS sequence, this tool can compute
|
||||
* the BER (Bit Error Rate) of the (possibly impaired) uplink. Doing this with different
|
||||
* RF channel model simulators in the uplink allows to establish BER at different levels and
|
||||
* channel conditions. */
|
||||
|
||||
/* (C) 2019 sysmocom - s.f.m.c. GmbH; Author: Sylvain Munaut
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osmocom/codec/codec.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/prbs.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/trau/osmo_ortp.h>
|
||||
|
||||
#include <codec_bit_class.h>
|
||||
|
||||
|
||||
struct app_state {
|
||||
struct osmo_rtp_socket *rs;
|
||||
|
||||
enum {
|
||||
WAIT_CONN = 0, /* Wait for incoming connection */
|
||||
WAIT_LOOP, /* Wait for a somewhat valid packet to start measuring */
|
||||
RUNNING, /* Main state */
|
||||
} state;
|
||||
|
||||
int pt;
|
||||
|
||||
int ref_len;
|
||||
uint8_t ref_bytes[GSM_FR_BYTES]; /* FR is the largest possible one */
|
||||
ubit_t ref_bits[8*GSM_FR_BYTES];
|
||||
|
||||
struct osmo_timer_list rtp_timer;
|
||||
|
||||
uint16_t rx_last_seq;
|
||||
uint32_t rx_last_ts;
|
||||
uint32_t rx_idx;
|
||||
uint32_t tx_idx;
|
||||
|
||||
const int *err_tbl; /* Classification table */
|
||||
int err_frames; /* Number of accumulated frames */
|
||||
int err_cnt[3]; /* Bit error counter */
|
||||
int err_tot[3]; /* Total # bits in that class */
|
||||
};
|
||||
|
||||
#define FLOW_REG_TX_MAX_ADVANCE 200
|
||||
#define FLOW_REG_TX_MIN_ADVANCE 50
|
||||
|
||||
|
||||
const struct log_info log_info;
|
||||
|
||||
|
||||
static const uint8_t amr_size_by_ft[] = {
|
||||
[0] = 12, /* 4.75 */
|
||||
[1] = 13, /* 5.15 */
|
||||
[2] = 15, /* 5.9 */
|
||||
[3] = 17, /* 6.7 */
|
||||
[4] = 19, /* 7.4 */
|
||||
[5] = 20, /* 7.95 */
|
||||
[6] = 26, /* 10.2 */
|
||||
[7] = 31, /* 12.2 */
|
||||
[8] = 5, /* SID */
|
||||
};
|
||||
|
||||
static const char * const amr_rate_by_ft[] = {
|
||||
[0] = "4.75",
|
||||
[1] = "5.15",
|
||||
[2] = "5.9",
|
||||
[3] = "6.7",
|
||||
[4] = "7.4",
|
||||
[5] = "7.95",
|
||||
[6] = "10.2",
|
||||
[7] = "12.2",
|
||||
[8] = "SID",
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
_gsm_fr_gen_ref(struct app_state *as)
|
||||
{
|
||||
struct osmo_prbs_state pn9;
|
||||
|
||||
/* Length */
|
||||
as->ref_len = GSM_FR_BYTES;
|
||||
|
||||
/* Marker */
|
||||
as->ref_bits[0] = 1;
|
||||
as->ref_bits[1] = 1;
|
||||
as->ref_bits[2] = 0;
|
||||
as->ref_bits[3] = 1;
|
||||
|
||||
/* PN */
|
||||
osmo_prbs_state_init(&pn9, &osmo_prbs9);
|
||||
pn9.state = 31;
|
||||
osmo_prbs_get_ubits(&as->ref_bits[4], 260, &pn9);
|
||||
|
||||
/* Convert to bytes */
|
||||
osmo_ubit2pbit_ext(as->ref_bytes, 0, as->ref_bits, 0, 8*GSM_FR_BYTES, 0);
|
||||
|
||||
/* Init error classes */
|
||||
as->err_tot[0] = 50;
|
||||
as->err_tot[1] = 132;
|
||||
as->err_tot[2] = 78;
|
||||
as->err_tbl = gsm_fr_bitclass;
|
||||
}
|
||||
|
||||
static void
|
||||
_gsm_efr_gen_ref(struct app_state *as)
|
||||
{
|
||||
struct osmo_prbs_state pn9;
|
||||
|
||||
/* Length */
|
||||
as->ref_len = GSM_EFR_BYTES;
|
||||
|
||||
/* Marker */
|
||||
as->ref_bits[0] = 1;
|
||||
as->ref_bits[1] = 1;
|
||||
as->ref_bits[2] = 0;
|
||||
as->ref_bits[3] = 0;
|
||||
|
||||
/* PN */
|
||||
osmo_prbs_state_init(&pn9, &osmo_prbs9);
|
||||
pn9.state = 31;
|
||||
osmo_prbs_get_ubits(&as->ref_bits[4], 244, &pn9);
|
||||
|
||||
/* Convert to bytes */
|
||||
osmo_ubit2pbit_ext(as->ref_bytes, 0, as->ref_bits, 0, 8*GSM_EFR_BYTES, 0);
|
||||
|
||||
/* Init error classes */
|
||||
as->err_tot[0] = 50;
|
||||
as->err_tot[1] = 125;
|
||||
as->err_tot[2] = 73;
|
||||
as->err_tbl = gsm_efr_bitclass;
|
||||
}
|
||||
|
||||
static void
|
||||
_gsm_amr_gen_ref(struct app_state *as)
|
||||
{
|
||||
struct osmo_prbs_state pn9;
|
||||
uint8_t hdr[2];
|
||||
|
||||
/* Length */
|
||||
as->ref_len = 33;
|
||||
|
||||
/* Header */
|
||||
hdr[0] = 0x70;
|
||||
hdr[1] = 0x3c;
|
||||
osmo_pbit2ubit_ext(as->ref_bits, 0, hdr, 0, 16, 0);
|
||||
|
||||
/* PN */
|
||||
osmo_prbs_state_init(&pn9, &osmo_prbs9);
|
||||
pn9.state = 31;
|
||||
osmo_prbs_get_ubits(&as->ref_bits[16], 244, &pn9);
|
||||
|
||||
/* Unused bits */
|
||||
as->ref_bits[260] = 0;
|
||||
as->ref_bits[261] = 0;
|
||||
as->ref_bits[262] = 0;
|
||||
as->ref_bits[263] = 0;
|
||||
|
||||
/* Convert to bytes */
|
||||
osmo_ubit2pbit_ext(as->ref_bytes, 0, as->ref_bits, 0, 264, 0);
|
||||
|
||||
/* Init error classes */
|
||||
as->err_tot[0] = 81;
|
||||
as->err_tot[1] = 163;
|
||||
as->err_tot[2] = -1;
|
||||
as->err_tbl = gsm_amr_12_2_bitclass;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_gsm_gen_ref(struct app_state *as)
|
||||
{
|
||||
switch (as->pt) {
|
||||
case RTP_PT_GSM_FULL:
|
||||
_gsm_fr_gen_ref(as);
|
||||
break;
|
||||
case RTP_PT_GSM_EFR:
|
||||
_gsm_efr_gen_ref(as);
|
||||
break;
|
||||
case RTP_PT_AMR:
|
||||
_gsm_amr_gen_ref(as);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "[!] Unsupported payload type for BER measurement\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_gsm_ber(struct app_state *as, const uint8_t *payload, unsigned int payload_len)
|
||||
{
|
||||
ubit_t rx_bits[8*33];
|
||||
int err[3]; /* Class 1a, 1b, 2 */
|
||||
int ones;
|
||||
int i, j;
|
||||
|
||||
if (payload) {
|
||||
/* Process real-payload */
|
||||
osmo_pbit2ubit_ext(rx_bits, 0, payload, 0, 8*payload_len, 0);
|
||||
|
||||
err[0] = err[1] = err[2] = 0;
|
||||
ones = 0;
|
||||
|
||||
for (i = 0; i < 8 * payload_len; i++) {
|
||||
j = as->err_tbl[i];
|
||||
if (j >= 0) {
|
||||
err[j] += rx_bits[i] ^ as->ref_bits[i];
|
||||
ones += rx_bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (ones < 32) { // This frames is probably us underrunning Tx, don't use it
|
||||
fprintf(stderr, "[w] Frame ignored as probably TX underrun %d %d\n", as->tx_idx, as->rx_idx);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* No payload -> Lost frame completely */
|
||||
err[0] = as->err_tot[0] / 2;
|
||||
err[1] = as->err_tot[1] / 2;
|
||||
err[2] = as->err_tot[2] / 2;
|
||||
}
|
||||
|
||||
if (as->state == RUNNING) {
|
||||
/* Update records */
|
||||
if (err[0] != 0) {
|
||||
/* Class 1a bits bad -> Frame error */
|
||||
as->err_cnt[0]++;
|
||||
}
|
||||
|
||||
as->err_cnt[1] += err[1]; /* Class 1b */
|
||||
as->err_cnt[2] += err[2]; /* class 2 */
|
||||
|
||||
as->err_frames++;
|
||||
|
||||
/* Enough for a read-out ? */
|
||||
if (as->err_frames == 200) {
|
||||
printf("FBER: %4.2f C1b RBER: %5.3f C2 RBER: %5.3f\n",
|
||||
100.0f * as->err_cnt[0] / as->err_frames,
|
||||
100.0f * as->err_cnt[1] / (as->err_tot[1] * as->err_frames),
|
||||
100.0f * as->err_cnt[2] / (as->err_tot[2] * as->err_frames)
|
||||
);
|
||||
memset(as->err_cnt, 0, sizeof(as->err_cnt));
|
||||
as->err_frames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return err[0] != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_rtp_check_payload_type(const uint8_t *payload, unsigned int payload_len)
|
||||
{
|
||||
uint8_t ft;
|
||||
int pt = -1;
|
||||
|
||||
switch (payload_len) {
|
||||
case GSM_FR_BYTES: /* FR or AMR 12.2k */
|
||||
/* Check for AMR */
|
||||
ft = (payload[1] >> 3) & 0xf;
|
||||
if (ft == 7)
|
||||
pt = RTP_PT_AMR;
|
||||
|
||||
/* Check for FR */
|
||||
else if ((payload[0] & 0xF0) == 0xD0)
|
||||
pt = RTP_PT_GSM_FULL;
|
||||
|
||||
/* None of the above */
|
||||
else
|
||||
fprintf(stderr, "[!] FR without 0xD0 signature or AMR with unknwon Frame Type ?!?\n");
|
||||
|
||||
break;
|
||||
case GSM_EFR_BYTES: /* EFR */
|
||||
if ((payload[0] & 0xF0) != 0xC0)
|
||||
fprintf(stderr, "[!] EFR without 0xC0 signature ?!?\n");
|
||||
pt = RTP_PT_GSM_EFR;
|
||||
break;
|
||||
case GSM_HR_BYTES: /* HR */
|
||||
pt = RTP_PT_GSM_HALF;
|
||||
break;
|
||||
default: /* AMR */
|
||||
{
|
||||
uint8_t cmr, cmi, sti;
|
||||
cmr = payload[0] >> 4;
|
||||
ft = (payload[1] >> 3) & 0xf;
|
||||
|
||||
if (payload_len != amr_size_by_ft[ft]+2)
|
||||
fprintf(stderr, "AMR FT %u(%s) but size %u\n",
|
||||
ft, amr_rate_by_ft[ft], payload_len);
|
||||
|
||||
switch (ft) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
case 4: case 5: case 6: case 7:
|
||||
cmi = ft;
|
||||
printf("AMR SPEECH with FT/CMI %u(%s), "
|
||||
"CMR %u\n",
|
||||
cmi, amr_rate_by_ft[cmi],
|
||||
cmr);
|
||||
break;
|
||||
case 8: /* SID */
|
||||
cmi = (payload[2+4] >> 1) & 0x7;
|
||||
sti = payload[2+4] & 0x10;
|
||||
printf("AMR SID %s with CMI %u(%s), CMR %u(%s)\n",
|
||||
sti ? "UPDATE" : "FIRST",
|
||||
cmi, amr_rate_by_ft[cmi],
|
||||
cmr, amr_rate_by_ft[cmr]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
static void
|
||||
rtp_timer_cb(void *priv)
|
||||
{
|
||||
struct app_state *as = (struct app_state *)priv;
|
||||
|
||||
/* Send at least one frame if we're not too far ahead */
|
||||
if (as->tx_idx < (as->rx_idx + FLOW_REG_TX_MAX_ADVANCE)) {
|
||||
osmo_rtp_send_frame(as->rs, as->ref_bytes, as->ref_len, GSM_RTP_DURATION);
|
||||
as->tx_idx++;
|
||||
} else {
|
||||
fprintf(stderr, "Skipped\n");
|
||||
}
|
||||
|
||||
/* Then maybe a second one to try and catch up to RX */
|
||||
if (as->tx_idx < (as->rx_idx + FLOW_REG_TX_MIN_ADVANCE)) {
|
||||
osmo_rtp_send_frame(as->rs, as->ref_bytes, as->ref_len, GSM_RTP_DURATION);
|
||||
as->tx_idx++;
|
||||
}
|
||||
|
||||
/* Re-schedule */
|
||||
osmo_timer_schedule(&as->rtp_timer, 0, 20000);
|
||||
}
|
||||
|
||||
static int
|
||||
rtp_seq_num_diff(uint16_t new, uint16_t old)
|
||||
{
|
||||
int d = (int)new - (int)old;
|
||||
while (d > 49152)
|
||||
d -= 65536;
|
||||
while (d < -49152)
|
||||
d += 65536;
|
||||
return d;
|
||||
}
|
||||
|
||||
static void
|
||||
rtp_rx_cb(struct osmo_rtp_socket *rs,
|
||||
const uint8_t *payload, unsigned int payload_len,
|
||||
uint16_t seq_number, uint32_t timestamp, bool marker)
|
||||
{
|
||||
struct app_state *as = (struct app_state *)rs->priv;
|
||||
int pt, rc, d;
|
||||
|
||||
// printf("Rx(%u, %d, %d, %d): %s\n", payload_len, seq_number, timestamp, marker, osmo_hexdump(payload, payload_len));
|
||||
|
||||
/* Identify payload */
|
||||
pt = _rtp_check_payload_type(payload, payload_len);
|
||||
|
||||
/* First packet ? */
|
||||
if (as->state == WAIT_CONN) {
|
||||
/* Setup for this payload type */
|
||||
as->pt = pt;
|
||||
osmo_rtp_socket_set_pt(as->rs, pt);
|
||||
_gsm_gen_ref(as);
|
||||
|
||||
/* Timer every 20 ms */
|
||||
osmo_timer_setup(&as->rtp_timer, rtp_timer_cb, as);
|
||||
osmo_timer_add(&as->rtp_timer);
|
||||
osmo_timer_schedule(&as->rtp_timer, 0, 20000);
|
||||
|
||||
/* Init our time tracking */
|
||||
as->rx_last_seq = seq_number;
|
||||
as->rx_last_ts = timestamp;
|
||||
|
||||
/* Now we wait for a loop */
|
||||
as->state = WAIT_LOOP;
|
||||
}
|
||||
|
||||
/* RX sequence & timstamp tracking */
|
||||
if (rtp_seq_num_diff(seq_number, as->rx_last_seq) > 1)
|
||||
fprintf(stderr, "[!] RTP sequence number discontinuity (%d -> %d)\n", as->rx_last_seq, seq_number);
|
||||
|
||||
d = (timestamp - as->rx_last_ts) / GSM_RTP_DURATION;
|
||||
|
||||
as->rx_idx += d;
|
||||
as->rx_last_seq = seq_number;
|
||||
as->rx_last_ts = timestamp;
|
||||
|
||||
/* Account for missing frames in BER tracking */
|
||||
if (d > 1) {
|
||||
fprintf(stderr, "[!] RTP %d missing frames assumed lost @%d\n", d-1, seq_number);
|
||||
while (--d)
|
||||
_gsm_ber(as, NULL, 0);
|
||||
}
|
||||
|
||||
/* BER analysis */
|
||||
rc = _gsm_ber(as, payload, payload_len);
|
||||
|
||||
if ((as->state == WAIT_LOOP) && (rc == 0))
|
||||
as->state = RUNNING;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct app_state _as, *as = &_as;
|
||||
int rc, port;
|
||||
|
||||
/* Args */
|
||||
if (argc < 2)
|
||||
return -1;
|
||||
|
||||
port = atoi(argv[1]);
|
||||
|
||||
/* App init */
|
||||
memset(as, 0x00, sizeof(struct app_state));
|
||||
|
||||
log_init(&log_info, NULL);
|
||||
osmo_rtp_init(NULL);
|
||||
|
||||
/* Start auto-connect RTP socket */
|
||||
as->rs = osmo_rtp_socket_create(NULL, 0);
|
||||
|
||||
as->rs->priv = as;
|
||||
as->rs->rx_cb = rtp_rx_cb;
|
||||
|
||||
/* Jitter buffer gets in the way, we want the raw traffic */
|
||||
osmo_rtp_socket_set_param(as->rs, OSMO_RTP_P_JIT_ADAP, 0);
|
||||
osmo_rtp_socket_set_param(as->rs, OSMO_RTP_P_JITBUF, 0);
|
||||
|
||||
/* Bind to requested port */
|
||||
fprintf(stderr, "[+] Binding RTP socket on port %u...\n", port);
|
||||
rc = osmo_rtp_socket_bind(as->rs, "0.0.0.0", port);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "[!] error binding RTP socket: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* We 'connect' to the first source we hear from */
|
||||
osmo_rtp_socket_autoconnect(as->rs);
|
||||
|
||||
/* Main loop */
|
||||
while (1)
|
||||
osmo_select_main(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
145
contrib/ber/rtp_gen_map.c
Normal file
145
contrib/ber/rtp_gen_map.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/* utility to generate codec_bit_class.h, a file with structures
|
||||
* describing which [protection] class each bit of a given codec frame belongs to */
|
||||
|
||||
/* (C) 2019 sysmocom - s.f.m.c. GmbH; Author: Sylvain Munaut
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <osmocom/codec/codec.h>
|
||||
|
||||
|
||||
static int
|
||||
gen_table_fr(int *tbl)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
tbl[0] = tbl[1] = tbl[2] = tbl[3] = -1;
|
||||
|
||||
for (i = 0; i < 260; i++) {
|
||||
j = 4 + gsm610_bitorder[i];
|
||||
if (i < 50)
|
||||
tbl[j] = 0; /* Class 1a */
|
||||
else if (i < 182)
|
||||
tbl[j] = 1; /* Class 1b */
|
||||
else
|
||||
tbl[j] = 2; /* Class 2 */
|
||||
}
|
||||
|
||||
return GSM_FR_BYTES * 8;
|
||||
}
|
||||
|
||||
static int
|
||||
gen_table_efr(int *tbl)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
tbl[0] = tbl[1] = tbl[2] = tbl[3] = -1;
|
||||
|
||||
for (i = 0; i < 260; i++) {
|
||||
j = gsm660_bitorder[i];
|
||||
|
||||
if (j < 71)
|
||||
k = j;
|
||||
else if (j < 73)
|
||||
k = 71;
|
||||
else if (j < 123)
|
||||
k = j - 2;
|
||||
else if (j < 125)
|
||||
k = 119;
|
||||
else if (j < 178)
|
||||
k = j - 4;
|
||||
else if (j < 180)
|
||||
k = 172;
|
||||
else if (j < 230)
|
||||
k = j - 6;
|
||||
else if (j < 232)
|
||||
k = 222;
|
||||
else if (j < 252)
|
||||
k = j - 8;
|
||||
else
|
||||
continue;
|
||||
|
||||
if (i < 50)
|
||||
tbl[k] = 0; /* Class 1a */
|
||||
else if (i < 182)
|
||||
tbl[k] = 1; /* Class 1b */
|
||||
else
|
||||
tbl[k] = 2; /* Class 2 */
|
||||
}
|
||||
|
||||
return GSM_EFR_BYTES * 8;
|
||||
}
|
||||
|
||||
static int
|
||||
gen_table_amr_12_2(int *tbl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
tbl[i] = -1;
|
||||
|
||||
for (i = 0; i < 244; i++)
|
||||
tbl[i+16] = i < 81 ? 0 : 1;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
tbl[i+16+244] = -1;
|
||||
|
||||
return 8 * 33;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_table(const char *name, int *tbl, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("static const int %s[] = {\n", name);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((i & 15) == 0)
|
||||
printf("\t");
|
||||
|
||||
printf("%2d", tbl[i]);
|
||||
|
||||
if (((i & 15) == 15) || (i == len-1))
|
||||
printf(",\n");
|
||||
else
|
||||
printf(", ");
|
||||
}
|
||||
|
||||
printf("};\n\n");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int tbl[33*8];
|
||||
int rv;
|
||||
|
||||
rv = gen_table_fr(tbl);
|
||||
print_table("gsm_fr_bitclass", tbl, rv);
|
||||
|
||||
rv = gen_table_efr(tbl);
|
||||
print_table("gsm_efr_bitclass", tbl, rv);
|
||||
|
||||
rv = gen_table_amr_12_2(tbl);
|
||||
print_table("gsm_amr_12_2_bitclass", tbl, rv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -27,15 +27,15 @@ BuildRequires: pkgconfig >= 0.20
|
||||
%if 0%{?suse_version}
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%endif
|
||||
BuildRequires: pkgconfig(libosmocodec) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmocoding) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmoctrl) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmogsm) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmoabis) >= 1.4.0
|
||||
BuildRequires: pkgconfig(libosmotrau) >= 1.4.0
|
||||
BuildRequires: pkgconfig(libosmo-netif) >= 1.3.0
|
||||
BuildRequires: pkgconfig(libosmocodec) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmocoding) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmogsm) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmoabis) >= 1.5.0
|
||||
BuildRequires: pkgconfig(libosmotrau) >= 1.5.0
|
||||
BuildRequires: pkgconfig(libosmo-netif) >= 1.4.0
|
||||
%{?systemd_requires}
|
||||
|
||||
%description
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
Description=osmo-bts manager for LC15 / sysmoBTS 2100
|
||||
After=lc15-sysdev-remap.service
|
||||
Wants=lc15-sysdev-remap.service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
Description=osmo-bts manager for OC-2G
|
||||
After=oc2g-sysdev-remap.service
|
||||
Wants=oc2g-sysdev-remap.service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[Unit]
|
||||
Description=osmo-bts for LC15 / sysmoBTS 2100
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@@ -9,7 +11,6 @@ WorkingDirectory=%S/osmocom
|
||||
RuntimeDirectory=osmo-bts
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
RestartPreventExitStatus=1
|
||||
|
||||
# CPU scheduling policy:
|
||||
CPUSchedulingPolicy=rr
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[Unit]
|
||||
Description=osmo-bts for OC-2G
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@@ -9,7 +11,6 @@ WorkingDirectory=%S/osmocom
|
||||
RuntimeDirectory=osmo-bts
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
RestartPreventExitStatus=1
|
||||
|
||||
# CPU scheduling policy:
|
||||
CPUSchedulingPolicy=rr
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[Unit]
|
||||
Description=osmo-bts for sysmocom sysmoBTS
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
@@ -11,12 +13,11 @@ StateDirectory=osmocom
|
||||
WorkingDirectory=%S/osmocom
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
RestartPreventExitStatus=1
|
||||
|
||||
# CPU scheduling policy:
|
||||
CPUSchedulingPolicy=rr
|
||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
||||
CPUSchedulingPriority=11
|
||||
CPUSchedulingPriority=20
|
||||
# See sched(7) for further details on real-time policies and priorities
|
||||
|
||||
[Install]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[Unit]
|
||||
Description=Osmocom osmo-bts for osmo-trx
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[Unit]
|
||||
Description=Osmocom GSM BTS for virtual Um layer based on GSMTAP/UDP
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[Unit]
|
||||
Description=osmo-bts manager for sysmoBTS
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
|
||||
236
debian/changelog
vendored
236
debian/changelog
vendored
@@ -1,3 +1,239 @@
|
||||
osmo-bts (1.7.0) unstable; urgency=medium
|
||||
|
||||
[ arehbein ]
|
||||
* common: Fix memleak in get_smscb_block()
|
||||
* doc: Adapt to use of 'telnet_init_default'
|
||||
* common: Remove redundant checks
|
||||
* common: Remove unused function gsm_objclass2nmstate()
|
||||
* gsm_objclass2mo(): Change signature/set NACK cause
|
||||
* gsm_objclass2obj(): Change signature/set NACK cause
|
||||
* PCU interface: Log version when starting listener
|
||||
* common: Have PCU socket connection use osmo_wqueue
|
||||
* common: Make socket queue max. length configurable
|
||||
|
||||
[ Max ]
|
||||
* bts-virtual: fix segfault
|
||||
* osmo-bts-trx: log TRXC/TRXD connection address
|
||||
* osmo-bts-trx: use bool for true/false flags
|
||||
* GSMTAP: allow configuring local address
|
||||
* license: fix typos
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* paging_add_imm_ass(): remove meaningless from_pcu argument
|
||||
* osmo-bts-{trx,virtual}: clean up bts_model_l1sap_down()
|
||||
* osmo-bts-{trx,virtual}: check lchan against NULL in bts_model_l1sap_down()
|
||||
* osmo-bts-{trx,virtual}: set rc on error in bts_model_l1sap_down()
|
||||
* GSMTAP: print 'gsmtap-local-host' if not NULL
|
||||
* osmo-bts-virtual: indicate BTS_FEAT_[E]GPRS to the BSC
|
||||
* rsl: remove redundant gsm_lchan_name() in rsl_tx_rf_rel_ack()
|
||||
* rsl: reduce logging verbosity on some messages
|
||||
* tests: use -no-install libtool flag to avoid ./lt-* scripts
|
||||
* scheduler: log pchan value in trx_sched_set_pchan()
|
||||
* osmo-bts-virtual: properly handle dynamic TS in vbts_set_ts()
|
||||
* contrib/osmo-bts.spec.in: do not depend on libosmogb
|
||||
* osmo-bts-trx: properly activate [CBCH/]BCCH/CCCH
|
||||
* rsl: rsl_handle_chan_mod_ie(): add missing GSM48_CMODE_* values
|
||||
* osmo-bts-{sysmo,lc15,oc2g}: fix segfault in ph_tch_req()
|
||||
* tests: $(BUILT_SOURCES) is not defined, depend on osmo-bts-virtual
|
||||
* osmo-bts-virtual: properly activate [CBCH/]BCCH/CCCH
|
||||
* flags: add missing entries to bts_impl_flag_desc[]
|
||||
* flags: group BTS_INTERNAL_FLAG_* into an enum
|
||||
* flags: ensure completeness of bts_impl_flag_desc[]
|
||||
* fixup: common: Remove unused function gsm_objclass2nmstate()
|
||||
* oml: gsm_objclass2{mo,obj}(): cosmetic: return immediately
|
||||
* oml: gsm_objclass2{mo,obj}(): set cause for unknown obj_class
|
||||
* oml: reset BCCH carrier power reduction mode (if enabled)
|
||||
* copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH
|
||||
* osmo-bts-trx: alloc/free burst buffers in trx_sched_set_lchan()
|
||||
* osmo-bts-trx: use direct pointer to chan_state->{ul,dl}_bursts
|
||||
* osmo-bts-trx: tch_dl_dequeue(): do not drop CSD frames
|
||||
* osmo-bts-trx: tx_pdtch_fn(): use msgb_l2len()
|
||||
* osmo-bts-trx: fix recent regression in Tx lchan handlers
|
||||
* osmo-bts-trx: remove redundant memset() on receipt of NOPE.ind
|
||||
* l1sap: use gsm0502_fn2ccch_block() from libosmogsm
|
||||
* scheduler: fix wrong union field in _sched_compose_tch_ind()
|
||||
* scheduler: use msgb_hexdump_l2() in _sched_compose_tch_ind()
|
||||
* scheduler: unify argument names/order for _sched_compose_*_ind()
|
||||
* scheduler: constify *data pointer in _sched_compose_*_ind()
|
||||
* scheduler: use size_t for data_len in _sched_compose_*_ind()
|
||||
* fix bts_supports_cm(): properly check feature flags for VGCS/VBS
|
||||
* measurement: suppress unsupported tch_mode warnings for CSD
|
||||
* osmo-bts-trx: pull the AMR header in tch_dl_dequeue()
|
||||
* osmo-bts-trx: implement CSD scheduling support
|
||||
* osmo-bts-trx: implement FACCH/[FH] support for CSD
|
||||
* osmo-bts-trx: implement TCH/F2.4 support for CSD
|
||||
* osmo-bts-trx: visualize rx_tch[fh]_fn() functions
|
||||
* osmo-bts-trx: unify and enrich 'Received bad data' logging
|
||||
* osmo-bts-trx: rx_tchf_fn(): move compute_ber10k() above
|
||||
* osmo-bts-trx: rx_tch[fh]_fn(): combine rc-checking ifs
|
||||
* osmo-bts-trx: change 'Received bad data' back to LOGL_DEBUG
|
||||
* osmo-bts-trx: tx_tch[fh]_fn(): fix NULL pointer dereference
|
||||
* osmo-bts-trx: document/clarify the meaning of BUFMAX=24
|
||||
* l1sap: proper rate adaptation for CSD (RFC4040 'clearmode')
|
||||
* csd_v110_rtp_encode(): properly set E1/E2/E3 bits
|
||||
* osmo-bts-trx: bts_supports_cm_data(): allow non-transparent modes
|
||||
* rsl: rsl_handle_chan_mod_ie(): set lchan->csd_mode
|
||||
* rsl: rsl_handle_chan_mod_ie(): do not use legacy defines
|
||||
* csd_v110: fix comments in csd_v110_rtp_{en,de}code()
|
||||
* csd_v110: properly set E1/E2/E3 for non-transparent data
|
||||
* csd_v110: handle empty/incomplete Uplink frames gracefully
|
||||
|
||||
[ Philipp Maier ]
|
||||
* pcu_sock: rename rc to fd
|
||||
* pcu_sock: cosmetic: remove whitespace after type cast
|
||||
* pcu_sock: cosmetic: remove unnecessary line breaks
|
||||
* pcu_sock: do not mess with the osmo fd flags directly
|
||||
* sched_lchan_tchx: use GSM_HR_BYTES_RTP_RFC5993 constant
|
||||
* l1sap: fix wording in comment
|
||||
* pcu_sock: don not continue when running out of TRX space
|
||||
* paging: cosmetic: rename all IMM.ASS references to MAC block
|
||||
* paging: parse PCUIF data indication outside of paging.c
|
||||
* paging: do not confirm PAGING COMMAND messages
|
||||
* pcu_sock: move variable declaration of imsi[4] into related scope
|
||||
* l1sap: cosmetic: rename payload_len to rtp_pl_len
|
||||
* pcu_sock: use PCUIF version 11 (direct TLLI)
|
||||
* paging: also accept zero length IMSI strings 3
|
||||
* pcuif_proto: rename tlli to msg_id
|
||||
* pcu_sock: get rid of fn parameter in pcu_tx_pch_data_cnf
|
||||
* pcuif_proto: remove unnecessary members from gsm_pcu_if_data_cnf_dt
|
||||
* pcuif_proto: get rid of _DT, _dt (Direct TLLI)
|
||||
* bts: make bts_agch_dequeue static
|
||||
* pcuif_proto: use confirm flag in struct gsm_pcu_if_pch
|
||||
* pcu_sock: use PCU_IF_SAPI_AGCH_2 instead PCU_IF_SAPI_AGCH
|
||||
* pcu_sock: print SAPI and msg_id when sending confirmation
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* bts-trx: Fix no NM Radio{Carrier,Channel} switching to Enabled if one TRX is rf_locked
|
||||
* pcu_sock: Submit all DATA.ind regardless of link quality
|
||||
* pcu_sock.c: Call osmo_fd_unregister() before closing and changing bfd->fd
|
||||
* Rewrite pcu_sock_write()
|
||||
* lchan: Improve error path logging in gsm_pchan2chan_nr()
|
||||
* cosmetic: gsm_pchan2chan_nr(): Update spec documentation
|
||||
* cosmetic: bts_trx.h: Fix whitespace
|
||||
* Avoid tx RF Resource Ind for disabled TRX
|
||||
* bts-trx: Avoid pushing interf_meas for disabled TRX
|
||||
* contrib/ber: Avoid regenerating codec_bit_class.h every build
|
||||
* bts-trx: Drop unused param to internal function
|
||||
* Clarify configuration of TSC on each timeslot
|
||||
* bts_model_apply_oml(): Drop unneded code
|
||||
* oml.c: Remove dot character at the end of log lines
|
||||
* nm: Apply BTS/TRX/TS OML Attributes through NM FSMs
|
||||
* nm: Drop NM_EV_SETATTR_{ACK/NACK}
|
||||
* oml: Get rid of unused tlv_parsed param in bts_model_apply_oml()
|
||||
* bts_model_apply_oml(): Improve definition of parameter
|
||||
* lc15,oc2g,sysmo: Update GPRS NM object state at the right time
|
||||
* Simplify implementation of bts_model_opstart() in all bts types
|
||||
* nm: Apply OPSTART through NM FSMs
|
||||
* NM: NACK received OML OPSTART if no attributes were set beforehand
|
||||
* Introduce NM FSM for GPRS NSE object
|
||||
* Fix octet 2 of NM GPRS Cell
|
||||
* Introduce NM FSM for GPRS Cell object
|
||||
* Rearrange declaration of struct gsm_bts_gprs_nsvc
|
||||
* Move NSVC structs to be part of NSE
|
||||
* bts: Simplify lifecycle of BTS inside bts_list
|
||||
* Introduce NM FSM for GPRS NSVC object
|
||||
* nm: Dispatch NM_EV_SW_ACT in cascade to BTS SiteMgr children
|
||||
* Merge gsm_network into gsm_bts_sm and place gsm_bts under it
|
||||
* Move GPRS NSE under BTS SiteMgr
|
||||
* Drop NM_EV_BBTRANSC_INSTALLED in favour of generic NM_EV_SW_ACT
|
||||
* nm: Document current state of SW_ACT in TRX related objects
|
||||
* Properly report all states through NM FSM upon OML link up
|
||||
* Update g_bts_sm->num_bts when bts is added/removed from bts list
|
||||
* Move pcu_sock_state to gprs section of bts_sm
|
||||
* pcu_sock: Allocate pcu_sock_state using g_bts_sm talloc context
|
||||
* pcu_sock: Drop bts_sm pointer
|
||||
* oml: Fix potential null ptr access on trx object
|
||||
* bts-sysmo: Fix pinst->version filled too early
|
||||
* bts-sysmo: Delay marking phy_link as connected until L1 reset + got info
|
||||
* vty.c: Use already available tpp pointer
|
||||
* octphy: Fix clearly wrong noop assignment
|
||||
* bbtransc/rcarrier: Fix statechg done twice upon NM_EV_RX_OPSTART
|
||||
* Increase PCUIF wqueue size
|
||||
* bts-trx: Fix CCCH not enabled if BS_AG_BLKS_RES!=1 is provided by BSC
|
||||
* rsl: Improve logic reactivating CCCH upon SI3 BS_AG_BLKS_RES change
|
||||
|
||||
[ Oliver Smith ]
|
||||
* gitignore: add vty pdf
|
||||
* doc: rsl: add RSL_IE_IPAC_RTP_CSD_FORMAT
|
||||
* rsl_rx_ipac_XXcx: parse csd_fmt_d/ir
|
||||
* debian: set compat level to 10
|
||||
* systemd: depend on networking-online.target
|
||||
* gitignore: add arm-poky-linux-gnueabi-libtool
|
||||
* osmo-bts-sysmo: trx_mute_on_init_cb: call bts_update_status
|
||||
* osmo-bts-sysmo: activate_rf: no dispatch on fail
|
||||
* osmo-bts-sysmo/l1_if: move mute_rf_compl_cb up
|
||||
* osmo-bts-sysmo: mute PHY until OML is ready
|
||||
|
||||
[ Harald Welte ]
|
||||
* DTX: bts-{sysmo,oc2g,lc15}: Print DEBUG messages about ONSET
|
||||
* cosmetic: Replace %i with %d
|
||||
* Introduce LOGPLCFN() for logging lchan-name + frame number
|
||||
* bts-{sysmo,oc2g,lc15}: Fix RTP of AMR SID_FIRST_P1
|
||||
* common/vty: Print AMR MultiRate Configuration in "show lchan"
|
||||
* bts-{sysmo,oc2g,lc15}: Dump logical channel params during MPH-ACTIVATE.req
|
||||
* cosmetic: use __func__ instead of __FUNCTION__
|
||||
* lc15: fix compiler warning about wrong indent
|
||||
* lc15: Remove unused warning
|
||||
* lc15/oc2g: remove unused variables
|
||||
* oc2g: Fix 'unused variable' compiler warning
|
||||
* cosmetic: Remove "FIXME?" from Odd AMR CMI phase
|
||||
* lc15: fix compiler warning about unused variable cell_size
|
||||
* Replace explicit gsm_lchan_name() calls with LOGPLCHAN
|
||||
* logging: Introduce LOGPLCGT()
|
||||
* cosmetic: Change LOGPLCFN argument order
|
||||
* paging: Add support for generating NLN/NLN-Status in P1 Rest Octets
|
||||
* Add ASCI (advanced speech call items) log sub-system
|
||||
* ASCI: NCH / NOTIFICATION support
|
||||
* validate RSL "channel rate and type" against VGCS/VBS flags
|
||||
* Store "Channel rate and type" from RSL Channel Mode IE in BTS
|
||||
* ASCI: VGCS/VBS RACH -> RSL TALKER/LISTENER DETECT
|
||||
* sysmo: Enable VGSCS + VBS feature flags
|
||||
* omldummy: Claim to support VBS + VGCS towards BSC
|
||||
|
||||
[ Mychaela N. Falconia ]
|
||||
* trx: detect UL SID in EFR just like in FR
|
||||
* sysmo: fix handling of SID in EFR
|
||||
* common: implement rtp continuous-streaming mode
|
||||
* rtp continuous-streaming: fix BFI in the quality-suppressed case
|
||||
* sysmo: emit empty RTP ticks during FACCH stealing on TCH/F
|
||||
* bts-{lc15,oc2g,sysmo}: support EFR in repeat_last_sid()
|
||||
* RTP input, FR & EFR: preen incoming payloads for SID errors
|
||||
* lc15,oc2g: fix handling of SID in EFR
|
||||
* all models, FR/EFR UL: change SID check to _is_any_sid()
|
||||
* trx: remove model-specific BFI packet formats
|
||||
* refactor: replace rtppayload_is_valid() with preening before enqueue
|
||||
* all models, HR1 codec: accept both TS101318 and RFC5993 formats
|
||||
* trx: fix HR1 codec breakage from format change
|
||||
* trx, HR1 codec: change UL PHY output format to TS 101 318
|
||||
* all models, HR1 codec: select RTP output format via vty option
|
||||
* FR/HR/EFR TCH DL: implement DTX rules
|
||||
* HR1 codec: validate ToC header in RFC5993 RTP input
|
||||
* HR1 codec: act on SID indication in RFC5993 RTP input
|
||||
* trx TCH DL: transmit invalid speech blocks instead of dummy FACCH
|
||||
* ECU in UL path: make it optional per vty config
|
||||
* ECU in UL path: move state alloc/free to l1sap
|
||||
* ECU in UL path: move it from trx model to l1sap
|
||||
|
||||
[ Sylvain Munaut ]
|
||||
* contrib: Add BER testing tool
|
||||
|
||||
[ Andreas Eversberg ]
|
||||
* Change return value of bts_supports_cm() from int to bool
|
||||
* ASCI: Add function to reactivate channel
|
||||
* ASCI: Retrieve NCH position from System Information 1
|
||||
* ASCI: Add Notification CHannel (NCH) support
|
||||
* ASCI: Add support for rest octets in Paging request type 2 and 3
|
||||
* ASCI: Send only NLN on Paging request type 1 rest octets
|
||||
* ASCI: Add Notification/FACCH support
|
||||
* ASCI: Repeat UPLINK FREE message until uplink becomes busy
|
||||
* Add test cases for rest octets of Paging Requests
|
||||
* ASCI: Enable UPLINK ACCESS on various BTS models
|
||||
|
||||
[ Keith ]
|
||||
* Fix incorrect order of params passed to logging macro
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 16:05:30 +0200
|
||||
|
||||
osmo-bts (1.6.0) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
|
||||
2
debian/compat
vendored
2
debian/compat
vendored
@@ -1 +1 @@
|
||||
9
|
||||
10
|
||||
|
||||
10
debian/control
vendored
10
debian/control
vendored
@@ -2,17 +2,17 @@ Source: osmo-bts
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Section: net
|
||||
Priority: optional
|
||||
Build-Depends: debhelper (>= 9),
|
||||
Build-Depends: debhelper (>= 10),
|
||||
pkg-config,
|
||||
dh-autoreconf,
|
||||
autotools-dev,
|
||||
pkg-config,
|
||||
libosmocore-dev (>= 1.8.0),
|
||||
libosmo-abis-dev (>= 1.4.0),
|
||||
libosmo-netif-dev (>= 1.3.0),
|
||||
libosmocore-dev (>= 1.9.0),
|
||||
libosmo-abis-dev (>= 1.5.0),
|
||||
libosmo-netif-dev (>= 1.4.0),
|
||||
libgps-dev,
|
||||
txt2man,
|
||||
osmo-gsm-manuals-dev (>= 1.4.0)
|
||||
osmo-gsm-manuals-dev (>= 1.5.0)
|
||||
Standards-Version: 3.9.8
|
||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-bts
|
||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-bts
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
!!
|
||||
!
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print category 0
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level temp info
|
||||
logging level fw info
|
||||
logging level find info
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level rsl info
|
||||
logging level oml info
|
||||
logging level rll notice
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
!!
|
||||
!
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print category 0
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level temp info
|
||||
logging level fw info
|
||||
logging level find info
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level rsl info
|
||||
logging level oml info
|
||||
logging level rll notice
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level rsl info
|
||||
logging level oml info
|
||||
logging level rll notice
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level rsl info
|
||||
logging level oml info
|
||||
logging level rll notice
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level rsl info
|
||||
logging level oml info
|
||||
logging level rll notice
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
!!
|
||||
!
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level temp info
|
||||
logging level fw info
|
||||
logging level find info
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level rsl notice
|
||||
logging level oml notice
|
||||
logging level rll notice
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level rsl notice
|
||||
logging level oml notice
|
||||
logging level rll notice
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
!!
|
||||
!
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 0
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
logging level rsl info
|
||||
logging level oml info
|
||||
logging level rll notice
|
||||
|
||||
98
doc/trx_sched_tch.txt
Normal file
98
doc/trx_sched_tch.txt
Normal file
@@ -0,0 +1,98 @@
|
||||
== rx_tchf_fn(): TCH/FS, TCH/EFS, TCH/AFS, TCH/F2.4, and FACCH/F
|
||||
|
||||
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 4
|
||||
| | | | | | | | | | | | | | | | | | | | | a | b | c | d | Rx bid={0,1,2,3}, decode
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 4
|
||||
| | | | | | | | | | | | | | | | | a | b | c | d | e | f | g | h | Rx bid={0,1,2,3}, decode
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 4
|
||||
|
|
||||
|<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame A
|
||||
| |<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame B
|
||||
@ decoding from here
|
||||
|
||||
|
||||
== rx_tchf_fn(): TCH/F14.4, TCH/F9.6, TCH/F4.8
|
||||
|
||||
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
|
||||
| | | | | | | | | | | | | | | | | | | | | a | b | c | d | Rx bid={0,1,2,3}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
|
||||
| | | | | | | | | | | | | | | | | a | b | c | d | e | f | g | h | Rx bid={0,1,2,3}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
|
||||
| | | | | | | | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | Rx bid={0,1,2,3}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
|
||||
| | | | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | Rx bid={0,1,2,3}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
|
||||
| | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | Rx bid={0,1,2,3}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
|
||||
| a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | Rx bid={0,1,2,3}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 4
|
||||
|
|
||||
|<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame A
|
||||
| |<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame B
|
||||
@ decoding from here
|
||||
|
||||
|
||||
== rx_tchh_fn(): TCH/HS, TCH/AHS
|
||||
|
||||
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | | | | | a | b | | | Rx bid={0,1}, decode
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | | | a | b | c | d | | | Rx bid={0,1}, decode
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | a | b | c | d | e | f | | | Rx bid={0,1}, decode
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
|
||||
|
|
||||
|<~~~~~~~~~~~~~>| frame A
|
||||
| |<~~~~~~~~~~~~~>| frame B
|
||||
@ decoding from here
|
||||
|
||||
|
||||
== rx_tchh_fn(): FACCH/H
|
||||
|
||||
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | | | | | a | b | | | Rx bid={0,1}, decode
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | | | a | b | c | d | | | Rx bid={0,1}
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | a | b | c | d | e | f | | | Rx bid={0,1}, decode
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+ << 2
|
||||
|
|
||||
|<~~~~~~~~~~~~~~~~~~~~~>| frame A
|
||||
| |<~~~~~~~~~~~~~~~~~~~~~>| frame B
|
||||
@ decoding from here
|
||||
|
||||
|
||||
== rx_tchh_fn(): TCH/H4.8, TCH/H2.4
|
||||
|
||||
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | | | | | a | b | | | Rx bid={0,1}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | | | a | b | c | d | | | Rx bid={0,1}
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | | | a | b | c | d | e | f | | | Rx bid={0,1}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | | | a | b | c | d | e | f | g | h | | | Rx bid={0,1}
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | | | a | b | c | d | e | f | g | h | i | j | | | Rx bid={0,1}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | | | Rx bid={0,1}
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | | | Rx bid={0,1}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | | | Rx bid={0,1}
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | | | Rx bid={0,1}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | | | Rx bid={0,1}
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
| a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | | | Rx bid={0,1}, decode
|
||||
|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ << 2
|
||||
|
|
||||
|<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame A
|
||||
| |<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>| frame B
|
||||
@ decoding from here
|
||||
@@ -1,9 +1,11 @@
|
||||
noinst_HEADERS = \
|
||||
abis.h \
|
||||
abis_osmo.h \
|
||||
asci.h \
|
||||
bts.h \
|
||||
bts_model.h \
|
||||
bts_shutdown_fsm.h \
|
||||
bts_sm.h \
|
||||
bts_trx.h \
|
||||
gsm_data.h \
|
||||
logging.h \
|
||||
@@ -11,6 +13,7 @@ noinst_HEADERS = \
|
||||
oml.h \
|
||||
paging.h \
|
||||
rsl.h \
|
||||
rtp_input_preen.h \
|
||||
signal.h \
|
||||
vty.h \
|
||||
amr.h \
|
||||
@@ -21,6 +24,7 @@ noinst_HEADERS = \
|
||||
tx_power.h \
|
||||
control_if.h \
|
||||
cbch.h \
|
||||
csd_v110.h \
|
||||
l1sap.h \
|
||||
lchan.h \
|
||||
power_control.h \
|
||||
@@ -30,5 +34,6 @@ noinst_HEADERS = \
|
||||
dtx_dl_amr_fsm.h \
|
||||
ta_control.h \
|
||||
nm_common_fsm.h \
|
||||
notification.h \
|
||||
osmux.h \
|
||||
$(NULL)
|
||||
|
||||
43
include/osmo-bts/asci.h
Normal file
43
include/osmo-bts/asci.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmo-bts/lchan.h>
|
||||
|
||||
enum {
|
||||
VGCS_TALKER_NONE = 0,
|
||||
VGCS_TALKER_WAIT_FRAME,
|
||||
VGCS_TALKER_ACTIVE,
|
||||
};
|
||||
|
||||
void vgcs_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay, uint32_t fn);
|
||||
|
||||
void vgcs_lchan_activate(struct gsm_lchan *lchan);
|
||||
|
||||
void vgcs_lchan_react(struct gsm_lchan *lchan);
|
||||
|
||||
void vgcs_talker_frame(struct gsm_lchan *lchan);
|
||||
|
||||
void vgcs_talker_reset(struct gsm_lchan *lchan, bool ul_access);
|
||||
|
||||
void vgcs_listener_reset(struct gsm_lchan *lchan);
|
||||
|
||||
static inline bool vgcs_is_uplink_free(struct gsm_lchan *lchan)
|
||||
{
|
||||
return lchan->asci.uplink_free;
|
||||
}
|
||||
|
||||
static inline void vgcs_uplink_free_get(struct gsm_lchan *lchan, uint8_t *msg)
|
||||
{
|
||||
memcpy(msg, lchan->asci.uplink_free_msg, GSM_MACBLOCK_LEN);
|
||||
}
|
||||
|
||||
static inline void vgcs_uplink_free_set(struct gsm_lchan *lchan, uint8_t *msg)
|
||||
{
|
||||
memcpy(lchan->asci.uplink_free_msg, msg, GSM_MACBLOCK_LEN);
|
||||
lchan->asci.uplink_free = true;
|
||||
}
|
||||
|
||||
static inline void vgcs_uplink_free_reset(struct gsm_lchan *lchan)
|
||||
{
|
||||
lchan->asci.uplink_free = false;
|
||||
}
|
||||
@@ -25,6 +25,7 @@ enum {
|
||||
BTS_CTR_RACH_RCVD,
|
||||
BTS_CTR_RACH_DROP,
|
||||
BTS_CTR_RACH_HO,
|
||||
BTS_CTR_RACH_VGCS,
|
||||
BTS_CTR_RACH_CS,
|
||||
BTS_CTR_RACH_PS,
|
||||
BTS_CTR_AGCH_RCVD,
|
||||
@@ -53,36 +54,28 @@ enum gsm_bts_type_variant {
|
||||
};
|
||||
const char *btsvariant2str(enum gsm_bts_type_variant v);
|
||||
|
||||
/* TODO: add a brief description of this flag */
|
||||
#define BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP (1 << 0)
|
||||
/* When this flag is set then the measurement data is included in
|
||||
* (PRIM_PH_DATA) and struct ph_tch_param (PRIM_TCH). Otherwise the
|
||||
* measurement data is passed using a separate MPH INFO MEAS IND.
|
||||
* (See also ticket: OS#2977) */
|
||||
#define BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB (1 << 1)
|
||||
/* Whether the BTS model requires RadioCarrier MO to be in Enabled state
|
||||
* (OPSTARTed) before OPSTARTing the RadioChannel MOs. See OS#5157 */
|
||||
#define BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER (1 << 2)
|
||||
/* Whether the BTS model reports interference measurements to L1SAP. */
|
||||
#define BTS_INTERNAL_FLAG_INTERF_MEAS (1 << 3)
|
||||
enum bts_impl_flag {
|
||||
/* TODO: add a brief description of this flag */
|
||||
BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP,
|
||||
/* When this flag is set then the measurement data is included in
|
||||
* (PRIM_PH_DATA) and struct ph_tch_param (PRIM_TCH). Otherwise the
|
||||
* measurement data is passed using a separate MPH INFO MEAS IND.
|
||||
* (See also ticket: OS#2977) */
|
||||
BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB,
|
||||
/* Whether the BTS model requires RadioCarrier MO to be in Enabled state
|
||||
* (OPSTARTed) before OPSTARTing the RadioChannel MOs. See OS#5157 */
|
||||
BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER,
|
||||
/* Whether the BTS model reports interference measurements to L1SAP. */
|
||||
BTS_INTERNAL_FLAG_INTERF_MEAS,
|
||||
|
||||
_BTS_INTERNAL_FLAG_NUM, /* must be at the end */
|
||||
};
|
||||
|
||||
/* BTS implementation flags (internal use, not exposed via OML) */
|
||||
#define bts_internal_flag_get(bts, flag) \
|
||||
((bts->flags & (typeof(bts->flags)) flag) != 0)
|
||||
((bts->flags & (typeof(bts->flags))(1 << flag)) != 0)
|
||||
#define bts_internal_flag_set(bts, flag) \
|
||||
bts->flags |= (typeof(bts->flags)) flag
|
||||
|
||||
struct gsm_bts_gprs_nsvc {
|
||||
struct gsm_bts *bts;
|
||||
/* data read via VTY config file, to configure the BTS
|
||||
* via OML from BSC */
|
||||
int id;
|
||||
uint16_t nsvci;
|
||||
struct osmo_sockaddr local; /* on the BTS */
|
||||
struct osmo_sockaddr remote; /* on the SGSN */
|
||||
|
||||
struct gsm_abis_mo mo;
|
||||
};
|
||||
bts->flags |= (typeof(bts->flags))(1 << flag)
|
||||
|
||||
struct gprs_rlc_cfg {
|
||||
uint16_t parameter[_NUM_RLC_PAR];
|
||||
@@ -131,9 +124,15 @@ struct bts_power_ctrl_params {
|
||||
} pf;
|
||||
};
|
||||
|
||||
/* BTS Site Manager */
|
||||
struct gsm_bts_sm {
|
||||
/* GPRS CELL; ip.access specific NM Object */
|
||||
struct gsm_gprs_cell {
|
||||
struct gsm_abis_mo mo;
|
||||
uint16_t bvci;
|
||||
uint8_t timer[11];
|
||||
struct gprs_rlc_cfg rlc_cfg;
|
||||
struct {
|
||||
uint32_t gprs_codings; /* see NM_IPAC_F_GPRS_CODING_* flags */
|
||||
} support;
|
||||
};
|
||||
|
||||
/* Struct that holds one OML-Address (Address of the BSC) */
|
||||
@@ -142,9 +141,11 @@ struct bsc_oml_host {
|
||||
char *addr;
|
||||
};
|
||||
|
||||
#define BTS_PCU_SOCK_WQUEUE_LEN_DEFAULT 100
|
||||
|
||||
/* One BTS */
|
||||
struct gsm_bts {
|
||||
/* list header in net->bts_list */
|
||||
/* list header in g_bts_sm->bts_list */
|
||||
struct llist_head list;
|
||||
|
||||
/* number of the BTS in network */
|
||||
@@ -158,6 +159,7 @@ struct gsm_bts {
|
||||
/* Base Station Identification Code (BSIC), lower 3 bits is BCC,
|
||||
* which is used as TSC for the CCCH */
|
||||
uint8_t bsic;
|
||||
bool bsic_configured;
|
||||
/* type of BTS */
|
||||
enum gsm_bts_type_variant variant;
|
||||
enum gsm_band band;
|
||||
@@ -193,7 +195,7 @@ struct gsm_bts {
|
||||
/* CCCH is on C0 */
|
||||
struct gsm_bts_trx *c0;
|
||||
|
||||
struct gsm_bts_sm site_mgr;
|
||||
struct gsm_bts_sm *site_mgr;
|
||||
|
||||
/* bitmask of all SI that are present/valid in si_buf */
|
||||
uint32_t si_valid;
|
||||
@@ -223,18 +225,7 @@ struct gsm_bts {
|
||||
|
||||
/* Not entirely sure how ip.access specific this is */
|
||||
struct {
|
||||
struct {
|
||||
struct gsm_abis_mo mo;
|
||||
uint16_t nsei;
|
||||
uint8_t timer[7];
|
||||
} nse;
|
||||
struct {
|
||||
struct gsm_abis_mo mo;
|
||||
uint16_t bvci;
|
||||
uint8_t timer[11];
|
||||
struct gprs_rlc_cfg rlc_cfg;
|
||||
} cell;
|
||||
struct gsm_bts_gprs_nsvc nsvc[2];
|
||||
struct gsm_gprs_cell cell;
|
||||
uint8_t rac;
|
||||
} gprs;
|
||||
|
||||
@@ -250,8 +241,9 @@ struct gsm_bts {
|
||||
int16_t boundary[6];
|
||||
uint8_t intave;
|
||||
} interference;
|
||||
unsigned int t200_ms[7];
|
||||
uint32_t t200_fn[7];
|
||||
unsigned int t3105_ms;
|
||||
unsigned int t3115_ms; /* VGCS UPLINK GRANT repeat timer */
|
||||
struct {
|
||||
uint8_t overload_period;
|
||||
struct {
|
||||
@@ -274,6 +266,7 @@ struct gsm_bts {
|
||||
} rach;
|
||||
} load;
|
||||
uint8_t ny1;
|
||||
uint8_t ny2; /* maximum number of repetitions for the VGCS UPLINK GRANT */
|
||||
uint8_t max_ta;
|
||||
|
||||
/* AGCH queuing */
|
||||
@@ -303,6 +296,15 @@ struct gsm_bts {
|
||||
bool pni; /* Primary Notification Identifier */
|
||||
} etws;
|
||||
|
||||
/* Advanced Speech Call Items (VBS/VGCS) + NCH related bits */
|
||||
struct {
|
||||
int pos_nch; /* position of the NCH or < 0, if not available */
|
||||
uint8_t nln, nln_status; /* current notification list number and status */
|
||||
struct llist_head notifications;
|
||||
int notification_entries; /* current number of entries in the list */
|
||||
int notification_count; /* counter to count all entries */
|
||||
} asci;
|
||||
|
||||
struct paging_state *paging_state;
|
||||
struct llist_head bsc_oml_hosts;
|
||||
unsigned int rtp_jitter_buf_ms;
|
||||
@@ -314,8 +316,13 @@ struct gsm_bts {
|
||||
int rtp_ip_dscp;
|
||||
int rtp_priority;
|
||||
|
||||
bool rtp_nogaps_mode; /* emit RTP stream without any gaps */
|
||||
bool use_ul_ecu; /* "rtp internal-uplink-ecu" option */
|
||||
bool emit_hr_rfc5993;
|
||||
|
||||
struct {
|
||||
uint8_t ciphers; /* flags A5/1==0x1, A5/2==0x2, A5/3==0x4 */
|
||||
uint8_t max_ta; /* maximum timing advance */
|
||||
} support;
|
||||
struct {
|
||||
uint8_t tc4_ctr;
|
||||
@@ -360,6 +367,7 @@ struct gsm_bts {
|
||||
|
||||
struct {
|
||||
char *sock_path;
|
||||
unsigned int sock_wqueue_len_max;
|
||||
} pcu;
|
||||
|
||||
/* GSMTAP Um logging (disabled by default) */
|
||||
@@ -389,12 +397,13 @@ extern void *tall_bts_ctx;
|
||||
#define GSM_BTS_HAS_SI(bts, i) ((bts)->si_valid & (1 << i))
|
||||
#define GSM_BTS_SI(bts, i) (void *)((bts)->si_buf[i][0])
|
||||
|
||||
static inline struct gsm_bts *gsm_bts_sm_get_bts(struct gsm_bts_sm *site_mgr) {
|
||||
return (struct gsm_bts *)container_of(site_mgr, struct gsm_bts, site_mgr);
|
||||
static inline struct gsm_bts *gsm_gprs_cell_get_bts(struct gsm_gprs_cell *cell)
|
||||
{
|
||||
return (struct gsm_bts *)container_of(cell, struct gsm_bts, gprs.cell);
|
||||
}
|
||||
|
||||
struct gsm_bts *gsm_bts_alloc(void *talloc_ctx, uint8_t bts_num);
|
||||
struct gsm_bts *gsm_bts_num(const struct gsm_network *net, int num);
|
||||
struct gsm_bts *gsm_bts_alloc(struct gsm_bts_sm *bts_sm, uint8_t bts_num);
|
||||
struct gsm_bts *gsm_bts_num(const struct gsm_bts_sm *bts_sm, int num);
|
||||
|
||||
int bts_init(struct gsm_bts *bts);
|
||||
void bts_shutdown(struct gsm_bts *bts, const char *reason);
|
||||
@@ -403,10 +412,15 @@ void bts_shutdown_ext(struct gsm_bts *bts, const char *reason, bool exit_proc, b
|
||||
int bts_link_estab(struct gsm_bts *bts);
|
||||
|
||||
int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg);
|
||||
struct msgb *bts_agch_dequeue(struct gsm_bts *bts);
|
||||
int bts_agch_max_queue_length(int T, int bcch_conf);
|
||||
int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
|
||||
int is_ag_res);
|
||||
|
||||
enum ccch_msgt {
|
||||
CCCH_MSGT_AGCH,
|
||||
CCCH_MSGT_PCH,
|
||||
CCCH_MSGT_NCH,
|
||||
};
|
||||
|
||||
int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, enum ccch_msgt ccch);
|
||||
int bts_supports_cipher(struct gsm_bts *bts, int rsl_cipher);
|
||||
uint8_t *bts_sysinfo_get(struct gsm_bts *bts, const struct gsm_time *g_time);
|
||||
void regenerate_si3_restoctets(struct gsm_bts *bts);
|
||||
@@ -422,8 +436,8 @@ struct gsm_time *get_time(struct gsm_bts *bts);
|
||||
|
||||
int bts_main(int argc, char **argv);
|
||||
|
||||
int bts_supports_cm(const struct gsm_bts *bts,
|
||||
const struct rsl_ie_chan_mode *cm);
|
||||
bool bts_supports_cm(const struct gsm_bts *bts,
|
||||
const struct rsl_ie_chan_mode *cm);
|
||||
|
||||
int32_t bts_get_avg_fn_advance(const struct gsm_bts *bts);
|
||||
|
||||
@@ -432,4 +446,11 @@ struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts);
|
||||
|
||||
int bts_set_c0_pwr_red(struct gsm_bts *bts, const uint8_t red);
|
||||
|
||||
/* Context information to be put in the control buffer (db) of the AGCH msg
|
||||
* buffer */
|
||||
struct bts_agch_msg_cb {
|
||||
uint32_t msg_id;
|
||||
bool confirm;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* _BTS_H */
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <osmocom/gsm/tlv.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
|
||||
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
|
||||
@@ -20,8 +21,8 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
|
||||
struct tlv_parsed *old_attr, struct tlv_parsed *new_attr,
|
||||
void *obj);
|
||||
|
||||
int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
|
||||
struct tlv_parsed *new_attr, int obj_kind, void *obj);
|
||||
int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
|
||||
struct gsm_abis_mo *mo, void *obj);
|
||||
|
||||
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
|
||||
void *obj);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* BTS shutdown FSM */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
|
||||
48
include/osmo-bts/bts_sm.h
Normal file
48
include/osmo-bts/bts_sm.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
|
||||
#include <osmo-bts/oml.h>
|
||||
|
||||
struct pcu_sock_state;
|
||||
|
||||
/* GPRS NSVC; ip.access specific NM Object */
|
||||
struct gsm_gprs_nse;
|
||||
struct gsm_gprs_nsvc {
|
||||
struct gsm_abis_mo mo;
|
||||
struct gsm_gprs_nse *nse;
|
||||
/* data read via VTY config file, to configure the BTS
|
||||
* via OML from BSC */
|
||||
int id;
|
||||
uint16_t nsvci;
|
||||
struct osmo_sockaddr local; /* on the BTS */
|
||||
struct osmo_sockaddr remote; /* on the SGSN */
|
||||
};
|
||||
|
||||
/* GPRS NSE; ip.access specific NM Object */
|
||||
struct gsm_gprs_nse {
|
||||
struct gsm_abis_mo mo;
|
||||
uint16_t nsei;
|
||||
uint8_t timer[7];
|
||||
struct gsm_gprs_nsvc nsvc[2];
|
||||
};
|
||||
|
||||
struct gsm_bts *gsm_gprs_nse_get_bts(const struct gsm_gprs_nse *nse);
|
||||
|
||||
/* BTS Site Manager */
|
||||
struct gsm_bts_sm {
|
||||
struct gsm_abis_mo mo;
|
||||
struct llist_head bts_list;
|
||||
unsigned int num_bts;
|
||||
struct osmo_plmn_id plmn;
|
||||
struct {
|
||||
struct pcu_sock_state *pcu_state;
|
||||
struct gsm_gprs_nse nse;
|
||||
} gprs;
|
||||
};
|
||||
|
||||
extern struct gsm_bts_sm *g_bts_sm;
|
||||
|
||||
struct gsm_bts_sm *gsm_bts_sm_alloc(void *talloc_ctx);
|
||||
@@ -1,9 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
|
||||
struct gsm_bts_bb_trx {
|
||||
struct gsm_abis_mo mo;
|
||||
/* how do we talk RSL with this TRX? */
|
||||
struct {
|
||||
struct osmo_sockaddr_str rem_addrstr;
|
||||
uint8_t tei;
|
||||
struct e1inp_sign_link *link;
|
||||
} rsl;
|
||||
};
|
||||
|
||||
/* One TRX in a BTS */
|
||||
@@ -16,9 +23,6 @@ struct gsm_bts_trx {
|
||||
uint8_t nr;
|
||||
/* human readable name / description */
|
||||
char *description;
|
||||
/* how do we talk RSL with this TRX? */
|
||||
uint8_t rsl_tei;
|
||||
struct e1inp_sign_link *rsl_link;
|
||||
|
||||
/* NM Radio Carrier and Baseband Transciever */
|
||||
struct gsm_abis_mo mo;
|
||||
@@ -40,6 +44,12 @@ struct gsm_bts_trx {
|
||||
/* The associated PHY instance */
|
||||
struct phy_instance *pinst;
|
||||
|
||||
struct {
|
||||
uint32_t freq_bands; /* see NM_IPAC_F_FREQ_BAND_* flags */
|
||||
uint32_t chan_types; /* see NM_IPAC_F_CHANT_* flags */
|
||||
uint32_t chan_modes; /* see NM_IPAC_F_CHANM_* flags */
|
||||
} support;
|
||||
|
||||
struct gsm_bts_trx_ts ts[TRX_NR_TS];
|
||||
};
|
||||
|
||||
@@ -58,6 +68,7 @@ int trx_link_estab(struct gsm_bts_trx *trx);
|
||||
void trx_operability_update(struct gsm_bts_trx *trx);
|
||||
|
||||
uint8_t num_agch(const struct gsm_bts_trx *trx, const char * arg);
|
||||
int pos_nch(const struct gsm_bts_trx *trx, const char *arg);
|
||||
bool trx_ms_pwr_ctrl_is_osmo(const struct gsm_bts_trx *trx);
|
||||
|
||||
#define LOGPTRX(trx, ss, lvl, fmt, args...) LOGP(ss, lvl, "%s " fmt, gsm_trx_name(trx), ## args)
|
||||
|
||||
23
include/osmo-bts/csd_v110.h
Normal file
23
include/osmo-bts/csd_v110.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
/* RFC4040 "clearmode" RTP payload length */
|
||||
#define RFC4040_RTP_PLEN 160
|
||||
|
||||
struct gsm_lchan;
|
||||
|
||||
struct csd_v110_frame_desc {
|
||||
uint16_t num_blocks;
|
||||
uint16_t num_bits;
|
||||
};
|
||||
|
||||
struct csd_v110_lchan_desc {
|
||||
struct csd_v110_frame_desc fr;
|
||||
struct csd_v110_frame_desc hr;
|
||||
};
|
||||
|
||||
extern const struct csd_v110_lchan_desc csd_v110_lchan_desc[256];
|
||||
|
||||
int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp,
|
||||
const uint8_t *data, size_t data_len);
|
||||
int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data,
|
||||
const uint8_t *rtp, size_t rtp_len);
|
||||
@@ -41,12 +41,6 @@
|
||||
#define GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT 41
|
||||
#define GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT 91
|
||||
|
||||
struct gsm_network {
|
||||
struct llist_head bts_list;
|
||||
unsigned int num_bts;
|
||||
struct osmo_plmn_id plmn;
|
||||
struct pcu_sock_state *pcu_state;
|
||||
};
|
||||
|
||||
/* 16 is the max. number of SI2quater messages according to 3GPP TS 44.018 Table 10.5.2.33b.1:
|
||||
4-bit index is used (2#1111 = 10#15) */
|
||||
@@ -65,6 +59,52 @@ struct gsm_network {
|
||||
|
||||
#define MAX_VERSION_LENGTH 64
|
||||
|
||||
/* NM_IPAC_F_CHANT_* mask for NM_IPAC_EIE_CHAN_TYPES (common) */
|
||||
#define NM_IPAC_MASK_CHANT_COMMON \
|
||||
(NM_IPAC_F_CHANT_TCHF | \
|
||||
NM_IPAC_F_CHANT_TCHH | \
|
||||
NM_IPAC_F_CHANT_SDCCH8 | \
|
||||
NM_IPAC_F_CHANT_BCCH | \
|
||||
NM_IPAC_F_CHANT_BCCH_SDCCH4)
|
||||
/* NM_IPAC_F_CHANM_SPEECH_* mask for NM_IPAC_EIE_CHAN_MODES */
|
||||
#define NM_IPAC_MASK_CHANM_SPEECH \
|
||||
(NM_IPAC_F_CHANM_SPEECH_FS | \
|
||||
NM_IPAC_F_CHANM_SPEECH_EFS | \
|
||||
NM_IPAC_F_CHANM_SPEECH_AFS | \
|
||||
NM_IPAC_F_CHANM_SPEECH_HS | \
|
||||
NM_IPAC_F_CHANM_SPEECH_AHS)
|
||||
/* NM_IPAC_F_CHANM_CSD_NT_* mask for NM_IPAC_EIE_CHAN_MODES */
|
||||
#define NM_IPAC_MASK_CHANM_CSD_NT \
|
||||
(NM_IPAC_F_CHANM_CSD_NT_4k8 | \
|
||||
NM_IPAC_F_CHANM_CSD_NT_9k6 | \
|
||||
NM_IPAC_F_CHANM_CSD_NT_14k4)
|
||||
/* NM_IPAC_F_CHANM_CSD_T_* mask for NM_IPAC_EIE_CHAN_MODES */
|
||||
#define NM_IPAC_MASK_CHANM_CSD_T \
|
||||
(NM_IPAC_F_CHANM_CSD_T_1200_75 | \
|
||||
NM_IPAC_F_CHANM_CSD_T_600 | \
|
||||
NM_IPAC_F_CHANM_CSD_T_1k2 | \
|
||||
NM_IPAC_F_CHANM_CSD_T_2k4 | \
|
||||
NM_IPAC_F_CHANM_CSD_T_4k8 | \
|
||||
NM_IPAC_F_CHANM_CSD_T_9k6 | \
|
||||
NM_IPAC_F_CHANM_CSD_T_14k4)
|
||||
/* NM_IPAC_F_GPRS_CODING_CS[1-4] mask for NM_IPAC_EIE_GPRS_CODING */
|
||||
#define NM_IPAC_MASK_GPRS_CODING_CS \
|
||||
(NM_IPAC_F_GPRS_CODING_CS1 | \
|
||||
NM_IPAC_F_GPRS_CODING_CS2 | \
|
||||
NM_IPAC_F_GPRS_CODING_CS3 | \
|
||||
NM_IPAC_F_GPRS_CODING_CS4)
|
||||
/* NM_IPAC_F_GPRS_CODING_MCS[1-9] mask for NM_IPAC_EIE_GPRS_CODING */
|
||||
#define NM_IPAC_MASK_GPRS_CODING_MCS \
|
||||
(NM_IPAC_F_GPRS_CODING_MCS1 | \
|
||||
NM_IPAC_F_GPRS_CODING_MCS2 | \
|
||||
NM_IPAC_F_GPRS_CODING_MCS3 | \
|
||||
NM_IPAC_F_GPRS_CODING_MCS4 | \
|
||||
NM_IPAC_F_GPRS_CODING_MCS5 | \
|
||||
NM_IPAC_F_GPRS_CODING_MCS6 | \
|
||||
NM_IPAC_F_GPRS_CODING_MCS7 | \
|
||||
NM_IPAC_F_GPRS_CODING_MCS8 | \
|
||||
NM_IPAC_F_GPRS_CODING_MCS9)
|
||||
|
||||
enum gsm_bts_trx_ts_flags {
|
||||
TS_F_PDCH_ACTIVE = 0x1000,
|
||||
TS_F_PDCH_ACT_PENDING = 0x2000,
|
||||
@@ -91,7 +131,10 @@ struct gsm_bts_trx_ts {
|
||||
|
||||
/* Training Sequence Code (range 0..7) */
|
||||
uint8_t tsc_oml; /* configured via OML */
|
||||
uint8_t tsc; /* currently in use */
|
||||
bool tsc_oml_configured;
|
||||
uint8_t tsc_rsl; /* configured via RSL (Osmo extension) */
|
||||
bool tsc_rsl_configured;
|
||||
uint8_t tsc; /* TSC currently in use. Preference: RSL, OML, BTS-BSIC-OML */
|
||||
/* Training Sequence Set (range 0..3) */
|
||||
uint8_t tsc_set;
|
||||
|
||||
@@ -194,6 +237,8 @@ int conf_lchans_as_pchan(struct gsm_bts_trx_ts *ts,
|
||||
|
||||
bool ts_is_pdch(const struct gsm_bts_trx_ts *ts);
|
||||
|
||||
void gsm_ts_apply_configured_tsc(struct gsm_bts_trx_ts *ts);
|
||||
|
||||
void gsm_ts_release(struct gsm_bts_trx_ts *ts);
|
||||
|
||||
#endif /* _GSM_DATA_H */
|
||||
|
||||
@@ -102,6 +102,7 @@ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr);
|
||||
int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr);
|
||||
int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr);
|
||||
int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr);
|
||||
int l1sap_uplink_access(struct gsm_lchan *lchan, bool active);
|
||||
|
||||
enum l1sap_common_sapi {
|
||||
L1SAP_COMMON_SAPI_UNKNOWN,
|
||||
@@ -141,9 +142,11 @@ int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
|
||||
|
||||
#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h)
|
||||
|
||||
void radio_link_timeout_reset(struct gsm_lchan *lchan);
|
||||
|
||||
int bts_check_for_first_ciphrd(struct gsm_lchan *lchan,
|
||||
uint8_t *data, int len);
|
||||
|
||||
int is_ccch_for_agch(struct gsm_bts_trx *trx, uint32_t fn);
|
||||
enum ccch_msgt get_ccch_msgt(struct gsm_bts_trx *trx, uint32_t fn);
|
||||
|
||||
#endif /* L1SAP_H */
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
#include <osmocom/codec/ecu.h>
|
||||
#include <osmocom/gsm/lapdm.h>
|
||||
#include <osmocom/gsm/sysinfo.h>
|
||||
@@ -74,15 +75,17 @@ struct amr_multirate_conf {
|
||||
};
|
||||
|
||||
enum lchan_csd_mode {
|
||||
LCHAN_CSD_M_NT,
|
||||
LCHAN_CSD_M_NT = 0,
|
||||
LCHAN_CSD_M_T_1200_75,
|
||||
LCHAN_CSD_M_T_600,
|
||||
LCHAN_CSD_M_T_1200,
|
||||
LCHAN_CSD_M_T_2400,
|
||||
LCHAN_CSD_M_T_4800,
|
||||
LCHAN_CSD_M_T_9600,
|
||||
LCHAN_CSD_M_T_14400,
|
||||
LCHAN_CSD_M_T_29000,
|
||||
LCHAN_CSD_M_T_32000,
|
||||
_LCHAN_CSD_M_NUM,
|
||||
};
|
||||
|
||||
/* State of the SAPIs in the lchan */
|
||||
@@ -140,6 +143,8 @@ struct gsm_lchan {
|
||||
uint8_t nr;
|
||||
/* The logical channel type */
|
||||
enum gsm_chan_t type;
|
||||
/* RSL channel rate and type */
|
||||
enum rsl_cmod_crt rsl_chan_rt;
|
||||
/* RSL channel mode */
|
||||
enum rsl_cmod_spd rsl_cmode;
|
||||
/* If TCH, traffic channel mode */
|
||||
@@ -203,6 +208,8 @@ struct gsm_lchan {
|
||||
uint8_t sapis_dl[23];
|
||||
uint8_t sapis_ul[23];
|
||||
struct lapdm_channel lapdm_ch;
|
||||
/* It is required to have L3 info with DL establishment. */
|
||||
bool l3_info_estab;
|
||||
struct llist_head dl_tch_queue;
|
||||
unsigned int dl_tch_queue_len;
|
||||
struct {
|
||||
@@ -265,6 +272,19 @@ struct gsm_lchan {
|
||||
/* last UL SPEECH resume flag */
|
||||
bool is_speech_resume;
|
||||
} dtx;
|
||||
struct {
|
||||
bool last_rtp_input_was_sid;
|
||||
uint8_t last_sid[GSM_FR_BYTES];
|
||||
uint8_t last_sid_len;
|
||||
uint8_t last_sid_age;
|
||||
/* A SID was transmitted on the DL in the period
|
||||
* beginning with the last transmitted speech frame
|
||||
* or the last mandatory-Tx position, whichever was
|
||||
* more recent. */
|
||||
bool dl_sid_transmitted;
|
||||
/* The current frame in the DL is taken up by FACCH */
|
||||
bool dl_facch_stealing;
|
||||
} dtx_fr_hr_efr;
|
||||
uint8_t last_cmr;
|
||||
uint32_t last_fn;
|
||||
|
||||
@@ -287,6 +307,19 @@ struct gsm_lchan {
|
||||
/* counts up to Ny1 */
|
||||
unsigned int phys_info_count;
|
||||
} ho;
|
||||
struct {
|
||||
bool listener_detected;
|
||||
uint8_t talker_active;
|
||||
uint8_t ref;
|
||||
uint32_t fn;
|
||||
/* T3115: VGCS UPLINK GRANT retransmission */
|
||||
struct osmo_timer_list t3115;
|
||||
/* counts up to Ny2 */
|
||||
unsigned int vgcs_ul_grant_count;
|
||||
/* uplink free message */
|
||||
bool uplink_free;
|
||||
uint8_t uplink_free_msg[GSM_MACBLOCK_LEN];
|
||||
} asci;
|
||||
/* S counter for link loss */
|
||||
int s;
|
||||
/* Kind of the release/activation. E.g. RSL or PCU */
|
||||
|
||||
@@ -21,6 +21,7 @@ enum {
|
||||
DABIS,
|
||||
DRTP,
|
||||
DOSMUX,
|
||||
DASCI,
|
||||
};
|
||||
|
||||
extern const struct log_info bts_log_info;
|
||||
@@ -37,4 +38,12 @@ extern const struct log_info bts_log_info;
|
||||
#define DEBUGPFN(ss, fn, fmt, args...) \
|
||||
LOGP(ss, LOGL_DEBUG, "%s " fmt, gsm_fn_as_gsmtime_str(fn), ## args)
|
||||
|
||||
/* LOGP with lchan + frame number prefix */
|
||||
#define LOGPLCFN(lchan, fn, ss, lvl, fmt, args...) \
|
||||
LOGP(ss, lvl, "%s %s " fmt, gsm_lchan_name(lchan), gsm_fn_as_gsmtime_str(fn), ## args)
|
||||
|
||||
/* LOGP with lchan + gsm_time prefix */
|
||||
#define LOGPLCGT(lchan, gt, ss, lvl, fmt, args...) \
|
||||
LOGP(ss, lvl, "%s %s " fmt, gsm_lchan_name(lchan), osmo_dump_gsmtime(gt), ## args)
|
||||
|
||||
#endif /* _LOGGING_H */
|
||||
|
||||
@@ -22,6 +22,9 @@ struct msgb;
|
||||
/* Access 3rd part of msgb control buffer */
|
||||
#define rtpmsg_ts(x) ((x)->cb[2])
|
||||
|
||||
/* Access 4th part of msgb control buffer */
|
||||
#define rtpmsg_is_rfc5993_sid(x) ((x)->cb[3])
|
||||
|
||||
/**
|
||||
* Classification of OML message. ETSI for plain GSM 12.21
|
||||
* messages and IPA/Osmo for manufacturer messages.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Header for all NM FSM. Following 3GPP TS 12.21 Figure 2/GSM 12.21:
|
||||
GSM 12.21 Objects' Operational state and availability status behaviour during initialization */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -30,18 +30,18 @@
|
||||
/* Common */
|
||||
enum nm_fsm_events {
|
||||
NM_EV_SW_ACT,
|
||||
NM_EV_SETATTR_ACK, /* data: struct nm_fsm_ev_setattr_data */
|
||||
NM_EV_SETATTR_NACK, /* data: struct nm_fsm_ev_setattr_data */
|
||||
NM_EV_RX_SETATTR, /* data: struct nm_fsm_ev_setattr_data */
|
||||
NM_EV_RX_OPSTART,
|
||||
NM_EV_OPSTART_ACK,
|
||||
NM_EV_OPSTART_NACK,
|
||||
NM_EV_SHUTDOWN_START,
|
||||
NM_EV_SHUTDOWN_FINISH,
|
||||
NM_EV_OML_UP,
|
||||
NM_EV_RSL_UP, /* RadioCarrier and BaseBand Transceiver only */
|
||||
NM_EV_RSL_DOWN, /* RadioCarrier and BaseBand Transceiver only */
|
||||
NM_EV_PHYLINK_UP, /* RadioCarrier and BaseBand Transceiver only */
|
||||
NM_EV_PHYLINK_DOWN, /* RadioCarrier and BaseBand Transceiver only */
|
||||
NM_EV_DISABLE, /* RadioCarrier and BaseBand Transceiver only */
|
||||
NM_EV_BBTRANSC_INSTALLED, /* Radio Channel only */
|
||||
NM_EV_BBTRANSC_ENABLED, /* Radio Channel only */
|
||||
NM_EV_BBTRANSC_DISABLED, /* Radio Channel only */
|
||||
NM_EV_RCARRIER_ENABLED, /* Radio Channel only */
|
||||
@@ -50,8 +50,7 @@ enum nm_fsm_events {
|
||||
extern const struct value_string nm_fsm_event_names[];
|
||||
|
||||
struct nm_fsm_ev_setattr_data {
|
||||
struct msgb *msg; /* msgb ownership is transferred to FSM */
|
||||
int cause;
|
||||
const struct msgb *msg;
|
||||
};
|
||||
|
||||
|
||||
@@ -95,3 +94,30 @@ enum nm_chan_op_fsm_states {
|
||||
NM_CHAN_ST_OP_ENABLED,
|
||||
};
|
||||
extern struct osmo_fsm nm_chan_fsm;
|
||||
|
||||
/* GPRS NSE */
|
||||
enum nm_gprs_nse_op_fsm_states {
|
||||
NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED,
|
||||
NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY,
|
||||
NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE,
|
||||
NM_GPRS_NSE_ST_OP_ENABLED,
|
||||
};
|
||||
extern struct osmo_fsm nm_gprs_nse_fsm;
|
||||
|
||||
/* GPRS NSVC */
|
||||
enum nm_gprs_nsvc_op_fsm_states {
|
||||
NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED,
|
||||
NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY,
|
||||
NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE,
|
||||
NM_GPRS_NSVC_ST_OP_ENABLED,
|
||||
};
|
||||
extern struct osmo_fsm nm_gprs_nsvc_fsm;
|
||||
|
||||
/* GPRS CELL */
|
||||
enum nm_gprs_cell_op_fsm_states {
|
||||
NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED,
|
||||
NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY,
|
||||
NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE,
|
||||
NM_GPRS_CELL_ST_OP_ENABLED,
|
||||
};
|
||||
extern struct osmo_fsm nm_gprs_cell_fsm;
|
||||
|
||||
61
include/osmo-bts/notification.h
Normal file
61
include/osmo-bts/notification.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* Maintain and generate ASCI notifications */
|
||||
|
||||
/*
|
||||
* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* Author: Harald Welte
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* one [concurrent] ASCI (VBS/VGCS) notification */
|
||||
struct asci_notification {
|
||||
struct llist_head list; /* linked to bts->asci.notifications */
|
||||
|
||||
/* Group call reference (TS 24.008 10.5.1.9 "Descriptive group or broadcast call reference") */
|
||||
uint8_t group_call_ref[5];
|
||||
|
||||
/* Group Channel Description (TS 44.018 10.5.2.14b) */
|
||||
struct {
|
||||
bool present;
|
||||
uint8_t value[255];
|
||||
uint8_t len;
|
||||
} chan_desc;
|
||||
|
||||
/* NCH DRX Information (TS 48.058 9.3.47) */
|
||||
struct {
|
||||
bool present;
|
||||
struct rsl_ie_nch_drx_info value;
|
||||
} nch_drx_info;
|
||||
};
|
||||
|
||||
int bts_asci_notification_add(struct gsm_bts *bts, const uint8_t *group_call_ref, const uint8_t *chan_desc,
|
||||
uint8_t chan_desc_len, const struct rsl_ie_nch_drx_info *nch_drx_info);
|
||||
|
||||
int bts_asci_notification_del(struct gsm_bts *bts, const uint8_t *group_call_ref);
|
||||
|
||||
int bts_asci_notification_reset(struct gsm_bts *bts);
|
||||
|
||||
const struct asci_notification *bts_asci_notification_get_next(struct gsm_bts *bts);
|
||||
|
||||
void append_group_call_information(struct bitvec *bv, const uint8_t *gcr, const uint8_t *ch_desc, uint8_t ch_desc_len);
|
||||
|
||||
int bts_asci_notify_nch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf);
|
||||
int bts_asci_notify_facch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf, const uint8_t *group_call_ref,
|
||||
const uint8_t *chan_desc, uint8_t chan_desc_len);
|
||||
@@ -63,11 +63,12 @@ int oml_tx_state_changed(const struct gsm_abis_mo *mo);
|
||||
int oml_mo_tx_sw_act_rep(const struct gsm_abis_mo *mo);
|
||||
|
||||
int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause);
|
||||
int oml_fom_ack_nack_copy_msg(const struct msgb *old_msg, uint8_t cause);
|
||||
|
||||
int oml_mo_fom_ack_nack(const struct gsm_abis_mo *mo, uint8_t orig_msg_type,
|
||||
uint8_t cause);
|
||||
|
||||
extern const unsigned int oml_default_t200_ms[7];
|
||||
extern const uint32_t oml_default_t200_fn[7];
|
||||
|
||||
/* Transmit failure event report */
|
||||
int oml_tx_failure_event_rep(const struct gsm_abis_mo *mo, enum abis_nm_severity severity,
|
||||
@@ -77,11 +78,11 @@ void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts,
|
||||
uint8_t obj_class, uint8_t p1, uint8_t p2, uint8_t p3);
|
||||
|
||||
struct gsm_abis_mo *gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
|
||||
const struct abis_om_obj_inst *obj_inst);
|
||||
const struct abis_om_obj_inst *obj_inst,
|
||||
enum abis_nm_nack_cause *c);
|
||||
|
||||
struct gsm_nm_state *gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
|
||||
const struct abis_om_obj_inst *obj_inst);
|
||||
void *gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
|
||||
const struct abis_om_obj_inst *obj_inst);
|
||||
const struct abis_om_obj_inst *obj_inst,
|
||||
enum abis_nm_nack_cause *c);
|
||||
|
||||
#endif // _OML_H */
|
||||
|
||||
@@ -7,6 +7,55 @@
|
||||
|
||||
struct paging_state;
|
||||
struct gsm_bts;
|
||||
struct asci_notification;
|
||||
|
||||
/* abstract representation of P1 rest octets; we only implement those parts we need for now */
|
||||
struct p1_rest_octets {
|
||||
struct {
|
||||
bool present;
|
||||
uint8_t nln;
|
||||
uint8_t nln_status;
|
||||
} nln_pch;
|
||||
bool packet_page_ind[2];
|
||||
bool r8_present;
|
||||
struct {
|
||||
bool prio_ul_access;
|
||||
bool etws_present;
|
||||
struct {
|
||||
bool is_first;
|
||||
uint8_t page_nr;
|
||||
const uint8_t *page;
|
||||
size_t page_bytes;
|
||||
} etws;
|
||||
} r8;
|
||||
};
|
||||
|
||||
/* abstract representation of P2 rest octets; we only implement those parts we need for now */
|
||||
struct p2_rest_octets {
|
||||
struct {
|
||||
bool present;
|
||||
uint8_t cn3;
|
||||
} cneed;
|
||||
struct {
|
||||
bool present;
|
||||
uint8_t nln;
|
||||
uint8_t nln_status;
|
||||
} nln_pch;
|
||||
};
|
||||
|
||||
/* abstract representation of P3 rest octets; we only implement those parts we need for now */
|
||||
struct p3_rest_octets {
|
||||
struct {
|
||||
bool present;
|
||||
uint8_t cn3;
|
||||
uint8_t cn4;
|
||||
} cneed;
|
||||
struct {
|
||||
bool present;
|
||||
uint8_t nln;
|
||||
uint8_t nln_status;
|
||||
} nln_pch;
|
||||
};
|
||||
|
||||
/* initialize paging code */
|
||||
struct paging_state *paging_init(struct gsm_bts *bts,
|
||||
@@ -35,9 +84,15 @@ int paging_si_update(struct paging_state *ps, struct gsm48_control_channel_descr
|
||||
int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
|
||||
const uint8_t *identity_lv, uint8_t chan_needed);
|
||||
|
||||
/* Add an IMM.ASS message to the paging queue */
|
||||
int paging_add_imm_ass(struct paging_state *ps,
|
||||
const uint8_t *data, uint8_t len);
|
||||
/* Add a ready formatted MAC block message to the paging queue, this can be an IMMEDIATE ASSIGNMENT, or a
|
||||
* PAGING COMMAND (from the PCU) */
|
||||
int paging_add_macblock(struct paging_state *ps, uint32_t msg_id, const char *imsi, bool confirm, const uint8_t *macblock);
|
||||
|
||||
/* Paging rest octests */
|
||||
void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets *p1ro,
|
||||
const struct asci_notification *notif);
|
||||
void append_p2_rest_octets(struct bitvec *bv, const struct p2_rest_octets *p2ro);
|
||||
void append_p3_rest_octets(struct bitvec *bv, const struct p3_rest_octets *p3ro);
|
||||
|
||||
/* generate paging message for given gsm time */
|
||||
int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *gt,
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <osmo-bts/pcuif_proto.h>
|
||||
|
||||
struct gsm_bts_sm;
|
||||
|
||||
extern int pcu_direct;
|
||||
|
||||
#define PCUIF_HDR_SIZE (sizeof(struct gsm_pcu_if) - sizeof(((struct gsm_pcu_if *)0)->u))
|
||||
@@ -21,11 +23,11 @@ int pcu_tx_rach_ind(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
|
||||
int pcu_tx_time_ind(uint32_t fn);
|
||||
int pcu_tx_interf_ind(const struct gsm_bts_trx *trx, uint32_t fn);
|
||||
int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed);
|
||||
int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len);
|
||||
int pcu_tx_data_cnf(uint32_t msg_id, uint8_t sapi);
|
||||
int pcu_tx_susp_req(struct gsm_lchan *lchan, uint32_t tlli, const uint8_t *ra_id, uint8_t cause);
|
||||
int pcu_sock_send(struct gsm_network *net, struct msgb *msg);
|
||||
int pcu_sock_send(struct msgb *msg);
|
||||
|
||||
int pcu_sock_init(const char *path);
|
||||
int pcu_sock_init(const char *path, int qlength_max);
|
||||
void pcu_sock_exit(void);
|
||||
|
||||
bool pcu_connected(void);
|
||||
|
||||
@@ -3,20 +3,20 @@
|
||||
|
||||
#include <osmocom/gsm/l1sap.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
|
||||
#define PCU_SOCK_DEFAULT "/tmp/pcu_bts"
|
||||
|
||||
#define PCU_IF_VERSION 0x0a
|
||||
#define PCU_IF_VERSION 0x0c
|
||||
#define TXT_MAX_LEN 128
|
||||
|
||||
/* msg_type */
|
||||
#define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */
|
||||
#define PCU_IF_MSG_DATA_CNF 0x01 /* confirm (e.g. transmission on PCH) */
|
||||
#define PCU_IF_MSG_DATA_IND 0x02 /* receive data from given channel */
|
||||
#define PCU_IF_MSG_SUSP_REQ 0x03 /* BTS forwards GPRS SUSP REQ to PCU */
|
||||
#define PCU_IF_MSG_APP_INFO_REQ 0x04 /* BTS asks PCU to transmit APP INFO via PACCH */
|
||||
#define PCU_IF_MSG_RTS_REQ 0x10 /* ready to send request */
|
||||
#define PCU_IF_MSG_DATA_CNF_DT 0x11 /* confirm (with direct tlli) */
|
||||
#define PCU_IF_MSG_DATA_CNF_2 0x11 /* confirm (using message id) */
|
||||
#define PCU_IF_MSG_RACH_IND 0x22 /* receive RACH */
|
||||
#define PCU_IF_MSG_INFO_IND 0x32 /* retrieve BTS info */
|
||||
#define PCU_IF_MSG_ACT_REQ 0x40 /* activate/deactivate PDCH */
|
||||
@@ -28,17 +28,16 @@
|
||||
|
||||
/* sapi */
|
||||
#define PCU_IF_SAPI_RACH 0x01 /* channel request on CCCH */
|
||||
#define PCU_IF_SAPI_AGCH 0x02 /* assignment on AGCH */
|
||||
#define PCU_IF_SAPI_PCH 0x03 /* paging/assignment on PCH */
|
||||
#define PCU_IF_SAPI_BCCH 0x04 /* SI on BCCH */
|
||||
#define PCU_IF_SAPI_PDTCH 0x05 /* packet data/control/ccch block */
|
||||
#define PCU_IF_SAPI_PRACH 0x06 /* packet random access channel */
|
||||
#define PCU_IF_SAPI_PTCCH 0x07 /* packet TA control channel */
|
||||
#define PCU_IF_SAPI_AGCH_DT 0x08 /* assignment on AGCH but with additional TLLI */
|
||||
#define PCU_IF_SAPI_PCH_2 0x08 /* assignment on PCH (confirmed using message id) */
|
||||
#define PCU_IF_SAPI_AGCH_2 0x09 /* assignment on AGCH (confirmed using message id) */
|
||||
|
||||
/* flags */
|
||||
#define PCU_IF_FLAG_ACTIVE (1 << 0)/* BTS is active */
|
||||
#define PCU_IF_FLAG_SYSMO (1 << 1)/* access PDCH of sysmoBTS directly */
|
||||
#define PCU_IF_FLAG_DIRECT_PHY (1 << 1)/* access PHY directly via dedicated hardware support */
|
||||
#define PCU_IF_FLAG_CS1 (1 << 16)
|
||||
#define PCU_IF_FLAG_CS2 (1 << 17)
|
||||
#define PCU_IF_FLAG_CS3 (1 << 18)
|
||||
@@ -58,6 +57,17 @@
|
||||
#define PCU_IF_ADDR_TYPE_IPV4 0x04 /* IPv4 address */
|
||||
#define PCU_IF_ADDR_TYPE_IPV6 0x29 /* IPv6 address */
|
||||
|
||||
/* BTS model */
|
||||
enum gsm_pcuif_bts_model {
|
||||
PCU_IF_BTS_MODEL_UNSPEC,
|
||||
PCU_IF_BTS_MODEL_LC15,
|
||||
PCU_IF_BTS_MODEL_OC2G,
|
||||
PCU_IF_BTS_MODEL_OCTPHY,
|
||||
PCU_IF_BTS_MODEL_SYSMO,
|
||||
PCU_IF_BTS_MODEL_TRX,
|
||||
PCU_IF_BTS_MODEL_RBS,
|
||||
};
|
||||
|
||||
#define PCU_IF_NUM_NSVC 2
|
||||
#define PCU_IF_NUM_TRX 8
|
||||
|
||||
@@ -86,19 +96,10 @@ struct gsm_pcu_if_data {
|
||||
int16_t lqual_cb; /* !< \brief Link quality in centiBel */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* data confirmation with direct tlli (instead of raw mac block with tlli) */
|
||||
struct gsm_pcu_if_data_cnf_dt {
|
||||
/* data confirmation with message id (instead of raw mac block) */
|
||||
struct gsm_pcu_if_data_cnf {
|
||||
uint8_t sapi;
|
||||
uint32_t tlli;
|
||||
uint32_t fn;
|
||||
uint16_t arfcn;
|
||||
uint8_t trx_nr;
|
||||
uint8_t ts_nr;
|
||||
uint8_t block_nr;
|
||||
int8_t rssi;
|
||||
uint16_t ber10k; /* !< \brief BER in units of 0.01% */
|
||||
int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */
|
||||
int16_t lqual_cb; /* !< \brief Link quality in centiBel */
|
||||
uint32_t msg_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct gsm_pcu_if_rts_req {
|
||||
@@ -180,6 +181,7 @@ struct gsm_pcu_if_info_ind {
|
||||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
} remote_ip[PCU_IF_NUM_NSVC];
|
||||
uint8_t bts_model; /* enum gsm_pcuif_bts_model */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct gsm_pcu_if_act_req {
|
||||
@@ -229,6 +231,32 @@ struct gsm_pcu_if_container {
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Struct to send a (confirmed) IMMEDIATE ASSIGNMENT message via PCH. The struct is sent as a data request
|
||||
* (data_req) under SAPI PCU_IF_SAPI_PCH_2. */
|
||||
struct gsm_pcu_if_pch {
|
||||
/* message id as reference for confirmation */
|
||||
uint32_t msg_id;
|
||||
/* IMSI (to derive paging group) */
|
||||
char imsi[OSMO_IMSI_BUF_SIZE];
|
||||
/* GSM mac-block (with immediate assignment message) */
|
||||
uint8_t data[GSM_MACBLOCK_LEN];
|
||||
/* Set to true in case the receiving end must send a confirmation
|
||||
* when the MAC block (data) has been sent. */
|
||||
bool confirm;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Struct to send a (confirmed) IMMEDIATE ASSIGNMENT message via AGCH. The struct is sent as a data request
|
||||
* (data_req) under SAPI PCU_IF_SAPI_AGCH_2. */
|
||||
struct gsm_pcu_if_agch {
|
||||
/* message id as reference for confirmation */
|
||||
uint32_t msg_id;
|
||||
/* GSM mac-block (with immediate assignment message) */
|
||||
uint8_t data[GSM_MACBLOCK_LEN];
|
||||
/* Set to true in case the receiving end must send a confirmation
|
||||
* when the MAC block (data) has been sent. */
|
||||
bool confirm;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct gsm_pcu_if {
|
||||
/* context based information */
|
||||
uint8_t msg_type; /* message type */
|
||||
@@ -237,8 +265,7 @@ struct gsm_pcu_if {
|
||||
|
||||
union {
|
||||
struct gsm_pcu_if_data data_req;
|
||||
struct gsm_pcu_if_data data_cnf;
|
||||
struct gsm_pcu_if_data_cnf_dt data_cnf_dt;
|
||||
struct gsm_pcu_if_data_cnf data_cnf2;
|
||||
struct gsm_pcu_if_data data_ind;
|
||||
struct gsm_pcu_if_susp_req susp_req;
|
||||
struct gsm_pcu_if_rts_req rts_req;
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#define LCHAN_FN_DUMMY 0xFFFFFFFF
|
||||
#define LCHAN_FN_WAIT 0xFFFFFFFE
|
||||
|
||||
bool rsl_chan_rt_is_asci(enum rsl_cmod_crt chan_rt);
|
||||
bool rsl_chan_rt_is_vgcs(enum rsl_cmod_crt chan_rt);
|
||||
|
||||
int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg);
|
||||
int rsl_tx_rf_res(struct gsm_bts_trx *trx);
|
||||
int rsl_tx_chan_rqd(struct gsm_bts_trx *trx, struct gsm_time *gtime,
|
||||
@@ -14,6 +17,8 @@ int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause);
|
||||
int rsl_tx_conn_fail(const struct gsm_lchan *lchan, uint8_t cause);
|
||||
int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan);
|
||||
int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay);
|
||||
int rsl_tx_listener_det(struct gsm_lchan *lchan, uint8_t *acc_delay);
|
||||
int rsl_tx_talker_det(struct gsm_lchan *lchan, uint8_t *acc_delay);
|
||||
|
||||
/* call-back for LAPDm code, called when it wants to send msgs UP */
|
||||
int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx);
|
||||
|
||||
20
include/osmo-bts/rtp_input_preen.h
Normal file
20
include/osmo-bts/rtp_input_preen.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* RTP input validation function: makes the accept-or-drop decision,
|
||||
* and for some codecs signals additional required actions such as
|
||||
* dropping one header octet.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmo-bts/lchan.h>
|
||||
|
||||
enum pl_input_decision {
|
||||
PL_DECISION_DROP,
|
||||
PL_DECISION_ACCEPT,
|
||||
PL_DECISION_STRIP_HDR_OCTET,
|
||||
};
|
||||
|
||||
enum pl_input_decision
|
||||
rtp_payload_input_preen(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
|
||||
unsigned rtp_pl_len, bool *rfc5993_sid_flag);
|
||||
@@ -90,10 +90,10 @@ struct l1sched_chan_state {
|
||||
bool active; /* Channel is active */
|
||||
ubit_t *dl_bursts; /* burst buffer for TX */
|
||||
enum trx_mod_type dl_mod_type; /* Downlink modulation type */
|
||||
uint8_t dl_mask; /* mask of transmitted bursts */
|
||||
sbit_t *ul_bursts; /* burst buffer for RX */
|
||||
sbit_t *ul_bursts_prev;/* previous burst buffer for RX (repeated SACCH) */
|
||||
uint32_t ul_first_fn; /* fn of first burst */
|
||||
uint8_t ul_mask; /* mask of received bursts */
|
||||
uint32_t ul_mask; /* mask of received bursts */
|
||||
|
||||
/* loss detection */
|
||||
uint32_t last_tdma_fn; /* last processed TDMA frame number */
|
||||
@@ -131,7 +131,7 @@ struct l1sched_chan_state {
|
||||
/* Uplink measurements */
|
||||
struct {
|
||||
/* Active channel measurements (simple ring buffer) */
|
||||
struct l1sched_meas_set buf[8]; /* up to 8 entries */
|
||||
struct l1sched_meas_set buf[24]; /* up to 24 (BUFMAX) entries */
|
||||
unsigned int current; /* current position */
|
||||
|
||||
/* Interference measurements */
|
||||
@@ -185,6 +185,9 @@ int trx_sched_set_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pch
|
||||
/*! \brief set all matching logical channels active/inactive */
|
||||
int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_id, bool active);
|
||||
|
||||
/*! \brief set uplink access on given logical channels active/inactive */
|
||||
int trx_sched_set_ul_access(struct gsm_lchan *lchan, uint8_t chan_nr, bool active);
|
||||
|
||||
/*! \brief set all logical channels of BCCH/CCCH active/inactive */
|
||||
int trx_sched_set_bcch_ccch(struct gsm_lchan *lchan, bool active);
|
||||
|
||||
@@ -300,6 +303,10 @@ int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi);
|
||||
|
||||
/* Averaging mode for trx_sched_meas_avg() */
|
||||
enum sched_meas_avg_mode {
|
||||
/* first 22 of last 24 bursts (for TCH/F14.4, TCH/F9.6, TCH/F4.8) */
|
||||
SCHED_MEAS_AVG_M_S24N22,
|
||||
/* last 22 bursts (for TCH/H4.8, TCH/H2.4) */
|
||||
SCHED_MEAS_AVG_M_S22N22,
|
||||
/* last 4 bursts (default for xCCH, PTCCH and PDTCH) */
|
||||
SCHED_MEAS_AVG_M_S4N4,
|
||||
/* last 8 bursts (default for TCH/F and FACCH/F) */
|
||||
|
||||
@@ -42,16 +42,18 @@ extern const ubit_t _sched_train_seq_gmsk_sb[64];
|
||||
struct msgb *_sched_dequeue_prim(struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
|
||||
|
||||
int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *l2,
|
||||
uint8_t l2_len, float rssi,
|
||||
enum trx_chan_type chan,
|
||||
const uint8_t *data, size_t data_len,
|
||||
uint16_t ber10k, float rssi,
|
||||
int16_t ta_offs_256bits, int16_t link_qual_cb,
|
||||
uint16_t ber10k,
|
||||
enum osmo_ph_pres_info_type presence_info);
|
||||
|
||||
int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len,
|
||||
int16_t ta_offs_256bits, uint16_t ber10k, float rssi,
|
||||
int16_t link_qual_cb, uint8_t is_sub);
|
||||
enum trx_chan_type chan,
|
||||
const uint8_t *data, size_t data_len,
|
||||
uint16_t ber10k, float rssi,
|
||||
int16_t ta_offs_256bits, int16_t link_qual_cb,
|
||||
uint8_t is_sub);
|
||||
|
||||
int tx_fcch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
int tx_sch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
|
||||
@@ -21,12 +21,9 @@ extern struct cmd_element cfg_bts_no_auto_band_cmd;
|
||||
struct phy_instance *vty_get_phy_instance(struct vty *vty, int phy_nr, int inst_nr);
|
||||
|
||||
int bts_vty_go_parent(struct vty *vty);
|
||||
int bts_vty_is_config_node(struct vty *vty, int node);
|
||||
|
||||
int bts_vty_init(void *ctx);
|
||||
|
||||
struct gsm_network *gsmnet_from_vty(struct vty *v);
|
||||
|
||||
extern struct vty_app_info bts_vty_info;
|
||||
extern struct gsm_bts *g_bts;
|
||||
|
||||
|
||||
@@ -33,12 +33,15 @@ libbts_a_SOURCES = \
|
||||
oml.c \
|
||||
osmux.c \
|
||||
bts.c \
|
||||
bts_sm.c \
|
||||
bts_trx.c \
|
||||
rsl.c \
|
||||
rtp_input_preen.c \
|
||||
vty.c \
|
||||
paging.c \
|
||||
measurement.c \
|
||||
amr.c \
|
||||
asci.c \
|
||||
lchan.c \
|
||||
load_indication.c \
|
||||
pcu_sock.c \
|
||||
@@ -48,6 +51,7 @@ libbts_a_SOURCES = \
|
||||
bts_ctrl_commands.c \
|
||||
bts_ctrl_lookup.c \
|
||||
bts_shutdown_fsm.c \
|
||||
csd_v110.c \
|
||||
l1sap.c \
|
||||
cbch.c \
|
||||
power_control.c \
|
||||
@@ -61,7 +65,11 @@ libbts_a_SOURCES = \
|
||||
nm_bts_fsm.c \
|
||||
nm_bb_transc_fsm.c \
|
||||
nm_channel_fsm.c \
|
||||
nm_gprs_cell_fsm.c \
|
||||
nm_gprs_nse_fsm.c \
|
||||
nm_gprs_nsvc_fsm.c \
|
||||
nm_radio_carrier_fsm.c \
|
||||
notification.c \
|
||||
probes.d \
|
||||
$(NULL)
|
||||
|
||||
|
||||
@@ -225,9 +225,9 @@ static void abis_link_connected(struct osmo_fsm_inst *fi, uint32_t event, void *
|
||||
|
||||
/* Then iterate over the RSL signalling links */
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
if (trx->rsl_link) {
|
||||
e1inp_sign_link_destroy(trx->rsl_link);
|
||||
trx->rsl_link = NULL;
|
||||
if (trx->bb_transc.rsl.link) {
|
||||
e1inp_sign_link_destroy(trx->bb_transc.rsl.link);
|
||||
trx->bb_transc.rsl.link = NULL;
|
||||
if (trx == trx->bts->c0)
|
||||
load_timer_stop(trx->bts);
|
||||
} else {
|
||||
@@ -364,7 +364,7 @@ int abis_bts_rsl_sendmsg(struct msgb *msg)
|
||||
|
||||
/* osmo-bts uses msg->trx internally, but libosmo-abis uses
|
||||
* the signalling link at msg->dst */
|
||||
msg->dst = msg->trx->rsl_link;
|
||||
msg->dst = msg->trx->bb_transc.rsl.link;
|
||||
return abis_sendmsg(msg);
|
||||
}
|
||||
|
||||
@@ -404,10 +404,10 @@ static struct e1inp_sign_link *sign_link_up(void *unit, struct e1inp_line *line,
|
||||
break;
|
||||
}
|
||||
e1inp_ts_config_sign(sign_ts, line);
|
||||
trx->rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
|
||||
trx, trx->rsl_tei, 0);
|
||||
trx->bb_transc.rsl.link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
|
||||
trx, trx->bb_transc.rsl.tei, 0);
|
||||
trx_link_estab(trx);
|
||||
return trx->rsl_link;
|
||||
return trx->bb_transc.rsl.link;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* OSMO extenion link associated to same line as oml_link: */
|
||||
|
||||
/* (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -30,8 +30,7 @@
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/pcu_if.h>
|
||||
#include <osmo-bts/pcuif_proto.h>
|
||||
|
||||
extern struct gsm_network bts_gsmnet;
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
|
||||
#define OM_HEADROOM_SIZE 128
|
||||
|
||||
@@ -106,7 +105,7 @@ static int rx_down_osmo_pcu(struct gsm_bts *bts, struct msgb *msg)
|
||||
/* Trim Abis lower layers: */
|
||||
msgb_pull_to_l2(msg);
|
||||
/* we simply forward it to PCUIF: */
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
/* incoming IPA/OSMO extension Abis message from BSC */
|
||||
|
||||
211
src/common/asci.c
Normal file
211
src/common/asci.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/* ASCI (VGCS/VBS) related common code */
|
||||
|
||||
/* (C) 2023 by Harald Welte <laforge@osmocom.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 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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
#include <osmocom/gsm/rsl.h>
|
||||
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/rsl.h>
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/l1sap.h>
|
||||
#include <osmo-bts/asci.h>
|
||||
|
||||
static int tx_vgcs_ul_grant(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct gsm0408_vgcs_ul_grant ul_grant;
|
||||
struct gsm_time gt;
|
||||
struct msgb *msg;
|
||||
|
||||
gsm_fn2gsmtime(>, lchan->asci.fn);
|
||||
|
||||
/* build the RR VGCS UPLINK GRANT message as per TS 44.018 Section 9.1.49 */
|
||||
ul_grant = (struct gsm0408_vgcs_ul_grant) {
|
||||
.hdr = {
|
||||
.proto_discr = GSM48_PDISC_RR,
|
||||
.msg_type = GSM48_MT_RR_VGCS_UPL_GRANT,
|
||||
},
|
||||
.req_ref = {
|
||||
.ra = lchan->asci.ref,
|
||||
.t1 = gt.t1,
|
||||
.t2 = gt.t2,
|
||||
.t3_low = gt.t3 & 7,
|
||||
.t3_high = gt.t3 >> 3,
|
||||
},
|
||||
.ta = lchan->ta_ctrl.current,
|
||||
};
|
||||
|
||||
/* Wrap it in a RSL UNITDATA REQUEST */
|
||||
msg = rsl_rll_simple(RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan), 0x00, 0);
|
||||
msg->l3h = msg->tail; /* emulate rsl_rx_rll() behaviour */
|
||||
msgb_tl16v_put(msg, RSL_IE_L3_INFO, sizeof(ul_grant), (uint8_t *) &ul_grant);
|
||||
|
||||
/* send it towards MS, just like a RSL message from the BSC */
|
||||
return lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch);
|
||||
}
|
||||
|
||||
/* timer call-back for T3115 (VGCS UPLINK GRANT re-transmit) */
|
||||
static void vgcs_t3115_cb(void *data)
|
||||
{
|
||||
struct gsm_lchan *lchan = data;
|
||||
struct gsm_bts *bts = lchan->ts->trx->bts;
|
||||
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_INFO, "T3115 timeout (%d resends left)\n",
|
||||
bts->ny2 - lchan->asci.vgcs_ul_grant_count);
|
||||
|
||||
if (lchan->state != LCHAN_S_ACTIVE) {
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "is not active. It is in state %s. Ignoring\n",
|
||||
gsm_lchans_name(lchan->state));
|
||||
return;
|
||||
}
|
||||
|
||||
if (lchan->asci.vgcs_ul_grant_count >= bts->ny2) {
|
||||
lchan->asci.vgcs_ul_grant_count = 0;
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "NY2 reached, sending CONNection FAILure to BSC.\n");
|
||||
rsl_tx_conn_fail(lchan, RSL_ERR_TALKER_ACC_FAIL);
|
||||
lchan->asci.talker_active = VGCS_TALKER_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
tx_vgcs_ul_grant(lchan);
|
||||
lchan->asci.vgcs_ul_grant_count++;
|
||||
osmo_timer_schedule(&lchan->asci.t3115, 0, bts->t3115_ms * 1000);
|
||||
}
|
||||
|
||||
/* Received random access on dedicated channel. */
|
||||
void vgcs_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay, uint32_t fn)
|
||||
{
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "VGCS RACH on dedicated channel type %s received with "
|
||||
"TA=%u, ref=%u\n", gsm_lchant_name(lchan->type), acc_delay, ra);
|
||||
|
||||
if (ra == 0x25) { /* See TS 44.018 Table 9.1.45.1 */
|
||||
/* Listener Detection (TS 48.058 Section 4.14) */
|
||||
if (!lchan->asci.listener_detected) {
|
||||
rsl_tx_listener_det(lchan, &acc_delay);
|
||||
lchan->asci.listener_detected = true;
|
||||
}
|
||||
} else {
|
||||
/* Talker Detection (TS 48.058 Section 4.13) */
|
||||
struct gsm_bts *bts = lchan->ts->trx->bts;
|
||||
|
||||
/* Talker detection on group channels only */
|
||||
if (!rsl_chan_rt_is_vgcs(lchan->rsl_chan_rt))
|
||||
return;
|
||||
|
||||
if (lchan->asci.talker_active != VGCS_TALKER_NONE) {
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_DEBUG, "Ignoring RACH, there is an active talker already.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set timing advance, power level and activate SACCH */
|
||||
lchan->ta_ctrl.current = acc_delay;
|
||||
lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;
|
||||
lchan->want_dl_sacch_active = true;
|
||||
|
||||
/* Stop RACH detection, wait for valid frame */
|
||||
lchan->asci.talker_active = VGCS_TALKER_WAIT_FRAME;
|
||||
if (l1sap_uplink_access(lchan, false) != 0) {
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_ERROR, "Failed to deactivate uplink access after TALKER DET.\n");
|
||||
rsl_tx_conn_fail(lchan, RSL_ERR_EQUIPMENT_FAIL);
|
||||
lchan->asci.talker_active = VGCS_TALKER_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
lchan->asci.ref = ra;
|
||||
lchan->asci.fn = fn;
|
||||
|
||||
/* Send TALKER DETECT via RSL to BSC */
|
||||
rsl_tx_talker_det(lchan, &acc_delay);
|
||||
|
||||
/* Send VGCS UPLINK GRANT */
|
||||
lchan->asci.vgcs_ul_grant_count = 1;
|
||||
tx_vgcs_ul_grant(lchan);
|
||||
|
||||
/* Start T3115 */
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_DEBUG, "Starting T3115 with %u ms\n", bts->t3115_ms);
|
||||
lchan->asci.t3115.cb = vgcs_t3115_cb;
|
||||
lchan->asci.t3115.data = lchan;
|
||||
osmo_timer_schedule(&lchan->asci.t3115, 0, bts->t3115_ms * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/* Received channel activation. */
|
||||
void vgcs_lchan_activate(struct gsm_lchan *lchan)
|
||||
{
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_INFO, "Channel is activated.\n");
|
||||
if (l1sap_uplink_access(lchan, true) != 0) {
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_ERROR, "Failed to activate uplink access after channel activation.\n");
|
||||
rsl_tx_conn_fail(lchan, RSL_ERR_EQUIPMENT_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Received channel reactivation. (for assignment) */
|
||||
void vgcs_lchan_react(struct gsm_lchan *lchan)
|
||||
{
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_INFO, "Channel is activated for assignment.\n");
|
||||
lchan->asci.talker_active = VGCS_TALKER_WAIT_FRAME;
|
||||
if (l1sap_uplink_access(lchan, false) != 0) {
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_ERROR, "Failed to deactivate uplink access for assignment.\n");
|
||||
rsl_tx_conn_fail(lchan, RSL_ERR_EQUIPMENT_FAIL);
|
||||
}
|
||||
radio_link_timeout_reset(lchan);
|
||||
}
|
||||
|
||||
/* Received first valid data frame on dedicated channel. */
|
||||
void vgcs_talker_frame(struct gsm_lchan *lchan)
|
||||
{
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_INFO, "First valid frame detected, talker now active.\n");
|
||||
osmo_timer_del(&lchan->asci.t3115);
|
||||
lchan->asci.talker_active = VGCS_TALKER_ACTIVE;
|
||||
radio_link_timeout_reset(lchan);
|
||||
}
|
||||
|
||||
/* Release VGCS Talker state. */
|
||||
void vgcs_talker_reset(struct gsm_lchan *lchan, bool ul_access)
|
||||
{
|
||||
if (lchan->asci.talker_active == VGCS_TALKER_NONE)
|
||||
return;
|
||||
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_INFO, "Uplink released, no talker.\n");
|
||||
|
||||
/* Stop T3115 */
|
||||
osmo_timer_del(&lchan->asci.t3115);
|
||||
|
||||
/* Talker released. */
|
||||
lchan->asci.talker_active = VGCS_TALKER_NONE;
|
||||
if (ul_access) {
|
||||
if (l1sap_uplink_access(lchan, true) != 0) {
|
||||
LOGPLCHAN(lchan, DASCI, LOGL_ERROR,
|
||||
"Failed to activate uplink access after uplink became free.\n");
|
||||
rsl_tx_conn_fail(lchan, RSL_ERR_EQUIPMENT_FAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Release VGCS Listener state. */
|
||||
void vgcs_listener_reset(struct gsm_lchan *lchan)
|
||||
{
|
||||
lchan->asci.listener_detected = false;
|
||||
}
|
||||
282
src/common/bts.c
282
src/common/bts.c
@@ -44,8 +44,10 @@
|
||||
#include <osmo-bts/abis.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/dtx_dl_amr_fsm.h>
|
||||
#include <osmo-bts/pcuif_proto.h>
|
||||
#include <osmo-bts/pcu_if.h>
|
||||
#include <osmo-bts/rsl.h>
|
||||
#include <osmo-bts/oml.h>
|
||||
#include <osmo-bts/signal.h>
|
||||
@@ -55,17 +57,14 @@
|
||||
#include <osmo-bts/nm_common_fsm.h>
|
||||
#include <osmo-bts/power_control.h>
|
||||
#include <osmo-bts/osmux.h>
|
||||
#include <osmo-bts/notification.h>
|
||||
|
||||
#define MAX_TA_DEF 63 /* default max Timing Advance value */
|
||||
#define MIN_QUAL_RACH 50 /* minimum link quality (in centiBels) for Access Bursts */
|
||||
#define MIN_QUAL_NORM -5 /* minimum link quality (in centiBels) for Normal Bursts */
|
||||
|
||||
static void bts_update_agch_max_queue_length(struct gsm_bts *bts);
|
||||
|
||||
struct gsm_network bts_gsmnet = {
|
||||
.bts_list = { &bts_gsmnet.bts_list, &bts_gsmnet.bts_list },
|
||||
.num_bts = 0,
|
||||
};
|
||||
|
||||
void *tall_bts_ctx;
|
||||
|
||||
/* Table 3.1 TS 04.08: Values of parameter S */
|
||||
@@ -98,6 +97,7 @@ static const struct rate_ctr_desc bts_ctr_desc[] = {
|
||||
[BTS_CTR_RACH_RCVD] = {"rach:rcvd", "Received RACH requests (Um)"},
|
||||
[BTS_CTR_RACH_DROP] = {"rach:drop", "Dropped RACH requests (Um)"},
|
||||
[BTS_CTR_RACH_HO] = {"rach:handover", "Received RACH requests (Handover)"},
|
||||
[BTS_CTR_RACH_VGCS] = {"rach:vgcs", "Received RACH requests (VGCS)"},
|
||||
[BTS_CTR_RACH_CS] = {"rach:cs", "Received RACH requests (CS/Abis)"},
|
||||
[BTS_CTR_RACH_PS] = {"rach:ps", "Received RACH requests (PS/PCU)"},
|
||||
|
||||
@@ -149,7 +149,6 @@ struct osmo_tdef abis_T_defs[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const uint8_t bts_nse_timer_default[] = { 3, 3, 3, 3, 30, 3, 10 };
|
||||
static const uint8_t bts_cell_timer_default[] =
|
||||
{ 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 };
|
||||
static const struct gprs_rlc_cfg rlc_cfg_default = {
|
||||
@@ -207,15 +206,16 @@ const char *btsatttr2str(enum bts_attribute v)
|
||||
const struct value_string bts_impl_flag_desc[] = {
|
||||
{ BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP, "DSP/HW based MS Power Control Loop" },
|
||||
{ BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB, "Measurement and Payload data combined" },
|
||||
{ BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER, "OML RadioChannel MO depends on RadioCarrier MO" },
|
||||
{ BTS_INTERNAL_FLAG_INTERF_MEAS, "Uplink interference measurements" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Ensure that all BTS_INTERNAL_FLAG_* entries are present in bts_impl_flag_desc[] */
|
||||
osmo_static_assert(ARRAY_SIZE(bts_impl_flag_desc) == _BTS_INTERNAL_FLAG_NUM + 1, _bts_impl_flag_desc);
|
||||
|
||||
static int gsm_bts_talloc_destructor(struct gsm_bts *bts)
|
||||
{
|
||||
if (bts->site_mgr.mo.fi) {
|
||||
osmo_fsm_inst_free(bts->site_mgr.mo.fi);
|
||||
bts->site_mgr.mo.fi = NULL;
|
||||
}
|
||||
if (bts->mo.fi) {
|
||||
osmo_fsm_inst_free(bts->mo.fi);
|
||||
bts->mo.fi = NULL;
|
||||
@@ -226,19 +226,26 @@ static int gsm_bts_talloc_destructor(struct gsm_bts *bts)
|
||||
}
|
||||
|
||||
bts_osmux_release(bts);
|
||||
|
||||
llist_del(&bts->list);
|
||||
g_bts_sm->num_bts--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
|
||||
struct gsm_bts *gsm_bts_alloc(struct gsm_bts_sm *bts_sm, uint8_t bts_num)
|
||||
{
|
||||
struct gsm_bts *bts = talloc_zero(ctx, struct gsm_bts);
|
||||
int i;
|
||||
struct gsm_bts *bts = talloc_zero(bts_sm, struct gsm_bts);
|
||||
|
||||
if (!bts)
|
||||
return NULL;
|
||||
|
||||
talloc_set_destructor(bts, gsm_bts_talloc_destructor);
|
||||
|
||||
/* add to list of BTSs */
|
||||
llist_add_tail(&bts->list, &bts_sm->bts_list);
|
||||
g_bts_sm->num_bts++;
|
||||
|
||||
bts->site_mgr = bts_sm;
|
||||
bts->nr = bts_num;
|
||||
bts->num_trx = 0;
|
||||
INIT_LLIST_HEAD(&bts->trx_list);
|
||||
@@ -251,32 +258,19 @@ struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
|
||||
LOGL_INFO, NULL);
|
||||
osmo_fsm_inst_update_id_f(bts->shutdown_fi, "bts%d", bts->nr);
|
||||
|
||||
bts->site_mgr.mo.fi = osmo_fsm_inst_alloc(&nm_bts_sm_fsm, bts, &bts->site_mgr,
|
||||
LOGL_INFO, "bts_sm");
|
||||
gsm_mo_init(&bts->site_mgr.mo, bts, NM_OC_SITE_MANAGER,
|
||||
0xff, 0xff, 0xff);
|
||||
|
||||
/* NM BTS */
|
||||
bts->mo.fi = osmo_fsm_inst_alloc(&nm_bts_fsm, bts, bts,
|
||||
LOGL_INFO, NULL);
|
||||
osmo_fsm_inst_update_id_f(bts->mo.fi, "bts%d", bts->nr);
|
||||
gsm_mo_init(&bts->mo, bts, NM_OC_BTS, bts->nr, 0xff, 0xff);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
|
||||
bts->gprs.nsvc[i].bts = bts;
|
||||
bts->gprs.nsvc[i].id = i;
|
||||
gsm_mo_init(&bts->gprs.nsvc[i].mo, bts, NM_OC_GPRS_NSVC,
|
||||
bts->nr, i, 0xff);
|
||||
}
|
||||
memcpy(&bts->gprs.nse.timer, bts_nse_timer_default,
|
||||
sizeof(bts->gprs.nse.timer));
|
||||
gsm_mo_init(&bts->gprs.nse.mo, bts, NM_OC_GPRS_NSE,
|
||||
bts->nr, 0xff, 0xff);
|
||||
memcpy(&bts->gprs.cell.timer, bts_cell_timer_default,
|
||||
sizeof(bts->gprs.cell.timer));
|
||||
gsm_mo_init(&bts->gprs.cell.mo, bts, NM_OC_GPRS_CELL,
|
||||
bts->nr, 0xff, 0xff);
|
||||
memcpy(&bts->gprs.cell.rlc_cfg, &rlc_cfg_default,
|
||||
sizeof(bts->gprs.cell.rlc_cfg));
|
||||
/* NM GPRS CELL */
|
||||
bts->gprs.cell.mo.fi = osmo_fsm_inst_alloc(&nm_gprs_cell_fsm, bts, &bts->gprs.cell,
|
||||
LOGL_INFO, NULL);
|
||||
osmo_fsm_inst_update_id_f(bts->gprs.cell.mo.fi, "gprs_cell%d-0", bts->nr);
|
||||
gsm_mo_init(&bts->gprs.cell.mo, bts, NM_OC_GPRS_CELL, bts->nr, 0, 0xff);
|
||||
memcpy(&bts->gprs.cell.rlc_cfg, &rlc_cfg_default, sizeof(bts->gprs.cell.rlc_cfg));
|
||||
memcpy(&bts->gprs.cell.timer, bts_cell_timer_default, sizeof(bts->gprs.cell.timer));
|
||||
|
||||
/* create our primary TRX. It will be initialized during bts_init() */
|
||||
bts->c0 = gsm_bts_trx_alloc(bts);
|
||||
@@ -292,14 +286,14 @@ struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
|
||||
return bts;
|
||||
}
|
||||
|
||||
struct gsm_bts *gsm_bts_num(const struct gsm_network *net, int num)
|
||||
struct gsm_bts *gsm_bts_num(const struct gsm_bts_sm *bts_sm, int num)
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
|
||||
if (num >= net->num_bts)
|
||||
if (num >= bts_sm->num_bts)
|
||||
return NULL;
|
||||
|
||||
llist_for_each_entry(bts, &net->bts_list, list) {
|
||||
llist_for_each_entry(bts, &bts_sm->bts_list, list) {
|
||||
if (bts->nr == num)
|
||||
return bts;
|
||||
}
|
||||
@@ -315,19 +309,14 @@ int bts_init(struct gsm_bts *bts)
|
||||
static int initialized = 0;
|
||||
void *tall_rtp_ctx;
|
||||
|
||||
/* add to list of BTSs */
|
||||
llist_add_tail(&bts->list, &bts_gsmnet.bts_list);
|
||||
|
||||
bts->band = GSM_BAND_1800;
|
||||
|
||||
INIT_LLIST_HEAD(&bts->agch_queue.queue);
|
||||
bts->agch_queue.length = 0;
|
||||
|
||||
bts->ctrs = rate_ctr_group_alloc(bts, &bts_ctrg_desc, bts->nr);
|
||||
if (!bts->ctrs) {
|
||||
llist_del(&bts->list);
|
||||
if (!bts->ctrs)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* enable management with default levels,
|
||||
* raise threshold to GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE to
|
||||
@@ -345,37 +334,37 @@ int bts_init(struct gsm_bts *bts)
|
||||
bts->rtp_port_range_next = bts->rtp_port_range_start;
|
||||
bts->rtp_ip_dscp = -1;
|
||||
bts->rtp_priority = -1;
|
||||
bts->emit_hr_rfc5993 = true;
|
||||
|
||||
/* Default (fall-back) MS/BS Power control parameters */
|
||||
power_ctrl_params_def_reset(&bts->bs_dpc_params, true);
|
||||
power_ctrl_params_def_reset(&bts->ms_dpc_params, false);
|
||||
|
||||
/* configurable via OML */
|
||||
bts->bsic = 0xff; /* invalid value, guarded by bsc_configured=false */
|
||||
bts->bsic_configured = false;
|
||||
bts->load.ccch.load_ind_period = 112;
|
||||
bts->rtp_jitter_buf_ms = 100;
|
||||
bts->max_ta = 63;
|
||||
bts->max_ta = MAX_TA_DEF;
|
||||
bts->ny1 = 4;
|
||||
bts->ny2 = 4;
|
||||
bts->t3105_ms = 300;
|
||||
bts->t3115_ms = 300;
|
||||
bts->min_qual_rach = MIN_QUAL_RACH;
|
||||
bts->min_qual_norm = MIN_QUAL_NORM;
|
||||
bts->max_ber10k_rach = 1707; /* 7 of 41 bits is Eb/N0 of 0 dB = 0.1707 */
|
||||
bts->pcu.sock_path = talloc_strdup(bts, PCU_SOCK_DEFAULT);
|
||||
for (i = 0; i < ARRAY_SIZE(bts->t200_ms); i++)
|
||||
bts->t200_ms[i] = oml_default_t200_ms[i];
|
||||
bts->pcu.sock_wqueue_len_max = BTS_PCU_SOCK_WQUEUE_LEN_DEFAULT;
|
||||
for (i = 0; i < ARRAY_SIZE(bts->t200_fn); i++)
|
||||
bts->t200_fn[i] = oml_default_t200_fn[i];
|
||||
|
||||
/* default RADIO_LINK_TIMEOUT */
|
||||
bts->radio_link_timeout.oml = 32;
|
||||
bts->radio_link_timeout.current = bts->radio_link_timeout.oml;
|
||||
|
||||
/* Start with the site manager */
|
||||
oml_mo_state_init(&bts->site_mgr.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
/* Start with the BTS */
|
||||
oml_mo_state_init(&bts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
|
||||
/* set BTS attr to dependency */
|
||||
oml_mo_state_init(&bts->gprs.nse.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
|
||||
oml_mo_state_init(&bts->gprs.cell.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
|
||||
oml_mo_state_init(&bts->gprs.nsvc[0].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
|
||||
oml_mo_state_init(&bts->gprs.nsvc[1].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
|
||||
oml_mo_state_init(&bts->gprs.cell.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
|
||||
/* allocate a talloc pool for ORTP to ensure it doesn't have to go back
|
||||
* to the libc malloc all the time */
|
||||
@@ -384,10 +373,8 @@ int bts_init(struct gsm_bts *bts)
|
||||
|
||||
/* Osmux */
|
||||
rc = bts_osmux_init(bts);
|
||||
if (rc < 0) {
|
||||
llist_del(&bts->list);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* features implemented in 'common', available for all models,
|
||||
* order alphabetically */
|
||||
@@ -398,15 +385,15 @@ int bts_init(struct gsm_bts *bts)
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_IPV6_NSVC);
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_PAGING_COORDINATION);
|
||||
|
||||
/* Maximum TA supported by the PHY (can be overridden by PHY specific code) */
|
||||
bts->support.max_ta = MAX_TA_DEF;
|
||||
|
||||
rc = bts_model_init(bts);
|
||||
if (rc < 0) {
|
||||
llist_del(&bts->list);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* TRX0 was allocated early during gsm_bts_alloc, not later through VTY */
|
||||
bts_model_trx_init(bts->c0);
|
||||
bts_gsmnet.num_bts++;
|
||||
|
||||
if (!initialized) {
|
||||
osmo_signal_register_handler(SS_GLOBAL, bts_signal_cbfn, NULL);
|
||||
@@ -423,6 +410,9 @@ int bts_init(struct gsm_bts *bts)
|
||||
bts->smscb_queue_tgt_len = 2;
|
||||
bts->smscb_queue_hyst = 2;
|
||||
|
||||
bts->asci.pos_nch = -ENOTSUP;
|
||||
INIT_LLIST_HEAD(&bts->asci.notifications);
|
||||
|
||||
INIT_LLIST_HEAD(&bts->bsc_oml_hosts);
|
||||
|
||||
/* register DTX DL FSM */
|
||||
@@ -440,33 +430,13 @@ int bts_init(struct gsm_bts *bts)
|
||||
/* main link is established, send status report */
|
||||
int bts_link_estab(struct gsm_bts *bts)
|
||||
{
|
||||
int i, j;
|
||||
LOGP(DOML, LOGL_INFO, "Main link established, sending NM Status\n");
|
||||
|
||||
LOGP(DOML, LOGL_INFO, "Main link established, sending NM Status.\n");
|
||||
|
||||
/* BTS SITE MGR becomes Offline (tx SW ACT Report), BTS is DEPENDENCY */
|
||||
osmo_fsm_inst_dispatch(bts->site_mgr.mo.fi, NM_EV_SW_ACT, NULL);
|
||||
osmo_fsm_inst_dispatch(bts->mo.fi, NM_EV_SW_ACT, NULL);
|
||||
|
||||
/* those should all be in DEPENDENCY */
|
||||
oml_tx_state_changed(&bts->gprs.nse.mo);
|
||||
oml_tx_state_changed(&bts->gprs.cell.mo);
|
||||
oml_tx_state_changed(&bts->gprs.nsvc[0].mo);
|
||||
oml_tx_state_changed(&bts->gprs.nsvc[1].mo);
|
||||
|
||||
/* All other objects start off-line until the BTS Model code says otherwise */
|
||||
for (i = 0; i < bts->num_trx; i++) {
|
||||
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i);
|
||||
|
||||
oml_tx_state_changed(&trx->mo);
|
||||
oml_tx_state_changed(&trx->bb_transc.mo);
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {
|
||||
struct gsm_bts_trx_ts *ts = &trx->ts[j];
|
||||
|
||||
oml_tx_state_changed(&ts->mo);
|
||||
}
|
||||
}
|
||||
/* Signal OML UP to BTS SITE MGR. It will automatically SW_ACT repoort
|
||||
* and become Disabled-Offline, then dispatch same event to its children
|
||||
* objects.
|
||||
*/
|
||||
osmo_fsm_inst_dispatch(bts->site_mgr->mo.fi, NM_EV_OML_UP, NULL);
|
||||
|
||||
return bts_model_oml_estab(bts);
|
||||
}
|
||||
@@ -693,7 +663,7 @@ int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct msgb *bts_agch_dequeue(struct gsm_bts *bts)
|
||||
static struct msgb *bts_agch_dequeue(struct gsm_bts *bts)
|
||||
{
|
||||
struct msgb *msg = msgb_dequeue(&bts->agch_queue.queue);
|
||||
if (!msg)
|
||||
@@ -759,12 +729,12 @@ static void compact_agch_queue(struct gsm_bts *bts)
|
||||
return;
|
||||
}
|
||||
|
||||
int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
|
||||
int is_ag_res)
|
||||
int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, enum ccch_msgt ccch)
|
||||
{
|
||||
struct msgb *msg = NULL;
|
||||
int rc = 0;
|
||||
int is_empty = 1;
|
||||
const struct bts_agch_msg_cb *msg_cb;
|
||||
|
||||
/* Do queue house keeping.
|
||||
* This needs to be done every time a CCCH message is requested, since
|
||||
@@ -773,26 +743,39 @@ int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt
|
||||
*/
|
||||
compact_agch_queue(bts);
|
||||
|
||||
/* Check for paging messages first if this is PCH */
|
||||
if (!is_ag_res)
|
||||
switch (ccch) {
|
||||
case CCCH_MSGT_NCH:
|
||||
/* Send NCH message, it has priority over AGCH and does not overlap with PCH. */
|
||||
rc = bts_asci_notify_nch_gen_msg(bts, out_buf);
|
||||
return rc;
|
||||
case CCCH_MSGT_PCH:
|
||||
/* Check whether the block may be overwritten by AGCH. */
|
||||
rc = paging_gen_msg(bts->paging_state, out_buf, gt, &is_empty);
|
||||
|
||||
/* Check whether the block may be overwritten */
|
||||
if (!is_empty)
|
||||
return rc;
|
||||
|
||||
msg = bts_agch_dequeue(bts);
|
||||
if (!msg)
|
||||
return rc;
|
||||
if (!is_empty)
|
||||
return rc;
|
||||
/* fall-through */
|
||||
case CCCH_MSGT_AGCH:
|
||||
/* If fallen here and the AGCH queue is empty, return empty PCH message. */
|
||||
msg = bts_agch_dequeue(bts);
|
||||
if (!msg)
|
||||
return rc;
|
||||
/* Continue to return AGCH message. */
|
||||
break;
|
||||
}
|
||||
|
||||
rate_ctr_inc2(bts->ctrs, BTS_CTR_AGCH_SENT);
|
||||
|
||||
/* Confirm sending of the AGCH message towards the PCU */
|
||||
msg_cb = (struct bts_agch_msg_cb *) msg->cb;
|
||||
if (msg_cb->confirm)
|
||||
pcu_tx_data_cnf(msg_cb->msg_id, PCU_IF_SAPI_AGCH_2);
|
||||
|
||||
/* Copy AGCH message */
|
||||
memcpy(out_buf, msgb_l3(msg), msgb_l3len(msg));
|
||||
rc = msgb_l3len(msg);
|
||||
msgb_free(msg);
|
||||
|
||||
if (is_ag_res)
|
||||
if (ccch == CCCH_MSGT_AGCH)
|
||||
bts->agch_queue.agch_msgs++;
|
||||
else
|
||||
bts->agch_queue.pch_msgs++;
|
||||
@@ -820,30 +803,35 @@ struct gsm_time *get_time(struct gsm_bts *bts)
|
||||
return &bts->gsm_time;
|
||||
}
|
||||
|
||||
int bts_supports_cm(const struct gsm_bts *bts,
|
||||
const struct rsl_ie_chan_mode *cm)
|
||||
bool bts_supports_cm_speech(const struct gsm_bts *bts,
|
||||
const struct rsl_ie_chan_mode *cm)
|
||||
{
|
||||
enum osmo_bts_features feature = _NUM_BTS_FEAT;
|
||||
|
||||
switch (cm->spd_ind) {
|
||||
case RSL_CMOD_SPD_SIGN:
|
||||
/* We assume that signalling support is mandatory,
|
||||
* there is no BTS_FEAT_* definition to check that. */
|
||||
return 1;
|
||||
case RSL_CMOD_SPD_SPEECH:
|
||||
/* Stage 1: check support for the requested channel type */
|
||||
switch (cm->chan_rt) {
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Bm:
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Lm:
|
||||
if (!osmo_bts_has_feature(bts->features, BTS_FEAT_VGCS))
|
||||
return false;
|
||||
break;
|
||||
case RSL_CMOD_CRT_TCH_BCAST_Bm:
|
||||
case RSL_CMOD_CRT_TCH_BCAST_Lm:
|
||||
if (!osmo_bts_has_feature(bts->features, BTS_FEAT_VBS))
|
||||
return false;
|
||||
break;
|
||||
case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm:
|
||||
case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm:
|
||||
if (!osmo_bts_has_feature(bts->features, BTS_FEAT_VAMOS))
|
||||
return false;
|
||||
break;
|
||||
case RSL_CMOD_SPD_DATA:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Before the requested pchan/cm combination can be checked, we need to
|
||||
* convert it to a feature identifier we can check */
|
||||
/* Stage 2: check support for the requested codec */
|
||||
switch (cm->chan_rt) {
|
||||
case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm:
|
||||
if (!osmo_bts_has_feature(bts->features, BTS_FEAT_VAMOS))
|
||||
return 0;
|
||||
/* fall-through */
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Bm:
|
||||
case RSL_CMOD_CRT_TCH_BCAST_Bm:
|
||||
case RSL_CMOD_CRT_TCH_Bm:
|
||||
switch (cm->chan_rate) {
|
||||
case RSL_CMOD_SP_GSM1:
|
||||
@@ -857,14 +845,13 @@ int bts_supports_cm(const struct gsm_bts *bts,
|
||||
break;
|
||||
default:
|
||||
/* Invalid speech codec type => Not supported! */
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm:
|
||||
if (!osmo_bts_has_feature(bts->features, BTS_FEAT_VAMOS))
|
||||
return 0;
|
||||
/* fall-through */
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Lm:
|
||||
case RSL_CMOD_CRT_TCH_BCAST_Lm:
|
||||
case RSL_CMOD_CRT_TCH_Lm:
|
||||
switch (cm->chan_rate) {
|
||||
case RSL_CMOD_SP_GSM1:
|
||||
@@ -875,7 +862,7 @@ int bts_supports_cm(const struct gsm_bts *bts,
|
||||
break;
|
||||
default:
|
||||
/* Invalid speech codec type => Not supported! */
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -883,14 +870,59 @@ int bts_supports_cm(const struct gsm_bts *bts,
|
||||
LOGP(DRSL, LOGL_ERROR,
|
||||
"Unhandled RSL channel type=0x%02x/rate=0x%02x\n",
|
||||
cm->chan_rt, cm->chan_rate);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if the feature is supported by this BTS */
|
||||
if (osmo_bts_has_feature(bts->features, feature))
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool bts_supports_cm_data(const struct gsm_bts *bts,
|
||||
const struct rsl_ie_chan_mode *cm)
|
||||
{
|
||||
switch (bts->variant) {
|
||||
case BTS_OSMO_TRX:
|
||||
switch (cm->chan_rate) {
|
||||
/* TODO: RSL_CMOD_CSD_NT_14k5 */
|
||||
/* TODO: RSL_CMOD_CSD_T_14k4 */
|
||||
case RSL_CMOD_CSD_NT_12k0:
|
||||
case RSL_CMOD_CSD_T_9k6:
|
||||
if (cm->chan_rt != RSL_CMOD_CRT_TCH_Bm)
|
||||
return false; /* invalid */
|
||||
/* fall-through */
|
||||
case RSL_CMOD_CSD_NT_6k0:
|
||||
case RSL_CMOD_CSD_T_4k8:
|
||||
case RSL_CMOD_CSD_T_2k4:
|
||||
case RSL_CMOD_CSD_T_1k2:
|
||||
case RSL_CMOD_CSD_T_600:
|
||||
case RSL_CMOD_CSD_T_1200_75:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool bts_supports_cm(const struct gsm_bts *bts,
|
||||
const struct rsl_ie_chan_mode *cm)
|
||||
{
|
||||
switch (cm->spd_ind) {
|
||||
case RSL_CMOD_SPD_SIGN:
|
||||
/* We assume that signalling support is mandatory,
|
||||
* there is no BTS_FEAT_* definition to check that. */
|
||||
return true;
|
||||
case RSL_CMOD_SPD_SPEECH:
|
||||
return bts_supports_cm_speech(bts, cm);
|
||||
case RSL_CMOD_SPD_DATA:
|
||||
return bts_supports_cm_data(bts, cm);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the gsm_lchan for the CBCH (if it exists at all) */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* BTS shutdown FSM */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/nm_common_fsm.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
@@ -60,7 +61,7 @@ static void st_none(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
switch(event) {
|
||||
case BTS_SHUTDOWN_EV_START:
|
||||
/* Firt announce to NM objects that we are starting a shutdown procedure: */
|
||||
osmo_fsm_inst_dispatch(bts->site_mgr.mo.fi, NM_EV_SHUTDOWN_START, NULL);
|
||||
osmo_fsm_inst_dispatch(bts->site_mgr->mo.fi, NM_EV_SHUTDOWN_START, NULL);
|
||||
|
||||
count = count_trx_operational(bts);
|
||||
if (count) {
|
||||
@@ -164,7 +165,7 @@ static void st_exit_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
|
||||
|
||||
osmo_fsm_inst_dispatch(bts->site_mgr.mo.fi, NM_EV_SHUTDOWN_FINISH, NULL);
|
||||
osmo_fsm_inst_dispatch(bts->site_mgr->mo.fi, NM_EV_SHUTDOWN_FINISH, NULL);
|
||||
|
||||
if (bts->shutdown_fi_exit_proc) {
|
||||
LOGPFSML(fi, LOGL_NOTICE, "Shutdown process completed successfully, exiting process\n");
|
||||
|
||||
95
src/common/bts_sm.c
Normal file
95
src/common/bts_sm.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/* BTS support code common to all supported BTS models */
|
||||
|
||||
/* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU 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/talloc.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/nm_common_fsm.h>
|
||||
|
||||
struct gsm_bts_sm *g_bts_sm;
|
||||
|
||||
static const uint8_t nse_timer_default[] = { 3, 3, 3, 3, 30, 3, 10 };
|
||||
|
||||
struct gsm_bts *gsm_gprs_nse_get_bts(const struct gsm_gprs_nse *nse)
|
||||
{
|
||||
return gsm_bts_num(g_bts_sm, nse->mo.obj_inst.bts_nr);
|
||||
}
|
||||
|
||||
static int gsm_bts_sm_talloc_destructor(struct gsm_bts_sm *bts_sm)
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
|
||||
while ((bts = llist_first_entry_or_null(&bts_sm->bts_list, struct gsm_bts, list)))
|
||||
talloc_free(bts);
|
||||
|
||||
if (bts_sm->mo.fi) {
|
||||
osmo_fsm_inst_free(bts_sm->mo.fi);
|
||||
bts_sm->mo.fi = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gsm_bts_sm *gsm_bts_sm_alloc(void *talloc_ctx)
|
||||
{
|
||||
struct gsm_bts_sm *bts_sm = talloc_zero(talloc_ctx, struct gsm_bts_sm);
|
||||
struct gsm_gprs_nse *nse = &bts_sm->gprs.nse;
|
||||
unsigned int i;
|
||||
|
||||
if (!bts_sm)
|
||||
return NULL;
|
||||
|
||||
talloc_set_destructor(bts_sm, gsm_bts_sm_talloc_destructor);
|
||||
|
||||
INIT_LLIST_HEAD(&bts_sm->bts_list);
|
||||
|
||||
/* NM SITE_MGR */
|
||||
bts_sm->mo.fi = osmo_fsm_inst_alloc(&nm_bts_sm_fsm, bts_sm, bts_sm,
|
||||
LOGL_INFO, "bts_sm");
|
||||
gsm_mo_init(&bts_sm->mo, NULL, NM_OC_SITE_MANAGER,
|
||||
0xff, 0xff, 0xff);
|
||||
oml_mo_state_init(&bts_sm->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
|
||||
/* NM GPRS NSE */
|
||||
nse->mo.fi = osmo_fsm_inst_alloc(&nm_gprs_nse_fsm, bts_sm, nse,
|
||||
LOGL_INFO, "gprs_nse0");
|
||||
gsm_mo_init(&nse->mo, NULL, NM_OC_GPRS_NSE, 0, 0xff, 0xff);
|
||||
oml_mo_state_init(&nse->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
memcpy(&nse->timer, nse_timer_default, sizeof(nse->timer));
|
||||
|
||||
/* NM GPRS NSVCs */
|
||||
for (i = 0; i < ARRAY_SIZE(nse->nsvc); i++) {
|
||||
struct gsm_gprs_nsvc *nsvc = &nse->nsvc[i];
|
||||
nsvc->nse = nse;
|
||||
nsvc->id = i;
|
||||
nsvc->mo.fi = osmo_fsm_inst_alloc(&nm_gprs_nsvc_fsm, bts_sm, nsvc,
|
||||
LOGL_INFO, NULL);
|
||||
osmo_fsm_inst_update_id_f(nsvc->mo.fi, "gprs_nsvc%d-%d",
|
||||
nse->mo.obj_inst.bts_nr, i);
|
||||
gsm_mo_init(&nsvc->mo, NULL, NM_OC_GPRS_NSVC, nse->mo.obj_inst.bts_nr, i, 0xff);
|
||||
oml_mo_state_init(&nsvc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
}
|
||||
|
||||
return bts_sm;
|
||||
}
|
||||
@@ -74,12 +74,17 @@ static void gsm_bts_trx_init_ts(struct gsm_bts_trx *trx)
|
||||
ts->trx = trx;
|
||||
ts->nr = tn;
|
||||
|
||||
ts->tsc_oml_configured = false;
|
||||
ts->tsc_rsl_configured = false;
|
||||
ts->tsc = ts->tsc_oml = ts->tsc_rsl = 0xff;
|
||||
|
||||
ts->mo.fi = osmo_fsm_inst_alloc(&nm_chan_fsm, trx, ts,
|
||||
LOGL_INFO, NULL);
|
||||
osmo_fsm_inst_update_id_f(ts->mo.fi, "%s-ts%u",
|
||||
trx->bb_transc.mo.fi->id, ts->nr);
|
||||
gsm_mo_init(&ts->mo, trx->bts, NM_OC_CHANNEL,
|
||||
trx->bts->nr, trx->nr, ts->nr);
|
||||
oml_mo_state_init(&ts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
|
||||
gsm_bts_trx_ts_init_lchan(ts);
|
||||
}
|
||||
@@ -99,6 +104,10 @@ void gsm_bts_trx_init_shadow_ts(struct gsm_bts_trx *trx)
|
||||
ts->trx = trx;
|
||||
ts->nr = tn;
|
||||
|
||||
ts->tsc_oml_configured = false;
|
||||
ts->tsc_rsl_configured = false;
|
||||
ts->tsc = ts->tsc_oml = ts->tsc_rsl = 0xff;
|
||||
|
||||
/* Link both primary and shadow */
|
||||
trx->ts[tn].vamos.peer = ts;
|
||||
ts->vamos.peer = &trx->ts[tn];
|
||||
@@ -148,14 +157,14 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
|
||||
trx->mo.fi = osmo_fsm_inst_alloc(&nm_rcarrier_fsm, trx, trx,
|
||||
LOGL_INFO, NULL);
|
||||
osmo_fsm_inst_update_id_f(trx->mo.fi, "bts%d-trx%d", bts->nr, trx->nr);
|
||||
gsm_mo_init(&trx->mo, bts, NM_OC_RADIO_CARRIER,
|
||||
bts->nr, trx->nr, 0xff);
|
||||
gsm_mo_init(&trx->mo, bts, NM_OC_RADIO_CARRIER, bts->nr, trx->nr, 0xff);
|
||||
oml_mo_state_init(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
|
||||
trx->bb_transc.mo.fi = osmo_fsm_inst_alloc(&nm_bb_transc_fsm, trx, &trx->bb_transc,
|
||||
LOGL_INFO, NULL);
|
||||
osmo_fsm_inst_update_id_f(trx->bb_transc.mo.fi, "bts%d-trx%d", bts->nr, trx->nr);
|
||||
gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC,
|
||||
bts->nr, trx->nr, 0xff);
|
||||
gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC, bts->nr, trx->nr, 0xff);
|
||||
oml_mo_state_init(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
|
||||
|
||||
gsm_bts_trx_init_ts(trx);
|
||||
|
||||
|
||||
188
src/common/csd_v110.c
Normal file
188
src/common/csd_v110.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Vadim Yanitskiy <vyanitskiy@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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gsm/gsm44021.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
#include <osmocom/isdn/v110.h>
|
||||
|
||||
#include <osmo-bts/csd_v110.h>
|
||||
#include <osmo-bts/lchan.h>
|
||||
|
||||
/* key is enum gsm48_chan_mode, so assuming a value in range 0..255 */
|
||||
const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = {
|
||||
#if 0
|
||||
[GSM48_CMODE_DATA_14k5] = {
|
||||
/* TCH/F14.4: 290 bits every 20 ms (14.5 kbit/s) */
|
||||
.fr = { .num_blocks = 1, .num_bits = 290 },
|
||||
},
|
||||
#endif
|
||||
[GSM48_CMODE_DATA_12k0] = {
|
||||
/* TCH/F9.6: 4 * 60 bits every 20 ms (12.0 kbit/s) */
|
||||
.fr = { .num_blocks = 4, .num_bits = 60 },
|
||||
},
|
||||
[GSM48_CMODE_DATA_6k0] = {
|
||||
/* TCH/F4.8: 2 * 60 bits every 20 ms (6.0 kbit/s) */
|
||||
.fr = { .num_blocks = 2, .num_bits = 60 },
|
||||
/* TCH/H4.8: 4 * 60 bits every 40 ms (6.0 kbit/s) */
|
||||
.hr = { .num_blocks = 4, .num_bits = 60 },
|
||||
},
|
||||
[GSM48_CMODE_DATA_3k6] = {
|
||||
/* TCH/F2.4: 2 * 36 bits every 20 ms (3.6 kbit/s) */
|
||||
.fr = { .num_blocks = 2, .num_bits = 36 },
|
||||
/* TCH/H2.4: 4 * 36 bits every 40 ms (3.6 kbit/s) */
|
||||
.hr = { .num_blocks = 4, .num_bits = 36 },
|
||||
},
|
||||
};
|
||||
|
||||
/* 3GPP TS 44.021, Figure 4: Coding of data rates (E1/E2/E3 bits) */
|
||||
static const uint8_t e1e2e3_map[_LCHAN_CSD_M_NUM][3] = {
|
||||
[LCHAN_CSD_M_T_600] = { 1, 0, 0 },
|
||||
[LCHAN_CSD_M_T_1200] = { 0, 1, 0 },
|
||||
[LCHAN_CSD_M_T_2400] = { 1, 1, 0 },
|
||||
[LCHAN_CSD_M_T_4800] = { 0, 1, 1 },
|
||||
[LCHAN_CSD_M_T_9600] = { 0, 1, 1 },
|
||||
#if 0
|
||||
[LCHAN_CSD_M_T_19200] = { 0, 1, 1 },
|
||||
[LCHAN_CSD_M_T_38400] = { 0, 1, 1 },
|
||||
[LCHAN_CSD_M_T_14400] = { 1, 0, 1 },
|
||||
[LCHAN_CSD_M_T_28800] = { 1, 0, 1 },
|
||||
#endif
|
||||
};
|
||||
|
||||
int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp,
|
||||
const uint8_t *data, size_t data_len)
|
||||
{
|
||||
const struct csd_v110_frame_desc *desc;
|
||||
ubit_t ra_bits[80 * 4];
|
||||
|
||||
OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc));
|
||||
if (lchan->type == GSM_LCHAN_TCH_F)
|
||||
desc = &csd_v110_lchan_desc[lchan->tch_mode].fr;
|
||||
else
|
||||
desc = &csd_v110_lchan_desc[lchan->tch_mode].hr;
|
||||
if (OSMO_UNLIKELY(desc->num_blocks == 0))
|
||||
return -ENOTSUP;
|
||||
|
||||
/* handle empty/incomplete Uplink frames gracefully */
|
||||
if (OSMO_UNLIKELY(data_len < (desc->num_blocks * desc->num_bits))) {
|
||||
/* encode N idle frames as per 3GPP TS 44.021, section 8.1.6 */
|
||||
memset(&ra_bits[0], 0x01, sizeof(ra_bits));
|
||||
for (unsigned int i = 0; i < desc->num_blocks; i++)
|
||||
memset(&ra_bits[i * 80], 0x00, 8); /* alignment pattern */
|
||||
goto ra1_ra2;
|
||||
}
|
||||
|
||||
/* RA1'/RA1: convert from radio rate to an intermediate data rate */
|
||||
for (unsigned int i = 0; i < desc->num_blocks; i++) {
|
||||
struct osmo_v110_decoded_frame df;
|
||||
|
||||
/* convert a V.110 36-/60-bit frame to a V.110 80-bit frame */
|
||||
if (desc->num_bits == 60)
|
||||
osmo_csd_12k_6k_decode_frame(&df, &data[i * 60], 60);
|
||||
else /* desc->num_bits == 36 */
|
||||
osmo_csd_3k6_decode_frame(&df, &data[i * 36], 36);
|
||||
|
||||
/* E1 .. E3 must set by out-of-band knowledge */
|
||||
if (lchan->csd_mode == LCHAN_CSD_M_NT) {
|
||||
/* non-transparent: as per 3GPP TS 48.020, Table 7 */
|
||||
df.e_bits[0] = 0; /* E1: as per 15.1.2, shall be set to 0 (for BSS-MSC) */
|
||||
df.e_bits[1] = (i >> 1) & 0x01; /* E2: 0 for Q1/Q2, 1 for Q3/Q4 */
|
||||
df.e_bits[2] = (i >> 0) & 0x01; /* E3: 0 for Q1/Q3, 1 for Q2/Q4 */
|
||||
} else {
|
||||
/* transparent: as per 3GPP TS 44.021, Figure 4 */
|
||||
df.e_bits[0] = e1e2e3_map[lchan->csd_mode][0]; /* E1 */
|
||||
df.e_bits[1] = e1e2e3_map[lchan->csd_mode][1]; /* E2 */
|
||||
df.e_bits[2] = e1e2e3_map[lchan->csd_mode][2]; /* E3 */
|
||||
}
|
||||
|
||||
osmo_v110_encode_frame(&ra_bits[i * 80], 80, &df);
|
||||
}
|
||||
|
||||
ra1_ra2:
|
||||
/* RA1/RA2: convert from an intermediate rate to 64 kbit/s */
|
||||
if (desc->num_blocks == 4) {
|
||||
/* 4 * 80 bits (16 kbit/s) => 2 bits per octet */
|
||||
for (unsigned int i = 0, j = 0; i < RFC4040_RTP_PLEN; i++) {
|
||||
rtp[i] = (0xff >> 2);
|
||||
rtp[i] |= (ra_bits[j++] << 7);
|
||||
rtp[i] |= (ra_bits[j++] << 6);
|
||||
}
|
||||
} else {
|
||||
/* 2 * 80 bits (8 kbit/s) => 1 bit per octet */
|
||||
for (unsigned int i = 0; i < RFC4040_RTP_PLEN; i++) {
|
||||
rtp[i] = (0xff >> 1);
|
||||
rtp[i] |= (ra_bits[i] << 7);
|
||||
}
|
||||
}
|
||||
|
||||
return RFC4040_RTP_PLEN;
|
||||
}
|
||||
|
||||
int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data,
|
||||
const uint8_t *rtp, size_t rtp_len)
|
||||
{
|
||||
const struct csd_v110_frame_desc *desc;
|
||||
ubit_t ra_bits[80 * 4];
|
||||
|
||||
OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc));
|
||||
if (lchan->type == GSM_LCHAN_TCH_F)
|
||||
desc = &csd_v110_lchan_desc[lchan->tch_mode].fr;
|
||||
else
|
||||
desc = &csd_v110_lchan_desc[lchan->tch_mode].hr;
|
||||
if (OSMO_UNLIKELY(desc->num_blocks == 0))
|
||||
return -ENOTSUP;
|
||||
|
||||
if (OSMO_UNLIKELY(rtp_len != RFC4040_RTP_PLEN))
|
||||
return -EINVAL;
|
||||
|
||||
/* RA1/RA2: convert from 64 kbit/s to an intermediate rate */
|
||||
if (desc->num_blocks == 4) {
|
||||
/* 4 * 80 bits (16 kbit/s) => 2 bits per octet */
|
||||
for (unsigned int i = 0, j = 0; i < RFC4040_RTP_PLEN; i++) {
|
||||
ra_bits[j++] = (rtp[i] >> 7);
|
||||
ra_bits[j++] = (rtp[i] >> 6) & 0x01;
|
||||
}
|
||||
} else {
|
||||
/* 2 * 80 bits (8 kbit/s) => 1 bit per octet */
|
||||
for (unsigned int i = 0; i < RFC4040_RTP_PLEN; i++)
|
||||
ra_bits[i] = (rtp[i] >> 7);
|
||||
}
|
||||
|
||||
/* RA1'/RA1: convert from an intermediate rate to radio rate */
|
||||
for (unsigned int i = 0; i < desc->num_blocks; i++) {
|
||||
struct osmo_v110_decoded_frame df;
|
||||
|
||||
/* convert a V.110 80-bit frame to a V.110 36-/60-bit frame */
|
||||
osmo_v110_decode_frame(&df, &ra_bits[i * 80], 80);
|
||||
if (desc->num_bits == 60)
|
||||
osmo_csd_12k_6k_encode_frame(&data[i * 60], 60, &df);
|
||||
else /* desc->num_bits == 36 */
|
||||
osmo_csd_3k6_encode_frame(&data[i * 36], 36, &df);
|
||||
}
|
||||
|
||||
return desc->num_blocks * desc->num_bits;
|
||||
}
|
||||
@@ -306,6 +306,29 @@ bool ts_is_pdch(const struct gsm_bts_trx_ts *ts)
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply ts->tsc based on what was configured coming from different sources.
|
||||
* Priorities (preferred first, overrides ones afterward):
|
||||
* 1- RSL OSMO_TSC IE
|
||||
* 2- OML SetChannelAttr TSC IE
|
||||
* 3- OML SetBtsAttr BSIC IE
|
||||
*/
|
||||
void gsm_ts_apply_configured_tsc(struct gsm_bts_trx_ts *ts)
|
||||
{
|
||||
if (ts->tsc_rsl_configured) {
|
||||
ts->tsc = ts->tsc_rsl;
|
||||
return;
|
||||
}
|
||||
if (ts->tsc_oml_configured) {
|
||||
ts->tsc = ts->tsc_oml;
|
||||
return;
|
||||
}
|
||||
if (ts->trx->bts->bsic_configured) {
|
||||
ts->tsc = BTS_TSC(ts->trx->bts);
|
||||
return;
|
||||
}
|
||||
ts->tsc = 0xff; /* invalid value */
|
||||
}
|
||||
|
||||
void gsm_ts_release(struct gsm_bts_trx_ts *ts)
|
||||
{
|
||||
unsigned int ln;
|
||||
@@ -318,4 +341,8 @@ void gsm_ts_release(struct gsm_bts_trx_ts *ts)
|
||||
/* Make sure pchan_is is reset, since PCU act_req to release it will be
|
||||
* ignored as the lchan will already be released. */
|
||||
ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE;
|
||||
|
||||
ts->tsc_oml_configured = false;
|
||||
ts->tsc_rsl_configured = false;
|
||||
ts->tsc = ts->tsc_oml = ts->tsc_rsl = 0xff;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@
|
||||
#include <osmo-bts/handover.h>
|
||||
#include <osmo-bts/l1sap.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/asci.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const struct value_string lchan_s_names[] = {
|
||||
@@ -56,41 +57,40 @@ const struct value_string lchan_ciph_state_names[] = {
|
||||
};
|
||||
|
||||
/* prepare the per-SAPI T200 arrays for a given lchan */
|
||||
static int t200_by_lchan(int *t200_ms_dcch, int *t200_ms_acch, struct gsm_lchan *lchan)
|
||||
static int t200_by_lchan(uint32_t *t200_fn_dcch, uint32_t *t200_fn_acch, struct gsm_lchan *lchan)
|
||||
{
|
||||
struct gsm_bts *bts = lchan->ts->trx->bts;
|
||||
|
||||
/* we have to compensate for the "RTS advance" due to the asynchronous interface between
|
||||
* the BTS (LAPDm) and the PHY/L1 (OsmoTRX or DSP in case of osmo-bts-{sysmo,lc15,oc2g,octphy} */
|
||||
int32_t fn_advance = bts_get_avg_fn_advance(bts);
|
||||
int32_t fn_advance_us = fn_advance * 4615;
|
||||
int fn_advance_ms = fn_advance_us / 1000;
|
||||
|
||||
t200_ms_acch[DL_SAPI0] = bts->t200_ms[T200_SACCH_SDCCH] + fn_advance_ms;
|
||||
t200_ms_acch[DL_SAPI3] = bts->t200_ms[T200_SACCH_SDCCH] + fn_advance_ms;
|
||||
|
||||
if (lchan->rep_acch_cap.dl_facch_all && lchan_is_tch(lchan)) {
|
||||
t200_ms_acch[DL_SAPI0] *= 2;
|
||||
t200_ms_acch[DL_SAPI3] *= 2;
|
||||
}
|
||||
|
||||
switch (lchan->type) {
|
||||
case GSM_LCHAN_SDCCH:
|
||||
t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_SDCCH] + fn_advance_ms;
|
||||
t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_SDCCH_SAPI3] + fn_advance_ms;
|
||||
t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_SDCCH];
|
||||
t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_SDCCH_SAPI3];
|
||||
t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_SDCCH];
|
||||
t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_SDCCH];
|
||||
break;
|
||||
case GSM_LCHAN_TCH_F:
|
||||
t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_FACCH_F] + fn_advance_ms;
|
||||
t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_FACCH_F] + fn_advance_ms;
|
||||
t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_FACCH_F];
|
||||
t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_FACCH_F];
|
||||
t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_TCH_SAPI0];
|
||||
t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_TCH_SAPI3];
|
||||
break;
|
||||
case GSM_LCHAN_TCH_H:
|
||||
t200_ms_dcch[DL_SAPI0] = bts->t200_ms[T200_FACCH_H] + fn_advance_ms;
|
||||
t200_ms_dcch[DL_SAPI3] = bts->t200_ms[T200_FACCH_H] + fn_advance_ms;
|
||||
t200_fn_dcch[DL_SAPI0] = bts->t200_fn[T200_FACCH_H];
|
||||
t200_fn_dcch[DL_SAPI3] = bts->t200_fn[T200_FACCH_H];
|
||||
t200_fn_acch[DL_SAPI0] = bts->t200_fn[T200_SACCH_TCH_SAPI0];
|
||||
t200_fn_acch[DL_SAPI3] = bts->t200_fn[T200_SACCH_TCH_SAPI3];
|
||||
break;
|
||||
default:
|
||||
/* Channels such as CCCH don't use lapdm DL, and hence no T200 is needed */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add time of two extra messages frames. */
|
||||
if (lchan->rep_acch_cap.dl_facch_all && lchan_is_tch(lchan)) {
|
||||
t200_fn_acch[DL_SAPI0] += 104 * 2;
|
||||
t200_fn_acch[DL_SAPI3] += 104 * 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -151,17 +151,17 @@ void gsm_lchan_name_update(struct gsm_lchan *lchan)
|
||||
int lchan_init_lapdm(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct lapdm_channel *lc = &lchan->lapdm_ch;
|
||||
int t200_ms_dcch[_NR_DL_SAPI], t200_ms_acch[_NR_DL_SAPI];
|
||||
uint32_t t200_fn_dcch[_NR_DL_SAPI], t200_fn_acch[_NR_DL_SAPI];
|
||||
|
||||
if (t200_by_lchan(t200_ms_dcch, t200_ms_acch, lchan) == 0) {
|
||||
if (t200_by_lchan(t200_fn_dcch, t200_fn_acch, lchan) == 0) {
|
||||
LOGPLCHAN(lchan, DLLAPD, LOGL_DEBUG,
|
||||
"Setting T200 D0=%u, D3=%u, S0=%u, S3=%u (all in ms)\n",
|
||||
t200_ms_dcch[DL_SAPI0], t200_ms_dcch[DL_SAPI3],
|
||||
t200_ms_acch[DL_SAPI0], t200_ms_acch[DL_SAPI3]);
|
||||
lapdm_channel_init3(lc, LAPDM_MODE_BTS, t200_ms_dcch, t200_ms_acch, lchan->type,
|
||||
gsm_lchan_name(lchan));
|
||||
lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY);
|
||||
"Setting T200 D0=%u, D3=%u, S0=%u, S3=%u (all in frames)\n",
|
||||
t200_fn_dcch[DL_SAPI0], t200_fn_dcch[DL_SAPI3],
|
||||
t200_fn_acch[DL_SAPI0], t200_fn_acch[DL_SAPI3]);
|
||||
lapdm_channel_init3(lc, LAPDM_MODE_BTS, NULL, NULL, lchan->type, gsm_lchan_name(lchan));
|
||||
lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY | LAPDM_ENT_F_RTS);
|
||||
lapdm_channel_set_l1(lc, NULL, lchan);
|
||||
lapdm_channel_set_t200_fn(lc, t200_fn_dcch, t200_fn_acch);
|
||||
}
|
||||
/* We still need to set Rx callback to receive RACH requests: */
|
||||
lapdm_channel_set_l3(lc, lapdm_rll_tx_cb, lchan);
|
||||
@@ -216,8 +216,11 @@ void gsm_lchan_release(struct gsm_lchan *lchan, enum lchan_rel_act_kind rel_kind
|
||||
if (lchan->state == LCHAN_S_NONE)
|
||||
return;
|
||||
|
||||
/* release handover state */
|
||||
/* release handover, listener and talker states */
|
||||
handover_reset(lchan);
|
||||
vgcs_talker_reset(lchan, false);
|
||||
vgcs_listener_reset(lchan);
|
||||
vgcs_uplink_free_reset(lchan);
|
||||
|
||||
lchan->rel_act_kind = rel_kind;
|
||||
|
||||
|
||||
@@ -125,6 +125,13 @@ static struct log_info_cat bts_log_info_cat[] = {
|
||||
.loglevel = LOGL_NOTICE,
|
||||
.enabled = 1,
|
||||
},
|
||||
[DASCI] = {
|
||||
.name = "DASCI",
|
||||
.description = "ASCI (Advanced Speech Call Items: VGCS/VBS)",
|
||||
.loglevel = LOGL_NOTICE,
|
||||
.enabled = 1,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static int osmo_bts_filter_fn(const struct log_context *ctx, struct log_target *tgt)
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/abis.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/vty.h>
|
||||
#include <osmo-bts/l1sap.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
@@ -292,7 +293,13 @@ int bts_main(int argc, char **argv)
|
||||
if (vty_test_mode)
|
||||
fprintf(stderr, "--- VTY test mode: not connecting to BSC, not exiting ---\n");
|
||||
|
||||
g_bts = gsm_bts_alloc(tall_bts_ctx, 0);
|
||||
g_bts_sm = gsm_bts_sm_alloc(tall_bts_ctx);
|
||||
if (!g_bts_sm) {
|
||||
fprintf(stderr, "Failed to create BTS Site Manager structure\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g_bts = gsm_bts_alloc(g_bts_sm, 0);
|
||||
if (!g_bts) {
|
||||
fprintf(stderr, "Failed to create BTS structure\n");
|
||||
exit(1);
|
||||
@@ -373,7 +380,7 @@ int bts_main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pcu_sock_init(g_bts->pcu.sock_path)) {
|
||||
if (pcu_sock_init(g_bts->pcu.sock_path, g_bts->pcu.sock_wqueue_len_max)) {
|
||||
fprintf(stderr, "PCU L1 socket failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
/* Active TDMA frame subset for TCH/H in DTX mode (see 3GPP TS 45.008 Section 8.3).
|
||||
* This mapping is used to determine if a L2 block starting at the given TDMA FN
|
||||
* belongs to the SUB set and thus shall always be transmitted in DTX mode. */
|
||||
static const uint8_t ts45008_dtx_tchh_fn_map[104] = {
|
||||
static const uint8_t ts45008_dtx_tchh_speech_fn_map[104] = {
|
||||
/* TCH/H(0): 0, 2, 4, 6, 52, 54, 56, 58 */
|
||||
[0] = 1, /* block { 0, 2, 4, 6} */
|
||||
[52] = 1, /* block {52, 54, 56, 58} */
|
||||
@@ -28,6 +28,15 @@ static const uint8_t ts45008_dtx_tchh_fn_map[104] = {
|
||||
[66] = 1, /* block {66, 68, 70, 72} */
|
||||
};
|
||||
|
||||
static const uint8_t ts45008_dtx_tchh_data_fn_map[104] = {
|
||||
/* UL TCH/H(0): 52, 54, 56, 58, 60, 62, 65, 67, 69, 71 */
|
||||
[52] = 1, /* block {52, 54, 56, 58, 60, 62} */
|
||||
[60] = 1, /* block {60, 62, 65, 67, 69, 71} */
|
||||
/* UL TCH/H(1): 70, 72, 74, 76, 79, 81, 83, 85, 87, 89 */
|
||||
[70] = 1, /* block {70, 72, 74, 76, 79, 81} */
|
||||
[79] = 1, /* block {79, 81, 83, 85, 87, 89} */
|
||||
};
|
||||
|
||||
/* In cases where we less measurements than we expect we must assume that we
|
||||
* just did not receive the block because it was lost due to bad channel
|
||||
* conditions. We set up a dummy measurement result here that reflects the
|
||||
@@ -50,7 +59,7 @@ bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn)
|
||||
uint32_t fn104 = fn % 104;
|
||||
|
||||
/* See TS 45.008 Sections 8.3 and 8.4 for a detailed descriptions of the rules
|
||||
* implemented here. We only implement the logic for Voice, not CSD */
|
||||
* implemented here. We implement the logic for both speech and data (CSD). */
|
||||
|
||||
/* AMR is special, SID frames may be scheduled dynamically at any time */
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
@@ -59,8 +68,11 @@ bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn)
|
||||
switch (lchan->type) {
|
||||
case GSM_LCHAN_TCH_F:
|
||||
switch (lchan->tch_mode) {
|
||||
case GSM48_CMODE_SIGN: /* TCH/F sign: DTX *is* permitted */
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
case GSM48_CMODE_SPEECH_V1_VAMOS:
|
||||
case GSM48_CMODE_SPEECH_EFR:
|
||||
case GSM48_CMODE_SPEECH_V2_VAMOS:
|
||||
/* Active TDMA frame subset for TCH/F: 52, 53, 54, 55, 56, 57, 58, 59.
|
||||
* There is only one *complete* block in this subset starting at FN=52.
|
||||
* Incomplete blocks {... 52, 53, 54, 55} and {56, 57, 58, 59 ...}
|
||||
@@ -68,29 +80,38 @@ bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn)
|
||||
if (fn104 == 52)
|
||||
return true;
|
||||
break;
|
||||
case GSM48_CMODE_SIGN:
|
||||
/* No DTX allowed; SUB=FULL, therefore measurements at all frame numbers are
|
||||
* SUB */
|
||||
return true;
|
||||
case GSM48_CMODE_DATA_12k0: /* TCH/F9.6 */
|
||||
case GSM48_CMODE_DATA_6k0: /* TCH/F4.8 */
|
||||
/* FIXME: The RXQUAL_SUB (not RXLEV!) report shall include measurements on
|
||||
* the TDMA frames given in the table of subclause 8.3 only if L2 fill frames
|
||||
* have been received as FACCH/F frames at the corresponding frame positions. */
|
||||
default:
|
||||
LOGPFN(DMEAS, LOGL_ERROR, fn, "%s: Unsupported lchan->tch_mode %u\n",
|
||||
gsm_lchan_name(lchan), lchan->tch_mode);
|
||||
if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA)
|
||||
return fn104 == 52;
|
||||
LOGPLCFN(lchan, fn, DMEAS, LOGL_ERROR, "Unsupported lchan->tch_mode %u\n", lchan->tch_mode);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GSM_LCHAN_TCH_H:
|
||||
switch (lchan->tch_mode) {
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
if (ts45008_dtx_tchh_fn_map[fn104])
|
||||
case GSM48_CMODE_SPEECH_V1_VAMOS:
|
||||
if (ts45008_dtx_tchh_speech_fn_map[fn104])
|
||||
return true;
|
||||
break;
|
||||
case GSM48_CMODE_SIGN:
|
||||
/* No DTX allowed; SUB=FULL, therefore measurements at all frame numbers are
|
||||
* SUB */
|
||||
return true;
|
||||
case GSM48_CMODE_DATA_6k0: /* TCH/H4.8 */
|
||||
case GSM48_CMODE_DATA_3k6: /* TCH/H2.4 */
|
||||
/* FIXME: The RXQUAL_SUB (not RXLEV!) report shall include measurements on
|
||||
* the TDMA frames given in the table of subclause 8.3 only if L2 fill frames
|
||||
* have been received as FACCH/H frames at the corresponding frame positions. */
|
||||
default:
|
||||
LOGPFN(DMEAS, LOGL_ERROR, fn, "%s: Unsupported lchan->tch_mode %u\n",
|
||||
gsm_lchan_name(lchan), lchan->tch_mode);
|
||||
if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA)
|
||||
return ts45008_dtx_tchh_data_fn_map[fn104] == 1;
|
||||
LOGPLCFN(lchan, fn, DMEAS, LOGL_ERROR, "Unsupported lchan->tch_mode %u\n", lchan->tch_mode);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -269,9 +290,8 @@ int is_meas_complete(struct gsm_lchan *lchan, uint32_t fn)
|
||||
}
|
||||
|
||||
if (rc == 1) {
|
||||
DEBUGP(DMEAS,
|
||||
"%s meas period end fn:%u, fn_mod:%i, status:%d, pchan:%s\n",
|
||||
gsm_lchan_name(lchan), fn, fn_mod, rc, gsm_pchan_name(pchan));
|
||||
LOGPLCFN(lchan, fn, DMEAS, LOGL_DEBUG, "meas period end fn_mod:%d, status:%d, pchan:%s\n", fn_mod,
|
||||
rc, gsm_pchan_name(pchan));
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -307,16 +327,15 @@ int lchan_new_ul_meas(struct gsm_lchan *lchan,
|
||||
struct bts_ul_meas *dest;
|
||||
|
||||
if (lchan->state != LCHAN_S_ACTIVE) {
|
||||
LOGPFN(DMEAS, LOGL_NOTICE, fn,
|
||||
"%s measurement during state: %s, num_ul_meas=%d, fn_mod=%u\n",
|
||||
gsm_lchan_name(lchan), gsm_lchans_name(lchan->state),
|
||||
lchan->meas.num_ul_meas, fn_mod);
|
||||
LOGPLCFN(lchan, fn, DMEAS, LOGL_NOTICE,
|
||||
"measurement during state: %s, num_ul_meas=%d, fn_mod=%u\n",
|
||||
gsm_lchans_name(lchan->state), lchan->meas.num_ul_meas, fn_mod);
|
||||
}
|
||||
|
||||
if (lchan->meas.num_ul_meas >= ARRAY_SIZE(lchan->meas.uplink)) {
|
||||
LOGPFN(DMEAS, LOGL_NOTICE, fn,
|
||||
"%s no space for uplink measurement, num_ul_meas=%d, fn_mod=%u\n",
|
||||
gsm_lchan_name(lchan), lchan->meas.num_ul_meas, fn_mod);
|
||||
LOGPLCFN(lchan, fn, DMEAS, LOGL_NOTICE,
|
||||
"no space for uplink measurement, num_ul_meas=%d, fn_mod=%u\n", lchan->meas.num_ul_meas,
|
||||
fn_mod);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
@@ -328,10 +347,9 @@ int lchan_new_ul_meas(struct gsm_lchan *lchan,
|
||||
if (!ulm->is_sub)
|
||||
dest->is_sub = ts45008_83_is_sub(lchan, fn);
|
||||
|
||||
DEBUGPFN(DMEAS, fn, "%s adding a %s measurement (ber10k=%u, ta_offs=%d, ci_cB=%d, rssi=-%u), num_ul_meas=%d, fn_mod=%u\n",
|
||||
gsm_lchan_name(lchan),
|
||||
dest->is_sub ? "SUB" : "FULL",
|
||||
ulm->ber10k, ulm->ta_offs_256bits, ulm->ci_cb, ulm->inv_rssi,
|
||||
LOGPLCFN(lchan, fn, DMEAS, LOGL_DEBUG,
|
||||
"adding a %s measurement (ber10k=%u, ta_offs=%d, ci_cB=%d, rssi=-%u), num_ul_meas=%d, fn_mod=%u\n",
|
||||
dest->is_sub ? "SUB" : "FULL", ulm->ber10k, ulm->ta_offs_256bits, ulm->ci_cb, ulm->inv_rssi,
|
||||
lchan->meas.num_ul_meas, fn_mod);
|
||||
|
||||
lchan->meas.last_fn = fn;
|
||||
@@ -406,32 +424,50 @@ static unsigned int lchan_meas_num_expected(const struct gsm_lchan *lchan)
|
||||
}
|
||||
|
||||
/* In DTX a subset of blocks must always be transmitted
|
||||
* See also: GSM 05.08, chapter 8.3 Aspects of discontinuous transmission (DTX) */
|
||||
static unsigned int lchan_meas_sub_num_expected(const struct gsm_lchan *lchan)
|
||||
* See also: GSM 05.08, chapter 8.3 Aspects of discontinuous transmission (DTX)
|
||||
* Return value N: (N < 0) -- at least N SUB frames expected;
|
||||
* (N > 0) -- exactly N SUB frames expected;
|
||||
* (N == 0) - unknown channel type/mode? */
|
||||
static int lchan_meas_sub_num_expected(const struct gsm_lchan *lchan)
|
||||
{
|
||||
enum gsm_phys_chan_config pchan = ts_pchan(lchan->ts);
|
||||
|
||||
/* AMR is using a more elaborated model with a dymanic amount of
|
||||
* DTX blocks so this function is not applicable to determine the
|
||||
* amount of expected SUB Measurements when AMR is used */
|
||||
OSMO_ASSERT(lchan->tch_mode != GSM48_CMODE_SPEECH_AMR);
|
||||
|
||||
switch (pchan) {
|
||||
case GSM_PCHAN_TCH_F:
|
||||
if (lchan->tch_mode == GSM48_CMODE_SIGN) {
|
||||
/* 1 block SACCH, 24 blocks TCH (see note 1) */
|
||||
return 25;
|
||||
} else {
|
||||
/* 1 block SACCH, 1 block TCH */
|
||||
return 2;
|
||||
if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA)
|
||||
return 1 + 1; /* 1 x SACCH + 1 x FACCH */
|
||||
/* else: signalling or speech */
|
||||
switch (lchan->tch_mode) {
|
||||
case GSM48_CMODE_SIGN: /* TCH/F sign: DTX *is* permitted */
|
||||
case GSM48_CMODE_SPEECH_V1: /* TCH/FS */
|
||||
case GSM48_CMODE_SPEECH_V1_VAMOS:
|
||||
case GSM48_CMODE_SPEECH_EFR: /* TCH/EFS */
|
||||
case GSM48_CMODE_SPEECH_V2_VAMOS:
|
||||
return 1 + 1; /* 1 x SACCH + 1 x TCH */
|
||||
case GSM48_CMODE_SPEECH_AMR: /* TCH/AFS */
|
||||
case GSM48_CMODE_SPEECH_V3_VAMOS:
|
||||
case GSM48_CMODE_SPEECH_V4: /* O-TCH/WFS */
|
||||
case GSM48_CMODE_SPEECH_V5: /* TCH/WFS */
|
||||
case GSM48_CMODE_SPEECH_V5_VAMOS:
|
||||
default:
|
||||
return -1; /* at least 1 x SACCH + M x TCH (variable) */
|
||||
}
|
||||
case GSM_PCHAN_TCH_H:
|
||||
if (lchan->tch_mode == GSM48_CMODE_SIGN) {
|
||||
/* 1 block SACCH, 12 blocks TCH (see ynote 1) */
|
||||
return 13;
|
||||
} else {
|
||||
/* 1 block SACCH, 2 blocks TCH */
|
||||
return 3;
|
||||
if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA)
|
||||
return 1 + 2; /* 1 x SACCH + 2 x FACCH */
|
||||
/* else: signalling or speech */
|
||||
switch (lchan->tch_mode) {
|
||||
case GSM48_CMODE_SIGN: /* TCH/H sign: DTX *is not* permitted */
|
||||
return 1 + 12; /* 1 x SACCH + 12 x TCH */
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
case GSM48_CMODE_SPEECH_V1_VAMOS:
|
||||
return 1 + 2; /* 1 x SACCH + 2 x TCH */
|
||||
case GSM48_CMODE_SPEECH_AMR: /* TCH/AHS */
|
||||
case GSM48_CMODE_SPEECH_V3_VAMOS:
|
||||
case GSM48_CMODE_SPEECH_V4: /* O-TCH/WHS */
|
||||
case GSM48_CMODE_SPEECH_V6: /* O-TCH/AHS */
|
||||
default:
|
||||
return -1; /* at least 1 x SACCH + M x TCH (variable) */
|
||||
}
|
||||
case GSM_PCHAN_SDCCH8_SACCH8C:
|
||||
case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
|
||||
@@ -444,8 +480,6 @@ static unsigned int lchan_meas_sub_num_expected(const struct gsm_lchan *lchan)
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note 1: In signalling mode all blocks count as SUB blocks. */
|
||||
}
|
||||
|
||||
/* if we clip the TOA value to 12 bits, i.e. toa256=3200,
|
||||
@@ -551,7 +585,7 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
|
||||
unsigned int num_meas_sub = 0;
|
||||
unsigned int num_meas_sub_actual = 0;
|
||||
unsigned int num_meas_sub_subst = 0;
|
||||
unsigned int num_meas_sub_expect;
|
||||
int num_meas_sub_expect;
|
||||
unsigned int num_ul_meas;
|
||||
unsigned int num_ul_meas_actual = 0;
|
||||
unsigned int num_ul_meas_subst = 0;
|
||||
@@ -571,16 +605,7 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
|
||||
* intentionally to save energy. It is not necessarly an error
|
||||
* when we get less measurements as we expect. */
|
||||
num_ul_meas_expect = lchan_meas_num_expected(lchan);
|
||||
|
||||
if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR)
|
||||
num_meas_sub_expect = lchan_meas_sub_num_expected(lchan);
|
||||
else {
|
||||
/* When AMR is used, we expect at least one SUB frame, since
|
||||
* the SACCH will always be SUB frame. There may occur more
|
||||
* SUB frames but since DTX periods in AMR are dynamic, we
|
||||
* can not know how many exactly. */
|
||||
num_meas_sub_expect = 1;
|
||||
}
|
||||
num_meas_sub_expect = lchan_meas_sub_num_expected(lchan);
|
||||
|
||||
if (lchan->meas.num_ul_meas > num_ul_meas_expect)
|
||||
num_ul_meas_excess = lchan->meas.num_ul_meas - num_ul_meas_expect;
|
||||
@@ -626,12 +651,9 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
|
||||
} else {
|
||||
m = &measurement_dummy;
|
||||
|
||||
/* For AMR the amount of SUB frames is defined by the
|
||||
* the occurrence of DTX periods, which are dynamically
|
||||
* negotiated in AMR, so we can not know if and how many
|
||||
* SUB frames are missing. */
|
||||
if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) {
|
||||
if (num_meas_sub <= i) {
|
||||
/* only if we know the exact number of SUB measurements */
|
||||
if (num_meas_sub_expect >= 0) {
|
||||
if (num_meas_sub < num_meas_sub_expect) {
|
||||
num_meas_sub_subst++;
|
||||
is_sub = true;
|
||||
}
|
||||
@@ -647,16 +669,6 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
|
||||
}
|
||||
}
|
||||
|
||||
if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) {
|
||||
LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
|
||||
"Received UL measurements contain %u SUB measurements, expected %u\n",
|
||||
num_meas_sub_actual, num_meas_sub_expect);
|
||||
} else {
|
||||
LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
|
||||
"Received UL measurements contain %u SUB measurements, expected at least %u\n",
|
||||
num_meas_sub_actual, num_meas_sub_expect);
|
||||
}
|
||||
|
||||
LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG, "Replaced %u measurements with dummy values, "
|
||||
"from which %u were SUB measurements\n", num_ul_meas_subst, num_meas_sub_subst);
|
||||
|
||||
@@ -667,17 +679,24 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
|
||||
* above only adds missing measurements during the calculation
|
||||
* it can not remove excess SUB measurements or add missing SUB
|
||||
* measurements when there is no more room in the interval. */
|
||||
if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) {
|
||||
if (num_meas_sub != num_meas_sub_expect) {
|
||||
if (num_meas_sub_expect < 0) {
|
||||
num_meas_sub_expect = -num_meas_sub_expect;
|
||||
LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
|
||||
"Received UL measurements contain %u SUB measurements, expected at least %d\n",
|
||||
num_meas_sub_actual, num_meas_sub_expect);
|
||||
if (OSMO_UNLIKELY(num_meas_sub < num_meas_sub_expect)) {
|
||||
LOGPLCHAN(lchan, DMEAS, LOGL_ERROR,
|
||||
"Incorrect number of SUB measurements detected! "
|
||||
"(%u vs exp %u)\n", num_meas_sub, num_meas_sub_expect);
|
||||
"(%u vs exp >=%d)\n", num_meas_sub, num_meas_sub_expect);
|
||||
}
|
||||
} else {
|
||||
if (num_meas_sub < num_meas_sub_expect) {
|
||||
LOGPLCHAN(lchan, DMEAS, LOGL_DEBUG,
|
||||
"Received UL measurements contain %u SUB measurements, expected %d\n",
|
||||
num_meas_sub_actual, num_meas_sub_expect);
|
||||
if (OSMO_UNLIKELY(num_meas_sub != num_meas_sub_expect)) {
|
||||
LOGPLCHAN(lchan, DMEAS, LOGL_ERROR,
|
||||
"Incorrect number of SUB measurements detected! "
|
||||
"(%u vs exp >=%u)\n", num_meas_sub, num_meas_sub_expect);
|
||||
"(%u vs exp %d)\n", num_meas_sub, num_meas_sub_expect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -380,15 +380,19 @@ static inline bool dtx_sched_optional(struct gsm_lchan *lchan, uint32_t fn)
|
||||
static const uint8_t f[] = { 52, 53, 54, 55, 56, 57, 58, 59 },
|
||||
h0[] = { 0, 2, 4, 6, 52, 54, 56, 58 },
|
||||
h1[] = { 14, 16, 18, 20, 66, 68, 70, 72 };
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_V1) {
|
||||
switch (lchan->tch_mode) {
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
if (lchan->type == GSM_LCHAN_TCH_F)
|
||||
return fn_chk(f, fn, ARRAY_SIZE(f));
|
||||
else
|
||||
return fn_chk(lchan->nr ? h1 : h0, fn,
|
||||
lchan->nr ? ARRAY_SIZE(h1) :
|
||||
ARRAY_SIZE(h0));
|
||||
case GSM48_CMODE_SPEECH_EFR:
|
||||
return fn_chk(f, fn, ARRAY_SIZE(f));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! \brief Check if DTX DL AMR is enabled for a given lchan (it have proper type,
|
||||
@@ -466,10 +470,6 @@ void dtx_int_signal(struct gsm_lchan *lchan)
|
||||
*/
|
||||
uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn)
|
||||
{
|
||||
/* FIXME: add EFR support */
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_EFR)
|
||||
return 0;
|
||||
|
||||
if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) {
|
||||
if (dtx_sched_optional(lchan, fn))
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NM Radio Carrier FSM */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -70,17 +70,17 @@ static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint3
|
||||
static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;
|
||||
struct gsm_bts_trx *trx = gsm_bts_bb_trx_get_trx(bb_transc);
|
||||
int i;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SW_ACT:
|
||||
oml_mo_tx_sw_act_rep(&bb_transc->mo);
|
||||
nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_DISABLED_OFFLINE);
|
||||
for (i = 0; i < TRX_NR_TS; i++) {
|
||||
struct gsm_bts_trx_ts *ts = &trx->ts[i];
|
||||
osmo_fsm_inst_dispatch(ts->mo.fi, NM_EV_BBTRANSC_INSTALLED, NULL);
|
||||
}
|
||||
ev_dispatch_children(bb_transc, event);
|
||||
return;
|
||||
case NM_EV_OML_UP:
|
||||
/* Report current state: */
|
||||
oml_tx_state_changed(&bb_transc->mo);
|
||||
ev_dispatch_children(bb_transc, event);
|
||||
return;
|
||||
case NM_EV_RSL_UP:
|
||||
return;
|
||||
@@ -119,17 +119,48 @@ static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, voi
|
||||
{
|
||||
struct gsm_bts_bb_trx *bb_transc = (struct gsm_bts_bb_trx *)fi->priv;
|
||||
struct gsm_bts_trx *trx = gsm_bts_bb_trx_get_trx(bb_transc);
|
||||
struct gsm_bts *bts = trx->bts;
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
bool phy_state_connected;
|
||||
bool rsl_link_connected;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SETATTR_ACK:
|
||||
case NM_EV_SETATTR_NACK:
|
||||
case NM_EV_OML_UP:
|
||||
/* Report current state: */
|
||||
oml_tx_state_changed(&bb_transc->mo);
|
||||
ev_dispatch_children(bb_transc, event);
|
||||
return;
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
bb_transc->mo.setattr_success = setattr_data->cause == 0;
|
||||
oml_fom_ack_nack(setattr_data->msg, setattr_data->cause);
|
||||
break;
|
||||
rc = bts_model_apply_oml(trx->bts, setattr_data->msg,
|
||||
&bb_transc->mo, bb_transc);
|
||||
bb_transc->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
return;
|
||||
case NM_EV_RX_OPSTART:
|
||||
#if 0
|
||||
/* Disabled because osmo-bsc doesn't send SetAttr on BB_TRANSC object */
|
||||
if (!bb_transc->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&bb_transc->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* Connect RSL link: */
|
||||
if (bts->variant == BTS_OSMO_OMLDUMMY) {
|
||||
LOGPFSML(fi, LOGL_NOTICE, "Not connecting RSL in OML-DUMMY!\n");
|
||||
} else {
|
||||
rc = e1inp_ipa_bts_rsl_connect_n(bts->oml_link->ts->line,
|
||||
bb_transc->rsl.rem_addrstr.ip,
|
||||
bb_transc->rsl.rem_addrstr.port, trx->nr);
|
||||
if (rc < 0) {
|
||||
LOGPFSML(fi, LOGL_NOTICE, "Error connecting IPA RSL: %d\n", rc);
|
||||
oml_mo_opstart_nack(&bb_transc->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
bts_model_opstart(trx->bts, &bb_transc->mo, bb_transc);
|
||||
return;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
bb_transc->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&bb_transc->mo);
|
||||
@@ -153,10 +184,10 @@ static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, voi
|
||||
}
|
||||
|
||||
|
||||
if (trx->bts->variant != BTS_OSMO_OMLDUMMY) { /* In OMLDUMMY, phy=NULL */
|
||||
if (bts->variant != BTS_OSMO_OMLDUMMY) { /* In OMLDUMMY, phy=NULL */
|
||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
phy_state_connected = phy_link_state_get(pinst->phy_link) == PHY_LINK_CONNECTED;
|
||||
rsl_link_connected = !!trx->rsl_link;
|
||||
rsl_link_connected = !!trx->bb_transc.rsl.link;
|
||||
} else {
|
||||
phy_state_connected = true;
|
||||
rsl_link_connected = true;
|
||||
@@ -231,6 +262,7 @@ static struct osmo_fsm_state nm_bb_transc_fsm_states[] = {
|
||||
[NM_BBTRANSC_ST_OP_DISABLED_NOTINSTALLED] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SW_ACT) |
|
||||
X(NM_EV_OML_UP) |
|
||||
X(NM_EV_RSL_UP) |
|
||||
X(NM_EV_RSL_DOWN) |
|
||||
X(NM_EV_PHYLINK_UP) |
|
||||
@@ -245,8 +277,9 @@ static struct osmo_fsm_state nm_bb_transc_fsm_states[] = {
|
||||
},
|
||||
[NM_BBTRANSC_ST_OP_DISABLED_OFFLINE] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SETATTR_ACK) |
|
||||
X(NM_EV_SETATTR_NACK) |
|
||||
X(NM_EV_OML_UP) |
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) |
|
||||
X(NM_EV_OPSTART_ACK) |
|
||||
X(NM_EV_OPSTART_NACK) |
|
||||
X(NM_EV_RSL_UP) |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NM BTS FSM */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <osmo-bts/nm_common_fsm.h>
|
||||
#include <osmo-bts/phy_link.h>
|
||||
#include <osmo-bts/cbch.h>
|
||||
#include <osmo-bts/notification.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
@@ -60,8 +61,13 @@ static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint3
|
||||
struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
|
||||
/* Reset state: */
|
||||
bts->si_valid = 0;
|
||||
bts->bsic_configured = false;
|
||||
bts->bsic = 0xff; /* invalid value */
|
||||
TALLOC_FREE(bts->mo.nm_attr);
|
||||
bts_cbch_reset(bts);
|
||||
bts_asci_notification_reset(bts);
|
||||
if (bts->c0_power_red_db > 0)
|
||||
bts_set_c0_pwr_red(bts, 0);
|
||||
|
||||
bts->mo.setattr_success = false;
|
||||
bts->mo.opstart_success = false;
|
||||
@@ -74,7 +80,8 @@ static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event
|
||||
struct gsm_bts_trx *trx;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SW_ACT:
|
||||
case NM_EV_OML_UP:
|
||||
/* automatic SW_ACT upon OML link establishment: */
|
||||
oml_mo_tx_sw_act_rep(&bts->mo);
|
||||
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
@@ -91,6 +98,7 @@ static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event
|
||||
}
|
||||
|
||||
nm_bts_fsm_state_chg(fi, NM_BTS_ST_OP_DISABLED_OFFLINE);
|
||||
ev_dispatch_children(bts, event);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
@@ -109,13 +117,21 @@ static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, voi
|
||||
{
|
||||
struct gsm_bts *bts = (struct gsm_bts *)fi->priv;
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SETATTR_ACK:
|
||||
case NM_EV_SETATTR_NACK:
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
bts->mo.setattr_success = setattr_data->cause == 0;
|
||||
oml_fom_ack_nack(setattr_data->msg, setattr_data->cause);
|
||||
rc = bts_model_apply_oml(bts, setattr_data->msg, &bts->mo, bts);
|
||||
bts->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!bts->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&bts->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(bts, &bts->mo, bts);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
bts->mo.opstart_success = true;
|
||||
@@ -166,7 +182,7 @@ static void nm_bts_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data
|
||||
static struct osmo_fsm_state nm_bts_fsm_states[] = {
|
||||
[NM_BTS_ST_OP_DISABLED_NOTINSTALLED] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SW_ACT),
|
||||
X(NM_EV_OML_UP),
|
||||
.out_state_mask =
|
||||
X(NM_BTS_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_BTS_ST_OP_DISABLED_OFFLINE),
|
||||
@@ -176,8 +192,8 @@ static struct osmo_fsm_state nm_bts_fsm_states[] = {
|
||||
},
|
||||
[NM_BTS_ST_OP_DISABLED_OFFLINE] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SETATTR_ACK) |
|
||||
X(NM_EV_SETATTR_NACK) |
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) |
|
||||
X(NM_EV_OPSTART_ACK) |
|
||||
X(NM_EV_OPSTART_NACK),
|
||||
.out_state_mask =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NM BTS Site Manager FSM */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/rsl.h>
|
||||
#include <osmo-bts/nm_common_fsm.h>
|
||||
#include <osmo-bts/phy_link.h>
|
||||
@@ -44,8 +45,11 @@
|
||||
|
||||
static void ev_dispatch_children(struct gsm_bts_sm *site_mgr, uint32_t event)
|
||||
{
|
||||
struct gsm_bts *bts = gsm_bts_sm_get_bts(site_mgr);
|
||||
osmo_fsm_inst_dispatch(bts->mo.fi, event, NULL);
|
||||
struct gsm_bts *bts;
|
||||
osmo_fsm_inst_dispatch(site_mgr->gprs.nse.mo.fi, event, NULL);
|
||||
llist_for_each_entry(bts, &site_mgr->bts_list, list) {
|
||||
osmo_fsm_inst_dispatch(bts->mo.fi, event, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
@@ -65,9 +69,11 @@ static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event
|
||||
struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SW_ACT:
|
||||
case NM_EV_OML_UP:
|
||||
/* automatic SW_ACT upon OML link establishment: */
|
||||
oml_mo_tx_sw_act_rep(&site_mgr->mo);
|
||||
nm_bts_sm_fsm_state_chg(fi, NM_BTS_SM_ST_OP_DISABLED_OFFLINE);
|
||||
ev_dispatch_children(site_mgr, event);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
@@ -86,13 +92,25 @@ static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, voi
|
||||
{
|
||||
struct gsm_bts_sm *site_mgr = (struct gsm_bts_sm *)fi->priv;
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SETATTR_ACK:
|
||||
case NM_EV_SETATTR_NACK:
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
site_mgr->mo.setattr_success = setattr_data->cause == 0;
|
||||
oml_fom_ack_nack(setattr_data->msg, setattr_data->cause);
|
||||
/* No bts_model_apply_oml() needed yet for site_mgr obj yet: */
|
||||
rc = 0;
|
||||
site_mgr->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
#if 0
|
||||
/* Disabled because osmo-bsc doesn't send SetAttr on SITE_MGR object */
|
||||
if (!site_mgr->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&site_mgr->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
bts_model_opstart(NULL, &site_mgr->mo, site_mgr);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
site_mgr->mo.opstart_success = true;
|
||||
@@ -143,7 +161,7 @@ static void nm_bts_sm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *d
|
||||
static struct osmo_fsm_state nm_bts_sm_fsm_states[] = {
|
||||
[NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SW_ACT),
|
||||
X(NM_EV_OML_UP),
|
||||
.out_state_mask =
|
||||
X(NM_BTS_SM_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_BTS_SM_ST_OP_DISABLED_OFFLINE),
|
||||
@@ -153,8 +171,8 @@ static struct osmo_fsm_state nm_bts_sm_fsm_states[] = {
|
||||
},
|
||||
[NM_BTS_SM_ST_OP_DISABLED_OFFLINE] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SETATTR_ACK) |
|
||||
X(NM_EV_SETATTR_NACK) |
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) |
|
||||
X(NM_EV_OPSTART_ACK) |
|
||||
X(NM_EV_OPSTART_NACK),
|
||||
.out_state_mask =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NM Radio Carrier FSM */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -71,7 +71,11 @@ static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event
|
||||
struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_BBTRANSC_INSTALLED:
|
||||
case NM_EV_OML_UP:
|
||||
/* Report current state: */
|
||||
oml_tx_state_changed(&ts->mo);
|
||||
return;
|
||||
case NM_EV_SW_ACT:
|
||||
oml_mo_tx_sw_act_rep(&ts->mo);
|
||||
if (ts_can_be_enabled(ts))
|
||||
nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_OFFLINE);
|
||||
@@ -94,17 +98,30 @@ static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event,
|
||||
{
|
||||
struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SETATTR_ACK:
|
||||
case NM_EV_SETATTR_NACK:
|
||||
case NM_EV_OML_UP:
|
||||
/* Report current state: */
|
||||
oml_tx_state_changed(&ts->mo);
|
||||
return;
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
ts->mo.setattr_success = setattr_data->cause == 0;
|
||||
oml_fom_ack_nack(setattr_data->msg, setattr_data->cause);
|
||||
rc = bts_model_apply_oml(ts->trx->bts, setattr_data->msg,
|
||||
&ts->mo, ts);
|
||||
ts->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
LOGPFSML(fi, LOGL_NOTICE, "BSC trying to activate TS while still in avail=dependency. "
|
||||
"Allowing it to stay backward-compatible with older osmo-bts versions, but BSC is wrong.\n");
|
||||
if (!ts->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&ts->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(ts->trx->bts, &ts->mo, ts);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
LOGPFSML(fi, LOGL_NOTICE, "BSC trying to activate TS while still in avail=dependency. "
|
||||
"Allowing it to stay backward-compatible with older osmo-bts versions, but BSC is wrong.\n");
|
||||
ts->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&ts->mo);
|
||||
nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
|
||||
@@ -138,13 +155,26 @@ static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, voi
|
||||
{
|
||||
struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SETATTR_ACK:
|
||||
case NM_EV_SETATTR_NACK:
|
||||
case NM_EV_OML_UP:
|
||||
/* Report current state: */
|
||||
oml_tx_state_changed(&ts->mo);
|
||||
return;
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
ts->mo.setattr_success = setattr_data->cause == 0;
|
||||
oml_fom_ack_nack(setattr_data->msg, setattr_data->cause);
|
||||
rc = bts_model_apply_oml(ts->trx->bts, setattr_data->msg,
|
||||
&ts->mo, ts);
|
||||
ts->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!ts->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&ts->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(ts->trx->bts, &ts->mo, ts);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
ts->mo.opstart_success = true;
|
||||
@@ -209,7 +239,8 @@ static void nm_chan_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *dat
|
||||
static struct osmo_fsm_state nm_chan_fsm_states[] = {
|
||||
[NM_CHAN_ST_OP_DISABLED_NOTINSTALLED] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_BBTRANSC_INSTALLED),
|
||||
X(NM_EV_SW_ACT) |
|
||||
X(NM_EV_OML_UP),
|
||||
.out_state_mask =
|
||||
X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
|
||||
@@ -220,10 +251,11 @@ static struct osmo_fsm_state nm_chan_fsm_states[] = {
|
||||
},
|
||||
[NM_CHAN_ST_OP_DISABLED_DEPENDENCY] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SETATTR_ACK) |
|
||||
X(NM_EV_SETATTR_NACK) |
|
||||
X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_NACK) |
|
||||
X(NM_EV_OML_UP) |
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_NACK) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_BBTRANSC_ENABLED) |
|
||||
X(NM_EV_RCARRIER_ENABLED) |
|
||||
X(NM_EV_BBTRANSC_DISABLED) |
|
||||
@@ -238,8 +270,9 @@ static struct osmo_fsm_state nm_chan_fsm_states[] = {
|
||||
},
|
||||
[NM_CHAN_ST_OP_DISABLED_OFFLINE] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SETATTR_ACK) |
|
||||
X(NM_EV_SETATTR_NACK) |
|
||||
X(NM_EV_OML_UP) |
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) |
|
||||
X(NM_EV_OPSTART_ACK) |
|
||||
X(NM_EV_OPSTART_NACK) |
|
||||
X(NM_EV_BBTRANSC_DISABLED) |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NM FSM, common bits */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -25,18 +25,18 @@
|
||||
|
||||
const struct value_string nm_fsm_event_names[] = {
|
||||
{ NM_EV_SW_ACT, "SW_ACT" },
|
||||
{ NM_EV_SETATTR_ACK, "SETATTR_ACK" },
|
||||
{ NM_EV_SETATTR_NACK, "SETATTR_NACK" },
|
||||
{ NM_EV_RX_SETATTR, "RX_SETATTR" },
|
||||
{ NM_EV_RX_OPSTART, "RX_OPSTART" },
|
||||
{ NM_EV_OPSTART_ACK, "OPSTART_ACK" },
|
||||
{ NM_EV_OPSTART_NACK, "OPSTART_NACK" },
|
||||
{ NM_EV_SHUTDOWN_START, "SHUTDOWN_START" },
|
||||
{ NM_EV_SHUTDOWN_FINISH, "SHUTDOWN_FINISH" },
|
||||
{ NM_EV_OML_UP, "OML_UP" },
|
||||
{ NM_EV_RSL_UP, "RSL_UP" },
|
||||
{ NM_EV_RSL_DOWN, "RSL_DOWN" },
|
||||
{ NM_EV_PHYLINK_UP, "PHYLINK_UP" },
|
||||
{ NM_EV_PHYLINK_DOWN, "PHYLINK_DOWN" },
|
||||
{ NM_EV_DISABLE, "DISABLE" },
|
||||
{ NM_EV_BBTRANSC_INSTALLED, "BBTRANSC_INSTALLED" },
|
||||
{ NM_EV_BBTRANSC_ENABLED, "BBTRANSC_ENABLED" },
|
||||
{ NM_EV_BBTRANSC_DISABLED, "BBTRANSC_DISABLED" },
|
||||
{ NM_EV_RCARRIER_ENABLED, "RCARRIER_ENABLED" },
|
||||
|
||||
260
src/common/nm_gprs_cell_fsm.c
Normal file
260
src/common/nm_gprs_cell_fsm.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/* NM GPRS Cell FSM */
|
||||
|
||||
/* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@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 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
|
||||
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/rsl.h>
|
||||
#include <osmo-bts/nm_common_fsm.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
#define nm_gprs_cell_fsm_state_chg(fi, NEXT_STATE) \
|
||||
osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
|
||||
|
||||
/* Can the GPRS Cell be enabled (OPSTARTed)? aka should it stay in "Disabled Dependency" state? */
|
||||
static bool gprs_cell_can_be_enabled(struct gsm_gprs_cell *cell)
|
||||
{
|
||||
struct gsm_bts *bts = gsm_gprs_cell_get_bts(cell);
|
||||
return bts->site_mgr->gprs.nse.mo.nm_state.operational == NM_OPSTATE_ENABLED;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// FSM STATE ACTIONS
|
||||
//////////////////////////
|
||||
|
||||
static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
|
||||
/* Reset state here: */
|
||||
|
||||
cell->mo.setattr_success = false;
|
||||
cell->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&cell->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
|
||||
}
|
||||
|
||||
static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_OML_UP:
|
||||
/* automatic SW_ACT upon OML link establishment: */
|
||||
oml_mo_tx_sw_act_rep(&cell->mo);
|
||||
if (gprs_cell_can_be_enabled(cell))
|
||||
nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE);
|
||||
else
|
||||
nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_disabled_dependency_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
|
||||
cell->mo.setattr_success = false;
|
||||
cell->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&cell->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY, -1);
|
||||
}
|
||||
|
||||
static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
|
||||
struct gsm_bts *bts = gsm_gprs_cell_get_bts(cell);
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
rc = bts_model_apply_oml(bts, setattr_data->msg,
|
||||
&cell->mo, cell);
|
||||
cell->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!cell->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&cell->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(bts, &cell->mo, cell);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
cell->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&cell->mo);
|
||||
nm_gprs_cell_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
|
||||
return;
|
||||
case NM_EV_OPSTART_NACK:
|
||||
cell->mo.opstart_success = false;
|
||||
oml_mo_opstart_nack(&cell->mo, (int)(intptr_t)data);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
|
||||
cell->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&cell->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
|
||||
}
|
||||
|
||||
static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
|
||||
struct gsm_bts *bts = gsm_gprs_cell_get_bts(cell);
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
rc = bts_model_apply_oml(bts, setattr_data->msg, &cell->mo, bts);
|
||||
cell->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!cell->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&cell->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(bts, &cell->mo, bts);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
cell->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&cell->mo);
|
||||
nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_ENABLED);
|
||||
break; /* check statechg below */
|
||||
case NM_EV_OPSTART_NACK:
|
||||
cell->mo.opstart_success = false;
|
||||
oml_mo_opstart_nack(&cell->mo, (int)(intptr_t)data);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
|
||||
oml_mo_state_chg(&cell->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
|
||||
}
|
||||
|
||||
static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void nm_gprs_cell_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_cell *cell = (struct gsm_gprs_cell *)fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SHUTDOWN_START:
|
||||
/* Announce we start shutting down */
|
||||
oml_mo_state_chg(&cell->mo, -1, -1, NM_STATE_SHUTDOWN);
|
||||
break;
|
||||
case NM_EV_SHUTDOWN_FINISH:
|
||||
nm_gprs_cell_fsm_state_chg(fi, NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static struct osmo_fsm_state nm_gprs_cell_fsm_states[] = {
|
||||
[NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_OML_UP),
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY) |
|
||||
X(NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE),
|
||||
.name = "DISABLED_NOTINSTALLED",
|
||||
.onenter = st_op_disabled_notinstalled_on_enter,
|
||||
.action = st_op_disabled_notinstalled,
|
||||
},
|
||||
[NM_GPRS_CELL_ST_OP_DISABLED_DEPENDENCY] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_NACK), /* backward compatibility, buggy BSC */
|
||||
.out_state_mask =
|
||||
X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
|
||||
X(NM_CHAN_ST_OP_ENABLED), /* backward compatibility, buggy BSC */
|
||||
.name = "DISABLED_DEPENDENCY",
|
||||
.onenter = st_op_disabled_dependency_on_enter,
|
||||
.action = st_op_disabled_dependency,
|
||||
},
|
||||
[NM_GPRS_CELL_ST_OP_DISABLED_OFFLINE] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) |
|
||||
X(NM_EV_OPSTART_ACK) |
|
||||
X(NM_EV_OPSTART_NACK),
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_GPRS_CELL_ST_OP_ENABLED),
|
||||
.name = "DISABLED_OFFLINE",
|
||||
.onenter = st_op_disabled_offline_on_enter,
|
||||
.action = st_op_disabled_offline,
|
||||
},
|
||||
[NM_GPRS_CELL_ST_OP_ENABLED] = {
|
||||
.in_event_mask = 0,
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_CELL_ST_OP_DISABLED_NOTINSTALLED),
|
||||
.name = "ENABLED",
|
||||
.onenter = st_op_enabled_on_enter,
|
||||
.action = st_op_enabled,
|
||||
},
|
||||
};
|
||||
|
||||
struct osmo_fsm nm_gprs_cell_fsm = {
|
||||
.name = "NM_GPRS_CELL_OP",
|
||||
.states = nm_gprs_cell_fsm_states,
|
||||
.num_states = ARRAY_SIZE(nm_gprs_cell_fsm_states),
|
||||
.event_names = nm_fsm_event_names,
|
||||
.allstate_action = nm_gprs_cell_allstate,
|
||||
.allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
|
||||
X(NM_EV_SHUTDOWN_FINISH),
|
||||
.log_subsys = DOML,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void nm_gprs_cell_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&nm_gprs_cell_fsm) == 0);
|
||||
}
|
||||
280
src/common/nm_gprs_nse_fsm.c
Normal file
280
src/common/nm_gprs_nse_fsm.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/* NM GPRS NSE FSM */
|
||||
|
||||
/* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@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 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
|
||||
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/rsl.h>
|
||||
#include <osmo-bts/nm_common_fsm.h>
|
||||
#include <osmo-bts/phy_link.h>
|
||||
#include <osmo-bts/cbch.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
#define nm_gprs_nse_fsm_state_chg(fi, NEXT_STATE) \
|
||||
osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
|
||||
|
||||
static void ev_dispatch_children(struct gsm_gprs_nse *nse, uint32_t event)
|
||||
{
|
||||
unsigned int i;
|
||||
struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
|
||||
|
||||
osmo_fsm_inst_dispatch(bts->gprs.cell.mo.fi, event, NULL);
|
||||
for (i = 0; i < ARRAY_SIZE(nse->nsvc); i++) {
|
||||
struct gsm_gprs_nsvc *nsvc = &nse->nsvc[i];
|
||||
osmo_fsm_inst_dispatch(nsvc->mo.fi, event, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Can the NSE be enabled (OPSTARTed)? aka should it stay in "Disabled Dependency" state? */
|
||||
static bool nse_can_be_enabled(struct gsm_gprs_nse *nse)
|
||||
{
|
||||
struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
|
||||
return bts->mo.nm_state.operational == NM_OPSTATE_ENABLED;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// FSM STATE ACTIONS
|
||||
//////////////////////////
|
||||
|
||||
static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
|
||||
/* Reset state here: */
|
||||
|
||||
nse->mo.setattr_success = false;
|
||||
nse->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&nse->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
|
||||
}
|
||||
|
||||
static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_OML_UP:
|
||||
/* automatic SW_ACT upon OML link establishment: */
|
||||
oml_mo_tx_sw_act_rep(&nse->mo);
|
||||
ev_dispatch_children(nse, event);
|
||||
if (nse_can_be_enabled(nse))
|
||||
nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE);
|
||||
else
|
||||
nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_disabled_dependency_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
|
||||
nse->mo.setattr_success = false;
|
||||
nse->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&nse->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY, -1);
|
||||
}
|
||||
|
||||
static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
|
||||
struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
rc = bts_model_apply_oml(bts, setattr_data->msg,
|
||||
&nse->mo, nse);
|
||||
nse->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!nse->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&nse->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(bts, &nse->mo, nse);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
nse->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&nse->mo);
|
||||
nm_gprs_nse_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
|
||||
return;
|
||||
case NM_EV_OPSTART_NACK:
|
||||
nse->mo.opstart_success = false;
|
||||
oml_mo_opstart_nack(&nse->mo, (int)(intptr_t)data);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
|
||||
nse->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&nse->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
|
||||
}
|
||||
|
||||
static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
|
||||
struct gsm_bts *bts = gsm_gprs_nse_get_bts(nse);
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
rc = bts_model_apply_oml(bts, setattr_data->msg, &nse->mo, bts);
|
||||
nse->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!nse->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&nse->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(bts, &nse->mo, bts);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
nse->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&nse->mo);
|
||||
nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_ENABLED);
|
||||
break; /* check statechg below */
|
||||
case NM_EV_OPSTART_NACK:
|
||||
nse->mo.opstart_success = false;
|
||||
oml_mo_opstart_nack(&nse->mo, (int)(intptr_t)data);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
|
||||
oml_mo_state_chg(&nse->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
|
||||
}
|
||||
|
||||
static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void nm_gprs_nse_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_nse *nse = (struct gsm_gprs_nse *)fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SHUTDOWN_START:
|
||||
/* Announce we start shutting down */
|
||||
oml_mo_state_chg(&nse->mo, -1, -1, NM_STATE_SHUTDOWN);
|
||||
|
||||
/* Propagate event to children: */
|
||||
ev_dispatch_children(nse, event);
|
||||
break;
|
||||
case NM_EV_SHUTDOWN_FINISH:
|
||||
/* Propagate event to children: */
|
||||
ev_dispatch_children(nse, event);
|
||||
nm_gprs_nse_fsm_state_chg(fi, NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static struct osmo_fsm_state nm_gprs_nse_fsm_states[] = {
|
||||
[NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_OML_UP),
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY) |
|
||||
X(NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE),
|
||||
.name = "DISABLED_NOTINSTALLED",
|
||||
.onenter = st_op_disabled_notinstalled_on_enter,
|
||||
.action = st_op_disabled_notinstalled,
|
||||
},
|
||||
[NM_GPRS_NSE_ST_OP_DISABLED_DEPENDENCY] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_NACK), /* backward compatibility, buggy BSC */
|
||||
.out_state_mask =
|
||||
X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
|
||||
X(NM_CHAN_ST_OP_ENABLED), /* backward compatibility, buggy BSC */
|
||||
.name = "DISABLED_DEPENDENCY",
|
||||
.onenter = st_op_disabled_dependency_on_enter,
|
||||
.action = st_op_disabled_dependency,
|
||||
},
|
||||
[NM_GPRS_NSE_ST_OP_DISABLED_OFFLINE] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) |
|
||||
X(NM_EV_OPSTART_ACK) |
|
||||
X(NM_EV_OPSTART_NACK),
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_GPRS_NSE_ST_OP_ENABLED),
|
||||
.name = "DISABLED_OFFLINE",
|
||||
.onenter = st_op_disabled_offline_on_enter,
|
||||
.action = st_op_disabled_offline,
|
||||
},
|
||||
[NM_GPRS_NSE_ST_OP_ENABLED] = {
|
||||
.in_event_mask = 0,
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_NSE_ST_OP_DISABLED_NOTINSTALLED),
|
||||
.name = "ENABLED",
|
||||
.onenter = st_op_enabled_on_enter,
|
||||
.action = st_op_enabled,
|
||||
},
|
||||
};
|
||||
|
||||
struct osmo_fsm nm_gprs_nse_fsm = {
|
||||
.name = "NM_GPRS_NSE_OP",
|
||||
.states = nm_gprs_nse_fsm_states,
|
||||
.num_states = ARRAY_SIZE(nm_gprs_nse_fsm_states),
|
||||
.event_names = nm_fsm_event_names,
|
||||
.allstate_action = nm_gprs_nse_allstate,
|
||||
.allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
|
||||
X(NM_EV_SHUTDOWN_FINISH),
|
||||
.log_subsys = DOML,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void nm_gprs_nse_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&nm_gprs_nse_fsm) == 0);
|
||||
}
|
||||
259
src/common/nm_gprs_nsvc_fsm.c
Normal file
259
src/common/nm_gprs_nsvc_fsm.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/* NM GPRS NSVC FSM */
|
||||
|
||||
/* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@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 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
|
||||
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/rsl.h>
|
||||
#include <osmo-bts/nm_common_fsm.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
#define nm_gprs_nsvc_fsm_state_chg(fi, NEXT_STATE) \
|
||||
osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)
|
||||
|
||||
/* Can the GPRS Cell be enabled (OPSTARTed)? aka should it stay in "Disabled Dependency" state? */
|
||||
static bool gprs_nsvc_can_be_enabled(struct gsm_gprs_nsvc *nsvc)
|
||||
{
|
||||
return nsvc->nse->mo.nm_state.operational == NM_OPSTATE_ENABLED;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// FSM STATE ACTIONS
|
||||
//////////////////////////
|
||||
|
||||
static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
|
||||
/* Reset state here: */
|
||||
|
||||
nsvc->mo.setattr_success = false;
|
||||
nsvc->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&nsvc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED, NM_STATE_LOCKED);
|
||||
}
|
||||
|
||||
static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_OML_UP:
|
||||
/* automatic SW_ACT upon OML link establishment: */
|
||||
oml_mo_tx_sw_act_rep(&nsvc->mo);
|
||||
if (gprs_nsvc_can_be_enabled(nsvc))
|
||||
nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE);
|
||||
else
|
||||
nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_disabled_dependency_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
|
||||
nsvc->mo.setattr_success = false;
|
||||
nsvc->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&nsvc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY, -1);
|
||||
}
|
||||
|
||||
static void st_op_disabled_dependency(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
|
||||
struct gsm_bts *bts = gsm_gprs_nse_get_bts(nsvc->nse);
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
rc = bts_model_apply_oml(bts, setattr_data->msg,
|
||||
&nsvc->mo, nsvc);
|
||||
nsvc->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!nsvc->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&nsvc->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(bts, &nsvc->mo, nsvc);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
nsvc->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&nsvc->mo);
|
||||
nm_gprs_nsvc_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);
|
||||
return;
|
||||
case NM_EV_OPSTART_NACK:
|
||||
nsvc->mo.opstart_success = false;
|
||||
oml_mo_opstart_nack(&nsvc->mo, (int)(intptr_t)data);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
|
||||
nsvc->mo.opstart_success = false;
|
||||
oml_mo_state_chg(&nsvc->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE, -1);
|
||||
}
|
||||
|
||||
static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
|
||||
struct gsm_bts *bts = gsm_gprs_nse_get_bts(nsvc->nse);
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
rc = bts_model_apply_oml(bts, setattr_data->msg, &nsvc->mo, bts);
|
||||
nsvc->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break;
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!nsvc->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&nsvc->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(bts, &nsvc->mo, bts);
|
||||
break;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
nsvc->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&nsvc->mo);
|
||||
nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_ENABLED);
|
||||
break; /* check statechg below */
|
||||
case NM_EV_OPSTART_NACK:
|
||||
nsvc->mo.opstart_success = false;
|
||||
oml_mo_opstart_nack(&nsvc->mo, (int)(intptr_t)data);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
|
||||
oml_mo_state_chg(&nsvc->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, -1);
|
||||
}
|
||||
|
||||
static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void nm_gprs_nsvc_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gsm_gprs_nsvc *nsvc = (struct gsm_gprs_nsvc *)fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SHUTDOWN_START:
|
||||
/* Announce we start shutting down */
|
||||
oml_mo_state_chg(&nsvc->mo, -1, -1, NM_STATE_SHUTDOWN);
|
||||
break;
|
||||
case NM_EV_SHUTDOWN_FINISH:
|
||||
nm_gprs_nsvc_fsm_state_chg(fi, NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static struct osmo_fsm_state nm_gprs_nsvc_fsm_states[] = {
|
||||
[NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_OML_UP),
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY) |
|
||||
X(NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE),
|
||||
.name = "DISABLED_NOTINSTALLED",
|
||||
.onenter = st_op_disabled_notinstalled_on_enter,
|
||||
.action = st_op_disabled_notinstalled,
|
||||
},
|
||||
[NM_GPRS_NSVC_ST_OP_DISABLED_DEPENDENCY] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_ACK) | /* backward compatibility, buggy BSC */
|
||||
X(NM_EV_OPSTART_NACK), /* backward compatibility, buggy BSC */
|
||||
.out_state_mask =
|
||||
X(NM_CHAN_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |
|
||||
X(NM_CHAN_ST_OP_ENABLED), /* backward compatibility, buggy BSC */
|
||||
.name = "DISABLED_DEPENDENCY",
|
||||
.onenter = st_op_disabled_dependency_on_enter,
|
||||
.action = st_op_disabled_dependency,
|
||||
},
|
||||
[NM_GPRS_NSVC_ST_OP_DISABLED_OFFLINE] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) |
|
||||
X(NM_EV_OPSTART_ACK) |
|
||||
X(NM_EV_OPSTART_NACK),
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED) |
|
||||
X(NM_GPRS_NSVC_ST_OP_ENABLED),
|
||||
.name = "DISABLED_OFFLINE",
|
||||
.onenter = st_op_disabled_offline_on_enter,
|
||||
.action = st_op_disabled_offline,
|
||||
},
|
||||
[NM_GPRS_NSVC_ST_OP_ENABLED] = {
|
||||
.in_event_mask = 0,
|
||||
.out_state_mask =
|
||||
X(NM_GPRS_NSVC_ST_OP_DISABLED_NOTINSTALLED),
|
||||
.name = "ENABLED",
|
||||
.onenter = st_op_enabled_on_enter,
|
||||
.action = st_op_enabled,
|
||||
},
|
||||
};
|
||||
|
||||
struct osmo_fsm nm_gprs_nsvc_fsm = {
|
||||
.name = "NM_GPRS_NSVC_OP",
|
||||
.states = nm_gprs_nsvc_fsm_states,
|
||||
.num_states = ARRAY_SIZE(nm_gprs_nsvc_fsm_states),
|
||||
.event_names = nm_fsm_event_names,
|
||||
.allstate_action = nm_gprs_nsvc_allstate,
|
||||
.allstate_event_mask = X(NM_EV_SHUTDOWN_START) |
|
||||
X(NM_EV_SHUTDOWN_FINISH),
|
||||
.log_subsys = DOML,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void nm_gprs_nsvc_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&nm_gprs_nsvc_fsm) == 0);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NM Radio Carrier FSM */
|
||||
|
||||
/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
@@ -65,6 +65,10 @@ static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event
|
||||
oml_mo_tx_sw_act_rep(&trx->mo);
|
||||
nm_rcarrier_fsm_state_chg(fi, NM_RCARRIER_ST_OP_DISABLED_OFFLINE);
|
||||
return;
|
||||
case NM_EV_OML_UP:
|
||||
/* Report current state: */
|
||||
oml_tx_state_changed(&trx->mo);
|
||||
return;
|
||||
case NM_EV_RSL_UP:
|
||||
return;
|
||||
case NM_EV_RSL_DOWN:
|
||||
@@ -103,14 +107,27 @@ static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, voi
|
||||
struct nm_fsm_ev_setattr_data *setattr_data;
|
||||
bool phy_state_connected;
|
||||
bool rsl_link_connected;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case NM_EV_SETATTR_ACK:
|
||||
case NM_EV_SETATTR_NACK:
|
||||
case NM_EV_OML_UP:
|
||||
/* Report current state: */
|
||||
oml_tx_state_changed(&trx->mo);
|
||||
return;
|
||||
case NM_EV_RX_SETATTR:
|
||||
setattr_data = (struct nm_fsm_ev_setattr_data *)data;
|
||||
trx->mo.setattr_success = setattr_data->cause == 0;
|
||||
oml_fom_ack_nack(setattr_data->msg, setattr_data->cause);
|
||||
break;
|
||||
rc = bts_model_apply_oml(trx->bts, setattr_data->msg,
|
||||
&trx->mo, trx);
|
||||
trx->mo.setattr_success = rc == 0;
|
||||
oml_fom_ack_nack_copy_msg(setattr_data->msg, rc);
|
||||
break; /* check statechg below */
|
||||
case NM_EV_RX_OPSTART:
|
||||
if (!trx->mo.setattr_success) {
|
||||
oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM);
|
||||
return;
|
||||
}
|
||||
bts_model_opstart(trx->bts, &trx->mo, trx);
|
||||
return;
|
||||
case NM_EV_OPSTART_ACK:
|
||||
trx->mo.opstart_success = true;
|
||||
oml_mo_opstart_ack(&trx->mo);
|
||||
@@ -136,7 +153,7 @@ static void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, voi
|
||||
if (trx->bts->variant != BTS_OSMO_OMLDUMMY) { /* In OMLDUMMY, phy=NULL */
|
||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
phy_state_connected = phy_link_state_get(pinst->phy_link) == PHY_LINK_CONNECTED;
|
||||
rsl_link_connected = !!trx->rsl_link;
|
||||
rsl_link_connected = !!trx->bb_transc.rsl.link;
|
||||
} else {
|
||||
phy_state_connected = true;
|
||||
rsl_link_connected = true;
|
||||
@@ -205,6 +222,7 @@ static struct osmo_fsm_state nm_rcarrier_fsm_states[] = {
|
||||
[NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SW_ACT) |
|
||||
X(NM_EV_OML_UP) |
|
||||
X(NM_EV_RSL_UP) |
|
||||
X(NM_EV_RSL_DOWN) |
|
||||
X(NM_EV_PHYLINK_UP) |
|
||||
@@ -219,8 +237,9 @@ static struct osmo_fsm_state nm_rcarrier_fsm_states[] = {
|
||||
},
|
||||
[NM_RCARRIER_ST_OP_DISABLED_OFFLINE] = {
|
||||
.in_event_mask =
|
||||
X(NM_EV_SETATTR_ACK) |
|
||||
X(NM_EV_SETATTR_NACK) |
|
||||
X(NM_EV_OML_UP) |
|
||||
X(NM_EV_RX_SETATTR) |
|
||||
X(NM_EV_RX_OPSTART) |
|
||||
X(NM_EV_OPSTART_ACK) |
|
||||
X(NM_EV_OPSTART_NACK) |
|
||||
X(NM_EV_RSL_UP) |
|
||||
|
||||
256
src/common/notification.c
Normal file
256
src/common/notification.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/* Maintain and generate ASCI notifications */
|
||||
|
||||
/*
|
||||
* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* Author: Harald Welte
|
||||
*
|
||||
* 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 <errno.h>
|
||||
|
||||
#include <osmocom/core/bitvec.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/gsm/protocol/gsm_08_58.h>
|
||||
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/notification.h>
|
||||
|
||||
static struct asci_notification *bts_asci_notification_find(struct gsm_bts *bts, const uint8_t *group_call_ref)
|
||||
{
|
||||
struct asci_notification *n;
|
||||
llist_for_each_entry(n, &bts->asci.notifications, list) {
|
||||
if (!memcmp(n->group_call_ref, group_call_ref, sizeof(n->group_call_ref)))
|
||||
return n;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int bts_asci_notification_add(struct gsm_bts *bts, const uint8_t *group_call_ref, const uint8_t *chan_desc,
|
||||
uint8_t chan_desc_len, const struct rsl_ie_nch_drx_info *nch_drx_info)
|
||||
{
|
||||
struct asci_notification *n;
|
||||
|
||||
if (bts_asci_notification_find(bts, group_call_ref))
|
||||
return -EEXIST;
|
||||
|
||||
n = talloc_zero(bts, struct asci_notification);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(n->group_call_ref, group_call_ref, sizeof(n->group_call_ref));
|
||||
if (chan_desc && chan_desc_len) {
|
||||
n->chan_desc.present = true;
|
||||
n->chan_desc.len = chan_desc_len;
|
||||
memcpy(&n->chan_desc.value, chan_desc, chan_desc_len);
|
||||
}
|
||||
if (nch_drx_info) {
|
||||
n->nch_drx_info.present = true;
|
||||
n->nch_drx_info.value = *nch_drx_info;
|
||||
}
|
||||
|
||||
LOGP(DASCI, LOGL_INFO, "Added ASCI Notification for group call reference %s\n",
|
||||
osmo_hexdump_nospc(n->group_call_ref, ARRAY_SIZE(n->group_call_ref)));
|
||||
|
||||
/* add at beginning of "queue" to make sure a new call is notified first */
|
||||
llist_add(&n->list, &bts->asci.notifications);
|
||||
|
||||
bts->asci.notification_entries++;
|
||||
bts->asci.notification_count = 0;
|
||||
bts->asci.nln = (bts->asci.nln + 1) % 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bts_asci_notification_del(struct gsm_bts *bts, const uint8_t *group_call_ref)
|
||||
{
|
||||
struct asci_notification *n = bts_asci_notification_find(bts, group_call_ref);
|
||||
if (!n)
|
||||
return -ENODEV;
|
||||
|
||||
LOGP(DASCI, LOGL_INFO, "Deleting ASCI Notification for group call reference %s\n",
|
||||
osmo_hexdump_nospc(n->group_call_ref, ARRAY_SIZE(n->group_call_ref)));
|
||||
|
||||
llist_del(&n->list);
|
||||
talloc_free(n);
|
||||
|
||||
bts->asci.notification_entries--;
|
||||
bts->asci.notification_count = 0;
|
||||
bts->asci.nln_status = (bts->asci.nln_status + 1) % 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bts_asci_notification_reset(struct gsm_bts *bts)
|
||||
{
|
||||
struct asci_notification *n, *n2;
|
||||
|
||||
LOGP(DASCI, LOGL_INFO, "Deleting all %u ASCI Notifications of BTS\n",
|
||||
llist_count(&bts->asci.notifications));
|
||||
|
||||
llist_for_each_entry_safe(n, n2, &bts->asci.notifications, list) {
|
||||
llist_del(&n->list);
|
||||
talloc_free(n);
|
||||
}
|
||||
|
||||
bts->asci.notification_entries = 0;
|
||||
bts->asci.notification_count = 0;
|
||||
bts->asci.nln_status = (bts->asci.nln_status + 1) % 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct asci_notification *bts_asci_notification_get_next(struct gsm_bts *bts)
|
||||
{
|
||||
struct asci_notification *n;
|
||||
|
||||
n = llist_first_entry_or_null(&bts->asci.notifications, struct asci_notification, list);
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
/* move to end of list to iterate over them */
|
||||
llist_del(&n->list);
|
||||
llist_add_tail(&n->list, &bts->asci.notifications);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/*! append a "Group Call Information" CSN.1 structure to the caller-provided bit-vector.
|
||||
* \param[out] bv caller-provided output bit-vector
|
||||
* \param[in] gcr 5-byte group call reference
|
||||
* \param[in] ch_desc optional group channel description (may be NULL)
|
||||
* \param[in] ch_desc_len length of group channel description (in bytes) */
|
||||
void append_group_call_information(struct bitvec *bv, const uint8_t *gcr, const uint8_t *ch_desc, uint8_t ch_desc_len)
|
||||
{
|
||||
/* spec reference: TS 44.018 Section 9.1.21a */
|
||||
|
||||
/* <Group Call Reference : bit(36)> */
|
||||
struct bitvec *gcr_bv = bitvec_alloc(5*8, NULL);
|
||||
OSMO_ASSERT(gcr_bv);
|
||||
bitvec_unpack(gcr_bv, gcr);
|
||||
for (unsigned int i = 0; i < 36; i++)
|
||||
bitvec_set_bit(bv, bitvec_get_bit_pos(gcr_bv, i));
|
||||
|
||||
/* Group Channel Description */
|
||||
if (ch_desc && ch_desc_len) {
|
||||
struct bitvec *chd_bv = bitvec_alloc(ch_desc_len*8, NULL);
|
||||
OSMO_ASSERT(chd_bv);
|
||||
bitvec_unpack(chd_bv, ch_desc);
|
||||
bitvec_set_bit(bv, 1);
|
||||
/* <Channel Description : bit(24)> */
|
||||
for (unsigned int i = 0; i < ch_desc_len * 8; i++)
|
||||
bitvec_set_bit(bv, bitvec_get_bit_pos(chd_bv, i));
|
||||
bitvec_free(chd_bv);
|
||||
/* FIXME: hopping */
|
||||
bitvec_set_bit(bv, 0);
|
||||
} else {
|
||||
bitvec_set_bit(bv, 0);
|
||||
}
|
||||
|
||||
bitvec_free(gcr_bv);
|
||||
}
|
||||
|
||||
#define L2_PLEN(len) (((len - 1) << 2) | 0x01)
|
||||
|
||||
int bts_asci_notify_nch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf)
|
||||
{
|
||||
struct gsm48_notification_nch *nn = (struct gsm48_notification_nch *) out_buf;
|
||||
const struct asci_notification *notif;
|
||||
unsigned int ro_len;
|
||||
|
||||
notif = bts_asci_notification_get_next(bts);
|
||||
|
||||
*nn = (struct gsm48_notification_nch) {
|
||||
.proto_discr = GSM48_PDISC_RR,
|
||||
.msg_type = GSM48_MT_RR_NOTIF_NCH,
|
||||
};
|
||||
|
||||
nn->l2_plen = L2_PLEN(nn->data - out_buf);
|
||||
|
||||
/* Pad remaining octets with constant '2B'O */
|
||||
ro_len = GSM_MACBLOCK_LEN - (nn->data - out_buf);
|
||||
memset(nn->data, GSM_MACBLOCK_PADDING, ro_len);
|
||||
|
||||
struct bitvec bv = {
|
||||
.data_len = ro_len,
|
||||
.data = nn->data,
|
||||
};
|
||||
|
||||
/* {0 | 1 < NLN(NCH) : bit (2) >}
|
||||
* Only send NLN, at the last notifications.
|
||||
* When the phone receives two NLN with the same value, it knows that all notifications has been received.
|
||||
* Also send NLN if no notification is available. */
|
||||
if (bts->asci.notification_count >= bts->asci.notification_entries - 1) {
|
||||
bitvec_set_bit(&bv, 1);
|
||||
bitvec_set_uint(&bv, bts->asci.nln, 2);
|
||||
} else {
|
||||
bitvec_set_bit(&bv, 0);
|
||||
}
|
||||
|
||||
/* Count NLN. */
|
||||
if (++bts->asci.notification_count >= bts->asci.notification_entries)
|
||||
bts->asci.notification_count = 0;
|
||||
|
||||
/* < List of Group Call NCH information > ::=
|
||||
* { 0 | 1 < Group Call information > < List of Group Call NCH information > } ; */
|
||||
if (notif) {
|
||||
bitvec_set_bit(&bv, 1);
|
||||
append_group_call_information(&bv, notif->group_call_ref,
|
||||
notif->chan_desc.present ? notif->chan_desc.value : NULL,
|
||||
notif->chan_desc.len);
|
||||
}
|
||||
bitvec_set_bit(&bv, 0); /* End of list */
|
||||
|
||||
/* TODO: Additions in Release 6 */
|
||||
/* TODO: Additions in Release 7 */
|
||||
|
||||
return GSM_MACBLOCK_LEN;
|
||||
}
|
||||
|
||||
int bts_asci_notify_facch_gen_msg(struct gsm_bts *bts, uint8_t *out_buf, const uint8_t *group_call_ref,
|
||||
const uint8_t *chan_desc, uint8_t chan_desc_len)
|
||||
{
|
||||
struct gsm48_hdr_sh *sh = (struct gsm48_hdr_sh *) out_buf;
|
||||
unsigned int ro_len;
|
||||
|
||||
*sh = (struct gsm48_hdr_sh) {
|
||||
.rr_short_pd = GSM48_PDISC_SH_RR,
|
||||
.msg_type = GSM48_MT_RR_SH_FACCH,
|
||||
.l2_header = 0,
|
||||
};
|
||||
|
||||
/* Pad remaining octets with constant '2B'O */
|
||||
ro_len = GSM_MACBLOCK_LEN - (sh->data - out_buf);
|
||||
memset(sh->data, GSM_MACBLOCK_PADDING, ro_len);
|
||||
|
||||
struct bitvec bv = {
|
||||
.data_len = ro_len,
|
||||
.data = sh->data,
|
||||
};
|
||||
|
||||
/* 0 < Group Call information > */
|
||||
bitvec_set_bit(&bv, 0);
|
||||
append_group_call_information(&bv, group_call_ref, chan_desc, chan_desc_len);
|
||||
|
||||
/* TODO: Additions in Release 6 */
|
||||
/* TODO: Additions in Release 7 */
|
||||
|
||||
return GSM_MACBLOCK_LEN;
|
||||
}
|
||||
1088
src/common/oml.c
1088
src/common/oml.c
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/* Osmux related routines & logic */
|
||||
|
||||
/* (C) 2022 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
|
||||
@@ -43,13 +43,14 @@
|
||||
#include <osmo-bts/paging.h>
|
||||
#include <osmo-bts/signal.h>
|
||||
#include <osmo-bts/pcu_if.h>
|
||||
#include <osmo-bts/notification.h>
|
||||
|
||||
#define MAX_PAGING_BLOCKS_CCCH 9
|
||||
#define MAX_BS_PA_MFRMS 9
|
||||
|
||||
enum paging_record_type {
|
||||
PAGING_RECORD_PAGING,
|
||||
PAGING_RECORD_IMM_ASS
|
||||
PAGING_RECORD_NORMAL,
|
||||
PAGING_RECORD_MACBLOCK
|
||||
};
|
||||
|
||||
struct paging_record {
|
||||
@@ -60,10 +61,12 @@ struct paging_record {
|
||||
time_t expiration_time;
|
||||
uint8_t chan_needed;
|
||||
uint8_t identity_lv[9];
|
||||
} paging;
|
||||
} normal;
|
||||
struct {
|
||||
uint8_t msg[GSM_MACBLOCK_LEN];
|
||||
} imm_ass;
|
||||
bool confirm;
|
||||
uint32_t msg_id; /* used as identifier for confirmation */
|
||||
} macblock;
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -88,9 +91,9 @@ struct paging_state {
|
||||
|
||||
/* The prioritization of cs pagings is controlled by a hysteresis. When the
|
||||
* fill state of the paging queue exceeds the upper fill level
|
||||
* THRESHOLD_CONGESTED [%], then PS pagings (immediate assignments) will be
|
||||
* dropped until fill state of the paging queue drops under the lower fill
|
||||
* level THRESHOLD_CLEAR [%]. */
|
||||
* THRESHOLD_CONGESTED [%], then PS pagings (immediate assignments and pagings
|
||||
* from the PCU) will be dropped until fill state of the paging queue drops
|
||||
* under the lower fill level THRESHOLD_CLEAR [%]. */
|
||||
#define THRESHOLD_CONGESTED 66 /* (percent of num_paging_max) */
|
||||
#define THRESHOLD_CLEAR 50 /* (percent of num_paging_max) */
|
||||
|
||||
@@ -230,13 +233,13 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
|
||||
|
||||
/* Check if we already have this identity */
|
||||
llist_for_each_entry(pr, group_q, list) {
|
||||
if (pr->type != PAGING_RECORD_PAGING)
|
||||
if (pr->type != PAGING_RECORD_NORMAL)
|
||||
continue;
|
||||
if (identity_lv[0] == pr->u.paging.identity_lv[0] &&
|
||||
!memcmp(identity_lv+1, pr->u.paging.identity_lv+1,
|
||||
if (identity_lv[0] == pr->u.normal.identity_lv[0] &&
|
||||
!memcmp(identity_lv+1, pr->u.normal.identity_lv+1,
|
||||
identity_lv[0])) {
|
||||
LOGP(DPAG, LOGL_INFO, "Ignoring duplicate paging\n");
|
||||
pr->u.paging.expiration_time =
|
||||
pr->u.normal.expiration_time =
|
||||
time(NULL) + ps->paging_lifetime;
|
||||
return -EEXIST;
|
||||
}
|
||||
@@ -245,9 +248,9 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
|
||||
pr = talloc_zero(ps, struct paging_record);
|
||||
if (!pr)
|
||||
return -ENOMEM;
|
||||
pr->type = PAGING_RECORD_PAGING;
|
||||
pr->type = PAGING_RECORD_NORMAL;
|
||||
|
||||
if (*identity_lv + 1 > sizeof(pr->u.paging.identity_lv)) {
|
||||
if (*identity_lv + 1 > sizeof(pr->u.normal.identity_lv)) {
|
||||
talloc_free(pr);
|
||||
return -E2BIG;
|
||||
}
|
||||
@@ -255,9 +258,9 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
|
||||
LOGP(DPAG, LOGL_INFO, "Add paging to queue (group=%u, queue_len=%u)\n",
|
||||
paging_group, ps->num_paging+1);
|
||||
|
||||
pr->u.paging.expiration_time = time(NULL) + ps->paging_lifetime;
|
||||
pr->u.paging.chan_needed = chan_needed;
|
||||
memcpy(&pr->u.paging.identity_lv, identity_lv, identity_lv[0]+1);
|
||||
pr->u.normal.expiration_time = time(NULL) + ps->paging_lifetime;
|
||||
pr->u.normal.chan_needed = chan_needed;
|
||||
memcpy(&pr->u.normal.identity_lv, identity_lv, identity_lv[0]+1);
|
||||
|
||||
/* enqueue the new identity to the HEAD of the queue,
|
||||
* to ensure it will be paged quickly at least once. */
|
||||
@@ -267,13 +270,35 @@ int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add an IMM.ASS message to the paging queue */
|
||||
int paging_add_imm_ass(struct paging_state *ps,
|
||||
const uint8_t *data, uint8_t len)
|
||||
/* Convert the last three digits of a given IMSI string to their decimal representation. In case the given IMSI string
|
||||
* is shorter than three or zero digits, it will be assumed as "000" */
|
||||
static uint16_t convert_imsi_to_decimal(const char *imsi)
|
||||
{
|
||||
uint16_t _imsi;
|
||||
size_t imsi_len = strlen(imsi);
|
||||
|
||||
/* Tha paging group is calculated from the last three digits of the IMSI */
|
||||
if (imsi_len < 3) {
|
||||
LOGP(DPAG, LOGL_ERROR, "short IMSI (%zu digits), will assume \"000\" to calculate paging group\n", imsi_len);
|
||||
_imsi = 0;
|
||||
} else {
|
||||
imsi = imsi + imsi_len - 3;
|
||||
_imsi = 100 * ((*(imsi++)) - '0');
|
||||
_imsi += 10 * ((*(imsi++)) - '0');
|
||||
_imsi += (*(imsi++)) - '0';
|
||||
}
|
||||
|
||||
return _imsi;
|
||||
}
|
||||
|
||||
/* Add a ready formatted MAC block message to the paging queue, this can be an IMMEDIATE ASSIGNMENT, or a
|
||||
* PAGING COMMAND (from the PCU) */
|
||||
int paging_add_macblock(struct paging_state *ps, uint32_t msg_id, const char *imsi, bool confirm, const uint8_t *macblock)
|
||||
{
|
||||
struct llist_head *group_q;
|
||||
struct paging_record *pr;
|
||||
uint16_t imsi, paging_group;
|
||||
uint16_t paging_group;
|
||||
uint16_t _imsi;
|
||||
|
||||
check_congestion(ps);
|
||||
|
||||
@@ -284,27 +309,20 @@ int paging_add_imm_ass(struct paging_state *ps,
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
if (len != GSM_MACBLOCK_LEN + 3) {
|
||||
LOGP(DPAG, LOGL_ERROR, "IMM.ASS invalid length %d\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
len -= 3;
|
||||
|
||||
imsi = 100 * ((*(data++)) - '0');
|
||||
imsi += 10 * ((*(data++)) - '0');
|
||||
imsi += (*(data++)) - '0';
|
||||
paging_group = gsm0502_calc_paging_group(&ps->chan_desc, imsi);
|
||||
|
||||
_imsi = convert_imsi_to_decimal(imsi);
|
||||
paging_group = gsm0502_calc_paging_group(&ps->chan_desc, _imsi);
|
||||
group_q = &ps->paging_queue[paging_group];
|
||||
|
||||
pr = talloc_zero(ps, struct paging_record);
|
||||
if (!pr)
|
||||
return -ENOMEM;
|
||||
pr->type = PAGING_RECORD_IMM_ASS;
|
||||
pr->type = PAGING_RECORD_MACBLOCK;
|
||||
|
||||
LOGP(DPAG, LOGL_INFO, "Add IMM.ASS to queue (group=%u)\n",
|
||||
LOGP(DPAG, LOGL_INFO, "Add MAC block to paging queue (group=%u)\n",
|
||||
paging_group);
|
||||
memcpy(pr->u.imm_ass.msg, data, GSM_MACBLOCK_LEN);
|
||||
memcpy(pr->u.macblock.msg, macblock, GSM_MACBLOCK_LEN);
|
||||
pr->u.macblock.confirm = confirm;
|
||||
pr->u.macblock.msg_id = msg_id;
|
||||
|
||||
/* enqueue the new message to the HEAD of the queue */
|
||||
llist_add(&pr->list, group_q);
|
||||
@@ -314,22 +332,6 @@ int paging_add_imm_ass(struct paging_state *ps,
|
||||
|
||||
#define L2_PLEN(len) (((len - 1) << 2) | 0x01)
|
||||
|
||||
/* abstract representation of P1 rest octets; we only implement those parts we need for now */
|
||||
struct p1_rest_octets {
|
||||
bool packet_page_ind[2];
|
||||
bool r8_present;
|
||||
struct {
|
||||
bool prio_ul_access;
|
||||
bool etws_present;
|
||||
struct {
|
||||
bool is_first;
|
||||
uint8_t page_nr;
|
||||
const uint8_t *page;
|
||||
size_t page_bytes;
|
||||
} etws;
|
||||
} r8;
|
||||
};
|
||||
|
||||
/* 3GPP TS 44.018 10.5.2.23 append a segment/page of an ETWS primary notification to given bitvec */
|
||||
static void append_etws_prim_notif(struct bitvec *bv, bool is_first, uint8_t page_nr,
|
||||
const uint8_t *etws, ssize_t etws_len)
|
||||
@@ -356,13 +358,27 @@ static void append_etws_prim_notif(struct bitvec *bv, bool is_first, uint8_t pag
|
||||
}
|
||||
|
||||
/* 3GPP TS 44.018 10.5.2.23 append P1 Rest Octets to given bit-vector */
|
||||
static void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets *p1ro)
|
||||
void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets *p1ro,
|
||||
const struct asci_notification *notif)
|
||||
{
|
||||
/* Paging 1 RO (at least 10 bits before ETWS struct) */
|
||||
bitvec_set_bit(bv, L); /* no NLN */
|
||||
if (p1ro->nln_pch.present) {
|
||||
bitvec_set_bit(bv, H);
|
||||
bitvec_set_uint(bv, p1ro->nln_pch.nln, 2);
|
||||
bitvec_set_uint(bv, p1ro->nln_pch.nln_status, 1);
|
||||
} else {
|
||||
bitvec_set_bit(bv, L); /* no NLN */
|
||||
}
|
||||
bitvec_set_bit(bv, L); /* no Priority1 */
|
||||
bitvec_set_bit(bv, L); /* no Priority2 */
|
||||
bitvec_set_bit(bv, L); /* no Group Call Info */
|
||||
if (notif) {
|
||||
bitvec_set_bit(bv, H); /* Group Call Info */
|
||||
append_group_call_information(bv, notif->group_call_ref,
|
||||
notif->chan_desc.present ? notif->chan_desc.value : NULL,
|
||||
notif->chan_desc.len);
|
||||
} else {
|
||||
bitvec_set_bit(bv, L); /* no Group Call Info */
|
||||
}
|
||||
if (p1ro->packet_page_ind[0])
|
||||
bitvec_set_bit(bv, H); /* Packet Page Indication 1 */
|
||||
else
|
||||
@@ -387,9 +403,53 @@ static void append_p1_rest_octets(struct bitvec *bv, const struct p1_rest_octets
|
||||
}
|
||||
}
|
||||
|
||||
/* 3GPP TS 44.018 10.5.2.24 append P2 Rest Octets to given bit-vector */
|
||||
void append_p2_rest_octets(struct bitvec *bv, const struct p2_rest_octets *p2ro)
|
||||
{
|
||||
/* {L | H <CN3: bit (2)>} */
|
||||
if (p2ro->cneed.present) {
|
||||
bitvec_set_bit(bv, H);
|
||||
bitvec_set_uint(bv, p2ro->cneed.cn3, 2);
|
||||
} else
|
||||
bitvec_set_bit(bv, L); /* no CN3 */
|
||||
|
||||
/* {L | H < NLN(PCH) : bit (2) <NLN status(PCH) : bit>} */
|
||||
if (p2ro->nln_pch.present) {
|
||||
bitvec_set_bit(bv, H);
|
||||
bitvec_set_uint(bv, p2ro->nln_pch.nln, 2);
|
||||
bitvec_set_uint(bv, p2ro->nln_pch.nln_status, 1);
|
||||
} else
|
||||
bitvec_set_bit(bv, L); /* no NLN */
|
||||
|
||||
/* Note: If this needs to be extended in the future, check if it actually fits into rest of P2! */
|
||||
}
|
||||
|
||||
/* 3GPP TS 44.018 10.5.2.25 append P3 Rest Octets to given bit-vector */
|
||||
void append_p3_rest_octets(struct bitvec *bv, const struct p3_rest_octets *p3ro)
|
||||
{
|
||||
/* {L | H <CN3: bit (2)> <CN3: bit (2)>} */
|
||||
if (p3ro->cneed.present) {
|
||||
bitvec_set_bit(bv, H);
|
||||
bitvec_set_uint(bv, p3ro->cneed.cn3, 2);
|
||||
bitvec_set_uint(bv, p3ro->cneed.cn4, 2);
|
||||
} else
|
||||
bitvec_set_bit(bv, L); /* no CN3/CN4 */
|
||||
|
||||
/* {L | H < NLN(PCH) : bit (2) <NLN status(PCH) : bit>} */
|
||||
if (p3ro->nln_pch.present) {
|
||||
bitvec_set_bit(bv, H);
|
||||
bitvec_set_uint(bv, p3ro->nln_pch.nln, 2);
|
||||
bitvec_set_uint(bv, p3ro->nln_pch.nln_status, 1);
|
||||
} else
|
||||
bitvec_set_bit(bv, L); /* no NLN */
|
||||
|
||||
/* Note: If this needs to be extended in the future, check if it actually fits into 3 octets! */
|
||||
}
|
||||
|
||||
static int fill_paging_type_1(uint8_t *out_buf, const uint8_t *identity1_lv,
|
||||
uint8_t chan1, const uint8_t *identity2_lv,
|
||||
uint8_t chan2, const struct p1_rest_octets *p1ro)
|
||||
uint8_t chan2, const struct p1_rest_octets *p1ro,
|
||||
const struct asci_notification *notif)
|
||||
{
|
||||
struct gsm48_paging1 *pt1 = (struct gsm48_paging1 *) out_buf;
|
||||
unsigned int ro_len;
|
||||
@@ -420,7 +480,7 @@ static int fill_paging_type_1(uint8_t *out_buf, const uint8_t *identity1_lv,
|
||||
.data = cur,
|
||||
};
|
||||
|
||||
append_p1_rest_octets(&bv, p1ro);
|
||||
append_p1_rest_octets(&bv, p1ro, notif);
|
||||
}
|
||||
|
||||
return GSM_MACBLOCK_LEN;
|
||||
@@ -428,10 +488,12 @@ static int fill_paging_type_1(uint8_t *out_buf, const uint8_t *identity1_lv,
|
||||
|
||||
static int fill_paging_type_2(uint8_t *out_buf, const uint8_t *tmsi1_lv,
|
||||
uint8_t cneed1, const uint8_t *tmsi2_lv,
|
||||
uint8_t cneed2, const uint8_t *identity3_lv)
|
||||
uint8_t cneed2, const uint8_t *identity3_lv,
|
||||
const struct p2_rest_octets *p2ro)
|
||||
{
|
||||
struct gsm48_paging2 *pt2 = (struct gsm48_paging2 *) out_buf;
|
||||
uint32_t tmsi;
|
||||
unsigned int ro_len;
|
||||
uint8_t *cur;
|
||||
int rc;
|
||||
|
||||
@@ -455,16 +517,32 @@ static int fill_paging_type_2(uint8_t *out_buf, const uint8_t *tmsi1_lv,
|
||||
|
||||
pt2->l2_plen = L2_PLEN(cur - out_buf);
|
||||
|
||||
return cur - out_buf;
|
||||
/* Pad remaining octets with constant '2B'O */
|
||||
ro_len = GSM_MACBLOCK_LEN - (cur - out_buf);
|
||||
memset(cur, GSM_MACBLOCK_PADDING, ro_len);
|
||||
|
||||
/* Optional P2 Rest Octets */
|
||||
if (p2ro) {
|
||||
struct bitvec bv = {
|
||||
.data_len = ro_len,
|
||||
.data = cur,
|
||||
};
|
||||
|
||||
append_p2_rest_octets(&bv, p2ro);
|
||||
}
|
||||
|
||||
return GSM_MACBLOCK_LEN;
|
||||
}
|
||||
|
||||
static int fill_paging_type_3(uint8_t *out_buf, const uint8_t *tmsi1_lv, uint8_t cneed1,
|
||||
const uint8_t *tmsi2_lv, uint8_t cneed2,
|
||||
const uint8_t *tmsi3_lv, uint8_t cneed3,
|
||||
const uint8_t *tmsi4_lv, uint8_t cneed4)
|
||||
const uint8_t *tmsi3_lv, const uint8_t *tmsi4_lv,
|
||||
const struct p3_rest_octets *p3ro)
|
||||
{
|
||||
struct gsm48_paging3 *pt3 = (struct gsm48_paging3 *) out_buf;
|
||||
uint32_t tmsi;
|
||||
unsigned int ro_len;
|
||||
uint8_t *cur;
|
||||
int rc;
|
||||
|
||||
memset(out_buf, 0, sizeof(*pt3));
|
||||
@@ -486,13 +564,25 @@ static int fill_paging_type_3(uint8_t *out_buf, const uint8_t *tmsi1_lv, uint8_t
|
||||
rc = tmsi_mi_to_uint(&tmsi, tmsi4_lv);
|
||||
if (rc == 0)
|
||||
pt3->tmsi4 = tmsi;
|
||||
cur = out_buf + 20; /* Cannot use sizeof(*pt3), because it has more octets. */
|
||||
|
||||
/* The structure definition in libosmocore is wrong. It includes as last
|
||||
* byte some invalid definition of chneed3/chneed4, so we must do this by hand
|
||||
* here and cannot rely on sizeof(*pt3) */
|
||||
out_buf[20] = (0x23 & ~0xf8) | 0x80 | (cneed3 & 3) << 5 | (cneed4 & 3) << 3;
|
||||
pt3->l2_plen = L2_PLEN(cur - out_buf);
|
||||
|
||||
return 21;
|
||||
/* Pad remaining octets with constant '2B'O */
|
||||
ro_len = GSM_MACBLOCK_LEN - (cur - out_buf);
|
||||
memset(cur, GSM_MACBLOCK_PADDING, ro_len);
|
||||
|
||||
/* Optional P3 Rest Octets */
|
||||
if (p3ro) {
|
||||
struct bitvec bv = {
|
||||
.data_len = ro_len,
|
||||
.data = cur,
|
||||
};
|
||||
|
||||
append_p3_rest_octets(&bv, p3ro);
|
||||
}
|
||||
|
||||
return GSM_MACBLOCK_LEN;
|
||||
}
|
||||
|
||||
static const uint8_t empty_id_lv[] = { 0x01, 0xF0 };
|
||||
@@ -509,7 +599,7 @@ static struct paging_record *dequeue_pr(struct llist_head *group_q)
|
||||
|
||||
static int pr_is_imsi(struct paging_record *pr)
|
||||
{
|
||||
if ((pr->u.paging.identity_lv[1] & 7) == GSM_MI_TYPE_IMSI)
|
||||
if ((pr->u.normal.identity_lv[1] & 7) == GSM_MI_TYPE_IMSI)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
@@ -538,6 +628,7 @@ static void sort_pr_tmsi_imsi(struct paging_record *pr[], unsigned int n)
|
||||
static void build_p1_rest_octets(struct p1_rest_octets *p1ro, struct gsm_bts *bts)
|
||||
{
|
||||
memset(p1ro, 0, sizeof(*p1ro));
|
||||
p1ro->nln_pch.present = false;
|
||||
p1ro->packet_page_ind[0] = false;
|
||||
p1ro->packet_page_ind[1] = false;
|
||||
p1ro->r8_present = true;
|
||||
@@ -590,16 +681,24 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
|
||||
if (ps->bts->etws.prim_notif) {
|
||||
struct p1_rest_octets p1ro;
|
||||
build_p1_rest_octets(&p1ro, bts);
|
||||
len = fill_paging_type_1(out_buf, empty_id_lv, 0, NULL, 0, &p1ro);
|
||||
/* we intentioanally don't try to add notifications here, as ETWS is more critical */
|
||||
len = fill_paging_type_1(out_buf, empty_id_lv, 0, NULL, 0, &p1ro, NULL);
|
||||
} else if (llist_empty(group_q)) {
|
||||
struct p1_rest_octets p1ro;
|
||||
memset(&p1ro, 0, sizeof(p1ro));
|
||||
/* Use NLN to notify MS about ongoing VGCS/VBS calls.
|
||||
* This is required to make the phone read the NCH to get an updated list of ongoing calls.
|
||||
* Without this the phone will not allow making VGCS/VBS calls. */
|
||||
p1ro.nln_pch.present = (bts->asci.pos_nch >= 0);
|
||||
p1ro.nln_pch.nln = bts->asci.nln;
|
||||
p1ro.nln_pch.nln_status = bts->asci.nln_status;
|
||||
/* There is nobody to be paged, send Type1 with two empty ID */
|
||||
//DEBUGP(DPAG, "Tx PAGING TYPE 1 (empty)\n");
|
||||
len = fill_paging_type_1(out_buf, empty_id_lv, 0,
|
||||
NULL, 0, NULL);
|
||||
len = fill_paging_type_1(out_buf, empty_id_lv, 0, NULL, 0, &p1ro, NULL);
|
||||
*is_empty = 1;
|
||||
} else {
|
||||
struct paging_record *pr[4];
|
||||
unsigned int num_pr = 0, imm_ass = 0;
|
||||
unsigned int num_pr = 0, macblock = 0;
|
||||
time_t now = time(NULL);
|
||||
unsigned int i, num_imsi = 0;
|
||||
|
||||
@@ -611,9 +710,9 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
|
||||
break;
|
||||
pr[i] = dequeue_pr(group_q);
|
||||
|
||||
/* check for IMM.ASS */
|
||||
if (pr[i]->type == PAGING_RECORD_IMM_ASS) {
|
||||
imm_ass = 1;
|
||||
/* check for MAC block */
|
||||
if (pr[i]->type == PAGING_RECORD_MACBLOCK) {
|
||||
macblock = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -624,17 +723,18 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
|
||||
num_imsi++;
|
||||
}
|
||||
|
||||
/* if we have an IMMEDIATE ASSIGNMENT */
|
||||
if (imm_ass) {
|
||||
/* re-add paging records */
|
||||
/* Handle MAC block (from the PCU) */
|
||||
if (macblock) {
|
||||
/* re-add normal paging records */
|
||||
for (i = 0; i < num_pr; i++)
|
||||
llist_add(&pr[i]->list, group_q);
|
||||
|
||||
/* get message and free record */
|
||||
memcpy(out_buf, pr[num_pr]->u.imm_ass.msg,
|
||||
GSM_MACBLOCK_LEN);
|
||||
pcu_tx_pch_data_cnf(gt->fn, pr[num_pr]->u.imm_ass.msg,
|
||||
/* get MAC block message and free record */
|
||||
memcpy(out_buf, pr[num_pr]->u.macblock.msg,
|
||||
GSM_MACBLOCK_LEN);
|
||||
/* send a confirmation back (if required) */
|
||||
if (pr[num_pr]->u.macblock.confirm)
|
||||
pcu_tx_data_cnf(pr[num_pr]->u.macblock.msg_id, PCU_IF_SAPI_PCH_2);
|
||||
talloc_free(pr[num_pr]);
|
||||
return GSM_MACBLOCK_LEN;
|
||||
}
|
||||
@@ -645,24 +745,39 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
|
||||
if (num_pr == 4 && num_imsi == 0) {
|
||||
/* No IMSI: easy case, can use TYPE 3 */
|
||||
DEBUGP(DPAG, "Tx PAGING TYPE 3 (4 TMSI)\n");
|
||||
struct p3_rest_octets p3ro;
|
||||
memset(&p3ro, 0, sizeof(p3ro));
|
||||
p3ro.cneed.present = true;
|
||||
p3ro.cneed.cn3 = pr[2]->u.normal.chan_needed;
|
||||
p3ro.cneed.cn4 = pr[3]->u.normal.chan_needed;
|
||||
p3ro.nln_pch.present = (bts->asci.pos_nch >= 0);
|
||||
p3ro.nln_pch.nln = bts->asci.nln;
|
||||
p3ro.nln_pch.nln_status = bts->asci.nln_status;
|
||||
len = fill_paging_type_3(out_buf,
|
||||
pr[0]->u.paging.identity_lv,
|
||||
pr[0]->u.paging.chan_needed,
|
||||
pr[1]->u.paging.identity_lv,
|
||||
pr[1]->u.paging.chan_needed,
|
||||
pr[2]->u.paging.identity_lv,
|
||||
pr[2]->u.paging.chan_needed,
|
||||
pr[3]->u.paging.identity_lv,
|
||||
pr[3]->u.paging.chan_needed);
|
||||
pr[0]->u.normal.identity_lv,
|
||||
pr[0]->u.normal.chan_needed,
|
||||
pr[1]->u.normal.identity_lv,
|
||||
pr[1]->u.normal.chan_needed,
|
||||
pr[2]->u.normal.identity_lv,
|
||||
pr[3]->u.normal.identity_lv,
|
||||
&p3ro);
|
||||
} else if (num_pr >= 3 && num_imsi <= 1) {
|
||||
/* 3 or 4, of which only up to 1 is IMSI */
|
||||
DEBUGP(DPAG, "Tx PAGING TYPE 2 (2 TMSI,1 xMSI)\n");
|
||||
struct p2_rest_octets p2ro;
|
||||
memset(&p2ro, 0, sizeof(p2ro));
|
||||
p2ro.cneed.present = true;
|
||||
p2ro.cneed.cn3 = pr[2]->u.normal.chan_needed;
|
||||
p2ro.nln_pch.present = (bts->asci.pos_nch >= 0);
|
||||
p2ro.nln_pch.nln = bts->asci.nln;
|
||||
p2ro.nln_pch.nln_status = bts->asci.nln_status;
|
||||
len = fill_paging_type_2(out_buf,
|
||||
pr[0]->u.paging.identity_lv,
|
||||
pr[0]->u.paging.chan_needed,
|
||||
pr[1]->u.paging.identity_lv,
|
||||
pr[1]->u.paging.chan_needed,
|
||||
pr[2]->u.paging.identity_lv);
|
||||
pr[0]->u.normal.identity_lv,
|
||||
pr[0]->u.normal.chan_needed,
|
||||
pr[1]->u.normal.identity_lv,
|
||||
pr[1]->u.normal.chan_needed,
|
||||
pr[2]->u.normal.identity_lv,
|
||||
&p2ro);
|
||||
if (num_pr == 4) {
|
||||
/* re-add #4 for next time */
|
||||
llist_add(&pr[3]->list, group_q);
|
||||
@@ -670,19 +785,21 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
|
||||
}
|
||||
} else if (num_pr == 1) {
|
||||
DEBUGP(DPAG, "Tx PAGING TYPE 1 (1 xMSI,1 empty)\n");
|
||||
/* TODO: check if we can include an ASCI notification */
|
||||
len = fill_paging_type_1(out_buf,
|
||||
pr[0]->u.paging.identity_lv,
|
||||
pr[0]->u.paging.chan_needed,
|
||||
NULL, 0, NULL);
|
||||
pr[0]->u.normal.identity_lv,
|
||||
pr[0]->u.normal.chan_needed,
|
||||
NULL, 0, NULL, NULL);
|
||||
} else {
|
||||
/* 2 (any type) or
|
||||
* 3 or 4, of which only 2 will be sent */
|
||||
DEBUGP(DPAG, "Tx PAGING TYPE 1 (2 xMSI)\n");
|
||||
/* TODO: check if we can include an ASCI notification */
|
||||
len = fill_paging_type_1(out_buf,
|
||||
pr[0]->u.paging.identity_lv,
|
||||
pr[0]->u.paging.chan_needed,
|
||||
pr[1]->u.paging.identity_lv,
|
||||
pr[1]->u.paging.chan_needed, NULL);
|
||||
pr[0]->u.normal.identity_lv,
|
||||
pr[0]->u.normal.chan_needed,
|
||||
pr[1]->u.normal.identity_lv,
|
||||
pr[1]->u.normal.chan_needed, NULL, NULL);
|
||||
if (num_pr >= 3) {
|
||||
/* re-add #4 for next time */
|
||||
llist_add(&pr[2]->list, group_q);
|
||||
@@ -702,7 +819,7 @@ int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *g
|
||||
rate_ctr_inc2(bts->ctrs, BTS_CTR_PAGING_SENT);
|
||||
/* check if we can expire the paging record,
|
||||
* or if we need to re-queue it */
|
||||
if (pr[i]->u.paging.expiration_time <= now) {
|
||||
if (pr[i]->u.normal.expiration_time <= now) {
|
||||
talloc_free(pr[i]);
|
||||
ps->num_paging--;
|
||||
LOGP(DPAG, LOGL_INFO, "Removed paging record, queue_len=%u\n",
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/write_queue.h>
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/gsm/abis_nm.h>
|
||||
#include <osmo-bts/logging.h>
|
||||
@@ -38,6 +39,7 @@
|
||||
#include <osmo-bts/pcu_if.h>
|
||||
#include <osmo-bts/pcuif_proto.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/rsl.h>
|
||||
#include <osmo-bts/signal.h>
|
||||
#include <osmo-bts/l1sap.h>
|
||||
@@ -46,18 +48,17 @@
|
||||
|
||||
uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx);
|
||||
|
||||
extern struct gsm_network bts_gsmnet;
|
||||
int pcu_direct = 0;
|
||||
static int avail_lai = 0, avail_nse = 0, avail_cell = 0, avail_nsvc[2] = {0, 0};
|
||||
|
||||
static const char *sapi_string[] = {
|
||||
[PCU_IF_SAPI_RACH] = "RACH",
|
||||
[PCU_IF_SAPI_AGCH] = "AGCH",
|
||||
[PCU_IF_SAPI_PCH] = "PCH",
|
||||
[PCU_IF_SAPI_BCCH] = "BCCH",
|
||||
[PCU_IF_SAPI_PDTCH] = "PDTCH",
|
||||
[PCU_IF_SAPI_PRACH] = "PRACH",
|
||||
[PCU_IF_SAPI_PTCCH] = "PTCCH",
|
||||
[PCU_IF_SAPI_PCH_2] = "PCH_2",
|
||||
[PCU_IF_SAPI_AGCH_2] = "AGCH_2",
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -229,9 +230,27 @@ static void info_ind_fill_trx(struct gsm_pcu_if_info_trx *trx_info,
|
||||
}
|
||||
}
|
||||
|
||||
static enum gsm_pcuif_bts_model bts_model_from_variant(enum gsm_bts_type_variant variant)
|
||||
{
|
||||
switch (variant) {
|
||||
case BTS_OSMO_LITECELL15:
|
||||
return PCU_IF_BTS_MODEL_LC15;
|
||||
case BTS_OSMO_OC2G:
|
||||
return PCU_IF_BTS_MODEL_OC2G;
|
||||
case BTS_OSMO_OCTPHY:
|
||||
return PCU_IF_BTS_MODEL_OCTPHY;
|
||||
case BTS_OSMO_SYSMO:
|
||||
return PCU_IF_BTS_MODEL_SYSMO;
|
||||
case BTS_OSMO_TRX:
|
||||
case BTS_OSMO_VIRTUAL:
|
||||
return PCU_IF_BTS_MODEL_TRX;
|
||||
default:
|
||||
return PCU_IF_BTS_MODEL_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
int pcu_tx_info_ind(void)
|
||||
{
|
||||
struct gsm_network *net = &bts_gsmnet;
|
||||
struct msgb *msg;
|
||||
struct gsm_pcu_if *pcu_prim;
|
||||
struct gsm_pcu_if_info_ind *info_ind;
|
||||
@@ -239,11 +258,13 @@ int pcu_tx_info_ind(void)
|
||||
struct gprs_rlc_cfg *rlcc;
|
||||
struct gsm_bts_trx *trx;
|
||||
int i;
|
||||
struct gsm_gprs_nse *nse;
|
||||
|
||||
LOGP(DPCU, LOGL_INFO, "Sending info\n");
|
||||
|
||||
nse = &g_bts_sm->gprs.nse;
|
||||
/* FIXME: allow multiple BTS */
|
||||
bts = llist_entry(net->bts_list.next, struct gsm_bts, list);
|
||||
bts = llist_entry(g_bts_sm->bts_list.next, struct gsm_bts, list);
|
||||
rlcc = &bts->gprs.cell.rlc_cfg;
|
||||
|
||||
msg = pcu_msgb_alloc(PCU_IF_MSG_INFO_IND, bts->nr);
|
||||
@@ -260,19 +281,19 @@ int pcu_tx_info_ind(void)
|
||||
LOGP(DPCU, LOGL_INFO, "BTS is down\n");
|
||||
|
||||
if (pcu_direct)
|
||||
info_ind->flags |= PCU_IF_FLAG_SYSMO;
|
||||
info_ind->flags |= PCU_IF_FLAG_DIRECT_PHY;
|
||||
|
||||
info_ind->bsic = bts->bsic;
|
||||
/* RAI */
|
||||
info_ind->mcc = net->plmn.mcc;
|
||||
info_ind->mnc = net->plmn.mnc;
|
||||
info_ind->mnc_3_digits = net->plmn.mnc_3_digits;
|
||||
info_ind->mcc = g_bts_sm->plmn.mcc;
|
||||
info_ind->mnc = g_bts_sm->plmn.mnc;
|
||||
info_ind->mnc_3_digits = g_bts_sm->plmn.mnc_3_digits;
|
||||
info_ind->lac = bts->location_area_code;
|
||||
info_ind->rac = bts->gprs.rac;
|
||||
|
||||
/* NSE */
|
||||
info_ind->nsei = bts->gprs.nse.nsei;
|
||||
memcpy(info_ind->nse_timer, bts->gprs.nse.timer, 7);
|
||||
info_ind->nsei = nse->nsei;
|
||||
memcpy(info_ind->nse_timer, nse->timer, 7);
|
||||
memcpy(info_ind->cell_timer, bts->gprs.cell.timer, 11);
|
||||
|
||||
/* cell attributes */
|
||||
@@ -323,8 +344,8 @@ int pcu_tx_info_ind(void)
|
||||
info_ind->initial_mcs = rlcc->initial_mcs;
|
||||
|
||||
/* NSVC */
|
||||
for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
|
||||
const struct gsm_bts_gprs_nsvc *nsvc = &bts->gprs.nsvc[i];
|
||||
for (i = 0; i < ARRAY_SIZE(nse->nsvc); i++) {
|
||||
const struct gsm_gprs_nsvc *nsvc = &nse->nsvc[i];
|
||||
info_ind->nsvci[i] = nsvc->nsvci;
|
||||
/* PCUIF beauty: the NSVC addresses are sent in the network byte order,
|
||||
* while the port numbers need to be send in the host order. Sigh. */
|
||||
@@ -350,20 +371,21 @@ int pcu_tx_info_ind(void)
|
||||
LOGPTRX(trx, DPCU, LOGL_NOTICE, "PCU interface (version %u) "
|
||||
"cannot handle more than %zu transceivers => skipped\n",
|
||||
PCU_IF_VERSION, ARRAY_SIZE(info_ind->trx));
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
info_ind_fill_trx(&info_ind->trx[trx->nr], trx);
|
||||
}
|
||||
|
||||
return pcu_sock_send(net, msg);
|
||||
info_ind->bts_model = bts_model_from_variant(bts->variant);
|
||||
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
static int pcu_if_signal_cb(unsigned int subsys, unsigned int signal,
|
||||
void *hdlr_data, void *signal_data)
|
||||
{
|
||||
struct gsm_network *net = &bts_gsmnet;
|
||||
struct gsm_bts_gprs_nsvc *nsvc;
|
||||
struct gsm_gprs_nsvc *nsvc;
|
||||
struct gsm_bts *bts;
|
||||
struct gsm48_system_information_type_3 *si3;
|
||||
int id;
|
||||
@@ -378,7 +400,7 @@ static int pcu_if_signal_cb(unsigned int subsys, unsigned int signal,
|
||||
break;
|
||||
si3 = (struct gsm48_system_information_type_3 *)
|
||||
bts->si_buf[SYSINFO_TYPE_3];
|
||||
osmo_plmn_from_bcd(si3->lai.digits, &net->plmn);
|
||||
osmo_plmn_from_bcd(si3->lai.digits, &g_bts_sm->plmn);
|
||||
bts->location_area_code = ntohs(si3->lai.lac);
|
||||
bts->cell_identity = ntohs(si3->cell_identity);
|
||||
avail_lai = 1;
|
||||
@@ -434,7 +456,7 @@ int pcu_tx_app_info_req(struct gsm_bts *bts, uint8_t app_type, uint8_t len, cons
|
||||
ai_req->len = len;
|
||||
memcpy(ai_req->data, app_data, ai_req->len);
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
int pcu_tx_rts_req(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn,
|
||||
@@ -461,7 +483,7 @@ int pcu_tx_rts_req(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn,
|
||||
rts_req->ts_nr = ts->nr;
|
||||
rts_req->block_nr = block_nr;
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t sapi, uint32_t fn,
|
||||
@@ -496,7 +518,7 @@ int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t sapi, uint32_t fn,
|
||||
memcpy(data_ind->data, data, len);
|
||||
data_ind->len = len;
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
int pcu_tx_rach_ind(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
|
||||
@@ -525,7 +547,7 @@ int pcu_tx_rach_ind(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
|
||||
rach_ind->trx_nr = trx_nr;
|
||||
rach_ind->ts_nr = ts_nr;
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
int pcu_tx_time_ind(uint32_t fn)
|
||||
@@ -547,7 +569,7 @@ int pcu_tx_time_ind(uint32_t fn)
|
||||
|
||||
time_ind->fn = fn;
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
int pcu_tx_interf_ind(const struct gsm_bts_trx *trx, uint32_t fn)
|
||||
@@ -580,12 +602,12 @@ int pcu_tx_interf_ind(const struct gsm_bts_trx *trx, uint32_t fn)
|
||||
interf_ind->interf[tn] = -1 * lchan->meas.interf_meas_avg_dbm;
|
||||
}
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed)
|
||||
{
|
||||
struct pcu_sock_state *state = bts_gsmnet.pcu_state;
|
||||
struct pcu_sock_state *state = g_bts_sm->gprs.pcu_state;
|
||||
struct msgb *msg;
|
||||
struct gsm_pcu_if *pcu_prim;
|
||||
struct gsm_pcu_if_pag_req *pag_req;
|
||||
@@ -613,34 +635,31 @@ int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed)
|
||||
pag_req->chan_needed = chan_needed;
|
||||
memcpy(pag_req->identity_lv, identity_lv, identity_lv[0] + 1);
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len)
|
||||
int pcu_tx_data_cnf(uint32_t msg_id, uint8_t sapi)
|
||||
{
|
||||
struct gsm_network *net = &bts_gsmnet;
|
||||
struct gsm_bts *bts;
|
||||
struct msgb *msg;
|
||||
struct gsm_pcu_if *pcu_prim;
|
||||
struct gsm_pcu_if_data *data_cnf;
|
||||
|
||||
/* FIXME: allow multiple BTS */
|
||||
bts = llist_entry(net->bts_list.next, struct gsm_bts, list);
|
||||
bts = llist_entry(g_bts_sm->bts_list.next, struct gsm_bts, list);
|
||||
|
||||
LOGP(DPCU, LOGL_DEBUG, "Sending PCH confirm\n");
|
||||
LOGP(DPCU, LOGL_DEBUG, "Sending DATA.cnf: sapi=%s msg_id=%08x\n",
|
||||
sapi_string[sapi], msg_id);
|
||||
|
||||
msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_CNF, bts->nr);
|
||||
msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_CNF_2, bts->nr);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
pcu_prim = (struct gsm_pcu_if *) msg->data;
|
||||
data_cnf = &pcu_prim->u.data_cnf;
|
||||
pcu_prim->u.data_cnf2 = (struct gsm_pcu_if_data_cnf) {
|
||||
.sapi = sapi,
|
||||
.msg_id = msg_id,
|
||||
};
|
||||
|
||||
data_cnf->sapi = PCU_IF_SAPI_PCH;
|
||||
data_cnf->fn = fn;
|
||||
memcpy(data_cnf->data, data, len);
|
||||
data_cnf->len = len;
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
/* forward data from a RR GPRS SUSPEND REQ towards PCU */
|
||||
@@ -657,7 +676,7 @@ int pcu_tx_susp_req(struct gsm_lchan *lchan, uint32_t tlli, const uint8_t *ra_id
|
||||
memcpy(pcu_prim->u.susp_req.ra_id, ra_id, sizeof(pcu_prim->u.susp_req.ra_id));
|
||||
pcu_prim->u.susp_req.cause = cause;
|
||||
|
||||
return pcu_sock_send(&bts_gsmnet, msg);
|
||||
return pcu_sock_send(msg);
|
||||
}
|
||||
|
||||
static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type,
|
||||
@@ -675,22 +694,45 @@ static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type,
|
||||
osmo_hexdump(data_req->data, data_req->len));
|
||||
|
||||
switch (data_req->sapi) {
|
||||
case PCU_IF_SAPI_PCH:
|
||||
paging_add_imm_ass(bts->paging_state, data_req->data, data_req->len);
|
||||
case PCU_IF_SAPI_PCH_2:
|
||||
{
|
||||
const struct gsm_pcu_if_pch *gsm_pcu_if_pch;
|
||||
|
||||
if (OSMO_UNLIKELY(data_req->len != sizeof(*gsm_pcu_if_pch))) {
|
||||
LOGP(DPCU, LOGL_ERROR, "Rx malformed DATA.req for PCH\n");
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
gsm_pcu_if_pch = (struct gsm_pcu_if_pch *)data_req->data;
|
||||
rc = paging_add_macblock(bts->paging_state, gsm_pcu_if_pch->msg_id,
|
||||
gsm_pcu_if_pch->imsi, gsm_pcu_if_pch->confirm, gsm_pcu_if_pch->data);
|
||||
break;
|
||||
case PCU_IF_SAPI_AGCH:
|
||||
msg = msgb_alloc(data_req->len, "pcu_agch");
|
||||
}
|
||||
case PCU_IF_SAPI_AGCH_2:
|
||||
{
|
||||
const struct gsm_pcu_if_agch *gsm_pcu_if_agch;
|
||||
struct bts_agch_msg_cb *msg_cb;
|
||||
|
||||
gsm_pcu_if_agch = (struct gsm_pcu_if_agch *)data_req->data;
|
||||
|
||||
msg = msgb_alloc(GSM_MACBLOCK_LEN, "pcu_agch");
|
||||
if (!msg) {
|
||||
rc = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
msg->l3h = msgb_put(msg, data_req->len);
|
||||
memcpy(msg->l3h, data_req->data, data_req->len);
|
||||
msg->l3h = msgb_put(msg, GSM_MACBLOCK_LEN);
|
||||
memcpy(msg->l3h, gsm_pcu_if_agch->data, GSM_MACBLOCK_LEN);
|
||||
|
||||
msg_cb = (struct bts_agch_msg_cb *) msg->cb;
|
||||
msg_cb->confirm = gsm_pcu_if_agch->confirm;
|
||||
msg_cb->msg_id = gsm_pcu_if_agch->msg_id;
|
||||
if (bts_agch_enqueue(bts, msg) < 0) {
|
||||
msgb_free(msg);
|
||||
rc = -EIO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PCU_IF_SAPI_PDTCH:
|
||||
case PCU_IF_SAPI_PTCCH:
|
||||
trx = gsm_bts_trx_num(bts, data_req->trx_nr);
|
||||
@@ -895,14 +937,13 @@ static int pcu_rx_act_req(struct gsm_bts *bts,
|
||||
return -EINVAL; \
|
||||
} \
|
||||
} while (0)
|
||||
static int pcu_rx(struct gsm_network *net, uint8_t msg_type,
|
||||
struct gsm_pcu_if *pcu_prim, size_t prim_len)
|
||||
static int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim, size_t prim_len)
|
||||
{
|
||||
int rc = 0;
|
||||
struct gsm_bts *bts;
|
||||
size_t exp_len;
|
||||
|
||||
if ((bts = gsm_bts_num(net, pcu_prim->bts_nr)) == NULL) {
|
||||
if ((bts = gsm_bts_num(g_bts_sm, pcu_prim->bts_nr)) == NULL) {
|
||||
LOGP(DPCU, LOGL_ERROR, "Received PCU Prim for non-existent BTS %u\n", pcu_prim->bts_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -949,17 +990,18 @@ static int pcu_rx(struct gsm_network *net, uint8_t msg_type,
|
||||
*/
|
||||
|
||||
struct pcu_sock_state {
|
||||
struct gsm_network *net;
|
||||
struct osmo_fd listen_bfd; /* fd for listen socket */
|
||||
struct osmo_fd conn_bfd; /* fd for connection to lcr */
|
||||
struct llist_head upqueue; /* queue for sending messages */
|
||||
struct osmo_wqueue upqueue; /* For sending messages; has fd for conn. to PCU */
|
||||
};
|
||||
|
||||
int pcu_sock_send(struct gsm_network *net, struct msgb *msg)
|
||||
static void pcu_sock_close(struct pcu_sock_state *state);
|
||||
|
||||
int pcu_sock_send(struct msgb *msg)
|
||||
{
|
||||
struct pcu_sock_state *state = net->pcu_state;
|
||||
struct pcu_sock_state *state = g_bts_sm->gprs.pcu_state;
|
||||
struct osmo_fd *conn_bfd;
|
||||
struct gsm_pcu_if *pcu_prim = (struct gsm_pcu_if *) msg->data;
|
||||
int rc;
|
||||
|
||||
if (!state) {
|
||||
if (pcu_prim->msg_type != PCU_IF_MSG_TIME_IND &&
|
||||
@@ -969,7 +1011,7 @@ int pcu_sock_send(struct gsm_network *net, struct msgb *msg)
|
||||
msgb_free(msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
conn_bfd = &state->conn_bfd;
|
||||
conn_bfd = &state->upqueue.bfd;
|
||||
if (conn_bfd->fd <= 0) {
|
||||
if (pcu_prim->msg_type != PCU_IF_MSG_TIME_IND &&
|
||||
pcu_prim->msg_type != PCU_IF_MSG_INTERF_IND)
|
||||
@@ -978,21 +1020,28 @@ int pcu_sock_send(struct gsm_network *net, struct msgb *msg)
|
||||
msgb_free(msg);
|
||||
return -EIO;
|
||||
}
|
||||
msgb_enqueue(&state->upqueue, msg);
|
||||
osmo_fd_write_enable(conn_bfd);
|
||||
|
||||
rc = osmo_wqueue_enqueue(&state->upqueue, msg);
|
||||
if (rc < 0) {
|
||||
if (rc == -ENOSPC)
|
||||
LOGP(DPCU, LOGL_NOTICE, "PCU not reacting (more than %u messages waiting). Closing connection\n",
|
||||
state->upqueue.max_length);
|
||||
pcu_sock_close(state);
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcu_sock_close(struct pcu_sock_state *state)
|
||||
{
|
||||
struct osmo_fd *bfd = &state->conn_bfd;
|
||||
struct osmo_fd *bfd = &state->upqueue.bfd;
|
||||
struct gsm_bts *bts;
|
||||
struct gsm_bts_trx *trx;
|
||||
unsigned int tn;
|
||||
|
||||
/* FIXME: allow multiple BTS */
|
||||
bts = llist_entry(state->net->bts_list.next, struct gsm_bts, list);
|
||||
bts = llist_entry(g_bts_sm->bts_list.next, struct gsm_bts, list);
|
||||
|
||||
LOGP(DPCU, LOGL_NOTICE, "PCU socket has LOST connection\n");
|
||||
oml_tx_failure_event_rep(&bts->gprs.cell.mo, NM_SEVER_MAJOR, OSMO_EVT_PCU_VERS,
|
||||
@@ -1032,11 +1081,7 @@ static void pcu_sock_close(struct pcu_sock_state *state)
|
||||
}
|
||||
}
|
||||
|
||||
/* flush the queue */
|
||||
while (!llist_empty(&state->upqueue)) {
|
||||
struct msgb *msg = msgb_dequeue(&state->upqueue);
|
||||
msgb_free(msg);
|
||||
}
|
||||
osmo_wqueue_clear(&state->upqueue);
|
||||
}
|
||||
|
||||
static int pcu_sock_read(struct osmo_fd *bfd)
|
||||
@@ -1071,7 +1116,7 @@ static int pcu_sock_read(struct osmo_fd *bfd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = pcu_rx(state->net, pcu_prim->msg_type, pcu_prim, rc);
|
||||
rc = pcu_rx(pcu_prim->msg_type, pcu_prim, rc);
|
||||
|
||||
/* as we always synchronously process the message in pcu_rx() and
|
||||
* its callbacks, we can free the message here. */
|
||||
@@ -1085,59 +1130,34 @@ close:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pcu_sock_write(struct osmo_fd *bfd)
|
||||
static int pcu_sock_write(struct osmo_fd *bfd, struct msgb *msg)
|
||||
{
|
||||
struct pcu_sock_state *state = bfd->data;
|
||||
struct msgb *msg;
|
||||
int rc;
|
||||
|
||||
while ((msg = msgb_dequeue(&state->upqueue))) {
|
||||
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
|
||||
OSMO_ASSERT(msgb_length(msg) > 0);
|
||||
|
||||
/* try to send it over the socket */
|
||||
rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
|
||||
if (OSMO_UNLIKELY(rc == 0))
|
||||
goto close;
|
||||
if (OSMO_UNLIKELY(rc < 0)) {
|
||||
if (errno == EAGAIN) {
|
||||
/* Re-insert at the start of the queue, skip disabling fd WRITE */
|
||||
llist_add(&msg->list, &state->upqueue);
|
||||
return 0;
|
||||
}
|
||||
goto close;
|
||||
}
|
||||
msgb_free(msg);
|
||||
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
|
||||
OSMO_ASSERT(msgb_length(msg) > 0);
|
||||
/* try to send it over the socket */
|
||||
rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
|
||||
if (OSMO_UNLIKELY(rc == 0))
|
||||
goto close;
|
||||
if (OSMO_UNLIKELY(rc < 0)) {
|
||||
if (errno == EAGAIN)
|
||||
return -EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
osmo_fd_write_disable(bfd);
|
||||
return 0;
|
||||
|
||||
close:
|
||||
msgb_free(msg);
|
||||
pcu_sock_close(state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (flags & OSMO_FD_READ)
|
||||
rc = pcu_sock_read(bfd);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (flags & OSMO_FD_WRITE)
|
||||
rc = pcu_sock_write(bfd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* accept connection coming from PCU */
|
||||
static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags)
|
||||
{
|
||||
struct pcu_sock_state *state = (struct pcu_sock_state *)bfd->data;
|
||||
struct osmo_fd *conn_bfd = &state->conn_bfd;
|
||||
struct osmo_fd *conn_bfd = &state->upqueue.bfd;
|
||||
struct sockaddr_un un_addr;
|
||||
socklen_t len;
|
||||
int fd;
|
||||
@@ -1157,7 +1177,7 @@ static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
osmo_fd_setup(conn_bfd, fd, OSMO_FD_READ, pcu_sock_cb, state, 0);
|
||||
osmo_fd_setup(conn_bfd, fd, OSMO_FD_READ, osmo_wqueue_bfd_cb, state, 0);
|
||||
|
||||
if (osmo_fd_register(conn_bfd) != 0) {
|
||||
LOGP(DPCU, LOGL_ERROR, "Failed to register new connection fd\n");
|
||||
@@ -1174,19 +1194,20 @@ static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcu_sock_init(const char *path)
|
||||
int pcu_sock_init(const char *path, int qlength_max)
|
||||
{
|
||||
struct pcu_sock_state *state;
|
||||
struct osmo_fd *bfd;
|
||||
int rc;
|
||||
|
||||
state = talloc_zero(NULL, struct pcu_sock_state);
|
||||
state = talloc_zero(g_bts_sm, struct pcu_sock_state);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LLIST_HEAD(&state->upqueue);
|
||||
state->net = &bts_gsmnet;
|
||||
state->conn_bfd.fd = -1;
|
||||
osmo_wqueue_init(&state->upqueue, qlength_max);
|
||||
state->upqueue.read_cb = pcu_sock_read;
|
||||
state->upqueue.write_cb = pcu_sock_write;
|
||||
state->upqueue.bfd.fd = -1;
|
||||
|
||||
bfd = &state->listen_bfd;
|
||||
|
||||
@@ -1211,39 +1232,38 @@ int pcu_sock_init(const char *path)
|
||||
|
||||
osmo_signal_register_handler(SS_GLOBAL, pcu_if_signal_cb, NULL);
|
||||
|
||||
bts_gsmnet.pcu_state = state;
|
||||
g_bts_sm->gprs.pcu_state = state;
|
||||
|
||||
LOGP(DPCU, LOGL_INFO, "Started listening on PCU socket: %s\n", path);
|
||||
LOGP(DPCU, LOGL_INFO, "Started listening on PCU socket (PCU IF v%u): %s\n", PCU_IF_VERSION, path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pcu_sock_exit(void)
|
||||
{
|
||||
struct pcu_sock_state *state = bts_gsmnet.pcu_state;
|
||||
struct pcu_sock_state *state = g_bts_sm->gprs.pcu_state;
|
||||
struct osmo_fd *bfd, *conn_bfd;
|
||||
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
osmo_signal_unregister_handler(SS_GLOBAL, pcu_if_signal_cb, NULL);
|
||||
conn_bfd = &state->conn_bfd;
|
||||
conn_bfd = &state->upqueue.bfd;
|
||||
if (conn_bfd->fd > 0)
|
||||
pcu_sock_close(state);
|
||||
bfd = &state->listen_bfd;
|
||||
close(bfd->fd);
|
||||
osmo_fd_unregister(bfd);
|
||||
talloc_free(state);
|
||||
bts_gsmnet.pcu_state = NULL;
|
||||
g_bts_sm->gprs.pcu_state = NULL;
|
||||
}
|
||||
|
||||
bool pcu_connected(void) {
|
||||
struct gsm_network *net = &bts_gsmnet;
|
||||
struct pcu_sock_state *state = net->pcu_state;
|
||||
struct pcu_sock_state *state = g_bts_sm->gprs.pcu_state;
|
||||
|
||||
if (!state)
|
||||
return false;
|
||||
if (state->conn_bfd.fd <= 0)
|
||||
if (state->upqueue.bfd.fd <= 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* MS Power Control Loop L1 */
|
||||
|
||||
/* (C) 2014 by Holger Hans Peter Freyther
|
||||
* (C) 2020-2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
* (C) 2020-2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
|
||||
399
src/common/rsl.c
399
src/common/rsl.c
@@ -2,7 +2,7 @@
|
||||
|
||||
/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* (C) 2011-2019 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
@@ -56,6 +56,8 @@
|
||||
#include <osmo-bts/l1sap.h>
|
||||
#include <osmo-bts/bts_model.h>
|
||||
#include <osmo-bts/pcuif_proto.h>
|
||||
#include <osmo-bts/notification.h>
|
||||
#include <osmo-bts/asci.h>
|
||||
|
||||
//#define FAKE_CIPH_MODE_COMPL
|
||||
|
||||
@@ -63,6 +65,31 @@
|
||||
#define BS_POWER2DB(bs_power) \
|
||||
((bs_power & 0x0f) * 2)
|
||||
|
||||
bool rsl_chan_rt_is_asci(enum rsl_cmod_crt chan_rt)
|
||||
{
|
||||
switch (chan_rt) {
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Bm:
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Lm:
|
||||
case RSL_CMOD_CRT_TCH_BCAST_Bm:
|
||||
case RSL_CMOD_CRT_TCH_BCAST_Lm:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool rsl_chan_rt_is_vgcs(enum rsl_cmod_crt chan_rt)
|
||||
{
|
||||
switch (chan_rt) {
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Bm:
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Lm:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int rsl_tx_error_report(struct gsm_bts_trx *trx, uint8_t cause, const uint8_t *chan_nr,
|
||||
const uint8_t *link_id, const struct msgb *orig_msg);
|
||||
|
||||
@@ -112,6 +139,7 @@ static int rsl_handle_chan_mod_ie(struct gsm_lchan *lchan,
|
||||
|
||||
cm = (const struct rsl_ie_chan_mode *) TLVP_VAL(tp, RSL_IE_CHAN_MODE);
|
||||
lchan->rsl_cmode = cm->spd_ind;
|
||||
lchan->rsl_chan_rt = cm->chan_rt;
|
||||
lchan->ts->trx->bts->dtxd = (cm->dtx_dtu & RSL_CMOD_DTXd) ? true : false;
|
||||
|
||||
/* Octet 5: Channel rate and type */
|
||||
@@ -119,6 +147,10 @@ static int rsl_handle_chan_mod_ie(struct gsm_lchan *lchan,
|
||||
case RSL_CMOD_CRT_SDCCH:
|
||||
case RSL_CMOD_CRT_TCH_Bm:
|
||||
case RSL_CMOD_CRT_TCH_Lm:
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Bm:
|
||||
case RSL_CMOD_CRT_TCH_GROUP_Lm:
|
||||
case RSL_CMOD_CRT_TCH_BCAST_Bm:
|
||||
case RSL_CMOD_CRT_TCH_BCAST_Lm:
|
||||
break;
|
||||
case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm:
|
||||
case RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm:
|
||||
@@ -207,32 +239,50 @@ static int rsl_handle_chan_mod_ie(struct gsm_lchan *lchan,
|
||||
break;
|
||||
|
||||
/* If octet 4 indicates transparent data */
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_32000):
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_32k0):
|
||||
/* 32.0 kbit/s services, 32.0 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_32k0;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_32000;
|
||||
break;
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_29000):
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_29k0):
|
||||
/* 29.0 kbit/s services, 29.0 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_29k0;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_29000;
|
||||
break;
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_14400):
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_14k4):
|
||||
/* 14.4 kbit/s services, 14.5 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_14k5;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_14400;
|
||||
break;
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_9600):
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_9k6):
|
||||
/* 9.6 kbit/s services, 12.0 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_12k0;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_9600;
|
||||
break;
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_4800):
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_4k8):
|
||||
/* 4.8 kbit/s services, 6.0 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_6k0;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_4800;
|
||||
break;
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_2k4):
|
||||
/* 2.4 kbit/s *and less* services, 3.6 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_3k6;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_2400;
|
||||
break;
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_1k2):
|
||||
/* 2.4 kbit/s *and less* services, 3.6 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_3k6;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_1200;
|
||||
break;
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_2400):
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_1200):
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_600):
|
||||
/* 2.4 kbit/s *and less* services, 3.6 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_3k6;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_600;
|
||||
break;
|
||||
case RSL_CMODE(RSL_CMOD_SPD_DATA, RSL_CMOD_CSD_T_1200_75):
|
||||
/* 2.4 kbit/s *and less* services, 3.6 kbit/s radio interface rate */
|
||||
lchan->tch_mode = GSM48_CMODE_DATA_3k6;
|
||||
lchan->csd_mode = LCHAN_CSD_M_T_1200_75;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -247,7 +297,7 @@ static int rsl_handle_chan_mod_ie(struct gsm_lchan *lchan,
|
||||
|
||||
#undef RSL_CMODE
|
||||
|
||||
if (bts_supports_cm(lchan->ts->trx->bts, cm) != 1) {
|
||||
if (!bts_supports_cm(lchan->ts->trx->bts, cm)) {
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "Channel type=0x%02x/mode=%s "
|
||||
"is not supported by the PHY\n", cm->chan_rt,
|
||||
gsm48_chan_mode_name(lchan->tch_mode));
|
||||
@@ -294,11 +344,14 @@ static int rsl_handle_osmo_tsc_ie(struct gsm_lchan *lchan,
|
||||
if (TLVP_PRES_LEN(tp, RSL_IE_OSMO_TRAINING_SEQUENCE, 2)) {
|
||||
const uint8_t *ie = TLVP_VAL(tp, RSL_IE_OSMO_TRAINING_SEQUENCE);
|
||||
lchan->ts->tsc_set = ie[0] & 0x03; /* Range: 0..3 */
|
||||
lchan->ts->tsc = ie[1] & 0x07; /* Range: 0..7 */
|
||||
lchan->ts->tsc_rsl = ie[1] & 0x07; /* Range: 0..7 */
|
||||
lchan->ts->tsc_rsl_configured = true;
|
||||
} else {
|
||||
lchan->ts->tsc = lchan->ts->tsc_oml;
|
||||
lchan->ts->tsc_rsl_configured = false;
|
||||
lchan->ts->tsc_rsl = 0xff;
|
||||
lchan->ts->tsc_set = 0;
|
||||
}
|
||||
gsm_ts_apply_configured_tsc(lchan->ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -508,6 +561,7 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
struct gsm48_system_information_type_2quater *si2q;
|
||||
struct bitvec bv;
|
||||
const uint8_t *si_buf;
|
||||
uint8_t prev_bs_ag_blks_res = 0xff; /* 0xff = unknown */
|
||||
|
||||
if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
|
||||
LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
|
||||
@@ -539,7 +593,8 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
LOGP(DRSL, LOGL_INFO, " Rx RSL BCCH INFO (SI%s, %u bytes)\n",
|
||||
get_value_string(osmo_sitype_strs, osmo_si), len);
|
||||
|
||||
if (SYSINFO_TYPE_2quater == osmo_si) {
|
||||
switch (osmo_si) {
|
||||
case SYSINFO_TYPE_2quater:
|
||||
si2q = (struct gsm48_system_information_type_2quater *) TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO);
|
||||
bv.data = si2q->rest_octets;
|
||||
bv.data_len = GSM_MACBLOCK_LEN;
|
||||
@@ -567,7 +622,15 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
|
||||
memset(GSM_BTS_SI2Q(bts, bts->si2q_index), GSM_MACBLOCK_PADDING, sizeof(sysinfo_buf_t));
|
||||
memcpy(GSM_BTS_SI2Q(bts, bts->si2q_index), TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO), len);
|
||||
} else {
|
||||
break;
|
||||
case SYSINFO_TYPE_3:
|
||||
/* Keep previous BS_AG_BLKS_RES, used below */
|
||||
if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_3)) {
|
||||
const struct gsm48_system_information_type_3 *si3 = GSM_BTS_SI(bts, SYSINFO_TYPE_3);
|
||||
prev_bs_ag_blks_res = si3->control_channel_desc.bs_ag_blks_res;
|
||||
}
|
||||
/* fall-through */
|
||||
default:
|
||||
memset(bts->si_buf[osmo_si], GSM_MACBLOCK_PADDING, sizeof(sysinfo_buf_t));
|
||||
memcpy(bts->si_buf[osmo_si], TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO), len);
|
||||
}
|
||||
@@ -576,11 +639,15 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
|
||||
switch (osmo_si) {
|
||||
case SYSINFO_TYPE_3:
|
||||
if (trx->nr == 0 && num_agch(trx, "RSL") != 1) {
|
||||
lchan_deactivate(&trx->bts->c0->ts[0].lchan[CCCH_LCHAN]);
|
||||
/* will be reactivated by sapi_deactivate_cb() */
|
||||
/* If CCCH config on TS0 changed, reactivate the chan with the new config: */
|
||||
if (trx->nr == 0 && trx->bts->c0->ts[0].lchan[CCCH_LCHAN].state != LCHAN_S_NONE &&
|
||||
num_agch(trx, "RSL") != prev_bs_ag_blks_res) {
|
||||
trx->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =
|
||||
LCHAN_REL_ACT_REACT;
|
||||
lchan_deactivate(&trx->bts->c0->ts[0].lchan[CCCH_LCHAN]);
|
||||
/* will be reactivated by (see OS#1575):
|
||||
* - bts-trx: lchan_deactivate()
|
||||
* - sysmo,lc15,oc2g: lchan_deactivate()....[async]...sapi_deactivate_cb() */
|
||||
}
|
||||
/* decode original SI3 Rest Octets as sent by BSC */
|
||||
si_buf = (const uint8_t *) GSM_BTS_SI(bts, osmo_si);
|
||||
@@ -605,6 +672,10 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
}
|
||||
break;
|
||||
case SYSINFO_TYPE_1:
|
||||
/* Get the position of the NCH, if enabled. */
|
||||
trx->bts->asci.pos_nch = pos_nch(trx, "BCCH INFO");
|
||||
pcu_tx_si(trx->bts, SYSINFO_TYPE_1, true);
|
||||
break;
|
||||
case SYSINFO_TYPE_2:
|
||||
case SYSINFO_TYPE_13:
|
||||
pcu_tx_si(trx->bts, osmo_si, true);
|
||||
@@ -772,6 +843,100 @@ static int rsl_rx_sms_bcast_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Broadcast notification about new VGCS/VBS call on every dedicated channel.
|
||||
* This is required for MSs that are currently in dedicated mode that there is an ongoing call and on which channel
|
||||
* the call is active. Most MSs in dedicated mode may not be able to receive the NCH otherwise.
|
||||
* MSs that do not support ASCI will ignore it, as it is an unsupported message for them.
|
||||
*/
|
||||
static int asci_broadcast_facch(struct gsm_bts *bts, const uint8_t *group_call_ref, const uint8_t *chan_desc,
|
||||
uint8_t chan_desc_len, unsigned int count)
|
||||
{
|
||||
uint8_t notif[23];
|
||||
struct msgb *msg, *cmsg;
|
||||
struct gsm_bts_trx *trx;
|
||||
struct gsm_lchan *lchan;
|
||||
unsigned int tn, ln, n;
|
||||
int rc;
|
||||
|
||||
rc = bts_asci_notify_facch_gen_msg(bts, notif, group_call_ref, chan_desc, chan_desc_len);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
|
||||
for (ln = 0; ln < ARRAY_SIZE(trx->ts[tn].lchan); ln++) {
|
||||
lchan = &trx->ts[tn].lchan[ln];
|
||||
if (!lchan_is_dcch(lchan))
|
||||
continue;
|
||||
if (lchan->state != LCHAN_S_ACTIVE)
|
||||
continue;
|
||||
msg = rsl_rll_simple(RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan), 0x00, 0);
|
||||
msg->l3h = msg->tail; /* emulate rsl_rx_rll() behaviour */
|
||||
msgb_tl16v_put(msg, RSL_IE_L3_INFO, sizeof(notif), (uint8_t *) ¬if);
|
||||
for (n = 1; n < count; n++) {
|
||||
cmsg = msgb_copy(msg, "FACCH copy");
|
||||
lapdm_rslms_recvmsg(cmsg, &lchan->lapdm_ch);
|
||||
}
|
||||
lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Number of times to broadcast ASCI call on every dedicated channel. */
|
||||
#define ASCI_BROADCAST_NUM 3
|
||||
|
||||
/* 8.5.10 NOTIFICATION COMMAND */
|
||||
static int rsl_rx_notification_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
{
|
||||
struct abis_rsl_cchan_hdr *cch = msgb_l2(msg);
|
||||
struct tlv_parsed tp;
|
||||
uint8_t command_indicator;
|
||||
int rc;
|
||||
|
||||
if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
|
||||
LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
|
||||
return rsl_tx_error_report(trx, RSL_ERR_PROTO, &cch->chan_nr, NULL, msg);
|
||||
}
|
||||
|
||||
if (cch->chan_nr != RSL_CHAN_PCH_AGCH) {
|
||||
LOGPTRX(trx, DRSL, LOGL_ERROR, "%s(): chan nr is not Downlink CCCH\n", __func__);
|
||||
return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT, &cch->chan_nr, NULL, msg);
|
||||
}
|
||||
|
||||
if (!TLVP_PRES_LEN(&tp, RSL_IE_CMD_INDICATOR, 1))
|
||||
return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR, &cch->chan_nr, NULL, msg);
|
||||
command_indicator = *TLVP_VAL(&tp, RSL_IE_CMD_INDICATOR);
|
||||
|
||||
switch (command_indicator) {
|
||||
case RSL_CMD_INDICATOR_START:
|
||||
/* we need at least a Group Call Reference to start notification */
|
||||
if (!TLVP_PRES_LEN(&tp, RSL_IE_GROUP_CALL_REF, 5))
|
||||
return rsl_tx_error_report(trx, RSL_ERR_OPT_IE_ERROR, &cch->chan_nr, NULL, msg);
|
||||
rc = bts_asci_notification_add(trx->bts, TLVP_VAL(&tp, RSL_IE_GROUP_CALL_REF),
|
||||
TLVP_VAL(&tp, RSL_IE_CHAN_DESC), TLVP_LEN(&tp, RSL_IE_CHAN_DESC),
|
||||
(struct rsl_ie_nch_drx_info *) TLVP_VAL(&tp, RSL_IE_NCH_DRX_INFO));
|
||||
/* Broadcast to FACCH */
|
||||
asci_broadcast_facch(trx->bts, TLVP_VAL(&tp, RSL_IE_GROUP_CALL_REF), TLVP_VAL(&tp, RSL_IE_CHAN_DESC),
|
||||
TLVP_LEN(&tp, RSL_IE_CHAN_DESC), ASCI_BROADCAST_NUM);
|
||||
break;
|
||||
case RSL_CMD_INDICATOR_STOP:
|
||||
if (!TLVP_PRES_LEN(&tp, RSL_IE_GROUP_CALL_REF, 5)) {
|
||||
/* interpret this as stopping of all notification */
|
||||
rc = bts_asci_notification_reset(trx->bts);
|
||||
} else {
|
||||
rc = bts_asci_notification_del(trx->bts, TLVP_VAL(&tp, RSL_IE_GROUP_CALL_REF));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT, &cch->chan_nr, NULL, msg);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* OSMO_ETWS_CMD - proprietary extension as TS 48.058 has no standardized way to do this :( */
|
||||
static int rsl_rx_osmo_etws_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
{
|
||||
@@ -828,6 +993,15 @@ static int rsl_rx_osmo_etws_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
* \param[in] len length of \a current in octets */
|
||||
static inline void lapdm_ui_prefix(uint8_t *buf, uint32_t *valid, const uint8_t *current, uint8_t osmo_si, uint16_t len)
|
||||
{
|
||||
/* Special case for short header SI. Do not pre-fix the two-byte UI header. */
|
||||
switch (osmo_si) {
|
||||
case SYSINFO_TYPE_10:
|
||||
(*valid) |= (1 << osmo_si);
|
||||
memset(buf, GSM_MACBLOCK_PADDING, sizeof(sysinfo_buf_t));
|
||||
memcpy(buf, current, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We have to pre-fix with the two-byte LAPDM UI header */
|
||||
if (len > sizeof(sysinfo_buf_t) - 2) {
|
||||
LOGP(DRSL, LOGL_ERROR, "Truncating received SI%s (%u -> %zu) to prepend LAPDM UI header (2 bytes)\n",
|
||||
@@ -1357,28 +1531,50 @@ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan)
|
||||
return abis_bts_rsl_sendmsg(msg);
|
||||
}
|
||||
|
||||
/* 8.4.7 sending HANDOver DETection */
|
||||
int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay)
|
||||
/* common helper function for *_DETECT */
|
||||
static int _rsl_tx_detect(struct gsm_lchan *lchan, uint8_t msg_type, uint8_t *acc_delay)
|
||||
{
|
||||
struct msgb *msg;
|
||||
uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
|
||||
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending HANDOver DETect\n");
|
||||
|
||||
msg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
/* 9.3.17 Access Delay */
|
||||
if (ho_delay)
|
||||
msgb_tv_put(msg, RSL_IE_ACCESS_DELAY, *ho_delay);
|
||||
if (acc_delay)
|
||||
msgb_tv_put(msg, RSL_IE_ACCESS_DELAY, *acc_delay);
|
||||
|
||||
rsl_dch_push_hdr(msg, RSL_MT_HANDO_DET, chan_nr);
|
||||
rsl_dch_push_hdr(msg, msg_type, chan_nr);
|
||||
msg->trx = lchan->ts->trx;
|
||||
|
||||
return abis_bts_rsl_sendmsg(msg);
|
||||
}
|
||||
|
||||
/* 8.4.7 sending HANDOver DETection */
|
||||
int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay)
|
||||
{
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending HANDOver DETect\n");
|
||||
|
||||
return _rsl_tx_detect(lchan, RSL_MT_HANDO_DET, ho_delay);
|
||||
}
|
||||
|
||||
/* 8.4.22 sending LISTENER DETection */
|
||||
int rsl_tx_listener_det(struct gsm_lchan *lchan, uint8_t *acc_delay)
|
||||
{
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending LISTENER DETect\n");
|
||||
|
||||
return _rsl_tx_detect(lchan, RSL_MT_LISTENER_DET, acc_delay);
|
||||
}
|
||||
|
||||
/* 8.4.21 sending TALKER DETection */
|
||||
int rsl_tx_talker_det(struct gsm_lchan *lchan, uint8_t *acc_delay)
|
||||
{
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending TALKER DETect\n");
|
||||
|
||||
return _rsl_tx_detect(lchan, RSL_MT_TALKER_DET, acc_delay);
|
||||
}
|
||||
|
||||
/* 8.4.3 sending CHANnel ACTIVation Negative ACK */
|
||||
static int _rsl_tx_chan_act_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uint8_t cause,
|
||||
struct gsm_lchan *lchan)
|
||||
@@ -1386,7 +1582,7 @@ static int _rsl_tx_chan_act_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uint8
|
||||
struct msgb *msg;
|
||||
|
||||
if (lchan)
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s: ", gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "");
|
||||
else
|
||||
LOGP(DRSL, LOGL_NOTICE, "0x%02x: ", chan_nr);
|
||||
LOGPC(DRSL, LOGL_NOTICE, "Sending Channel Activated NACK: cause = 0x%02x\n", cause);
|
||||
@@ -1677,7 +1873,7 @@ static int parse_multirate_config(struct gsm_lchan *lchan,
|
||||
}
|
||||
|
||||
parsed:
|
||||
amr_log_mr_conf(DRTP, LOGL_INFO, gsm_lchan_name(lchan), &lchan->tch.amr_mr);
|
||||
amr_log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan), &lchan->tch.amr_mr);
|
||||
lchan->tch.last_cmr = AMR_CMR_NONE;
|
||||
return 0;
|
||||
}
|
||||
@@ -1692,14 +1888,39 @@ static int rsl_rx_chan_activ(struct msgb *msg)
|
||||
struct tlv_parsed tp;
|
||||
const struct tlv_p_entry *ie;
|
||||
uint8_t type, cause;
|
||||
bool reactivation = false;
|
||||
int rc;
|
||||
|
||||
if (lchan->state != LCHAN_S_NONE) {
|
||||
if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
|
||||
return rsl_tx_chan_act_nack(lchan, RSL_ERR_PROTO);
|
||||
}
|
||||
|
||||
/* 9.3.3 Activation Type */
|
||||
if (!TLVP_PRESENT(&tp, RSL_IE_ACT_TYPE)) {
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "missing Activation Type\n");
|
||||
return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR);
|
||||
}
|
||||
type = *TLVP_VAL(&tp, RSL_IE_ACT_TYPE);
|
||||
if ((type & RSL_ACT_TYPE_REACT)) {
|
||||
type -= RSL_ACT_TYPE_REACT;
|
||||
reactivation = true;
|
||||
}
|
||||
|
||||
/* If Activation Type is IMMEDIATE ASSIGNMENT, we expect L3 info with establishment. */
|
||||
lchan->l3_info_estab = (type == RSL_ACT_INTRA_IMM_ASS);
|
||||
|
||||
if (!reactivation && lchan->state != LCHAN_S_NONE) {
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "error: lchan is not available, but in state: %s.\n",
|
||||
gsm_lchans_name(lchan->state));
|
||||
return rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL);
|
||||
}
|
||||
|
||||
if (reactivation && lchan->state == LCHAN_S_NONE) {
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "error: reactivation on inactive lchan.\n");
|
||||
return rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL);
|
||||
}
|
||||
|
||||
/* We need to pick the real TS here to check NM state: */
|
||||
primary_ts = ts->vamos.is_shadow ? ts->vamos.peer : ts;
|
||||
if (primary_ts->mo.nm_state.operational != NM_OPSTATE_ENABLED ||
|
||||
@@ -1742,18 +1963,6 @@ static int rsl_rx_chan_activ(struct msgb *msg)
|
||||
.current = 0,
|
||||
};
|
||||
|
||||
if (rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg)) < 0) {
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "%s(): rsl_tlv_parse() failed\n", __func__);
|
||||
return rsl_tx_chan_act_nack(lchan, RSL_ERR_PROTO);
|
||||
}
|
||||
|
||||
/* 9.3.3 Activation Type */
|
||||
if (!TLVP_PRESENT(&tp, RSL_IE_ACT_TYPE)) {
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "missing Activation Type\n");
|
||||
return rsl_tx_chan_act_nack(lchan, RSL_ERR_MAND_IE_ERROR);
|
||||
}
|
||||
type = *TLVP_VAL(&tp, RSL_IE_ACT_TYPE);
|
||||
|
||||
/* 9.3.6 Channel Mode */
|
||||
if (type != RSL_ACT_OSMO_PDCH) {
|
||||
if (rsl_handle_chan_mod_ie(lchan, &tp, &cause) != 0)
|
||||
@@ -2000,6 +2209,23 @@ static int rsl_rx_chan_activ(struct msgb *msg)
|
||||
else
|
||||
lchan->top_acch_active = false;
|
||||
|
||||
/* set ASCI channel into right state */
|
||||
if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt)) {
|
||||
if (reactivation)
|
||||
vgcs_lchan_react(lchan);
|
||||
else
|
||||
vgcs_lchan_activate(lchan);
|
||||
}
|
||||
|
||||
/* on reactivation, the channel is already activated */
|
||||
if (reactivation) {
|
||||
rc = rsl_tx_chan_act_ack(lchan);
|
||||
if (rc < 0)
|
||||
LOGP(DRSL, LOGL_ERROR, "%s Cannot send act ack: %d\n",
|
||||
gsm_ts_and_pchan_name(ts), rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* actually activate the channel in the BTS */
|
||||
rc = l1sap_chan_act(lchan->ts->trx, dch->chan_nr);
|
||||
if (rc < 0)
|
||||
@@ -2170,7 +2396,7 @@ static int _rsl_tx_mode_modif_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uin
|
||||
struct msgb *msg;
|
||||
|
||||
if (lchan)
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s: ", gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_NOTICE, "");
|
||||
else
|
||||
LOGP(DRSL, LOGL_NOTICE, "0x%02x: ", chan_nr);
|
||||
LOGPC(DRSL, LOGL_NOTICE, "Tx MODE MODIFY NACK (cause = 0x%02x)\n", cause);
|
||||
@@ -2701,7 +2927,7 @@ static int tx_ipac_XXcx_nack(struct gsm_lchan *lchan, uint8_t cause,
|
||||
|
||||
static char *get_rsl_local_ip(struct gsm_bts_trx *trx)
|
||||
{
|
||||
struct e1inp_ts *ts = trx->rsl_link->ts;
|
||||
struct e1inp_ts *ts = trx->bb_transc.rsl.link->ts;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t sa_len = sizeof(ss);
|
||||
static char hostbuf[256];
|
||||
@@ -2844,7 +3070,7 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
|
||||
* address */
|
||||
if (connect_ip == 0) {
|
||||
struct e1inp_sign_link *sign_link =
|
||||
lchan->ts->trx->rsl_link;
|
||||
lchan->ts->trx->bb_transc.rsl.link;
|
||||
|
||||
ia.s_addr = htonl(get_signlink_remote_ip(sign_link));
|
||||
} else
|
||||
@@ -3086,7 +3312,6 @@ static void rsl_rx_dyn_pdch(struct msgb *msg, bool pdch_act)
|
||||
if (pdch_act) {
|
||||
/* Clear TCH state. Only first lchan matters for PDCH */
|
||||
clear_lchan_for_pdch_activ(ts->lchan);
|
||||
|
||||
/* First, disconnect the TCH channel, to connect PDTCH later */
|
||||
rc = bts_model_ts_disconnect(ts);
|
||||
} else {
|
||||
@@ -3115,14 +3340,12 @@ static void ipacc_dyn_pdch_ts_disconnected(struct gsm_bts_trx_ts *ts)
|
||||
enum gsm_phys_chan_config as_pchan;
|
||||
|
||||
if (ts->flags & TS_F_PDCH_DEACT_PENDING) {
|
||||
LOGP(DRSL, LOGL_DEBUG,
|
||||
"%s PDCH DEACT operation: channel disconnected, will reconnect as TCH\n",
|
||||
gsm_lchan_name(ts->lchan));
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG,
|
||||
"PDCH DEACT operation: channel disconnected, will reconnect as TCH\n");
|
||||
as_pchan = GSM_PCHAN_TCH_F;
|
||||
} else if (ts->flags & TS_F_PDCH_ACT_PENDING) {
|
||||
LOGP(DRSL, LOGL_DEBUG,
|
||||
"%s PDCH ACT operation: channel disconnected, will reconnect as PDTCH\n",
|
||||
gsm_lchan_name(ts->lchan));
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG,
|
||||
"PDCH ACT operation: channel disconnected, will reconnect as PDTCH\n");
|
||||
as_pchan = GSM_PCHAN_PDCH;
|
||||
} else
|
||||
/* No reconnect pending. */
|
||||
@@ -3183,39 +3406,31 @@ void cb_ts_disconnected(struct gsm_bts_trx_ts *ts)
|
||||
static void ipacc_dyn_pdch_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
|
||||
{
|
||||
if (rc) {
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s PDCH ACT IPA operation failed (%d) in bts model\n",
|
||||
gsm_lchan_name(ts->lchan), rc);
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_NOTICE, "PDCH ACT IPA operation failed (%d) in bts model\n", rc);
|
||||
ipacc_dyn_pdch_complete(ts, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ts->flags & TS_F_PDCH_DEACT_PENDING) {
|
||||
if (ts->lchan[0].type != GSM_LCHAN_TCH_F)
|
||||
LOGP(DRSL, LOGL_ERROR, "%s PDCH DEACT error:"
|
||||
" timeslot connected, so expecting"
|
||||
" lchan type TCH/F, but is %s\n",
|
||||
gsm_lchan_name(ts->lchan),
|
||||
gsm_lchant_name(ts->lchan[0].type));
|
||||
if (ts->lchan[0].type != GSM_LCHAN_TCH_F) {
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_ERROR, "PDCH DEACT error: timeslot connected, so "
|
||||
"expecting lchan type TCH/F, but is %s\n", gsm_lchant_name(ts->lchan[0].type));
|
||||
}
|
||||
|
||||
LOGP(DRSL, LOGL_DEBUG, "%s PDCH DEACT operation:"
|
||||
" timeslot connected as TCH/F\n",
|
||||
gsm_lchan_name(ts->lchan));
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "PDCH DEACT operation: timeslot connected as TCH/F\n");
|
||||
|
||||
/* During PDCH DEACT, we're done right after the TCH/F came
|
||||
* back up. */
|
||||
ipacc_dyn_pdch_complete(ts, 0);
|
||||
|
||||
} else if (ts->flags & TS_F_PDCH_ACT_PENDING) {
|
||||
if (ts->lchan[0].type != GSM_LCHAN_PDTCH)
|
||||
LOGP(DRSL, LOGL_ERROR, "%s PDCH ACT error:"
|
||||
" timeslot connected, so expecting"
|
||||
" lchan type PDTCH, but is %s\n",
|
||||
gsm_lchan_name(ts->lchan),
|
||||
if (ts->lchan[0].type != GSM_LCHAN_PDTCH) {
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_ERROR, "PDCH ACT error: timeslot connected, "
|
||||
"so expecting lchan type PDTCH, but is %s\n",
|
||||
gsm_lchant_name(ts->lchan[0].type));
|
||||
}
|
||||
|
||||
LOGP(DRSL, LOGL_DEBUG, "%s PDCH ACT operation:"
|
||||
" timeslot connected as PDTCH\n",
|
||||
gsm_lchan_name(ts->lchan));
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "PDCH ACT operation: timeslot connected as PDTCH\n");
|
||||
|
||||
/* The PDTCH is connected, now tell the PCU about it. Except
|
||||
* when the PCU is not connected (yet), then there's nothing
|
||||
@@ -3241,8 +3456,7 @@ static void osmo_dyn_ts_connected(struct gsm_bts_trx_ts *ts, int rc)
|
||||
unsigned int ln;
|
||||
|
||||
if (rc) {
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s PDCH ACT OSMO operation failed (%d) in bts model\n",
|
||||
gsm_lchan_name(ts->lchan), rc);
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_NOTICE, "PDCH ACT OSMO operation failed (%d) in bts model\n", rc);
|
||||
ipacc_dyn_pdch_complete(ts, rc);
|
||||
return;
|
||||
}
|
||||
@@ -3287,10 +3501,10 @@ void ipacc_dyn_pdch_complete(struct gsm_bts_trx_ts *ts, int rc)
|
||||
|
||||
pdch_act = ts->flags & TS_F_PDCH_ACT_PENDING;
|
||||
|
||||
if ((ts->flags & TS_F_PDCH_PENDING_MASK) == TS_F_PDCH_PENDING_MASK)
|
||||
LOGP(DRSL, LOGL_ERROR,
|
||||
"%s Internal Error: both PDCH ACT and PDCH DEACT pending\n",
|
||||
gsm_lchan_name(ts->lchan));
|
||||
if ((ts->flags & TS_F_PDCH_PENDING_MASK) == TS_F_PDCH_PENDING_MASK) {
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_ERROR,
|
||||
"Internal Error: both PDCH ACT and PDCH DEACT pending\n");
|
||||
}
|
||||
|
||||
ts->flags &= ~TS_F_PDCH_PENDING_MASK;
|
||||
|
||||
@@ -3306,9 +3520,8 @@ void ipacc_dyn_pdch_complete(struct gsm_bts_trx_ts *ts, int rc)
|
||||
ts->flags |= TS_F_PDCH_ACTIVE;
|
||||
else
|
||||
ts->flags &= ~TS_F_PDCH_ACTIVE;
|
||||
DEBUGP(DRSL, "%s %s switched to %s mode (ts->flags == %x)\n",
|
||||
gsm_lchan_name(ts->lchan), gsm_pchan_name(ts->pchan),
|
||||
pdch_act? "PDCH" : "TCH/F", ts->flags);
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "%s switched to %s mode (ts->flags == %x)\n",
|
||||
gsm_pchan_name(ts->pchan), pdch_act ? "PDCH" : "TCH/F", ts->flags);
|
||||
|
||||
rc = rsl_tx_dyn_pdch_ack(ts->lchan, pdch_act);
|
||||
if (rc)
|
||||
@@ -3410,8 +3623,11 @@ static int rsl_rx_rll(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP(DRLL, "%s Rx RLL %s Abis -> LAPDm\n", gsm_lchan_name(lchan),
|
||||
rsl_msg_name(rh->c.msg_type));
|
||||
/* VGCS Uplink is released by MSC using REL-REQ. */
|
||||
if (rh->c.msg_type == RSL_MT_REL_REQ)
|
||||
vgcs_talker_reset(lchan, true);
|
||||
|
||||
LOGPLCHAN(lchan, DRLL, LOGL_DEBUG, "Rx RLL %s Abis -> LAPDm\n", rsl_msg_name(rh->c.msg_type));
|
||||
|
||||
/* make copy of RLL header, as the message will be free'd in case of erroneous return */
|
||||
rh2 = *rh;
|
||||
@@ -3506,7 +3722,7 @@ static int handle_gprs_susp_req(struct msgb *msg)
|
||||
int rc;
|
||||
|
||||
if (!gh || msgb_l3len(msg) < sizeof(*gh)+sizeof(*gsr)) {
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s Short GPRS SUSPEND REQ received, ignoring\n", gsm_lchan_name(msg->lchan));
|
||||
LOGPLCHAN(msg->lchan, DRSL, LOGL_NOTICE, "Short GPRS SUSPEND REQ received, ignoring\n");
|
||||
msgb_free(msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -3514,8 +3730,7 @@ static int handle_gprs_susp_req(struct msgb *msg)
|
||||
gsr = (struct gsm48_gprs_susp_req *) gh->data;
|
||||
tlli = osmo_ntohl(gsr->tlli);
|
||||
|
||||
LOGP(DRSL, LOGL_INFO, "%s Fwd GPRS SUSPEND REQ for TLLI=0x%08x to PCU\n",
|
||||
gsm_lchan_name(msg->lchan), tlli);
|
||||
LOGPLCHAN(msg->lchan, DRSL, LOGL_INFO, "Fwd GPRS SUSPEND REQ for TLLI=0x%08x to PCU\n", tlli);
|
||||
rc = pcu_tx_susp_req(msg->lchan, tlli, gsr->ra_id, gsr->cause);
|
||||
|
||||
msgb_free(msg);
|
||||
@@ -3619,6 +3834,23 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
|
||||
msg->trx = lchan->ts->trx;
|
||||
msg->lchan = lchan;
|
||||
|
||||
/* If DL estabishment on main signaling link and SAPI 0 with L3 info is expected. */
|
||||
if (lchan->l3_info_estab && rh->msg_type == RSL_MT_EST_IND) {
|
||||
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
|
||||
if ((rllh->link_id & 0xc7) == 0) {
|
||||
/* Reject initial establishment without L3 info. */
|
||||
if (msgb_l2len(msg) == sizeof(struct abis_rsl_rll_hdr)) {
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_ERROR, "RLL EST IND without contention resolution.\n");
|
||||
/* Release normally, re-use the msgb. */
|
||||
rh->msg_type = RSL_MT_REL_REQ;
|
||||
msgb_tv_put(msg, RSL_IE_RELEASE_MODE, RSL_REL_NORMAL);
|
||||
return rsl_rx_rll(lchan->ts->trx, msg);
|
||||
}
|
||||
/* Re-estabishment without contention resoltuion is allowed. */
|
||||
lchan->l3_info_estab = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is a Measurement Report, then we simply ignore it,
|
||||
* because it has already been processed in l1sap_ph_data_ind(). */
|
||||
if (rslms_is_meas_rep(msg)) {
|
||||
@@ -3632,6 +3864,7 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
|
||||
|
||||
/* REL_IND handling */
|
||||
if (rh->msg_type == RSL_MT_REL_IND && lchan_is_tch(lchan)) {
|
||||
vgcs_talker_reset(lchan, true);
|
||||
LOGPLCHAN(lchan, DRSL, LOGL_INFO,
|
||||
"Scheduling %s to L3 in next associated TCH-RTS.ind\n",
|
||||
rsl_msg_name(rh->msg_type));
|
||||
@@ -3692,8 +3925,10 @@ static int rsl_rx_cchan(struct gsm_bts_trx *trx, struct msgb *msg)
|
||||
case RSL_MT_SMS_BC_CMD:
|
||||
ret = rsl_rx_sms_bcast_cmd(trx, msg);
|
||||
break;
|
||||
case RSL_MT_SMS_BC_REQ:
|
||||
case RSL_MT_NOT_CMD:
|
||||
ret = rsl_rx_notification_cmd(trx, msg);
|
||||
break;
|
||||
case RSL_MT_SMS_BC_REQ:
|
||||
LOGPLCHAN(msg->lchan, DRSL, LOGL_NOTICE, "unimplemented RSL cchan msg_type %s\n",
|
||||
rsl_msg_name(cch->c.msg_type));
|
||||
rsl_tx_error_report(trx, RSL_ERR_MSG_TYPE, &cch->chan_nr, NULL, msg);
|
||||
|
||||
151
src/common/rtp_input_preen.c
Normal file
151
src/common/rtp_input_preen.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* This module implements a helper function for the RTP input path:
|
||||
* validates incoming RTP payloads, makes the accept-or-drop decision,
|
||||
* and for some codecs signals additional required actions such as
|
||||
* dropping one header octet.
|
||||
*
|
||||
* Author: Mychaela N. Falconia <falcon@freecalypso.org>, 2023 - however,
|
||||
* Mother Mychaela's contributions are NOT subject to copyright.
|
||||
* No rights reserved, all rights relinquished.
|
||||
*
|
||||
* 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 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
#include <osmocom/codec/codec.h>
|
||||
|
||||
#include <osmo-bts/lchan.h>
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/rtp_input_preen.h>
|
||||
|
||||
static bool amr_is_octet_aligned(const uint8_t *rtp_pl, unsigned rtp_pl_len)
|
||||
{
|
||||
/*
|
||||
* Logic: If 1st bit padding is not zero, packet is either:
|
||||
* - bandwidth-efficient AMR payload.
|
||||
* - malformed packet.
|
||||
* However, Bandwidth-efficient AMR 4,75 frame last in payload(F=0, FT=0)
|
||||
* with 4th,5ht,6th AMR payload to 0 matches padding==0.
|
||||
* Furthermore, both AMR 4,75 bw-efficient and octet alignment are 14 bytes long (AMR 4,75 encodes 95b):
|
||||
* bw-efficient: 95b, + 4b hdr + 6b ToC = 105b, + padding = 112b = 14B.
|
||||
* octet-aligned: 1B hdr + 1B ToC + 95b = 111b, + padding = 112b = 14B.
|
||||
* We cannot use other fields to match since they are inside the AMR
|
||||
* payload bits which are unknown.
|
||||
* As a result, this function may return false positive (true) for some AMR
|
||||
* 4,75 AMR frames, but given the length, CMR and FT read is the same as a
|
||||
* consequence, the damage in here is harmless other than being unable to
|
||||
* decode the audio at the other side.
|
||||
*/
|
||||
#define AMR_PADDING1(rtp_pl) (rtp_pl[0] & 0x0f)
|
||||
#define AMR_PADDING2(rtp_pl) (rtp_pl[1] & 0x03)
|
||||
|
||||
if (rtp_pl_len < 2 || AMR_PADDING1(rtp_pl) || AMR_PADDING2(rtp_pl))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum pl_input_decision
|
||||
input_preen_fr(const uint8_t *rtp_pl, unsigned rtp_pl_len)
|
||||
{
|
||||
if (rtp_pl_len != GSM_FR_BYTES)
|
||||
return PL_DECISION_DROP;
|
||||
if ((rtp_pl[0] & 0xF0) != 0xD0)
|
||||
return PL_DECISION_DROP;
|
||||
return PL_DECISION_ACCEPT;
|
||||
}
|
||||
|
||||
static enum pl_input_decision
|
||||
input_preen_efr(const uint8_t *rtp_pl, unsigned rtp_pl_len)
|
||||
{
|
||||
if (rtp_pl_len != GSM_EFR_BYTES)
|
||||
return PL_DECISION_DROP;
|
||||
if ((rtp_pl[0] & 0xF0) != 0xC0)
|
||||
return PL_DECISION_DROP;
|
||||
return PL_DECISION_ACCEPT;
|
||||
}
|
||||
|
||||
static enum pl_input_decision
|
||||
input_preen_hr(const uint8_t *rtp_pl, unsigned rtp_pl_len,
|
||||
bool *rfc5993_sid_flag)
|
||||
{
|
||||
switch (rtp_pl_len) {
|
||||
case GSM_HR_BYTES:
|
||||
/* RTP input matches our internal format - we are good */
|
||||
return PL_DECISION_ACCEPT;
|
||||
case GSM_HR_BYTES_RTP_RFC5993:
|
||||
/* Validate ToC octet: for payload of this length to be valid,
|
||||
* the F bit must be 0 and the FT field must be either 0 (good
|
||||
* speech) or 2 (good SID). */
|
||||
switch (rtp_pl[0] & 0xF0) {
|
||||
case 0x00:
|
||||
break;
|
||||
case 0x20:
|
||||
*rfc5993_sid_flag = true;
|
||||
break;
|
||||
default:
|
||||
/* invalid payload */
|
||||
return PL_DECISION_DROP;
|
||||
}
|
||||
/* Strip ToC octet, leaving only "pure" TS 101 318 payload. */
|
||||
return PL_DECISION_STRIP_HDR_OCTET;
|
||||
default:
|
||||
/* invalid payload */
|
||||
return PL_DECISION_DROP;
|
||||
}
|
||||
}
|
||||
|
||||
enum pl_input_decision
|
||||
rtp_payload_input_preen(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
|
||||
unsigned rtp_pl_len, bool *rfc5993_sid_flag)
|
||||
{
|
||||
/* If rtp continuous-streaming is enabled, we shall emit RTP packets
|
||||
* with zero-length payloads as BFI markers. In a TrFO scenario such
|
||||
* RTP packets sent by call leg A will be received by call leg B,
|
||||
* hence we need to handle them gracefully. For the purposes of a BTS
|
||||
* that runs on its own TDMA timing and does not need timing ticks from
|
||||
* an incoming RTP stream, the correct action upon receiving such
|
||||
* timing-tick-only RTP packets should be the same as when receiving
|
||||
* no RTP packet at all. The simplest way to produce that behavior
|
||||
* is to treat zero-length RTP payloads as invalid. */
|
||||
if (rtp_pl_len == 0)
|
||||
return PL_DECISION_DROP;
|
||||
|
||||
switch (lchan->tch_mode) {
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
if (lchan->type == GSM_LCHAN_TCH_F)
|
||||
return input_preen_fr(rtp_pl, rtp_pl_len);
|
||||
else
|
||||
return input_preen_hr(rtp_pl, rtp_pl_len, rfc5993_sid_flag);
|
||||
case GSM48_CMODE_SPEECH_EFR:
|
||||
return input_preen_efr(rtp_pl, rtp_pl_len);
|
||||
case GSM48_CMODE_SPEECH_AMR:
|
||||
/* Avoid forwarding bw-efficient AMR to lower layers,
|
||||
* most bts models don't support it. */
|
||||
if (!amr_is_octet_aligned(rtp_pl, rtp_pl_len)) {
|
||||
LOGPLCHAN(lchan, DL1P, LOGL_NOTICE,
|
||||
"RTP->L1: Dropping unexpected AMR encoding (bw-efficient?) %s\n",
|
||||
osmo_hexdump(rtp_pl, rtp_pl_len));
|
||||
return PL_DECISION_DROP;
|
||||
}
|
||||
return PL_DECISION_ACCEPT;
|
||||
default:
|
||||
return PL_DECISION_ACCEPT;
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <osmocom/core/stats.h>
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_08_58.h>
|
||||
#include <osmocom/gsm/gsm0502.h>
|
||||
#include <osmocom/gsm/a5.h>
|
||||
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
@@ -542,9 +543,7 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
|
||||
.chan_nr = RSL_CHAN_OSMO_PDCH,
|
||||
|
||||
/* Rx and Tx, multiple coding schemes: CS-2..4 and MCS-1..9 (3GPP TS
|
||||
* 05.03, chapter 5), regular interleaving as specified for xCCH.
|
||||
* NOTE: the burst buffer is three times bigger because the
|
||||
* payload of EDGE bursts is three times longer. */
|
||||
* 05.03, chapter 5), regular interleaving as specified for xCCH. */
|
||||
.rts_fn = rts_data_fn,
|
||||
.dl_fn = tx_pdtch_fn,
|
||||
.ul_fn = rx_pdtch_fn,
|
||||
@@ -751,10 +750,10 @@ free_msg:
|
||||
}
|
||||
|
||||
int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *l2,
|
||||
uint8_t l2_len, float rssi,
|
||||
enum trx_chan_type chan,
|
||||
const uint8_t *data, size_t data_len,
|
||||
uint16_t ber10k, float rssi,
|
||||
int16_t ta_offs_256bits, int16_t link_qual_cb,
|
||||
uint16_t ber10k,
|
||||
enum osmo_ph_pres_info_type presence_info)
|
||||
{
|
||||
struct msgb *msg;
|
||||
@@ -766,7 +765,7 @@ int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
|
||||
|
||||
/* compose primitive */
|
||||
msg = l1sap_msgb_alloc(l2_len);
|
||||
msg = l1sap_msgb_alloc(data_len);
|
||||
l1sap = msgb_l1sap_prim(msg);
|
||||
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA,
|
||||
PRIM_OP_INDICATION, msg);
|
||||
@@ -778,9 +777,9 @@ int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
l1sap->u.data.ta_offs_256bits = ta_offs_256bits;
|
||||
l1sap->u.data.lqual_cb = link_qual_cb;
|
||||
l1sap->u.data.pdch_presence_info = presence_info;
|
||||
msg->l2h = msgb_put(msg, l2_len);
|
||||
if (l2_len)
|
||||
memcpy(msg->l2h, l2, l2_len);
|
||||
msg->l2h = msgb_put(msg, data_len);
|
||||
if (data_len)
|
||||
memcpy(msg->l2h, data, data_len);
|
||||
|
||||
/* forward primitive */
|
||||
l1sap_up(l1ts->ts->trx, l1sap);
|
||||
@@ -789,9 +788,11 @@ int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
}
|
||||
|
||||
int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len,
|
||||
int16_t ta_offs_256bits, uint16_t ber10k, float rssi,
|
||||
int16_t link_qual_cb, uint8_t is_sub)
|
||||
enum trx_chan_type chan,
|
||||
const uint8_t *data, size_t data_len,
|
||||
uint16_t ber10k, float rssi,
|
||||
int16_t ta_offs_256bits, int16_t link_qual_cb,
|
||||
uint8_t is_sub)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmo_phsap_prim *l1sap;
|
||||
@@ -803,7 +804,7 @@ int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
|
||||
|
||||
/* compose primitive */
|
||||
msg = l1sap_msgb_alloc(tch_len);
|
||||
msg = l1sap_msgb_alloc(data_len);
|
||||
l1sap = msgb_l1sap_prim(msg);
|
||||
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH,
|
||||
PRIM_OP_INDICATION, msg);
|
||||
@@ -815,12 +816,12 @@ int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
l1sap->u.tch.lqual_cb = link_qual_cb;
|
||||
l1sap->u.tch.is_sub = is_sub & 1;
|
||||
|
||||
msg->l2h = msgb_put(msg, tch_len);
|
||||
if (tch_len)
|
||||
memcpy(msg->l2h, tch, tch_len);
|
||||
msg->l2h = msgb_put(msg, data_len);
|
||||
if (data_len)
|
||||
memcpy(msg->l2h, data, data_len);
|
||||
|
||||
LOGL1S(DL1P, LOGL_INFO, l1ts, chan, l1sap->u.data.fn, "%s Rx -> RTP: %s\n",
|
||||
gsm_lchan_name(lchan), osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1ts, chan, l1sap->u.tch.fn, "%s Rx -> RTP: %s\n",
|
||||
gsm_lchan_name(lchan), msgb_hexdump_l2(msg));
|
||||
/* forward primitive */
|
||||
l1sap_up(l1ts->ts->trx, l1sap);
|
||||
|
||||
@@ -1070,26 +1071,21 @@ static void _trx_sched_set_lchan(struct gsm_lchan *lchan,
|
||||
(active) ? "Activating" : "Deactivating",
|
||||
trx_chan_desc[chan].name);
|
||||
|
||||
/* free burst memory, to cleanly start with burst 0 */
|
||||
if (chan_state->dl_bursts) {
|
||||
talloc_free(chan_state->dl_bursts);
|
||||
chan_state->dl_bursts = NULL;
|
||||
}
|
||||
if (chan_state->ul_bursts) {
|
||||
talloc_free(chan_state->ul_bursts);
|
||||
chan_state->ul_bursts = NULL;
|
||||
}
|
||||
if (chan_state->ul_bursts_prev) {
|
||||
talloc_free(chan_state->ul_bursts_prev);
|
||||
chan_state->ul_bursts_prev = NULL;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
/* Clean up everything */
|
||||
memset(chan_state, 0, sizeof(*chan_state));
|
||||
|
||||
/* Bind to generic 'struct gsm_lchan' */
|
||||
chan_state->lchan = lchan;
|
||||
|
||||
/* Allocate memory for Rx/Tx burst buffers. Use the maximim size
|
||||
* of 24 * (2 * 58) bytes, which is sufficient to store up to 24 GMSK
|
||||
* modulated bursts for CSD or up to 8 8PSK modulated bursts for EGPRS. */
|
||||
const size_t buf_size = 24 * GSM_NBITS_NB_GMSK_PAYLOAD;
|
||||
if (trx_chan_desc[chan].dl_fn != NULL)
|
||||
chan_state->dl_bursts = talloc_zero_size(l1ts, buf_size);
|
||||
if (trx_chan_desc[chan].ul_fn != NULL)
|
||||
chan_state->ul_bursts = talloc_zero_size(l1ts, buf_size);
|
||||
} else {
|
||||
chan_state->ho_rach_detect = 0;
|
||||
|
||||
@@ -1097,6 +1093,10 @@ static void _trx_sched_set_lchan(struct gsm_lchan *lchan,
|
||||
trx_sched_queue_filter(&l1ts->dl_prims,
|
||||
trx_chan_desc[chan].chan_nr,
|
||||
trx_chan_desc[chan].link_id);
|
||||
|
||||
/* Release memory used by Rx/Tx burst buffers */
|
||||
TALLOC_FREE(chan_state->dl_bursts);
|
||||
TALLOC_FREE(chan_state->ul_bursts);
|
||||
}
|
||||
|
||||
chan_state->active = active;
|
||||
@@ -1140,6 +1140,33 @@ int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_i
|
||||
return found ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
int trx_sched_set_ul_access(struct gsm_lchan *lchan, uint8_t chan_nr, bool active)
|
||||
{
|
||||
struct l1sched_ts *l1ts = lchan->ts->priv;
|
||||
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
|
||||
uint8_t ss = l1sap_chan2ss(chan_nr);
|
||||
int i;
|
||||
|
||||
if (!l1ts) {
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "%s UL access on lchan with uninitialized scheduler structure.\n",
|
||||
(active) ? "Activating" : "Deactivating");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* look for all matching chan_nr */
|
||||
for (i = 0; i < _TRX_CHAN_MAX; i++) {
|
||||
if (trx_chan_desc[i].chan_nr == (chan_nr & RSL_CHAN_NR_MASK)) {
|
||||
struct l1sched_chan_state *l1cs = &l1ts->chan_state[i];
|
||||
|
||||
l1cs->ho_rach_detect = active;
|
||||
}
|
||||
}
|
||||
|
||||
_sched_act_rach_det(lchan->ts->trx, tn, ss, active);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trx_sched_set_bcch_ccch(struct gsm_lchan *lchan, bool active)
|
||||
{
|
||||
struct l1sched_ts *l1ts = lchan->ts->priv;
|
||||
|
||||
@@ -164,6 +164,26 @@ uint8_t num_agch(const struct gsm_bts_trx *trx, const char * arg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns position of the NCH accroding to SI1 rest octets. See Table 10.5.2.32.1 of TS 44.018.
|
||||
* Returns < 0, if not present. */
|
||||
int pos_nch(const struct gsm_bts_trx *trx, const char *arg)
|
||||
{
|
||||
const struct gsm_bts *b = trx->bts;
|
||||
const struct gsm48_system_information_type_1 *si1;
|
||||
|
||||
if (GSM_BTS_HAS_SI(b, SYSINFO_TYPE_1)) {
|
||||
si1 = GSM_BTS_SI(b, SYSINFO_TYPE_1);
|
||||
if (si1->rest_octets[0] & 0x80) {
|
||||
/* H <NCH Position : bit (5)> */
|
||||
return (si1->rest_octets[0] >> 2) & 0x1f;
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
LOGP(DL1P, LOGL_NOTICE, "%s: Unable to determine actual NCH Position "
|
||||
"value as SI1 is not available yet.\n", arg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* re-generate SI3 restoctets with GPRS indicator depending on the PCU socket connection state */
|
||||
void regenerate_si3_restoctets(struct gsm_bts *bts)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Loop control for Timing Advance */
|
||||
|
||||
/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
|
||||
232
src/common/vty.c
232
src/common/vty.c
@@ -22,6 +22,7 @@
|
||||
#include "btsconfig.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -43,12 +44,14 @@
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
#include <osmocom/trau/osmo_ortp.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
|
||||
#include <osmo-bts/logging.h>
|
||||
#include <osmo-bts/gsm_data.h>
|
||||
#include <osmo-bts/phy_link.h>
|
||||
#include <osmo-bts/abis.h>
|
||||
#include <osmo-bts/bts.h>
|
||||
#include <osmo-bts/bts_sm.h>
|
||||
#include <osmo-bts/rsl.h>
|
||||
#include <osmo-bts/oml.h>
|
||||
#include <osmo-bts/signal.h>
|
||||
@@ -68,6 +71,9 @@
|
||||
#define BTS_TRX_STR BTS_NR_STR TRX_NR_STR
|
||||
#define BTS_TRX_TS_STR BTS_TRX_STR TS_NR_STR
|
||||
#define BTS_TRX_TS_LCHAN_STR BTS_TRX_TS_STR LCHAN_NR_STR
|
||||
/* INT32_MAX, because osmo_wqueue_init takes int as an argument
|
||||
* and INT_MAX can't be stringified as a decimal */
|
||||
#define BTS_CFG_PCU_SOCK_WQUEUE_LEN_MAX_MAX 2147483647
|
||||
|
||||
#define X(x) (1 << x)
|
||||
|
||||
@@ -134,20 +140,6 @@ int bts_vty_go_parent(struct vty *vty)
|
||||
return vty->node;
|
||||
}
|
||||
|
||||
int bts_vty_is_config_node(struct vty *vty, int node)
|
||||
{
|
||||
switch (node) {
|
||||
case TRX_NODE:
|
||||
case BTS_NODE:
|
||||
case PHY_NODE:
|
||||
case PHY_INST_NODE:
|
||||
case OSMUX_NODE:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char osmobts_copyright[] =
|
||||
"Copyright (C) 2010-2011 by Harald Welte, Andreas Eversberg and On-Waves\r\n"
|
||||
"Copyright (C) 2011-2022 by sysmocom - s.f.m.c. GmbH\r\n"
|
||||
@@ -160,7 +152,6 @@ struct vty_app_info bts_vty_info = {
|
||||
.version = PACKAGE_VERSION,
|
||||
.copyright = osmobts_copyright,
|
||||
.go_parent_cb = bts_vty_go_parent,
|
||||
.is_config_node = bts_vty_is_config_node,
|
||||
.usr_attr_desc = {
|
||||
[BTS_VTY_ATTR_NEW_LCHAN] = \
|
||||
"This command applies for newly created lchans",
|
||||
@@ -173,13 +164,6 @@ struct vty_app_info bts_vty_info = {
|
||||
},
|
||||
};
|
||||
|
||||
extern struct gsm_network bts_gsmnet;
|
||||
|
||||
struct gsm_network *gsmnet_from_vty(struct vty *v)
|
||||
{
|
||||
return &bts_gsmnet;
|
||||
}
|
||||
|
||||
static struct cmd_node bts_node = {
|
||||
BTS_NODE,
|
||||
"%s(bts)# ",
|
||||
@@ -418,9 +402,15 @@ static void config_write_bts_single(struct vty *vty, const struct gsm_bts *bts)
|
||||
vty_out(vty, " rtp port-range %u %u%s", bts->rtp_port_range_start,
|
||||
bts->rtp_port_range_end, VTY_NEWLINE);
|
||||
if (bts->rtp_ip_dscp != -1)
|
||||
vty_out(vty, " rtp ip-dscp %i%s", bts->rtp_ip_dscp, VTY_NEWLINE);
|
||||
vty_out(vty, " rtp ip-dscp %d%s", bts->rtp_ip_dscp, VTY_NEWLINE);
|
||||
if (bts->rtp_priority != -1)
|
||||
vty_out(vty, " rtp socket-priority %i%s", bts->rtp_priority, VTY_NEWLINE);
|
||||
vty_out(vty, " rtp socket-priority %d%s", bts->rtp_priority, VTY_NEWLINE);
|
||||
if (bts->rtp_nogaps_mode)
|
||||
vty_out(vty, " rtp continuous-streaming%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %srtp internal-uplink-ecu%s",
|
||||
bts->use_ul_ecu ? "" : "no ", VTY_NEWLINE);
|
||||
vty_out(vty, " rtp hr-format %s%s",
|
||||
bts->emit_hr_rfc5993 ? "rfc5993" : "ts101318", VTY_NEWLINE);
|
||||
vty_out(vty, " paging queue-size %u%s", paging_get_queue_max(bts->paging_state),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(bts->paging_state),
|
||||
@@ -465,6 +455,8 @@ static void config_write_bts_single(struct vty *vty, const struct gsm_bts *bts)
|
||||
VTY_NEWLINE);
|
||||
if (strcmp(bts->pcu.sock_path, PCU_SOCK_DEFAULT))
|
||||
vty_out(vty, " pcu-socket %s%s", bts->pcu.sock_path, VTY_NEWLINE);
|
||||
if (bts->pcu.sock_wqueue_len_max != BTS_CFG_PCU_SOCK_WQUEUE_LEN_MAX_MAX)
|
||||
vty_out(vty, " pcu-socket-wqueue-length %u%s", bts->pcu.sock_wqueue_len_max, VTY_NEWLINE);
|
||||
if (bts->supp_meas_toa256)
|
||||
vty_out(vty, " supp-meas-info toa256%s", VTY_NEWLINE);
|
||||
vty_out(vty, " smscb queue-max-length %d%s", bts->smscb_queue_max_len, VTY_NEWLINE);
|
||||
@@ -480,7 +472,7 @@ static void config_write_bts_single(struct vty *vty, const struct gsm_bts *bts)
|
||||
const struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE);
|
||||
|
||||
if (trx->power_params.user_gain_mdB)
|
||||
if (tpp->user_gain_mdB)
|
||||
vty_out(vty, " user-gain %u mdB%s",
|
||||
tpp->user_gain_mdB, VTY_NEWLINE);
|
||||
vty_out(vty, " power-ramp max-initial %d mdBm%s",
|
||||
@@ -503,10 +495,9 @@ static void config_write_bts_single(struct vty *vty, const struct gsm_bts *bts)
|
||||
|
||||
static int config_write_bts(struct vty *vty)
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
const struct gsm_bts *bts;
|
||||
|
||||
llist_for_each_entry(bts, &net->bts_list, list)
|
||||
llist_for_each_entry(bts, &g_bts_sm->bts_list, list)
|
||||
config_write_bts_single(vty, bts);
|
||||
|
||||
osmo_tdef_vty_groups_write(vty, "");
|
||||
@@ -565,16 +556,15 @@ DEFUN_ATTR(cfg_bts,
|
||||
"BTS Number\n",
|
||||
CMD_ATTR_IMMEDIATE)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
int bts_nr = atoi(argv[0]);
|
||||
struct gsm_bts *bts;
|
||||
|
||||
if (bts_nr >= gsmnet->num_bts) {
|
||||
if (bts_nr >= g_bts_sm->num_bts) {
|
||||
vty_out(vty, "%% Unknown BTS number %u (num %u)%s",
|
||||
bts_nr, gsmnet->num_bts, VTY_NEWLINE);
|
||||
bts_nr, g_bts_sm->num_bts, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
} else
|
||||
bts = gsm_bts_num(gsmnet, bts_nr);
|
||||
bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
|
||||
vty->index = bts;
|
||||
vty->index_sub = &bts->description;
|
||||
@@ -780,6 +770,62 @@ DEFUN_USRATTR(cfg_bts_rtp_priority,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_rtp_cont_stream,
|
||||
cfg_bts_rtp_cont_stream_cmd,
|
||||
"rtp continuous-streaming",
|
||||
RTP_STR "Always emit an RTP packet every 20 ms\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
bts->rtp_nogaps_mode = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_no_rtp_cont_stream,
|
||||
cfg_bts_no_rtp_cont_stream_cmd,
|
||||
"no rtp continuous-streaming",
|
||||
NO_STR RTP_STR "Always emit an RTP packet every 20 ms\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
bts->rtp_nogaps_mode = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_rtp_int_ul_ecu,
|
||||
cfg_bts_rtp_int_ul_ecu_cmd,
|
||||
"rtp internal-uplink-ecu",
|
||||
RTP_STR "Apply a BTS-internal ECU to the uplink traffic frame stream\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
bts->use_ul_ecu = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_no_rtp_int_ul_ecu,
|
||||
cfg_bts_no_rtp_int_ul_ecu_cmd,
|
||||
"no rtp internal-uplink-ecu",
|
||||
NO_STR RTP_STR "Apply a BTS-internal ECU to the uplink traffic frame stream\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
bts->use_ul_ecu = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(cfg_bts_rtp_hr_format,
|
||||
cfg_bts_rtp_hr_format_cmd,
|
||||
"rtp hr-format (rfc5993|ts101318)",
|
||||
RTP_STR "HRv1 codec output format\n" "RFC 5993\n" "TS 101 318\n",
|
||||
CMD_ATTR_IMMEDIATE)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
bts->emit_hr_rfc5993 = !strcmp(argv[0], "rfc5993");
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define PAG_STR "Paging related parameters\n"
|
||||
|
||||
DEFUN_ATTR(cfg_bts_paging_queue_size,
|
||||
@@ -968,7 +1014,7 @@ DEFUN_ATTR(cfg_bts_max_ber_rach, cfg_bts_max_ber_rach_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_pcu_sock, cfg_bts_pcu_sock_cmd,
|
||||
DEFUN(cfg_bts_pcu_sock_path, cfg_bts_pcu_sock_path_cmd,
|
||||
"pcu-socket PATH",
|
||||
"Configure the PCU socket file/path name\n"
|
||||
"UNIX socket path\n")
|
||||
@@ -981,6 +1027,16 @@ DEFUN(cfg_bts_pcu_sock, cfg_bts_pcu_sock_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_pcu_sock_ql, cfg_bts_pcu_sock_ql_cmd,
|
||||
"pcu-socket-wqueue-length <1-" OSMO_STRINGIFY_VAL(BTS_CFG_PCU_SOCK_WQUEUE_LEN_MAX_MAX) ">",
|
||||
"Configure the PCU socket queue length\n"
|
||||
"Queue length\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
bts->pcu.sock_wqueue_len_max = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(cfg_bts_supp_meas_toa256, cfg_bts_supp_meas_toa256_cmd,
|
||||
"supp-meas-info toa256",
|
||||
"Configure the RSL Supplementary Measurement Info\n"
|
||||
@@ -1211,10 +1267,10 @@ static void bts_dump_vty_features(struct vty *vty, const struct gsm_bts *bts)
|
||||
|
||||
vty_out(vty, " BTS model specific (internal) flags:%s", VTY_NEWLINE);
|
||||
|
||||
for (i = 0, no_features = true; i < sizeof(bts->flags) * 8; i++) {
|
||||
if (bts_internal_flag_get(bts, (1 << i))) {
|
||||
for (i = 0, no_features = true; i < _BTS_INTERNAL_FLAG_NUM; i++) {
|
||||
if (bts_internal_flag_get(bts, i)) {
|
||||
vty_out(vty, " %03u ", i);
|
||||
vty_out(vty, "%-40s%s", get_value_string(bts_impl_flag_desc, (1 << i)), VTY_NEWLINE);
|
||||
vty_out(vty, "%-40s%s", get_value_string(bts_impl_flag_desc, i), VTY_NEWLINE);
|
||||
no_features = false;
|
||||
}
|
||||
}
|
||||
@@ -1253,7 +1309,7 @@ static void bts_dump_vty(struct vty *vty, const struct gsm_bts *bts)
|
||||
vty_out(vty, " NM State: ");
|
||||
net_dump_nmstate(vty, &bts->mo.nm_state);
|
||||
vty_out(vty, " Site Mgr NM State: ");
|
||||
net_dump_nmstate(vty, &bts->site_mgr.mo.nm_state);
|
||||
net_dump_nmstate(vty, &g_bts_sm->mo.nm_state);
|
||||
if (strnlen(bts->pcu_version, MAX_VERSION_LENGTH))
|
||||
vty_out(vty, " PCU version %s connected%s",
|
||||
bts->pcu_version, VTY_NEWLINE);
|
||||
@@ -1312,23 +1368,22 @@ DEFUN(show_bts, show_bts_cmd, "show bts [<0-255>]",
|
||||
SHOW_STR "Display information about a BTS\n"
|
||||
BTS_NR_STR)
|
||||
{
|
||||
const struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
int bts_nr;
|
||||
|
||||
if (argc != 0) {
|
||||
/* use the BTS number that the user has specified */
|
||||
bts_nr = atoi(argv[0]);
|
||||
if (bts_nr >= net->num_bts) {
|
||||
if (bts_nr >= g_bts_sm->num_bts) {
|
||||
vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
|
||||
bts_dump_vty(vty, gsm_bts_num(g_bts_sm, bts_nr));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
/* print all BTS's */
|
||||
for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++)
|
||||
bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
|
||||
for (bts_nr = 0; bts_nr < g_bts_sm->num_bts; bts_nr++)
|
||||
bts_dump_vty(vty, gsm_bts_num(g_bts_sm, bts_nr));
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -1336,21 +1391,22 @@ DEFUN(show_bts, show_bts_cmd, "show bts [<0-255>]",
|
||||
static void gprs_dump_vty(struct vty *vty, const struct gsm_bts *bts)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct gsm_gprs_nse *nse = &bts->site_mgr->gprs.nse;
|
||||
|
||||
/* GPRS parameters received from the BSC */
|
||||
vty_out(vty, "BTS %u, RAC %u, NSEI %u, BVCI %u%s",
|
||||
bts->nr, bts->gprs.rac,
|
||||
bts->gprs.nse.nsei,
|
||||
nse->nsei,
|
||||
bts->gprs.cell.bvci,
|
||||
VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " Cell NM state: ");
|
||||
net_dump_nmstate(vty, &bts->gprs.cell.mo.nm_state);
|
||||
vty_out(vty, " NSE NM state: ");
|
||||
net_dump_nmstate(vty, &bts->gprs.nse.mo.nm_state);
|
||||
net_dump_nmstate(vty, &nse->mo.nm_state);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
|
||||
const struct gsm_bts_gprs_nsvc *nsvc = &bts->gprs.nsvc[i];
|
||||
for (i = 0; i < ARRAY_SIZE(nse->nsvc); i++) {
|
||||
const struct gsm_gprs_nsvc *nsvc = &nse->nsvc[i];
|
||||
|
||||
vty_out(vty, " NSVC%u (NSVCI %u) NM state: ", i, nsvc->nsvci);
|
||||
net_dump_nmstate(vty, &nsvc->mo.nm_state);
|
||||
@@ -1385,10 +1441,9 @@ DEFUN(show_bts_gprs, show_bts_gprs_cmd,
|
||||
SHOW_STR "Display information about a BTS\n"
|
||||
BTS_NR_STR "GPRS/EGPRS configuration\n")
|
||||
{
|
||||
const struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
const struct gsm_bts *bts;
|
||||
|
||||
bts = gsm_bts_num(net, atoi(argv[0]));
|
||||
bts = gsm_bts_num(g_bts_sm, atoi(argv[0]));
|
||||
if (bts == NULL) {
|
||||
vty_out(vty, "%% can't find BTS '%s'%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
@@ -1404,16 +1459,15 @@ DEFUN(test_send_failure_event_report, test_send_failure_event_report_cmd, "test
|
||||
"Various testing commands\n"
|
||||
"Send a test OML failure event report to the BSC\n" BTS_NR_STR)
|
||||
{
|
||||
const struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
int bts_nr = atoi(argv[0]);
|
||||
const struct gsm_bts *bts;
|
||||
|
||||
if (bts_nr >= net->num_bts) {
|
||||
if (bts_nr >= g_bts_sm->num_bts) {
|
||||
vty_out(vty, "%% can't find BTS '%s'%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
bts = gsm_bts_num(net, bts_nr);
|
||||
bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MINOR, OSMO_EVT_WARN_SW_WARN, "test message sent from VTY");
|
||||
|
||||
return CMD_SUCCESS;
|
||||
@@ -1425,9 +1479,8 @@ DEFUN_HIDDEN(radio_link_timeout, radio_link_timeout_cmd, "bts <0-0> radio-link-t
|
||||
"Use infinite timeout (DANGEROUS: only use during testing!)\n"
|
||||
"Number of lost SACCH blocks\n")
|
||||
{
|
||||
const struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
int bts_nr = atoi(argv[0]);
|
||||
struct gsm_bts *bts = gsm_bts_num(net, bts_nr);
|
||||
struct gsm_bts *bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% can't find BTS '%s'%s", argv[0], VTY_NEWLINE);
|
||||
@@ -1456,12 +1509,11 @@ DEFUN(bts_c0_power_red,
|
||||
"BCCH carrier power reduction operation\n"
|
||||
"Power reduction value (in dB, even numbers only)\n")
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
const int bts_nr = atoi(argv[0]);
|
||||
const int red = atoi(argv[1]);
|
||||
struct gsm_bts *bts;
|
||||
|
||||
bts = gsm_bts_num(net, atoi(argv[0]));
|
||||
bts = gsm_bts_num(g_bts_sm, atoi(argv[0]));
|
||||
if (bts == NULL) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -1592,10 +1644,10 @@ static void trx_dump_vty(struct vty *vty, const struct gsm_bts_trx *trx)
|
||||
|
||||
vty_out(vty, " NM State: ");
|
||||
net_dump_nmstate(vty, &trx->mo.nm_state);
|
||||
vty_out(vty, " RSL State: %s%s", trx->rsl_link? "connected" : "disconnected", VTY_NEWLINE);
|
||||
vty_out(vty, " RSL State: %s%s", trx->bb_transc.rsl.link ? "connected" : "disconnected", VTY_NEWLINE);
|
||||
vty_out(vty, " Baseband Transceiver NM State: ");
|
||||
net_dump_nmstate(vty, &trx->bb_transc.mo.nm_state);
|
||||
vty_out(vty, " IPA stream ID: 0x%02x%s", trx->rsl_tei, VTY_NEWLINE);
|
||||
vty_out(vty, " IPA stream ID: 0x%02x%s", trx->bb_transc.rsl.tei, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static inline void print_all_trx(struct vty *vty, const struct gsm_bts *bts)
|
||||
@@ -1611,19 +1663,18 @@ DEFUN(show_trx,
|
||||
SHOW_STR "Display information about a TRX\n"
|
||||
BTS_TRX_STR)
|
||||
{
|
||||
const struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
const struct gsm_bts *bts = NULL;
|
||||
int bts_nr, trx_nr;
|
||||
|
||||
if (argc >= 1) {
|
||||
/* use the BTS number that the user has specified */
|
||||
bts_nr = atoi(argv[0]);
|
||||
if (bts_nr >= net->num_bts) {
|
||||
if (bts_nr >= g_bts_sm->num_bts) {
|
||||
vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
bts = gsm_bts_num(net, bts_nr);
|
||||
bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
}
|
||||
if (argc >= 2) {
|
||||
trx_nr = atoi(argv[1]);
|
||||
@@ -1641,8 +1692,8 @@ DEFUN(show_trx,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++)
|
||||
print_all_trx(vty, gsm_bts_num(net, bts_nr));
|
||||
for (bts_nr = 0; bts_nr < g_bts_sm->num_bts; bts_nr++)
|
||||
print_all_trx(vty, gsm_bts_num(g_bts_sm, bts_nr));
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -1667,7 +1718,6 @@ DEFUN(show_ts,
|
||||
SHOW_STR "Display information about a TS\n"
|
||||
BTS_TRX_TS_STR)
|
||||
{
|
||||
const struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
const struct gsm_bts *bts = NULL;
|
||||
const struct gsm_bts_trx *trx = NULL;
|
||||
const struct gsm_bts_trx_ts *ts = NULL;
|
||||
@@ -1676,12 +1726,12 @@ DEFUN(show_ts,
|
||||
if (argc >= 1) {
|
||||
/* use the BTS number that the user has specified */
|
||||
bts_nr = atoi(argv[0]);
|
||||
if (bts_nr >= net->num_bts) {
|
||||
if (bts_nr >= g_bts_sm->num_bts) {
|
||||
vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
bts = gsm_bts_num(net, bts_nr);
|
||||
bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
}
|
||||
if (argc >= 2) {
|
||||
trx_nr = atoi(argv[1]);
|
||||
@@ -1722,8 +1772,8 @@ DEFUN(show_ts,
|
||||
}
|
||||
} else {
|
||||
/* Iterate over all BTS, TRX in each BTS, TS in each TRX */
|
||||
for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
|
||||
bts = gsm_bts_num(net, bts_nr);
|
||||
for (bts_nr = 0; bts_nr < g_bts_sm->num_bts; bts_nr++) {
|
||||
bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
|
||||
trx = gsm_bts_trx_num(bts, trx_nr);
|
||||
for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
|
||||
@@ -1941,6 +1991,19 @@ static void lchan_dump_full_vty(struct vty *vty, const struct gsm_lchan *lchan)
|
||||
vty_out(vty, " Channel Mode / Codec: %s%s",
|
||||
gsm48_chan_mode_name(lchan->tch_mode),
|
||||
VTY_NEWLINE);
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
const struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr;
|
||||
const struct gsm48_multi_rate_conf *mr_conf =
|
||||
(const struct gsm48_multi_rate_conf *) amr_mrc->gsm48_ie;
|
||||
vty_out(vty, " AMR Multi-Rate Configuration: ICMI=%u, Start Mode=%u gsm48=%02x%02x%s",
|
||||
mr_conf->icmi, mr_conf->smod, amr_mrc->gsm48_ie[0], amr_mrc->gsm48_ie[1], VTY_NEWLINE);
|
||||
for (uint8_t i = 0; i < amr_mrc->num_modes; i++) {
|
||||
const struct amr_mode *amode = &amr_mrc->mode[i];
|
||||
vty_out(vty, " AMR Mode %u (%s), threshold=%u, hysteresis=%u%s",
|
||||
amode->mode, osmo_amr_type_name(amode->mode),
|
||||
amode->threshold, amode->hysteresis, VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
|
||||
if (lchan->abis_ip.bound_ip) {
|
||||
ia.s_addr = htonl(lchan->abis_ip.bound_ip);
|
||||
@@ -2073,7 +2136,6 @@ static int dump_lchan_bts(const struct gsm_bts *bts, struct vty *vty,
|
||||
static int lchan_summary(struct vty *vty, int argc, const char **argv,
|
||||
void (*dump_cb)(struct vty *, const struct gsm_lchan *))
|
||||
{
|
||||
const struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
const struct gsm_bts *bts = NULL; /* initialize to avoid uninitialized false warnings on some gcc versions (11.1.0) */
|
||||
const struct gsm_bts_trx *trx = NULL; /* initialize to avoid uninitialized false warnings on some gcc versions (11.1.0) */
|
||||
const struct gsm_bts_trx_ts *ts = NULL; /* initialize to avoid uninitialized false warnings on some gcc versions (11.1.0) */
|
||||
@@ -2083,12 +2145,12 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
|
||||
if (argc >= 1) {
|
||||
/* use the BTS number that the user has specified */
|
||||
bts_nr = atoi(argv[0]);
|
||||
if (bts_nr >= net->num_bts) {
|
||||
if (bts_nr >= g_bts_sm->num_bts) {
|
||||
vty_out(vty, "%% can't find BTS %s%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
bts = gsm_bts_num(net, bts_nr);
|
||||
bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
|
||||
if (argc == 1)
|
||||
return dump_lchan_bts(bts, vty, dump_cb);
|
||||
@@ -2129,8 +2191,8 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
|
||||
bts = gsm_bts_num(net, bts_nr);
|
||||
for (bts_nr = 0; bts_nr < g_bts_sm->num_bts; bts_nr++) {
|
||||
bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
dump_lchan_bts(bts, vty, dump_cb);
|
||||
}
|
||||
|
||||
@@ -2156,8 +2218,7 @@ DEFUN(show_lchan_summary,
|
||||
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
|
||||
}
|
||||
|
||||
static struct gsm_lchan *resolve_lchan(const struct gsm_network *net,
|
||||
const char **argv, int idx)
|
||||
static struct gsm_lchan *resolve_lchan(const char **argv, int idx)
|
||||
{
|
||||
int bts_nr = atoi(argv[idx+0]);
|
||||
int trx_nr = atoi(argv[idx+1]);
|
||||
@@ -2168,7 +2229,7 @@ static struct gsm_lchan *resolve_lchan(const struct gsm_network *net,
|
||||
struct gsm_bts_trx *trx;
|
||||
struct gsm_bts_trx_ts *ts;
|
||||
|
||||
bts = gsm_bts_num(net, bts_nr);
|
||||
bts = gsm_bts_num(g_bts_sm, bts_nr);
|
||||
if (!bts)
|
||||
return NULL;
|
||||
|
||||
@@ -2433,11 +2494,10 @@ DEFUN(bts_t_t_l_jitter_buf,
|
||||
BTS_T_T_L_STR "RTP settings\n"
|
||||
"Jitter buffer\n" "Size of jitter buffer in (ms)\n")
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
struct gsm_lchan *lchan;
|
||||
int jitbuf_ms = atoi(argv[4]), rc;
|
||||
|
||||
lchan = resolve_lchan(net, argv, 0);
|
||||
lchan = resolve_lchan(argv, 0);
|
||||
if (!lchan) {
|
||||
vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -2466,10 +2526,9 @@ DEFUN_ATTR(bts_t_t_l_loopback,
|
||||
BTS_T_T_L_STR "Set loopback\n",
|
||||
CMD_ATTR_HIDDEN)
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
struct gsm_lchan *lchan;
|
||||
|
||||
lchan = resolve_lchan(net, argv, 0);
|
||||
lchan = resolve_lchan(argv, 0);
|
||||
if (!lchan) {
|
||||
vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -2485,10 +2544,9 @@ DEFUN_ATTR(no_bts_t_t_l_loopback,
|
||||
NO_STR BTS_T_T_L_STR "Set loopback\n",
|
||||
CMD_ATTR_HIDDEN)
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
struct gsm_lchan *lchan;
|
||||
|
||||
lchan = resolve_lchan(net, argv, 0);
|
||||
lchan = resolve_lchan(argv, 0);
|
||||
if (!lchan) {
|
||||
vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -2511,13 +2569,12 @@ DEFUN_ATTR(bts_t_t_l_power_ctrl_mode,
|
||||
"Enable the power control loop\n",
|
||||
CMD_ATTR_HIDDEN)
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
const struct gsm_power_ctrl_params *params;
|
||||
struct lchan_power_ctrl_state *state;
|
||||
const char **args = argv + 4;
|
||||
struct gsm_lchan *lchan;
|
||||
|
||||
lchan = resolve_lchan(net, argv, 0);
|
||||
lchan = resolve_lchan(argv, 0);
|
||||
if (!lchan) {
|
||||
vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -2548,12 +2605,11 @@ DEFUN_ATTR(bts_t_t_l_power_ctrl_current_max,
|
||||
"BS power reduction (in dB) or MS power level\n",
|
||||
CMD_ATTR_HIDDEN)
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
struct lchan_power_ctrl_state *state;
|
||||
const char **args = argv + 4;
|
||||
struct gsm_lchan *lchan;
|
||||
|
||||
lchan = resolve_lchan(net, argv, 0);
|
||||
lchan = resolve_lchan(argv, 0);
|
||||
if (!lchan) {
|
||||
vty_out(vty, "%% Could not resolve logical channel%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -2667,6 +2723,11 @@ int bts_vty_init(void *ctx)
|
||||
install_element(BTS_NODE, &cfg_bts_rtp_port_range_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rtp_ip_dscp_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rtp_priority_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rtp_cont_stream_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_no_rtp_cont_stream_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rtp_int_ul_ecu_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_no_rtp_int_ul_ecu_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rtp_hr_format_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_band_cmd);
|
||||
install_element(BTS_NODE, &cfg_description_cmd);
|
||||
install_element(BTS_NODE, &cfg_no_description_cmd);
|
||||
@@ -2681,7 +2742,8 @@ int bts_vty_init(void *ctx)
|
||||
install_element(BTS_NODE, &cfg_bts_min_qual_rach_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_min_qual_norm_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_max_ber_rach_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_pcu_sock_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_pcu_sock_path_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_pcu_sock_ql_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_supp_meas_toa256_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_no_supp_meas_toa256_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_smscb_max_qlen_cmd);
|
||||
|
||||
@@ -347,7 +347,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
|
||||
abort();
|
||||
}
|
||||
|
||||
len = msgb_l2len(msg);
|
||||
len = (msg->l2h) ? msgb_l2len(msg) : 0;
|
||||
|
||||
chan_nr = l1sap->u.data.chan_nr;
|
||||
link_id = l1sap->u.data.link_id;
|
||||
@@ -395,9 +395,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
|
||||
else
|
||||
sapi = GsmL1_Sapi_Agch;
|
||||
} else {
|
||||
LOGPFN(DL1C, LOGL_NOTICE, u32Fn, "unknown prim %d op %d "
|
||||
"chan_nr %d link_id %d\n", l1sap->oph.primitive,
|
||||
l1sap->oph.operation, chan_nr, link_id);
|
||||
LOGPLCFN(lchan, u32Fn, DL1C, LOGL_NOTICE, "unknown prim %d op %d chan_nr %d link_id %d\n",
|
||||
l1sap->oph.primitive, l1sap->oph.operation, chan_nr, link_id);
|
||||
msgb_free(l1msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -458,9 +457,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
|
||||
memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h,
|
||||
msgb_l2len(msg));
|
||||
}
|
||||
LOGPFN(DL1P, LOGL_DEBUG, u32Fn, "PH-DATA.req(%s)\n",
|
||||
osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
|
||||
l1p->u.phDataReq.msgUnitParam.u8Size));
|
||||
LOGPLCFN(lchan, u32Fn, DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n",
|
||||
osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, l1p->u.phDataReq.msgUnitParam.u8Size));
|
||||
} else {
|
||||
/* empty frame */
|
||||
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
|
||||
@@ -470,7 +468,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
|
||||
|
||||
/* send message to DSP's queue */
|
||||
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], l1msg) != 0) {
|
||||
LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
|
||||
LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
|
||||
msgb_free(l1msg);
|
||||
} else
|
||||
dtx_int_signal(lchan);
|
||||
@@ -553,7 +551,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
|
||||
}
|
||||
/* send message to DSP's queue */
|
||||
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg) < 0) {
|
||||
LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
|
||||
LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
|
||||
msgb_free(nmsg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
@@ -1249,7 +1247,6 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
|
||||
Litecell15_Prim_t *sysp = msgb_sysprim(resp);
|
||||
GsmL1_Status_t status;
|
||||
int on = 0;
|
||||
unsigned int i;
|
||||
|
||||
if (sysp->id == Litecell15_PrimId_ActivateRfCnf)
|
||||
on = 1;
|
||||
@@ -1280,8 +1277,8 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
|
||||
} else {
|
||||
if (bts_lc15->led_ctrl_mode == LC15_LED_CONTROL_BTS)
|
||||
bts_update_status(BTS_STATUS_RF_ACTIVE, 0);
|
||||
osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
|
||||
osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);
|
||||
osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
|
||||
osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL);
|
||||
}
|
||||
|
||||
msgb_free(resp);
|
||||
@@ -1429,6 +1426,30 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
|
||||
LOGP(DL1C, LOGL_FATAL, "BTS band %s not supported by hw\n",
|
||||
gsm_band_name(trx->bts->band));
|
||||
|
||||
/* Frequency bands indicated to the BSC */
|
||||
switch (fl1h->hw_info.band_support) {
|
||||
case GSM_BAND_450:
|
||||
trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_450;
|
||||
break;
|
||||
case GSM_BAND_480:
|
||||
trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_480;
|
||||
break;
|
||||
case GSM_BAND_850:
|
||||
trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_850;
|
||||
break;
|
||||
case GSM_BAND_900:
|
||||
trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PGSM;
|
||||
/* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_EGSM? */
|
||||
/* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_RGSM? */
|
||||
break;
|
||||
case GSM_BAND_1800:
|
||||
trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_DCS;
|
||||
break;
|
||||
case GSM_BAND_1900:
|
||||
trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PCS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Request the activation */
|
||||
l1if_activate_rf(fl1h, 1);
|
||||
|
||||
|
||||
@@ -89,6 +89,8 @@ int bts_model_init(struct gsm_bts *bts)
|
||||
bts->model_priv = bts_lc15;
|
||||
bts->variant = BTS_OSMO_LITECELL15;
|
||||
bts->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
|
||||
bts->gprs.cell.support.gprs_codings = NM_IPAC_MASK_GPRS_CODING_CS
|
||||
| NM_IPAC_MASK_GPRS_CODING_MCS;
|
||||
|
||||
/* specific default values for LC15 platform */
|
||||
bts_lc15->led_ctrl_mode = LC15_BTS_LED_CTRL_MODE_DEFAULT;
|
||||
@@ -102,6 +104,7 @@ int bts_model_init(struct gsm_bts *bts)
|
||||
|
||||
/* order alphabetically */
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_AGCH_PCH_PROP);
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_CBCH);
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_EGPRS);
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_GPRS);
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_OML_ALERTS);
|
||||
@@ -114,11 +117,28 @@ int bts_model_init(struct gsm_bts *bts)
|
||||
bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP);
|
||||
bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER);
|
||||
|
||||
/* The default HR codec output format in the absence of saved
|
||||
* vty config needs to match what was implemented previously,
|
||||
* for the sake of existing deployments, i.e., to avoid
|
||||
* a surprise functional change upon software update. */
|
||||
bts->emit_hr_rfc5993 = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bts_model_trx_init(struct gsm_bts_trx *trx)
|
||||
{
|
||||
/* Frequency bands indicated to the BSC */
|
||||
trx->support.freq_bands = 0x00; /* updated in info_compl_cb() */
|
||||
|
||||
/* Channel types and modes indicated to the BSC */
|
||||
trx->support.chan_types = NM_IPAC_MASK_CHANT_COMMON
|
||||
| NM_IPAC_F_CHANT_BCCH_SDCCH4_CBCH
|
||||
| NM_IPAC_F_CHANT_SDCCH8_CBCH
|
||||
| NM_IPAC_F_CHANT_PDCHF
|
||||
| NM_IPAC_F_CHANT_TCHF_PDCHF;
|
||||
trx->support.chan_modes = NM_IPAC_MASK_CHANM_SPEECH;
|
||||
|
||||
trx->nominal_power = 40;
|
||||
trx->power_params.trx_p_max_out_mdBm = to_mdB(trx->bts->c0->nominal_power);
|
||||
return 0;
|
||||
|
||||
@@ -89,39 +89,10 @@ static int go_to_parent(struct vty *vty)
|
||||
return vty->node;
|
||||
}
|
||||
|
||||
static int is_config_node(struct vty *vty, int node)
|
||||
{
|
||||
switch (node) {
|
||||
case MGR_NODE:
|
||||
case ACT_NORM_NODE:
|
||||
case ACT_WARN_NODE:
|
||||
case ACT_CRIT_NODE:
|
||||
case LIMIT_SUPPLY_TEMP_NODE:
|
||||
case LIMIT_SOC_NODE:
|
||||
case LIMIT_FPGA_NODE:
|
||||
case LIMIT_RMSDET_NODE:
|
||||
case LIMIT_OCXO_NODE:
|
||||
case LIMIT_TX0_TEMP_NODE:
|
||||
case LIMIT_TX1_TEMP_NODE:
|
||||
case LIMIT_PA0_TEMP_NODE:
|
||||
case LIMIT_PA1_TEMP_NODE:
|
||||
case LIMIT_SUPPLY_VOLT_NODE:
|
||||
case LIMIT_TX0_VSWR_NODE:
|
||||
case LIMIT_TX1_VSWR_NODE:
|
||||
case LIMIT_SUPPLY_PWR_NODE:
|
||||
case LIMIT_PA0_PWR_NODE:
|
||||
case LIMIT_PA1_PWR_NODE:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct vty_app_info vty_info = {
|
||||
.name = "lc15bts-mgr",
|
||||
.version = PACKAGE_VERSION,
|
||||
.go_parent_cb = go_to_parent,
|
||||
.is_config_node = is_config_node,
|
||||
.copyright = copyright,
|
||||
};
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
#include "lc15bts.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void dump_lch_par(int logl, GsmL1_LogChParam_t *lch_par, GsmL1_Sapi_t sapi);
|
||||
|
||||
static int mph_info_chan_confirm(struct gsm_lchan *lchan,
|
||||
enum osmo_mph_info_type type, uint8_t cause)
|
||||
{
|
||||
@@ -569,8 +571,7 @@ GsmL1_Sapi_t lchan_to_GsmL1_Sapi_t(const struct gsm_lchan *lchan)
|
||||
case GSM_LCHAN_TCH_H:
|
||||
return GsmL1_Sapi_TchH;
|
||||
default:
|
||||
LOGP(DL1C, LOGL_NOTICE, "%s cannot determine L1 SAPI\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "cannot determine L1 SAPI\n");
|
||||
break;
|
||||
}
|
||||
return GsmL1_Sapi_Idle;
|
||||
@@ -781,12 +782,8 @@ static void sapi_queue_dispatch(struct gsm_lchan *lchan, int status)
|
||||
talloc_free(cmd);
|
||||
|
||||
if (end || llist_empty(&lchan->sapi_cmds)) {
|
||||
LOGP(DL1C, LOGL_DEBUG,
|
||||
"%s End of SAPI cmd queue encountered.%s\n",
|
||||
gsm_lchan_name(lchan),
|
||||
llist_empty(&lchan->sapi_cmds)
|
||||
? " Queue is now empty."
|
||||
: " More pending.");
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_DEBUG, "End of SAPI cmd queue encountered.%s\n",
|
||||
llist_empty(&lchan->sapi_cmds) ? " Queue is now empty." : " More pending.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -826,9 +823,8 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOGP(DL1C, LOGL_INFO, "%s MPH-ACTIVATE.conf (%s ",
|
||||
gsm_lchan_name(lchan),
|
||||
get_value_string(lc15bts_l1sapi_names, ic->sapi));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-ACTIVATE.conf (%s ",
|
||||
get_value_string(lc15bts_l1sapi_names, ic->sapi));
|
||||
LOGPC(DL1C, LOGL_INFO, "%s)\n",
|
||||
get_value_string(lc15bts_dir_names, ic->dir));
|
||||
|
||||
@@ -849,19 +845,15 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
|
||||
lchan->sapis_ul[ic->sapi] = status;
|
||||
|
||||
if (llist_empty(&lchan->sapi_cmds)) {
|
||||
LOGP(DL1C, LOGL_ERROR,
|
||||
"%s Got activation confirmation with empty queue\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got activation confirmation with empty queue\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
|
||||
if (cmd->sapi != ic->sapi || cmd->dir != ic->dir ||
|
||||
cmd->type != SAPI_CMD_ACTIVATE) {
|
||||
LOGP(DL1C, LOGL_ERROR,
|
||||
"%s Confirmation mismatch (%d, %d) (%d, %d)\n",
|
||||
gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
|
||||
ic->sapi, ic->dir);
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Confirmation mismatch (%d, %d) (%d, %d)\n",
|
||||
cmd->sapi, cmd->dir, ic->sapi, ic->dir);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -942,8 +934,7 @@ static int lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
|
||||
(struct gsm48_multi_rate_conf *) amr_mrc->gsm48_ie;
|
||||
int j;
|
||||
|
||||
LOGP(DL1C, LOGL_INFO, "%s: %s tch_mode=0x%02x\n",
|
||||
gsm_lchan_name(lchan), __FUNCTION__, lchan->tch_mode);
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "%s tch_mode=0x%02x\n", __func__, lchan->tch_mode);
|
||||
|
||||
switch (lchan->tch_mode) {
|
||||
case GSM48_CMODE_SIGN:
|
||||
@@ -971,7 +962,9 @@ static int lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
|
||||
case GSM48_CMODE_SPEECH_AMR:
|
||||
lch_par->tch.tchPlType = GsmL1_TchPlType_Amr;
|
||||
set_payload_format(lch_par);
|
||||
lch_par->tch.amrCmiPhase = GsmL1_AmrCmiPhase_Odd; /* FIXME? */
|
||||
/* At call set-up, after every successful handover and after a channel mode modify, the
|
||||
* default phase (odd) shall be used in downlink direction. */
|
||||
lch_par->tch.amrCmiPhase = GsmL1_AmrCmiPhase_Odd;
|
||||
lch_par->tch.amrInitCodecMode = amr_get_initial_mode(lchan);
|
||||
|
||||
/* initialize to clean state */
|
||||
@@ -1094,9 +1087,9 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
|
||||
break;
|
||||
}
|
||||
|
||||
LOGP(DL1C, LOGL_INFO, "%s MPH-ACTIVATE.req (hL2=0x%08x, %s ",
|
||||
gsm_lchan_name(lchan), (uint32_t)act_req->hLayer2,
|
||||
get_value_string(lc15bts_l1sapi_names, act_req->sapi));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-ACTIVATE.req (hL2=0x%08x, %s ",
|
||||
(uint32_t)act_req->hLayer2, get_value_string(lc15bts_l1sapi_names, act_req->sapi));
|
||||
dump_lch_par(LOGL_INFO, lch_par, act_req->sapi);
|
||||
LOGPC(DL1C, LOGL_INFO, "%s)\n",
|
||||
get_value_string(lc15bts_dir_names, act_req->dir));
|
||||
|
||||
@@ -1120,9 +1113,7 @@ static int sapi_activate_cb(struct gsm_lchan *lchan, int status)
|
||||
|
||||
/* FIXME: Error handling */
|
||||
if (status != GsmL1_Status_Success) {
|
||||
LOGP(DL1C, LOGL_ERROR,
|
||||
"%s act failed mark broken due status: %d\n",
|
||||
gsm_lchan_name(lchan), status);
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "act failed mark broken due status: %d\n", status);
|
||||
lchan_set_state(lchan, LCHAN_S_BROKEN);
|
||||
sapi_clear_queue(&lchan->sapi_cmds);
|
||||
mph_info_chan_confirm(lchan, PRIM_INFO_ACTIVATE, RSL_ERR_PROCESSOR_OVERLOAD);
|
||||
@@ -1169,13 +1160,11 @@ int lchan_activate(struct gsm_lchan *lchan)
|
||||
lchan_set_state(lchan, LCHAN_S_ACT_REQ);
|
||||
|
||||
if (!llist_empty(&lchan->sapi_cmds))
|
||||
LOGP(DL1C, LOGL_ERROR,
|
||||
"%s Trying to activate lchan, but commands in queue\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Trying to activate lchan, but commands in queue\n");
|
||||
|
||||
/* For handover, always start the main channel immediately. lchan->want_dl_sacch_active indicates whether dl
|
||||
* SACCH should be activated. Also, for HO, start the RACH SAPI. */
|
||||
if (lchan->ho.active == HANDOVER_ENABLED)
|
||||
if (lchan->ho.active == HANDOVER_ENABLED || rsl_chan_rt_is_asci(lchan->rsl_chan_rt))
|
||||
enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
|
||||
|
||||
for (i = 0; i < s4l->num_sapis; i++) {
|
||||
@@ -1332,9 +1321,8 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.conf (%s) ",
|
||||
gsm_lchan_name(lchan),
|
||||
get_value_string(lc15bts_l1cfgt_names, cc->cfgParamId));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-CONFIG.conf (%s) ",
|
||||
get_value_string(lc15bts_l1cfgt_names, cc->cfgParamId));
|
||||
|
||||
switch (cc->cfgParamId) {
|
||||
case GsmL1_ConfigParamId_SetLogChParams:
|
||||
@@ -1366,9 +1354,7 @@ static int chmod_modif_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
|
||||
break;
|
||||
}
|
||||
if (llist_empty(&lchan->sapi_cmds)) {
|
||||
LOGP(DL1C, LOGL_ERROR,
|
||||
"%s Got ciphering conf with empty queue\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got ciphering conf with empty queue\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -1419,10 +1405,8 @@ static int mph_send_config_logchpar(struct gsm_lchan *lchan, struct sapi_cmd *cm
|
||||
|
||||
/* FIXME: update encryption */
|
||||
|
||||
LOGP(DL1C, LOGL_INFO, "%s MPH-CONFIG.req (%s) ",
|
||||
gsm_lchan_name(lchan),
|
||||
get_value_string(lc15bts_l1sapi_names,
|
||||
conf_req->cfgParams.setLogChParams.sapi));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-CONFIG.req (%s) ",
|
||||
get_value_string(lc15bts_l1sapi_names, conf_req->cfgParams.setLogChParams.sapi));
|
||||
LOGPC(DL1C, LOGL_INFO, "cfgParams Tn=%u, subCh=%u, dir=0x%x ",
|
||||
conf_req->cfgParams.setLogChParams.u8Tn,
|
||||
conf_req->cfgParams.setLogChParams.subCh,
|
||||
@@ -1532,11 +1516,9 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c
|
||||
return -EINVAL;
|
||||
cfgr->cfgParams.setCipheringParams.cipherId = rsl2l1_ciph[lchan->encr.alg_id];
|
||||
|
||||
LOGP(DL1C, LOGL_NOTICE, "%s SET_CIPHERING (ALG=%u %s)\n",
|
||||
gsm_lchan_name(lchan),
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "SET_CIPHERING (ALG=%u %s)\n",
|
||||
cfgr->cfgParams.setCipheringParams.cipherId,
|
||||
get_value_string(lc15bts_dir_names,
|
||||
cfgr->cfgParams.setCipheringParams.dir));
|
||||
get_value_string(lc15bts_dir_names, cfgr->cfgParams.setCipheringParams.dir));
|
||||
|
||||
memcpy(cfgr->cfgParams.setCipheringParams.u8Kc,
|
||||
lchan->encr.key, lchan->encr.key_len);
|
||||
@@ -1614,9 +1596,8 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOGP(DL1C, LOGL_INFO, "%s MPH-DEACTIVATE.conf (%s ",
|
||||
gsm_lchan_name(lchan),
|
||||
get_value_string(lc15bts_l1sapi_names, ic->sapi));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-DEACTIVATE.conf (%s ",
|
||||
get_value_string(lc15bts_l1sapi_names, ic->sapi));
|
||||
LOGPC(DL1C, LOGL_INFO, "%s)\n",
|
||||
get_value_string(lc15bts_dir_names, ic->dir));
|
||||
|
||||
@@ -1638,19 +1619,15 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
|
||||
|
||||
|
||||
if (llist_empty(&lchan->sapi_cmds)) {
|
||||
LOGP(DL1C, LOGL_ERROR,
|
||||
"%s Got de-activation confirmation with empty queue\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Got de-activation confirmation with empty queue\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
|
||||
if (cmd->sapi != ic->sapi || cmd->dir != ic->dir ||
|
||||
cmd->type != SAPI_CMD_DEACTIVATE) {
|
||||
LOGP(DL1C, LOGL_ERROR,
|
||||
"%s Confirmation mismatch (%d, %d) (%d, %d)\n",
|
||||
gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
|
||||
ic->sapi, ic->dir);
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Confirmation mismatch (%d, %d) (%d, %d)\n",
|
||||
cmd->sapi, cmd->dir, ic->sapi, ic->dir);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -1675,9 +1652,8 @@ static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd
|
||||
deact_req->sapi = cmd->sapi;
|
||||
deact_req->hLayer3 = (HANDLE)l1if_lchan_to_hLayer(lchan);
|
||||
|
||||
LOGP(DL1C, LOGL_INFO, "%s MPH-DEACTIVATE.req (%s ",
|
||||
gsm_lchan_name(lchan),
|
||||
get_value_string(lc15bts_l1sapi_names, deact_req->sapi));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "MPH-DEACTIVATE.req (%s ",
|
||||
get_value_string(lc15bts_l1sapi_names, deact_req->sapi));
|
||||
LOGPC(DL1C, LOGL_INFO, "%s)\n",
|
||||
get_value_string(lc15bts_dir_names, deact_req->dir));
|
||||
|
||||
@@ -1689,8 +1665,7 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status)
|
||||
{
|
||||
/* FIXME: Error handling. There is no NACK... */
|
||||
if (status != GsmL1_Status_Success && lchan->state == LCHAN_S_REL_REQ) {
|
||||
LOGP(DL1C, LOGL_ERROR, "%s is now broken. Stopping the release.\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "is now broken. Stopping the release.\n");
|
||||
lchan_set_state(lchan, LCHAN_S_BROKEN);
|
||||
sapi_clear_queue(&lchan->sapi_cmds);
|
||||
mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0);
|
||||
@@ -1775,8 +1750,7 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
|
||||
|
||||
/* nothing was queued */
|
||||
if (res == 0) {
|
||||
LOGP(DL1C, LOGL_ERROR, "%s all SAPIs already released?\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "all SAPIs already released?\n");
|
||||
lchan_set_state(lchan, LCHAN_S_BROKEN);
|
||||
mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0);
|
||||
}
|
||||
@@ -1827,36 +1801,22 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
|
||||
}
|
||||
|
||||
/* callback from OML */
|
||||
int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
|
||||
struct tlv_parsed *new_attr, int kind, void *obj)
|
||||
int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg,
|
||||
struct gsm_abis_mo *mo, void *obj)
|
||||
{
|
||||
struct abis_om_fom_hdr *foh = msgb_l3(msg);
|
||||
struct gsm_abis_mo *mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
|
||||
struct nm_fsm_ev_setattr_data ev_data = {
|
||||
.msg = msg,
|
||||
.cause = 0,
|
||||
};
|
||||
int rc;
|
||||
struct gsm_bts_trx *trx;
|
||||
struct lc15l1_hdl *fl1h;
|
||||
uint8_t cell_size;
|
||||
|
||||
/* TODO: NM Object without FSM: */
|
||||
switch (foh->obj_class) {
|
||||
case NM_OC_GPRS_NSE:
|
||||
case NM_OC_GPRS_CELL:
|
||||
case NM_OC_GPRS_NSVC:
|
||||
return oml_fom_ack_nack(ev_data.msg, ev_data.cause);
|
||||
}
|
||||
|
||||
switch (foh->msg_type) {
|
||||
case NM_MT_SET_RADIO_ATTR:
|
||||
trx = obj;
|
||||
fl1h = trx_lc15l1_hdl(trx);
|
||||
/* convert max TA to max cell size in qbits */
|
||||
cell_size = bts->max_ta << 2;
|
||||
|
||||
#if LITECELL15_API_VERSION >= LITECELL15_API(2,1,7)
|
||||
{
|
||||
/* convert max TA to max cell size in qbits */
|
||||
uint8_t cell_size = bts->max_ta << 2;
|
||||
/* We do not need to check for L1 handle
|
||||
* because the max cell size parameter can receive before MphInit */
|
||||
if (fl1h->phy_inst->u.lc15.max_cell_size != cell_size) {
|
||||
@@ -1865,6 +1825,7 @@ int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
|
||||
/* update current max cell size */
|
||||
fl1h->phy_inst->u.lc15.max_cell_size = cell_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Did we go through MphInit yet? If yes fire and forget */
|
||||
@@ -1889,11 +1850,7 @@ int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
|
||||
break;
|
||||
}
|
||||
|
||||
rc = osmo_fsm_inst_dispatch(mo->fi,
|
||||
ev_data.cause == 0 ? NM_EV_SETATTR_ACK : NM_EV_SETATTR_NACK,
|
||||
&ev_data);
|
||||
/* msgb ownership is transferred to FSM if it received ev: */
|
||||
return rc == 0 ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* callback from OML */
|
||||
@@ -1907,35 +1864,21 @@ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
|
||||
|
||||
switch (mo->obj_class) {
|
||||
case NM_OC_SITE_MANAGER:
|
||||
rc = osmo_fsm_inst_dispatch(bts->site_mgr.mo.fi, NM_EV_OPSTART_ACK, NULL);
|
||||
break;
|
||||
case NM_OC_BTS:
|
||||
rc = osmo_fsm_inst_dispatch(bts->mo.fi, NM_EV_OPSTART_ACK, NULL);
|
||||
case NM_OC_BASEB_TRANSC:
|
||||
case NM_OC_GPRS_NSE:
|
||||
case NM_OC_GPRS_CELL:
|
||||
case NM_OC_GPRS_NSVC:
|
||||
rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL);
|
||||
break;
|
||||
case NM_OC_RADIO_CARRIER:
|
||||
trx = (struct gsm_bts_trx *) obj;
|
||||
rc = trx_init(trx);
|
||||
break;
|
||||
case NM_OC_BASEB_TRANSC:
|
||||
bb_transc = (struct gsm_bts_bb_trx *) obj;
|
||||
rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL);
|
||||
break;
|
||||
case NM_OC_CHANNEL:
|
||||
ts = (struct gsm_bts_trx_ts*) obj;
|
||||
rc = ts_opstart(ts);
|
||||
break;
|
||||
case NM_OC_GPRS_NSE:
|
||||
case NM_OC_GPRS_CELL:
|
||||
case NM_OC_GPRS_NSVC:
|
||||
oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, -1, -1);
|
||||
rc = oml_mo_opstart_ack(mo);
|
||||
if (mo->obj_class == NM_OC_BTS) {
|
||||
oml_mo_state_chg(&bts->mo, -1, NM_AVSTATE_OK, -1);
|
||||
oml_mo_state_chg(&bts->gprs.nse.mo, -1, NM_AVSTATE_OK, -1);
|
||||
oml_mo_state_chg(&bts->gprs.cell.mo, -1, NM_AVSTATE_OK, -1);
|
||||
oml_mo_state_chg(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_OK, -1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP);
|
||||
}
|
||||
@@ -2005,14 +1948,10 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan)
|
||||
*/
|
||||
int l1if_rsl_chan_mod(struct gsm_lchan *lchan)
|
||||
{
|
||||
const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type];
|
||||
unsigned int i;
|
||||
|
||||
if (lchan->ho.active == HANDOVER_NONE)
|
||||
return -1;
|
||||
|
||||
LOGP(DHO, LOGL_ERROR, "%s modifying channel for handover\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DHO, LOGL_ERROR, "modifying channel for handover\n");
|
||||
|
||||
/* Give up listening to RACH bursts */
|
||||
release_sapi_ul_rach(lchan);
|
||||
@@ -2028,8 +1967,7 @@ int l1if_rsl_chan_rel(struct gsm_lchan *lchan)
|
||||
{
|
||||
/* A duplicate RF Release Request, ignore it */
|
||||
if (lchan->state == LCHAN_S_REL_REQ) {
|
||||
LOGP(DL1C, LOGL_ERROR, "%s already in release request state.\n",
|
||||
gsm_lchan_name(lchan));
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "already in release request state.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2065,8 +2003,7 @@ static int ts_disconnect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
|
||||
struct gsm_bts_trx_ts *ts = &trx->ts[cnf->u8Tn];
|
||||
OSMO_ASSERT(cnf->u8Tn < TRX_NR_TS);
|
||||
|
||||
LOGP(DL1C, LOGL_DEBUG, "%s Rx mphDisconnectCnf\n",
|
||||
gsm_lchan_name(ts->lchan));
|
||||
LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "Rx mphDisconnectCnf\n");
|
||||
|
||||
cb_ts_disconnected(ts);
|
||||
|
||||
@@ -2081,7 +2018,7 @@ int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
|
||||
struct lc15l1_hdl *fl1h = trx_lc15l1_hdl(ts->trx);
|
||||
GsmL1_MphDisconnectReq_t *cr;
|
||||
|
||||
DEBUGP(DRSL, "%s TS disconnect\n", gsm_lchan_name(ts->lchan));
|
||||
LOGPLCHAN(ts->lchan, DRSL, LOGL_DEBUG, "TS disconnect\n");
|
||||
cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphDisconnectReq, fl1h,
|
||||
l1p_handle_for_ts(ts));
|
||||
cr->u8Tn = ts->nr;
|
||||
@@ -2097,8 +2034,7 @@ static int ts_connect_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,
|
||||
struct gsm_bts_trx_ts *ts = &trx->ts[cnf->u8Tn];
|
||||
OSMO_ASSERT(cnf->u8Tn < TRX_NR_TS);
|
||||
|
||||
DEBUGP(DL1C, "%s %s Rx mphConnectCnf flags=%s%s%s\n",
|
||||
gsm_lchan_name(ts->lchan),
|
||||
LOGPLCHAN(ts->lchan, DL1C, LOGL_DEBUG, "%s Rx mphConnectCnf flags=%s%s%s\n",
|
||||
gsm_pchan_name(ts->pchan),
|
||||
ts->flags & TS_F_PDCH_ACTIVE ? "ACTIVE " : "",
|
||||
ts->flags & TS_F_PDCH_ACT_PENDING ? "ACT_PENDING " : "",
|
||||
|
||||
@@ -68,7 +68,7 @@ static struct msgb *l1_to_rtppayload_fr(uint8_t *l1_payload, uint8_t payload_len
|
||||
cur = msgb_put(msg, GSM_FR_BYTES);
|
||||
memcpy(cur, l1_payload, GSM_FR_BYTES);
|
||||
|
||||
lchan_set_marker(osmo_fr_check_sid(l1_payload, payload_len), lchan);
|
||||
lchan_set_marker(osmo_fr_is_any_sid(l1_payload), lchan);
|
||||
|
||||
return msg;
|
||||
}
|
||||
@@ -101,12 +101,8 @@ static struct msgb *l1_to_rtppayload_efr(uint8_t *l1_payload,
|
||||
/* new L1 can deliver bits like we need them */
|
||||
cur = msgb_put(msg, GSM_EFR_BYTES);
|
||||
memcpy(cur, l1_payload, GSM_EFR_BYTES);
|
||||
enum osmo_amr_type ft;
|
||||
enum osmo_amr_quality bfi;
|
||||
uint8_t cmr;
|
||||
int8_t sti, cmi;
|
||||
osmo_amr_rtp_dec(l1_payload, payload_len, &cmr, &cmi, &ft, &bfi, &sti);
|
||||
lchan_set_marker(ft == AMR_GSM_EFR_SID, lchan);
|
||||
|
||||
lchan_set_marker(osmo_efr_is_any_sid(l1_payload), lchan);
|
||||
|
||||
return msg;
|
||||
}
|
||||
@@ -259,7 +255,10 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
|
||||
*payload_type = GsmL1_TchPlType_Efr;
|
||||
rc = rtppayload_to_l1_efr(l1_payload, rtp_pl,
|
||||
rtp_pl_len);
|
||||
/* FIXME: detect and save EFR SID */
|
||||
if (rc && lchan->ts->trx->bts->dtxd)
|
||||
is_sid = osmo_efr_check_sid(rtp_pl, rtp_pl_len);
|
||||
if (is_sid)
|
||||
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1);
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_AMR:
|
||||
if (use_cache) {
|
||||
@@ -360,7 +359,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
{
|
||||
GsmL1_Prim_t *l1p = msgb_l1prim(l1p_msg);
|
||||
GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
|
||||
uint8_t *payload, payload_type, payload_len, sid_first[9] = { 0 };
|
||||
uint8_t *payload, payload_type, payload_len;
|
||||
struct msgb *rmsg = NULL;
|
||||
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
|
||||
|
||||
@@ -368,7 +367,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
return -EAGAIN;
|
||||
|
||||
if (data_ind->msgUnitParam.u8Size < 1) {
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "chan_nr %d Rx Payload size 0\n", chan_nr);
|
||||
LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "chan_nr %d Rx Payload size 0\n", chan_nr);
|
||||
/* Push empty payload to upper layers */
|
||||
rmsg = msgb_alloc_headroom(256, 128, "L1P-to-RTP");
|
||||
return add_l1sap_header(trx, rmsg, lchan, chan_nr, data_ind->u32Fn,
|
||||
@@ -399,6 +398,8 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
if (lchan->type != GSM_LCHAN_TCH_H &&
|
||||
lchan->type != GSM_LCHAN_TCH_F)
|
||||
goto err_payload_match;
|
||||
LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received ONSET from L1 " "(%d bytes)\n",
|
||||
payload_len);
|
||||
/* according to 3GPP TS 26.093 ONSET frames precede the first
|
||||
speech frame of a speech burst - set the marker for next RTP
|
||||
frame */
|
||||
@@ -407,33 +408,32 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
case GsmL1_TchPlType_Amr_SidFirstP1:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H)
|
||||
goto err_payload_match;
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P1 from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_P1 from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidFirstP2:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H)
|
||||
goto err_payload_match;
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_P2 from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_P2 from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidFirstInH:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H)
|
||||
goto err_payload_match;
|
||||
lchan->rtp_tx_marker = true;
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_FIRST_INH from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_FIRST_INH from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidUpdateInH:
|
||||
if (lchan->type != GSM_LCHAN_TCH_H)
|
||||
goto err_payload_match;
|
||||
lchan->rtp_tx_marker = true;
|
||||
LOGPFN(DL1P, LOGL_DEBUG, data_ind->u32Fn, "DTX: received SID_UPDATE_INH from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_DEBUG, "DTX: received SID_UPDATE_INH from L1 "
|
||||
"(%d bytes)\n", payload_len);
|
||||
break;
|
||||
default:
|
||||
LOGPFN(DL1P, LOGL_NOTICE, data_ind->u32Fn, "%s Rx Payload Type %s is unsupported\n",
|
||||
gsm_lchan_name(lchan),
|
||||
get_value_string(lc15bts_tch_pl_names, payload_type));
|
||||
LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_NOTICE, "%s Rx Payload Type %s is unsupported\n",
|
||||
gsm_lchan_name(lchan), get_value_string(lc15bts_tch_pl_names, payload_type));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -449,14 +449,8 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
rmsg = l1_to_rtppayload_efr(payload, payload_len, lchan);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr:
|
||||
rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
|
||||
break;
|
||||
case GsmL1_TchPlType_Amr_SidFirstP1:
|
||||
memcpy(sid_first, payload, payload_len);
|
||||
int len = osmo_amr_rtp_enc(sid_first, 0, AMR_SID, AMR_GOOD);
|
||||
if (len < 0)
|
||||
return 0;
|
||||
rmsg = l1_to_rtppayload_amr(sid_first, len, lchan);
|
||||
rmsg = l1_to_rtppayload_amr(payload, payload_len, lchan);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -468,8 +462,8 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
|
||||
return 0;
|
||||
|
||||
err_payload_match:
|
||||
LOGPFN(DL1P, LOGL_ERROR, data_ind->u32Fn, "%s Rx Payload Type %s incompatible with lchan\n",
|
||||
gsm_lchan_name(lchan), get_value_string(lc15bts_tch_pl_names, payload_type));
|
||||
LOGPLCFN(lchan, data_ind->u32Fn, DL1P, LOGL_ERROR, "%s Rx Payload Type %s incompatible with lchan\n",
|
||||
gsm_lchan_name(lchan), get_value_string(lc15bts_tch_pl_names, payload_type));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user