mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-bts.git
synced 2025-11-05 22:53:28 +00:00
Compare commits
244 Commits
keith/dtx-
...
jolly/test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
152d8e5b8a | ||
|
|
9c6c6b043b | ||
|
|
5076fef0ec | ||
|
|
e01cf27678 | ||
|
|
b7aa08f69b | ||
|
|
36e4fb63b8 | ||
|
|
076324446d | ||
|
|
18e5eb668e | ||
|
|
38dbebc48c | ||
|
|
65337b739a | ||
|
|
3c09964b11 | ||
|
|
798b28728b | ||
|
|
aec0422c8f | ||
|
|
3c133dc386 | ||
|
|
3af73977dd | ||
|
|
a7263b6474 | ||
|
|
82a2a8d9b4 | ||
|
|
e94553a547 | ||
|
|
088f4ffd57 | ||
|
|
950ed8bc4d | ||
|
|
59c641d20e | ||
|
|
1f755bcfee | ||
|
|
7786d9b673 | ||
|
|
f60f45e7ab | ||
|
|
722767a49d | ||
|
|
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 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
open_collective: osmocom
|
||||
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
|
||||
|
||||
@@ -8,7 +8,6 @@ EXTRA_DIST = \
|
||||
.version \
|
||||
README.md \
|
||||
contrib/dump_docs.py \
|
||||
contrib/osmo-bts.spec.in \
|
||||
debian \
|
||||
git-version-gen \
|
||||
$(NULL)
|
||||
|
||||
16
README.md
16
README.md
@@ -57,6 +57,13 @@ There also is an
|
||||
[Abis reference Manual](https://ftp.osmocom.org/docs/latest/osmobts-abis.pdf)
|
||||
describing the OsmoBTS specific A-bis dialect.
|
||||
|
||||
Forum
|
||||
-----
|
||||
|
||||
We welcome any osmo-bts related discussions in the
|
||||
[Cellular Network Infrastructure -> 2G RAN (GERAN)](https://discourse.osmocom.org/c/cni/geran)
|
||||
section of the osmocom discourse (web based Forum).
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
|
||||
@@ -69,13 +76,20 @@ Please observe the [Osmocom Mailing List
|
||||
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
|
||||
when posting.
|
||||
|
||||
Issue Tracker
|
||||
-------------
|
||||
|
||||
We use the [issue tracker of the osmo-bts project on osmocom.org](https://osmocom.org/projects/osmobts/issues) for
|
||||
tracking the state of bug reports and feature requests. Feel free to submit any issues you may find, or help
|
||||
us out by resolving existing issues.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Our coding standards are described at
|
||||
https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards
|
||||
|
||||
We us a gerrit based patch submission/review process for managing
|
||||
We use a Gerrit based patch submission/review process for managing
|
||||
contributions. Please see
|
||||
https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit for
|
||||
more details
|
||||
|
||||
@@ -7,4 +7,7 @@
|
||||
# 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
|
||||
libosmogsm >1.9.0 use of RLP code in libosmogsm
|
||||
libosmogsm >1.9.0 BTS feature & RSL defs for ThemWi RTP extensions
|
||||
libosmoctrl >1.9.0 use ctrl_cmd_send2()
|
||||
|
||||
21
configure.ac
21
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,11 @@ 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;
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
#
|
||||
# spec file for package osmo-bts
|
||||
#
|
||||
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
|
||||
#
|
||||
# All modifications and additions to the file contributed by third parties
|
||||
# remain the property of their copyright owners, unless otherwise agreed
|
||||
# upon. The license for this file, and modifications and additions to the
|
||||
# file, is the same license as for the pristine package itself (unless the
|
||||
# license for the pristine package is not an Open Source License, in which
|
||||
# case the license is the MIT License). An "Open Source License" is a
|
||||
# license that conforms to the Open Source Definition (Version 1.9)
|
||||
# published by the Open Source Initiative.
|
||||
|
||||
Name: osmo-bts
|
||||
Version: @VERSION@
|
||||
Release: 0
|
||||
Summary: Osmocom BTS-Side code (Abis, scheduling)
|
||||
License: AGPL-3.0-or-later AND GPL-2.0-only
|
||||
Group: Productivity/Telephony/Servers
|
||||
URL: https://osmocom.org/projects/osmobts
|
||||
Source: %{name}-%{version}.tar.xz
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
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
|
||||
%{?systemd_requires}
|
||||
|
||||
%description
|
||||
Osmocom BTS-Side code (A-bis, scheduling).
|
||||
|
||||
%package -n osmo-bts-virtual
|
||||
Summary: Virtual Osmocom GSM BTS (no RF hardware; GSMTAP/UDP)
|
||||
License: GPL-2.0-or-later
|
||||
Group: Productivity/Telephony/Utilities
|
||||
|
||||
%description -n osmo-bts-virtual
|
||||
This version of OsmoBTS doesn't use actual GSM PHY/Hardware/RF, but
|
||||
utilizes GSMTAP-over-UDP frames for the Um interface. This is useful
|
||||
in fully virtualized setups e.g. in combination with OsmocomBB virt_phy.
|
||||
|
||||
%package -n osmo-bts-omldummy
|
||||
Summary: Osmocom CI: Bring up only OML without RSL
|
||||
License: GPL-2.0-or-later
|
||||
Group: Productivity/Telephony/Utilities
|
||||
|
||||
%description -n osmo-bts-omldummy
|
||||
This is used only in integration testing, where in the TTCN-3 testsuite
|
||||
we currently have no A-bis OML implementation, but only a RSL one.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
echo "%{version}" >.tarball-version
|
||||
autoreconf -fi
|
||||
%configure \
|
||||
--docdir="%{_docdir}/%{name}" \
|
||||
--with-systemdsystemunitdir=%{_unitdir} \
|
||||
--enable-trx
|
||||
make V=1 %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
%make_install
|
||||
|
||||
%if 0%{?suse_version}
|
||||
%pre %service_add_pre osmo-bts-trx.service
|
||||
%post %service_add_post osmo-bts-trx.service
|
||||
%preun %service_del_preun osmo-bts-trx.service
|
||||
%postun %service_del_postun osmo-bts-trx.service
|
||||
%pre virtual %service_add_pre osmo-bts-virtual.service
|
||||
%post virtual %service_add_post osmo-bts-virtual.service
|
||||
%preun virtual %service_del_preun osmo-bts-virtual.service
|
||||
%postun virtual %service_del_postun osmo-bts-virtual.service
|
||||
%endif
|
||||
|
||||
%check
|
||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
||||
|
||||
%files
|
||||
%license COPYING
|
||||
%doc README.md
|
||||
%dir %{_docdir}/%{name}
|
||||
%dir %{_docdir}/%{name}/examples
|
||||
%dir %{_docdir}/%{name}/examples/osmo-bts-trx
|
||||
%{_docdir}/%{name}/examples/osmo-bts-trx/osmo-bts-trx-calypso.cfg
|
||||
%{_docdir}/%{name}/examples/osmo-bts-trx/osmo-bts-trx.cfg
|
||||
%dir %{_docdir}/%{name}/examples/osmo-bts-virtual
|
||||
%{_docdir}/%{name}/examples/osmo-bts-virtual/osmo-bts-virtual.cfg
|
||||
%{_bindir}/osmo-bts-trx
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-bts-trx.cfg
|
||||
%{_unitdir}/osmo-bts-trx.service
|
||||
|
||||
%files -n osmo-bts-virtual
|
||||
%{_bindir}/osmo-bts-virtual
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-bts-virtual.cfg
|
||||
%{_unitdir}/osmo-bts-virtual.service
|
||||
|
||||
%files -n osmo-bts-omldummy
|
||||
%{_bindir}/osmo-bts-omldummy
|
||||
|
||||
%changelog
|
||||
@@ -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
|
||||
@@ -8,6 +10,9 @@ StateDirectory=osmocom
|
||||
WorkingDirectory=%S/osmocom
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
User=osmocom
|
||||
Group=osmocom
|
||||
AmbientCapabilities=CAP_SYS_NICE
|
||||
|
||||
# CPU scheduling policy:
|
||||
CPUSchedulingPolicy=rr
|
||||
|
||||
@@ -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
|
||||
@@ -8,6 +10,9 @@ StateDirectory=osmocom
|
||||
WorkingDirectory=%S/osmocom
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
User=osmocom
|
||||
Group=osmocom
|
||||
AmbientCapabilities=CAP_SYS_NICE
|
||||
|
||||
# CPU scheduling policy:
|
||||
CPUSchedulingPolicy=rr
|
||||
|
||||
@@ -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
|
||||
|
||||
39
debian/osmo-bts-trx.postinst
vendored
Executable file
39
debian/osmo-bts-trx.postinst
vendored
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh -e
|
||||
case "$1" in
|
||||
configure)
|
||||
# Create the osmocom group and user (if it doesn't exist yet)
|
||||
if ! getent group osmocom >/dev/null; then
|
||||
groupadd --system osmocom
|
||||
fi
|
||||
if ! getent passwd osmocom >/dev/null; then
|
||||
useradd \
|
||||
--system \
|
||||
--gid osmocom \
|
||||
--home-dir /var/lib/osmocom \
|
||||
--shell /sbin/nologin \
|
||||
--comment "Open Source Mobile Communications" \
|
||||
osmocom
|
||||
fi
|
||||
|
||||
# Fix permissions of previous (root-owned) install (OS#4107)
|
||||
if dpkg --compare-versions "$2" le "1.13.0"; then
|
||||
if [ -e /etc/osmocom/osmo-bts-trx.cfg ]; then
|
||||
chown -v osmocom:osmocom /etc/osmocom/osmo-bts-trx.cfg
|
||||
chmod -v 0660 /etc/osmocom/osmo-bts-trx.cfg
|
||||
fi
|
||||
|
||||
if [ -d /etc/osmocom ]; then
|
||||
chown -v root:osmocom /etc/osmocom
|
||||
chmod -v 2775 /etc/osmocom
|
||||
fi
|
||||
|
||||
mkdir -p /var/lib/osmocom
|
||||
chown -R -v osmocom:osmocom /var/lib/osmocom
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb(1) will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
#DEBHELPER#
|
||||
|
||||
39
debian/osmo-bts-virtual.postinst
vendored
Executable file
39
debian/osmo-bts-virtual.postinst
vendored
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh -e
|
||||
case "$1" in
|
||||
configure)
|
||||
# Create the osmocom group and user (if it doesn't exist yet)
|
||||
if ! getent group osmocom >/dev/null; then
|
||||
groupadd --system osmocom
|
||||
fi
|
||||
if ! getent passwd osmocom >/dev/null; then
|
||||
useradd \
|
||||
--system \
|
||||
--gid osmocom \
|
||||
--home-dir /var/lib/osmocom \
|
||||
--shell /sbin/nologin \
|
||||
--comment "Open Source Mobile Communications" \
|
||||
osmocom
|
||||
fi
|
||||
|
||||
# Fix permissions of previous (root-owned) install (OS#4107)
|
||||
if dpkg --compare-versions "$2" le "1.13.0"; then
|
||||
if [ -e /etc/osmocom/osmo-bts-virtual.cfg ]; then
|
||||
chown -v osmocom:osmocom /etc/osmocom/osmo-bts-virtual.cfg
|
||||
chmod -v 0660 /etc/osmocom/osmo-bts-virtual.cfg
|
||||
fi
|
||||
|
||||
if [ -d /etc/osmocom ]; then
|
||||
chown -v root:osmocom /etc/osmocom
|
||||
chmod -v 2775 /etc/osmocom
|
||||
fi
|
||||
|
||||
mkdir -p /var/lib/osmocom
|
||||
chown -R -v osmocom:osmocom /var/lib/osmocom
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb(1) will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
#DEBHELPER#
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
OSMOCONF_FILES = virtual/osmo-bts-virtual.cfg
|
||||
# all config examples must be listed here unconditionally, so that
|
||||
# all of them end up in the release tarball (see OS#6349)
|
||||
EXTRA_DIST = \
|
||||
trx/osmo-bts-trx.cfg \
|
||||
trx/osmo-bts-trx-calypso.cfg \
|
||||
octphy/osmo-bts-trx2dsp1.cfg \
|
||||
octphy/osmo-bts-octphy.cfg \
|
||||
oc2g/osmo-bts-oc2g.cfg \
|
||||
oc2g/oc2gbts-mgr.cfg \
|
||||
sysmo/sysmobts-mgr.cfg \
|
||||
sysmo/osmo-bts-sysmo.cfg \
|
||||
litecell15/osmo-bts-lc15.cfg \
|
||||
litecell15/lc15bts-mgr.cfg \
|
||||
virtual/osmo-bts-virtual.cfg \
|
||||
$(NULL)
|
||||
|
||||
doc_virtualdir = $(docdir)/examples/osmo-bts-virtual
|
||||
doc_virtual_DATA = \
|
||||
virtual/osmo-bts-virtual.cfg
|
||||
EXTRA_DIST = $(doc_virtual_DATA)
|
||||
OSMOCONF_FILES = virtual/osmo-bts-virtual.cfg
|
||||
|
||||
if ENABLE_SYSMOBTS
|
||||
doc_sysmodir = $(docdir)/examples/osmo-bts-sysmo
|
||||
doc_sysmo_DATA = \
|
||||
sysmo/osmo-bts-sysmo.cfg \
|
||||
sysmo/sysmobts-mgr.cfg
|
||||
EXTRA_DIST += $(doc_sysmo_DATA)
|
||||
OSMOCONF_FILES += sysmo/osmo-bts-sysmo.cfg sysmo/sysmobts-mgr.cfg
|
||||
endif
|
||||
|
||||
@@ -19,7 +32,6 @@ doc_trxdir = $(docdir)/examples/osmo-bts-trx
|
||||
doc_trx_DATA = \
|
||||
trx/osmo-bts-trx.cfg \
|
||||
trx/osmo-bts-trx-calypso.cfg
|
||||
EXTRA_DIST += $(doc_trx_DATA)
|
||||
OSMOCONF_FILES += trx/osmo-bts-trx.cfg
|
||||
endif
|
||||
|
||||
@@ -28,7 +40,6 @@ doc_octphydir = $(docdir)/examples/osmo-bts-octphy
|
||||
doc_octphy_DATA = \
|
||||
octphy/osmo-bts-trx2dsp1.cfg \
|
||||
octphy/osmo-bts-octphy.cfg
|
||||
EXTRA_DIST += $(doc_octphy_DATA)
|
||||
OSMOCONF_FILES += octphy/osmo-bts-octphy.cfg
|
||||
endif
|
||||
|
||||
@@ -37,7 +48,6 @@ doc_lc15dir = $(docdir)/examples/osmo-bts-lc15
|
||||
doc_lc15_DATA = \
|
||||
litecell15/osmo-bts-lc15.cfg \
|
||||
litecell15/lc15bts-mgr.cfg
|
||||
EXTRA_DIST += $(doc_lc15_DATA)
|
||||
OSMOCONF_FILES += litecell15/osmo-bts-lc15.cfg litecell15/lc15bts-mgr.cfg
|
||||
endif
|
||||
|
||||
@@ -46,7 +56,6 @@ doc_oc2gdir = $(docdir)/examples/osmo-bts-oc2g
|
||||
doc_oc2g_DATA = \
|
||||
oc2g/osmo-bts-oc2g.cfg \
|
||||
oc2g/oc2gbts-mgr.cfg
|
||||
EXTRA_DIST += $(doc_oc2g_DATA)
|
||||
OSMOCONF_FILES += oc2g/osmo-bts-oc2g.cfg oc2g/oc2gbts-mgr.cfg
|
||||
endif
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -867,6 +867,8 @@ addition to those indicated in 3GPP TS 48.058 Section 9.3:
|
||||
| 0x01 | RSL_IE_CHAN_NR | <<RSL_IE_CHAN_NR>>
|
||||
| 0x60 | RSL_IE_OSMO_REP_ACCH_CAP | <<RSL_IE_OSMO_REP_ACCH_CAP>>
|
||||
| 0x61 | RSL_IE_OSMO_TRAINING_SEQUENCE | <<RSL_IE_OSMO_TRAINING_SEQUENCE>>
|
||||
| 0x62 | RSL_IE_OSMO_TEMP_OVP_ACCH_CAP | <<RSL_IE_OSMO_TEMP_OVP_ACCH_CAP>>
|
||||
| 0x63 | RSL_IE_OSMO_OSMUX_CID | <<RSL_IE_OSMO_OSMUX_CID>>
|
||||
| 0xf0 | RSL_IE_IPAC_REMOTE_IP | <<RSL_IE_IPAC_REMOTE_IP>>
|
||||
| 0xf1 | RSL_IE_IPAC_REMOTE_PORT | <<RSL_IE_IPAC_REMOTE_PORT>>
|
||||
| 0xf3 | RSL_IE_IPAC_LOCAL_PORT | <<RSL_IE_IPAC_LOCAL_PORT>>
|
||||
@@ -1089,6 +1091,16 @@ for future use.
|
||||
| 8..255 | reserved values
|
||||
|===
|
||||
|
||||
[[RSL_IE_OSMO_TEMP_OVP_ACCH_CAP]]
|
||||
==== RSL_IE_OSMO_TEMP_OVP_ACCH_CAP
|
||||
|
||||
FIXME: this IE has been defined, but remains to be documented.
|
||||
|
||||
[[RSL_IE_OSMO_OSMUX_CID]]
|
||||
==== RSL_IE_OSMO_OSMUX_CID
|
||||
|
||||
FIXME: this IE has been defined, but remains to be documented.
|
||||
|
||||
[[RSL_IE_IPAC_RTP_CSD_FORMAT]]
|
||||
==== RSL_IE_IPAC_RTP_CSD_FORMAT
|
||||
|
||||
|
||||
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,11 +25,21 @@ 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,
|
||||
BTS_CTR_AGCH_SENT,
|
||||
BTS_CTR_AGCH_DELETED,
|
||||
|
||||
BTS_CTR_RTP_RX_TOTAL,
|
||||
BTS_CTR_RTP_RX_MARKER,
|
||||
BTS_CTR_RTP_RX_DROP_PREEN,
|
||||
BTS_CTR_RTP_RX_DROP_LOOPBACK,
|
||||
BTS_CTR_RTP_RX_DROP_OVERFLOW,
|
||||
BTS_CTR_RTP_RX_DROP_V110_DEC,
|
||||
BTS_CTR_RTP_TX_TOTAL,
|
||||
BTS_CTR_RTP_TX_MARKER,
|
||||
};
|
||||
|
||||
/* Used by OML layer for BTS Attribute reporting */
|
||||
@@ -53,36 +63,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 +133,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 +150,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 +168,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 +204,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 +234,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 +250,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 +275,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 +305,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 +325,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 +376,7 @@ struct gsm_bts {
|
||||
|
||||
struct {
|
||||
char *sock_path;
|
||||
unsigned int sock_wqueue_len_max;
|
||||
} pcu;
|
||||
|
||||
/* GSMTAP Um logging (disabled by default) */
|
||||
@@ -369,6 +386,8 @@ struct gsm_bts {
|
||||
char *local_host;
|
||||
uint32_t sapi_mask;
|
||||
uint8_t sapi_acch;
|
||||
bool rlp;
|
||||
bool rlp_skip_null;
|
||||
} gsmtap;
|
||||
|
||||
struct osmux_state osmux;
|
||||
@@ -389,12 +408,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 +423,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 +447,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 +457,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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
|
||||
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 */
|
||||
@@ -163,6 +168,7 @@ struct gsm_lchan {
|
||||
uint16_t conn_id;
|
||||
uint8_t rtp_payload;
|
||||
uint8_t rtp_payload2;
|
||||
uint8_t rtp_extensions;
|
||||
uint8_t speech_mode;
|
||||
struct {
|
||||
bool use;
|
||||
@@ -203,6 +209,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,9 +273,26 @@ 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;
|
||||
|
||||
struct {
|
||||
/* buffers to re-combine RLP frame from multiple Um blocks */
|
||||
uint8_t rlp_buf_ul[576/8]; /* maximum size of RLP frame */
|
||||
uint8_t rlp_buf_dl[576/8]; /* maximum size of RLP frame */
|
||||
} csd;
|
||||
} tch;
|
||||
|
||||
/* 3GPP TS 48.058 § 9.3.37: [0; 255] ok, -1 means invalid*/
|
||||
@@ -287,6 +312,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
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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 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 <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;
|
||||
}
|
||||
294
src/common/bts.c
294
src/common/bts.c
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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,12 +97,22 @@ 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)"},
|
||||
|
||||
[BTS_CTR_AGCH_RCVD] = {"agch:rcvd", "Received AGCH requests (Abis)"},
|
||||
[BTS_CTR_AGCH_SENT] = {"agch:sent", "Sent AGCH requests (Abis)"},
|
||||
[BTS_CTR_AGCH_DELETED] = {"agch:delete", "Sent AGCH DELETE IND (Abis)"},
|
||||
|
||||
[BTS_CTR_RTP_RX_TOTAL] = {"rtp:rx:total", "Total number of received RTP packets"},
|
||||
[BTS_CTR_RTP_RX_MARKER] = {"rtp:rx:marker", "Number of received RTP packets with marker bit set"},
|
||||
[BTS_CTR_RTP_RX_DROP_PREEN] = {"rtp:rx:drop:preen", "Total number of received RTP packets dropped during preening"},
|
||||
[BTS_CTR_RTP_RX_DROP_LOOPBACK] = {"rtp:rx:drop:loopback", "Total number of received RTP packets dropped during loopback"},
|
||||
[BTS_CTR_RTP_RX_DROP_OVERFLOW] = {"rtp:rx:drop:overflow", "Total number of received RTP packets dropped during DL queue overflow"},
|
||||
[BTS_CTR_RTP_RX_DROP_V110_DEC] = {"rtp:rx:drop:v110_dec", "Total number of received RTP packets dropped during V.110 decode"},
|
||||
[BTS_CTR_RTP_TX_TOTAL] = {"rtp:tx:total", "Total number of transmitted RTP packets"},
|
||||
[BTS_CTR_RTP_TX_MARKER] = {"rtp:tx:marker", "Number of transmitted RTP packets with marker bit set"},
|
||||
};
|
||||
static const struct rate_ctr_group_desc bts_ctrg_desc = {
|
||||
"bts",
|
||||
@@ -149,7 +158,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 +215,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 +235,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 +267,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 +295,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 +318,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 +343,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 +382,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 */
|
||||
@@ -397,16 +393,17 @@ int bts_init(struct gsm_bts *bts)
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_ETWS_PN);
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_IPV6_NSVC);
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_PAGING_COORDINATION);
|
||||
osmo_bts_set_feature(bts->features, BTS_FEAT_TWTS001);
|
||||
|
||||
/* 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 +420,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 +440,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 +673,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 +739,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 +753,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 +813,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 +855,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 +872,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 +880,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) */
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -84,12 +84,45 @@ static int set_oml_alert(struct ctrl_cmd *cmd, void *data)
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
static int verify_max_ber10k_rach(struct ctrl_cmd *cmd, const char *value, void *_data)
|
||||
{
|
||||
int max_ber10k_rach = atoi(cmd->value);
|
||||
|
||||
if (max_ber10k_rach < 0 || max_ber10k_rach > 10000) {
|
||||
cmd->reply = "Value is out of range";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_max_ber10k_rach(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
cmd->reply = talloc_asprintf(cmd, "%u", g_bts->max_ber10k_rach);
|
||||
if (!cmd->reply) {
|
||||
cmd->reply = "OOM";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
static int set_max_ber10k_rach(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
g_bts->max_ber10k_rach = atoi(cmd->value);
|
||||
cmd->reply = "OK";
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE(max_ber10k_rach, "max-ber10k-rach");
|
||||
|
||||
int bts_ctrl_cmds_install(struct gsm_bts *bts)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_therm_att);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_oml_alert);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_max_ber10k_rach);
|
||||
g_bts = bts;
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmocom/core/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);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <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;
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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;
|
||||
|
||||
@@ -649,9 +652,11 @@ void lchan_rtp_socket_free(struct gsm_lchan *lchan)
|
||||
/*! limit number of queue entries to %u; drops any surplus messages */
|
||||
void lchan_dl_tch_queue_enqueue(struct gsm_lchan *lchan, struct msgb *msg, unsigned int limit)
|
||||
{
|
||||
if (lchan->dl_tch_queue_len > limit)
|
||||
LOGPLCHAN(lchan, DL1P, LOGL_NOTICE, "freeing %d queued frames\n",
|
||||
lchan->dl_tch_queue_len - limit);
|
||||
if (lchan->dl_tch_queue_len > limit) {
|
||||
unsigned int excess = lchan->dl_tch_queue_len - limit;
|
||||
LOGPLCHAN(lchan, DL1P, LOGL_NOTICE, "freeing %d queued frames\n", excess);
|
||||
rate_ctr_add2(lchan->ts->trx->bts->ctrs, BTS_CTR_RTP_RX_DROP_OVERFLOW, excess);
|
||||
}
|
||||
while (lchan->dl_tch_queue_len > limit) {
|
||||
struct msgb *tmp = msgb_dequeue_count(&lchan->dl_tch_queue, &lchan->dl_tch_queue_len);
|
||||
msgb_free(tmp);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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 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 <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 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 <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 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 <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
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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;
|
||||
}
|
||||
1086
src/common/oml.c
1086
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>
|
||||
*
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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.
|
||||
* 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/>.
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user