mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-cbc.git
synced 2025-11-03 05:33:36 +00:00
Compare commits
56 Commits
pespin/fix
...
0.4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
311673c365 | ||
|
|
7fbd6aa472 | ||
|
|
66221e60d6 | ||
|
|
0422a10253 | ||
|
|
292b2e895b | ||
|
|
a7aca0333b | ||
|
|
d04fe38e73 | ||
|
|
eb82cbc249 | ||
|
|
43439c785f | ||
|
|
1d9d13ce6b | ||
|
|
6e64d1079f | ||
|
|
d5ea7f765e | ||
|
|
8d70759ab7 | ||
|
|
8f15c2c23d | ||
|
|
d5c0b73f00 | ||
|
|
65d3c505b7 | ||
|
|
13152304f7 | ||
|
|
40a6158e41 | ||
|
|
d78f13c89a | ||
|
|
28d3a53dc5 | ||
|
|
caba7fc493 | ||
|
|
cb4e11f984 | ||
|
|
a76d15048d | ||
|
|
20705a0877 | ||
|
|
041ae3246d | ||
|
|
e86af042fd | ||
|
|
0b8a08b698 | ||
|
|
d24c3dfba0 | ||
|
|
c190939f0c | ||
|
|
cb99991127 | ||
|
|
e6e878a2fc | ||
|
|
d8a537aca8 | ||
|
|
4a9d22e5a0 | ||
|
|
1429377005 | ||
|
|
bc21b3ae81 | ||
|
|
ab8b8402a4 | ||
|
|
e416069cf6 | ||
|
|
e67faef4ec | ||
|
|
745a2d6600 | ||
|
|
b093e6708d | ||
|
|
66625de21c | ||
|
|
6db8c13fea | ||
|
|
3f9d78e2a3 | ||
|
|
692243baf5 | ||
|
|
9ce5d4bad7 | ||
|
|
7beca6fda0 | ||
|
|
4dd20eec56 | ||
|
|
9144fd1fd8 | ||
|
|
3c804efcc6 | ||
|
|
5ae411980b | ||
|
|
93a588ba60 | ||
|
|
56d1ef3b52 | ||
|
|
3ef5020007 | ||
|
|
5044524f01 | ||
|
|
3468e90ab3 | ||
|
|
028b48b967 |
27
README.md
27
README.md
@@ -67,3 +67,30 @@ more details
|
||||
|
||||
The current patch queue for osmo-cbc can be seen at
|
||||
https://gerrit.osmocom.org/#/q/project:osmo-cbc+status:open
|
||||
|
||||
|
||||
Generating asn1c code
|
||||
---------------------
|
||||
|
||||
Upstream master as1nc from [vlm](https://github.com/vlm/asn1c) [doesn't support
|
||||
APER encoding](https://github.com/vlm/asn1c/issues/452). Nevertheless, the
|
||||
upstream fork maintained by a big contributor
|
||||
[mouse07410](https://github.com/mouse07410/asn1c) does support it, and it is
|
||||
used in osmo-cbc to generate the SBc-AP code from ASN.1 files present in
|
||||
src/sbcap/asn1/.
|
||||
|
||||
In order to regenerate the code, one shall adjust the ASN1C_SKELETON_PATH and
|
||||
ASN1C_BIN_PATH in configure.ac to point to the built & installed asn1c from
|
||||
mouse07410 (usually `vlm_master` branch). Last generated code was built using
|
||||
commit hash 08b293e8aa342d465d26805d1d66f3595b2ce261.
|
||||
|
||||
Then, do the usual `autoreconf -fi && ./configure`, using a buildir != srcdir
|
||||
(important, in order to avoid ending up with tempotary files in srcdir and
|
||||
making it difficult to stash the relevant changes).
|
||||
|
||||
Finally, run `make -C src/ regen`, which will regenerate the files and copy over
|
||||
the skeletons, with git possibily showing changes in the following paths:
|
||||
- include/osmocom/sbcap/
|
||||
- src/sbcap/gen/
|
||||
- src/sbcap/skel/
|
||||
|
||||
|
||||
@@ -31,10 +31,10 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
||||
fi
|
||||
PKG_PROG_PKG_CONFIG([0.20])
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.7.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.7.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.7.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.2.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(LIBOSMONETIF, libosmo-netif >= 1.4.0)
|
||||
PKG_CHECK_MODULES(ULFIUS, libulfius)
|
||||
PKG_CHECK_MODULES(JANSSON, jansson)
|
||||
PKG_CHECK_MODULES(ORCANIA, liborcania)
|
||||
|
||||
@@ -117,7 +117,7 @@ def main(argv):
|
||||
parser.add_argument("-p", "--port", help="TCP port to connect to", type=int, default=12345)
|
||||
parser.add_argument("-v", "--verbose", help="increase output verbosity", action='count', default=0)
|
||||
|
||||
subparsers = parser.add_subparsers()
|
||||
subparsers = parser.add_subparsers(required=True)
|
||||
|
||||
parser_c_cbs = subparsers.add_parser('create-cbs', help='Create a new CBS message')
|
||||
parser_c_cbs.add_argument("--msg-id", type=int, help='Message Identifier', required=True)
|
||||
|
||||
@@ -51,11 +51,12 @@ autoreconf --install --force
|
||||
./configure --enable-sanitize --enable-werror --enable-external-tests $CONFIG
|
||||
$MAKE $PARALLEL_MAKE
|
||||
DISTCHECK_CONFIGURE_FLAGS="--enable-external-tests $CONFIG" \
|
||||
$MAKE distcheck \
|
||||
$MAKE $PARALLEL_MAKE distcheck \
|
||||
|| cat-testlogs.sh
|
||||
|
||||
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
||||
make -C "$base/doc/manuals" publish
|
||||
fi
|
||||
|
||||
$MAKE $PARALLEL_MAKE maintainer-clean
|
||||
osmo-clean-workspace.sh
|
||||
|
||||
@@ -31,10 +31,10 @@ BuildRequires: pkgconfig >= 0.20
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%endif
|
||||
BuildRequires: pkgconfig(libsctp)
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.7.0
|
||||
BuildRequires: pkgconfig(libosmogsm) >= 1.7.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.7.0
|
||||
BuildRequires: pkgconfig(libosmo-netif) >= 1.2.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmogsm) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmo-netif) >= 1.4.0
|
||||
BuildRequires: pkgconfig(talloc)
|
||||
BuildRequires: pkgconfig(libulfius)
|
||||
%{?systemd_requires}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
[Unit]
|
||||
Description=Osmocom CBC (Cell Broadcasting Centre)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
StateDirectory=osmocom
|
||||
WorkingDirectory=%S/osmocom
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/osmo-cbc -c /etc/osmocom/osmo-cbc.cfg
|
||||
RestartSec=2
|
||||
|
||||
135
debian/changelog
vendored
135
debian/changelog
vendored
@@ -1,3 +1,138 @@
|
||||
osmo-cbc (0.4.2) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* {src,tests/sbcap}/Makefile.am: reorder libraries in LDADD
|
||||
* tests: use -no-install libtool flag to avoid ./lt-* scripts
|
||||
|
||||
[ Oliver Smith ]
|
||||
* debian: set compat level to 10
|
||||
* systemd: depend on networking-online.target
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* sbcap: Update asn1c skeleton files
|
||||
* README.md: Document generation of SBcAP code from ASN.1 files
|
||||
* Catch and forbid configuring peers before configuring main protocol node
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 17:08:37 +0200
|
||||
|
||||
osmo-cbc (0.4.1) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* contrib/jenkins.sh: also execute maintainer-clean target
|
||||
* contrib/jenkins.sh: execute 'distcheck' with $PARALLEL_MAKE
|
||||
* contrib/jenkins.sh: fix 'publish' target
|
||||
|
||||
[ Max ]
|
||||
* Set working directory in systemd service file
|
||||
|
||||
[ arehbein ]
|
||||
* osmo-cbc: Transition to use of 'telnet_init_default'
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 17:39:54 +0100
|
||||
|
||||
osmo-cbc (0.4.0) unstable; urgency=medium
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* Configure libosmocore logging system as multithread
|
||||
* Move peer to DELETED state before signalling parent FSM with DELETE_(N)ACK
|
||||
* Fix typos in error messages
|
||||
* main: remove newline char in perror() call
|
||||
* cbsp_server: Exit process gracefully if binding socket fails
|
||||
* Move header files to include/osmocom/cbc/ dir
|
||||
* Improve error handling when forwarding ECBE msg to CBSP
|
||||
* cbsp: Clean up conn closed paths
|
||||
* rest_api: Fix cbs.data_user_len not set in 'payload_encoded'
|
||||
* Add sbcap library
|
||||
* Add unit tests for sbcap
|
||||
* sbcap: Update asn1c skeleton files
|
||||
* Add initial SBc-AP support to osmo-cbc
|
||||
* doc: user manual: fix typo
|
||||
* doc: Document SBc-AP support and config
|
||||
* Fix printf format in 32bit arch
|
||||
* vty: Fix call to OSMO_STRBUF_PRINTF
|
||||
* sbcap: Update asn1c skeleton files
|
||||
* Improve example osmo-cbc.cfg file
|
||||
* sbcap_server.c: Remove unneeded goto
|
||||
* sbcap_server: Log all sctp notif
|
||||
* sbcap_server: Fix double-free of rx msg if conn is destroyed
|
||||
* Split cbc_peer to its own .c and .h files
|
||||
* cbc_peer: Close SBcAP conn when removing active peer
|
||||
* Move function defined in rest_it_op.c to rest_it_op.h
|
||||
* Move vty stuff to its own header cbc_vty.h
|
||||
* Split cbc_message related code to its own .c and .h file
|
||||
* Get rid of internal.h
|
||||
* sbcap_server.h: Remove unused fields
|
||||
* cbsp_server.c: Drop unused code
|
||||
* Rename CBSP,SABP,SBcAP structs and APIs
|
||||
* Rename {cbsp,sbcap}_server(_fsm).h s/server/link/
|
||||
* Rename fields in cbc_{cbsp,sbcap}_mgr
|
||||
* Use cbc_{cbsp,sbcap}_link_close when possible
|
||||
* cbc_vty: Use value_string to define proto names used in vty
|
||||
* cbc_vty: print correct protocol when writing config
|
||||
* Refactor {cbsp,sbcap}_cbc_accept_cb
|
||||
* cbc_vty: write peer config nodes at the end
|
||||
* Make cbsp,sbcap mgr available in data model
|
||||
* Fix cbc_vty_go_parent() not being called
|
||||
* cbc_main: Fix setting default SBc-AP local address
|
||||
* vty: Define peer proto during 'peer' node cmd
|
||||
* Move struct cbc bring up code to its own file and functions
|
||||
* Split cbsp/sbcap server socket creation from struct allocation
|
||||
* cbc-apitool: Fix port stored in var as a string
|
||||
* cbc-apitool: print usage instead of crashing if no subcmd passed
|
||||
* sbcap: Fix encoding of Warning-Type
|
||||
* cosmetic: smscb_message_fsm.c: Fix typo in comment
|
||||
* Support CBSP/TCP and SBc-AP/SCTP client mode
|
||||
* cbc_vty: Fix missing indent char in dump_one_etws_msg
|
||||
* vty: Fix 'show message' not finding expired messages
|
||||
* vty: Add command to delete expired messages
|
||||
* vty: Print created and expired times for each message
|
||||
* sbcap_msg: Improve spec references for used IEs
|
||||
* vty: Fix typo in vty output
|
||||
* Rearrange cbc_message and cbsp message code
|
||||
* Rename functions generating CBSP/SBc-AP Write-Replace request
|
||||
* sbcap: Fix typo in sbcap_cause_vals
|
||||
* sbcap: Send Error Indication if decoding rx msg fails
|
||||
* sbcap: Drop unused events
|
||||
* sbcap: Improve logging of rx Error Indication
|
||||
* sbcap: Improve logging on non-implemented PWS Restart/Failure Ind
|
||||
* sbcap: Tx Error ind if Rx ProcedureCode is unknown
|
||||
* Move sbcap_as_find_ie() to libsbcap
|
||||
* sbcap: Fix typo in comment
|
||||
* sbcap: Log info about messages received and trasmitted
|
||||
* Move cbc_cell_id2str() and make it public
|
||||
* Move ASN1C enc/dec logging to its own category
|
||||
* sbcap: Request and handle Write Replace Warning Indication
|
||||
* sbcap: Store reported failed TAIs from WriteReplaceResponse in cbc_message_peer
|
||||
* sbcap: Improve handling of WriteReplaceWarnResponse
|
||||
* Introduce logging category smscb
|
||||
* Split event list for smscb_message_fsm and smscb_peer_fsm
|
||||
* Split smscb_peer_fsm into CBSP and SBcAP specific FSMs
|
||||
* cbc_main: Enable logging of fsm timeouts
|
||||
* Propagate error to caller when tx cbsp/sbcap Write-Replace-Req fails
|
||||
* sbcap: Fix NULL pointer dereference
|
||||
* cbsp/sbcap: Fix memleak in error condition (tx without link)
|
||||
* *_smscb_peer_fsm: Immediately NACK if Tx of msg failed
|
||||
* cbsp: Fix heap-use-after-free closing cli conn in connecting state
|
||||
* cbsp/sbcap: Set link fsm id with peer's name
|
||||
* cbsp/sbcap: Fail if trying to Tx on non-connected (connecting) link
|
||||
* sbcap: Add Concurrent-Warning-Message-Indicator IE to Write-Replace-Req
|
||||
* cbsp: Log storing of CellId info received from peers
|
||||
* cbsp: Store content of received Cell Id from Failed List
|
||||
|
||||
[ Oliver Smith ]
|
||||
* gitreview: add new file
|
||||
* checkpatch.conf: ignore sbcap generated files
|
||||
* contrib/osmo-cbc.spec: add libosmo-sbcap0/-dev
|
||||
* debian: add subpackages libosmo-sbcap0/-dev
|
||||
* libosmo-sbcap.pc.in: new file
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* tests/sbcap: fix wrong operator used in OSMO_ASSERT statement
|
||||
* cbc_vty: use install_element[_ve](), not install_lib_element[_ve]()
|
||||
* libosmo-sbcap: add -no-undefined to libosmo_sbcap_la_LDFLAGS
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Mon, 08 Aug 2022 11:42:56 +0200
|
||||
|
||||
osmo-cbc (0.3.0) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
|
||||
2
debian/compat
vendored
2
debian/compat
vendored
@@ -1 +1 @@
|
||||
9
|
||||
10
|
||||
|
||||
6
debian/control
vendored
6
debian/control
vendored
@@ -2,7 +2,7 @@ Source: osmo-cbc
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Build-Depends: debhelper (>=9),
|
||||
Build-Depends: debhelper (>= 10),
|
||||
dh-autoreconf,
|
||||
autotools-dev,
|
||||
autoconf,
|
||||
@@ -11,8 +11,8 @@ Build-Depends: debhelper (>=9),
|
||||
pkg-config,
|
||||
python3-minimal,
|
||||
libtalloc-dev,
|
||||
libosmocore-dev (>= 1.7.0),
|
||||
libosmo-netif-dev (>= 1.2.0),
|
||||
libosmocore-dev (>= 1.9.0),
|
||||
libosmo-netif-dev (>= 1.4.0),
|
||||
libulfius-dev,
|
||||
libjansson-dev,
|
||||
libsctp-dev,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
log stderr
|
||||
logging level main notice
|
||||
logging level rest notice
|
||||
logging level smscb notice
|
||||
logging level cbsp notice
|
||||
logging level sbcap notice
|
||||
logging level asn1c notice
|
||||
logging level rest notice
|
||||
cbc
|
||||
unknown-peers reject
|
||||
ecbe
|
||||
@@ -16,9 +18,11 @@ cbc
|
||||
local-ip ::1
|
||||
local-port 29168
|
||||
peer cbsp example-bsc
|
||||
mode server
|
||||
remote-ip 127.0.0.2
|
||||
remote-port 48049
|
||||
peer sbcap example-mme
|
||||
mode client
|
||||
remote-ip 127.0.0.2
|
||||
remote-ip ::2
|
||||
remote-port 29168
|
||||
|
||||
@@ -5,6 +5,7 @@ noinst_HEADERS = \
|
||||
cbc_vty.h \
|
||||
cbsp_link.h \
|
||||
cbsp_link_fsm.h \
|
||||
cbsp_msg.h \
|
||||
charset.h \
|
||||
debug.h \
|
||||
sbcap_msg.h \
|
||||
@@ -12,4 +13,5 @@ noinst_HEADERS = \
|
||||
sbcap_link_fsm.h \
|
||||
rest_it_op.h \
|
||||
smscb_message_fsm.h \
|
||||
smscb_peer_fsm.h \
|
||||
$(NULL)
|
||||
|
||||
@@ -16,6 +16,8 @@ enum cbc_cell_id_type {
|
||||
CBC_CELL_ID_LAI,
|
||||
CBC_CELL_ID_LAC,
|
||||
CBC_CELL_ID_CI,
|
||||
CBC_CELL_ID_ECGI,
|
||||
CBC_CELL_ID_TAI,
|
||||
};
|
||||
|
||||
struct cbc_cell_id {
|
||||
@@ -27,6 +29,8 @@ struct cbc_cell_id {
|
||||
struct osmo_location_area_id lai;
|
||||
uint16_t lac;
|
||||
uint16_t ci;
|
||||
struct osmo_eutran_cell_global_id ecgi;
|
||||
struct osmo_tracking_area_id tai;
|
||||
} u;
|
||||
/* only in failure list */
|
||||
struct {
|
||||
@@ -39,6 +43,8 @@ struct cbc_cell_id {
|
||||
} num_compl;
|
||||
};
|
||||
|
||||
const char *cbc_cell_id2str(const struct cbc_cell_id *cid);
|
||||
|
||||
/*********************************************************************************
|
||||
* CBC itself
|
||||
*********************************************************************************/
|
||||
@@ -51,11 +57,13 @@ struct cbc {
|
||||
struct {
|
||||
char *local_host;
|
||||
int local_port;
|
||||
bool configured;
|
||||
} cbsp;
|
||||
struct {
|
||||
char *local_host[CBC_MAX_LOC_ADDRS];
|
||||
unsigned int num_local_host;
|
||||
int local_port;
|
||||
bool configured;
|
||||
} sbcap;
|
||||
struct {
|
||||
char *local_host;
|
||||
|
||||
@@ -99,9 +99,11 @@ struct cbc_message {
|
||||
};
|
||||
|
||||
struct cbc_message *cbc_message_alloc(void *ctx, const struct cbc_message *cbcmsg);
|
||||
void cbc_message_free(struct cbc_message *cbcmsg);
|
||||
int cbc_message_new(const struct cbc_message *cbcmsg, struct rest_it_op *op);
|
||||
void cbc_message_delete(struct cbc_message *cbcmsg, struct rest_it_op *op);
|
||||
struct cbc_message *cbc_message_by_id(uint16_t message_id);
|
||||
struct cbc_message *cbc_message_expired_by_id(uint16_t message_id);
|
||||
int peer_new_cbc_message(struct cbc_peer *peer, struct cbc_message *cbcmsg);
|
||||
|
||||
int cbc_message_del_peer(struct cbc_message *cbcmsg, struct cbc_peer *peer);
|
||||
|
||||
@@ -19,6 +19,16 @@ enum cbc_peer_protocol {
|
||||
CBC_PEER_PROTO_SBcAP
|
||||
};
|
||||
|
||||
enum cbc_peer_link_mode {
|
||||
CBC_PEER_LINK_MODE_DISABLED = 0,
|
||||
CBC_PEER_LINK_MODE_SERVER,
|
||||
CBC_PEER_LINK_MODE_CLIENT,
|
||||
};
|
||||
|
||||
extern const struct value_string cbc_peer_link_mode_names[];
|
||||
static inline const char *cbc_peer_link_mode_name(enum cbc_peer_link_mode val)
|
||||
{ return get_value_string(cbc_peer_link_mode_names, val); }
|
||||
|
||||
struct cbc_peer {
|
||||
struct llist_head list; /* linked to cbc.peers */
|
||||
const char *name;
|
||||
@@ -34,6 +44,7 @@ struct cbc_peer {
|
||||
struct cbc_sabp_link *sabp;
|
||||
struct cbc_sbcap_link *sbcap;
|
||||
} link;
|
||||
enum cbc_peer_link_mode link_mode;
|
||||
};
|
||||
|
||||
extern const struct value_string cbc_peer_proto_name[];
|
||||
@@ -44,3 +55,4 @@ void cbc_peer_remove(struct cbc_peer *peer);
|
||||
struct cbc_peer *cbc_peer_by_name(const char *name);
|
||||
struct cbc_peer *cbc_peer_by_addr_proto(const char *remote_host, uint16_t remote_port,
|
||||
enum cbc_peer_protocol proto);
|
||||
int cbc_peer_apply_cfg_chg(struct cbc_peer *peer);
|
||||
|
||||
@@ -31,19 +31,22 @@ int cbc_cbsp_mgr_open_srv(struct cbc_cbsp_mgr *mgr);
|
||||
struct cbc_cbsp_link {
|
||||
/* entry in osmo_cbsp_cbc.links */
|
||||
struct llist_head list;
|
||||
/* stream server connection for this link */
|
||||
struct osmo_stream_srv *conn;
|
||||
/* partially received CBSP message (rx completion pending) */
|
||||
struct msgb *rx_msg;
|
||||
|
||||
struct osmo_fsm_inst *fi;
|
||||
|
||||
struct cbc_peer *peer;
|
||||
bool is_client;
|
||||
union {
|
||||
struct osmo_stream_srv *srv_conn;
|
||||
struct osmo_stream_cli *cli_conn;
|
||||
void *conn; /* used when we just care about the pointer */
|
||||
};
|
||||
};
|
||||
|
||||
struct cbc_cbsp_link *cbc_cbsp_link_alloc(struct cbc_cbsp_mgr *cbc, struct cbc_peer *peer);
|
||||
void cbc_cbsp_link_free(struct cbc_cbsp_link *link);
|
||||
const char *cbc_cbsp_link_name(const struct cbc_cbsp_link *link);
|
||||
void cbc_cbsp_link_tx(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *cbsp);
|
||||
int cbc_cbsp_link_open_cli(struct cbc_cbsp_link *link);
|
||||
int cbc_cbsp_link_tx(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *cbsp);
|
||||
void cbc_cbsp_link_close(struct cbc_cbsp_link *link);
|
||||
int cbc_cbsp_link_rx_cb(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *dec);
|
||||
|
||||
5
include/osmocom/cbc/cbsp_msg.h
Normal file
5
include/osmocom/cbc/cbsp_msg.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <osmocom/gsm/cbsp.h>
|
||||
|
||||
struct cbc_message;
|
||||
struct osmo_cbsp_decoded *cbsp_gen_write_replace_req(void *ctx, const struct cbc_message *cbcmsg);
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
enum {
|
||||
DMAIN,
|
||||
DSMSCB,
|
||||
DCBSP,
|
||||
DSBcAP,
|
||||
DASN1C,
|
||||
DREST,
|
||||
};
|
||||
|
||||
@@ -33,15 +33,20 @@ int cbc_sbcap_mgr_open_srv(struct cbc_sbcap_mgr *mgr);
|
||||
struct cbc_sbcap_link {
|
||||
/* entry in osmo_sbcap_cbc.links */
|
||||
struct llist_head list;
|
||||
/* stream server connection for this link */
|
||||
struct osmo_stream_srv *conn;
|
||||
struct osmo_fsm_inst *fi;
|
||||
struct cbc_peer *peer;
|
||||
bool is_client;
|
||||
union {
|
||||
struct osmo_stream_srv *srv_conn;
|
||||
struct osmo_stream_cli *cli_conn;
|
||||
void *conn; /* used when we just care about the pointer */
|
||||
};
|
||||
};
|
||||
|
||||
struct cbc_sbcap_link *cbc_sbcap_link_alloc(struct cbc_sbcap_mgr *cbc, struct cbc_peer *peer);
|
||||
void cbc_sbcap_link_free(struct cbc_sbcap_link *link);
|
||||
const char *cbc_sbcap_link_name(const struct cbc_sbcap_link *link);
|
||||
void cbc_sbcap_link_tx(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu);
|
||||
int cbc_sbcap_link_open_cli(struct cbc_sbcap_link *link);
|
||||
int cbc_sbcap_link_tx(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu);
|
||||
void cbc_sbcap_link_close(struct cbc_sbcap_link *link);
|
||||
int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu);
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
extern struct osmo_fsm sbcap_link_fsm;
|
||||
|
||||
enum sbcap_link_event {
|
||||
SBcAP_LINK_E_RX_RST_COMPL, /* reset complete received */
|
||||
SBcAP_LINK_E_RX_RST_FAIL, /* reset failure received */
|
||||
SBcAP_LINK_E_RX_KA_COMPL, /* keep-alive complete received */
|
||||
SBcAP_LINK_E_RX_RESTART, /* restart received */
|
||||
SBcAP_LINK_E_RX_RESTART, /* SBc-AP PWS Restart Ind received */
|
||||
SBcAP_LINK_E_CMD_RESET, /* RESET command from CBC */
|
||||
SBcAP_LINK_E_CMD_CLOSE, /* CLOSE command from CBC */
|
||||
};
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#pragma once
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/netif/stream.h>
|
||||
#include <osmocom/sbcap/sbcap_common.h>
|
||||
|
||||
#include "cbc_data.h"
|
||||
|
||||
struct cbc_message;
|
||||
typedef struct SBcAP_SBC_AP_PDU SBcAP_SBC_AP_PDU_t;
|
||||
|
||||
SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg);
|
||||
SBcAP_SBC_AP_PDU_t *sbcap_gen_write_replace_warning_req(void *ctx, const struct cbc_message *cbcmsg);
|
||||
SBcAP_SBC_AP_PDU_t *sbcap_gen_stop_warning_req(void *ctx, const struct cbc_message *cbcmsg);
|
||||
SBcAP_SBC_AP_PDU_t *sbcap_gen_error_ind(void *ctx, SBcAP_Cause_t cause, SBcAP_SBC_AP_PDU_t *rx_pdu);
|
||||
|
||||
|
||||
void cci_from_sbcap_bcast_cell_id(struct cbc_cell_id *cci, const SBcAP_CellId_Broadcast_List_Item_t *it);
|
||||
void cci_from_sbcap_tai(struct cbc_cell_id *cci, const SBcAP_TAI_t *tai);
|
||||
|
||||
@@ -3,34 +3,28 @@
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
enum smscb_fsm_event {
|
||||
SMSCB_E_CHILD_DIED,
|
||||
enum smscb_message_fsm_event {
|
||||
SMSCB_MSG_E_CHILD_DIED,
|
||||
/* create a message (from REST) */
|
||||
SMSCB_E_CREATE,
|
||||
SMSCB_MSG_E_CREATE,
|
||||
/* replace a message (from REST) */
|
||||
SMSCB_E_REPLACE,
|
||||
SMSCB_MSG_E_REPLACE,
|
||||
/* get status of a message (from REST) */
|
||||
SMSCB_E_STATUS,
|
||||
SMSCB_MSG_E_STATUS,
|
||||
/* delete a message (from REST) */
|
||||
SMSCB_E_DELETE,
|
||||
/* CBSP peer confirms write */
|
||||
SMSCB_E_CBSP_WRITE_ACK,
|
||||
SMSCB_E_CBSP_WRITE_NACK,
|
||||
/* CBSP peer confirms replace */
|
||||
SMSCB_E_CBSP_REPLACE_ACK,
|
||||
SMSCB_E_CBSP_REPLACE_NACK,
|
||||
/* CBSP peer confirms delete */
|
||||
SMSCB_E_CBSP_DELETE_ACK,
|
||||
SMSCB_E_CBSP_DELETE_NACK,
|
||||
/* CBSP peer confirms status query */
|
||||
SMSCB_E_CBSP_STATUS_ACK,
|
||||
SMSCB_E_CBSP_STATUS_NACK,
|
||||
/* SBc-AP peer confirms write */
|
||||
SMSCB_E_SBCAP_WRITE_ACK,
|
||||
SMSCB_E_SBCAP_WRITE_NACK,
|
||||
/* SBc-AP peer confirms delete */
|
||||
SMSCB_E_SBCAP_DELETE_ACK,
|
||||
SMSCB_E_SBCAP_DELETE_NACK,
|
||||
SMSCB_MSG_E_DELETE,
|
||||
/* peer confirms write */
|
||||
SMSCB_MSG_E_WRITE_ACK,
|
||||
SMSCB_MSG_E_WRITE_NACK,
|
||||
/* peer confirms replace */
|
||||
SMSCB_MSG_E_REPLACE_ACK,
|
||||
SMSCB_MSG_E_REPLACE_NACK,
|
||||
/* peer confirms delete */
|
||||
SMSCB_MSG_E_DELETE_ACK,
|
||||
SMSCB_MSG_E_DELETE_NACK,
|
||||
/* peer confirms status query */
|
||||
SMSCB_MSG_E_STATUS_ACK,
|
||||
SMSCB_MSG_E_STATUS_NACK
|
||||
};
|
||||
|
||||
enum smscb_fsm_state {
|
||||
@@ -56,4 +50,4 @@ enum smscb_p_fsm_timer {
|
||||
T_WAIT_DELETE_ACK,
|
||||
};
|
||||
|
||||
extern const struct value_string smscb_fsm_event_names[];
|
||||
extern const struct value_string smscb_message_fsm_event_names[];
|
||||
|
||||
40
include/osmocom/cbc/smscb_peer_fsm.h
Normal file
40
include/osmocom/cbc/smscb_peer_fsm.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
enum smscb_peer_fsm_event {
|
||||
/* create a message (from REST) */
|
||||
SMSCB_PEER_E_CREATE,
|
||||
/* replace a message (from REST) */
|
||||
SMSCB_PEER_E_REPLACE,
|
||||
/* get status of a message (from REST) */
|
||||
SMSCB_PEER_E_STATUS,
|
||||
/* delete a message (from REST) */
|
||||
SMSCB_PEER_E_DELETE,
|
||||
/* CBSP peer confirms write */
|
||||
SMSCB_PEER_E_CBSP_WRITE_ACK,
|
||||
SMSCB_PEER_E_CBSP_WRITE_NACK,
|
||||
/* CBSP peer confirms replace */
|
||||
SMSCB_PEER_E_CBSP_REPLACE_ACK,
|
||||
SMSCB_PEER_E_CBSP_REPLACE_NACK,
|
||||
/* CBSP peer confirms delete */
|
||||
SMSCB_PEER_E_CBSP_DELETE_ACK,
|
||||
SMSCB_PEER_E_CBSP_DELETE_NACK,
|
||||
/* CBSP peer confirms status query */
|
||||
SMSCB_PEER_E_CBSP_STATUS_ACK,
|
||||
SMSCB_PEER_E_CBSP_STATUS_NACK,
|
||||
/* SBc-AP peer confirms write */
|
||||
SMSCB_PEER_E_SBCAP_WRITE_ACK,
|
||||
SMSCB_PEER_E_SBCAP_WRITE_NACK,
|
||||
/* SBc-AP peer confirms delete */
|
||||
SMSCB_PEER_E_SBCAP_DELETE_ACK,
|
||||
SMSCB_PEER_E_SBCAP_DELETE_NACK,
|
||||
/* SBc-AP peer sends Write Replace Warning Indication to us */
|
||||
SMSCB_PEER_E_SBCAP_WRITE_IND,
|
||||
};
|
||||
|
||||
extern const struct value_string smscb_peer_fsm_event_names[];
|
||||
|
||||
extern struct osmo_fsm cbsp_smscb_peer_fsm;
|
||||
extern struct osmo_fsm sbcap_smscb_peer_fsm;
|
||||
@@ -29,12 +29,12 @@ typedef long SBcAP_Concurrent_Warning_Message_Indicator_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_Concurrent_Warning_Message_Indicator_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Concurrent_Warning_Message_Indicator;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_Concurrent_Warning_Message_Indicator_specs_1;
|
||||
asn_struct_free_f Concurrent_Warning_Message_Indicator_free;
|
||||
asn_struct_print_f Concurrent_Warning_Message_Indicator_print;
|
||||
asn_constr_check_f Concurrent_Warning_Message_Indicator_constraint;
|
||||
per_type_decoder_f Concurrent_Warning_Message_Indicator_decode_aper;
|
||||
per_type_encoder_f Concurrent_Warning_Message_Indicator_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_Concurrent_Warning_Message_Indicator_specs_1;
|
||||
asn_struct_free_f SBcAP_Concurrent_Warning_Message_Indicator_free;
|
||||
asn_struct_print_f SBcAP_Concurrent_Warning_Message_Indicator_print;
|
||||
asn_constr_check_f SBcAP_Concurrent_Warning_Message_Indicator_constraint;
|
||||
per_type_decoder_f SBcAP_Concurrent_Warning_Message_Indicator_decode_aper;
|
||||
per_type_encoder_f SBcAP_Concurrent_Warning_Message_Indicator_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@ typedef long SBcAP_Criticality_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_Criticality_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Criticality;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_Criticality_specs_1;
|
||||
asn_struct_free_f Criticality_free;
|
||||
asn_struct_print_f Criticality_print;
|
||||
asn_constr_check_f Criticality_constraint;
|
||||
per_type_decoder_f Criticality_decode_aper;
|
||||
per_type_encoder_f Criticality_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_Criticality_specs_1;
|
||||
asn_struct_free_f SBcAP_Criticality_free;
|
||||
asn_struct_print_f SBcAP_Criticality_print;
|
||||
asn_constr_check_f SBcAP_Criticality_constraint;
|
||||
per_type_decoder_f SBcAP_Criticality_decode_aper;
|
||||
per_type_encoder_f SBcAP_Criticality_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ typedef struct SBcAP_Error_Indication {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Error_Indication;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Error_Indication_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_Error_Indication_1[1];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct SBcAP_PWS_Failure_Indication {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_PWS_Failure_Indication;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_PWS_Failure_Indication_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_PWS_Failure_Indication_1[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct SBcAP_PWS_Restart_Indication {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_PWS_Restart_Indication;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_PWS_Restart_Indication_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_PWS_Restart_Indication_1[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@ typedef long SBcAP_Presence_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_Presence_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Presence;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_Presence_specs_1;
|
||||
asn_struct_free_f Presence_free;
|
||||
asn_struct_print_f Presence_print;
|
||||
asn_constr_check_f Presence_constraint;
|
||||
per_type_decoder_f Presence_decode_aper;
|
||||
per_type_encoder_f Presence_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_Presence_specs_1;
|
||||
asn_struct_free_f SBcAP_Presence_free;
|
||||
asn_struct_print_f SBcAP_Presence_print;
|
||||
asn_constr_check_f SBcAP_Presence_constraint;
|
||||
per_type_decoder_f SBcAP_Presence_decode_aper;
|
||||
per_type_encoder_f SBcAP_Presence_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ typedef long SBcAP_RAT_Selector_5GS_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_RAT_Selector_5GS_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_RAT_Selector_5GS;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_RAT_Selector_5GS_specs_1;
|
||||
asn_struct_free_f RAT_Selector_5GS_free;
|
||||
asn_struct_print_f RAT_Selector_5GS_print;
|
||||
asn_constr_check_f RAT_Selector_5GS_constraint;
|
||||
per_type_decoder_f RAT_Selector_5GS_decode_aper;
|
||||
per_type_encoder_f RAT_Selector_5GS_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_RAT_Selector_5GS_specs_1;
|
||||
asn_struct_free_f SBcAP_RAT_Selector_5GS_free;
|
||||
asn_struct_print_f SBcAP_RAT_Selector_5GS_print;
|
||||
asn_constr_check_f SBcAP_RAT_Selector_5GS_constraint;
|
||||
per_type_decoder_f SBcAP_RAT_Selector_5GS_decode_aper;
|
||||
per_type_encoder_f SBcAP_RAT_Selector_5GS_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ typedef long SBcAP_Send_Stop_Warning_Indication_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_Send_Stop_Warning_Indication_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Send_Stop_Warning_Indication;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_Send_Stop_Warning_Indication_specs_1;
|
||||
asn_struct_free_f Send_Stop_Warning_Indication_free;
|
||||
asn_struct_print_f Send_Stop_Warning_Indication_print;
|
||||
asn_constr_check_f Send_Stop_Warning_Indication_constraint;
|
||||
per_type_decoder_f Send_Stop_Warning_Indication_decode_aper;
|
||||
per_type_encoder_f Send_Stop_Warning_Indication_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_Send_Stop_Warning_Indication_specs_1;
|
||||
asn_struct_free_f SBcAP_Send_Stop_Warning_Indication_free;
|
||||
asn_struct_print_f SBcAP_Send_Stop_Warning_Indication_print;
|
||||
asn_constr_check_f SBcAP_Send_Stop_Warning_Indication_constraint;
|
||||
per_type_decoder_f SBcAP_Send_Stop_Warning_Indication_decode_aper;
|
||||
per_type_encoder_f SBcAP_Send_Stop_Warning_Indication_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ typedef long SBcAP_Send_Write_Replace_Warning_Indication_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_Send_Write_Replace_Warning_Indication_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Send_Write_Replace_Warning_Indication;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_Send_Write_Replace_Warning_Indication_specs_1;
|
||||
asn_struct_free_f Send_Write_Replace_Warning_Indication_free;
|
||||
asn_struct_print_f Send_Write_Replace_Warning_Indication_print;
|
||||
asn_constr_check_f Send_Write_Replace_Warning_Indication_constraint;
|
||||
per_type_decoder_f Send_Write_Replace_Warning_Indication_decode_aper;
|
||||
per_type_encoder_f Send_Write_Replace_Warning_Indication_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_Send_Write_Replace_Warning_Indication_specs_1;
|
||||
asn_struct_free_f SBcAP_Send_Write_Replace_Warning_Indication_free;
|
||||
asn_struct_print_f SBcAP_Send_Write_Replace_Warning_Indication_print;
|
||||
asn_constr_check_f SBcAP_Send_Write_Replace_Warning_Indication_constraint;
|
||||
per_type_decoder_f SBcAP_Send_Write_Replace_Warning_Indication_decode_aper;
|
||||
per_type_encoder_f SBcAP_Send_Write_Replace_Warning_Indication_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ typedef long SBcAP_Stop_All_Indicator_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_Stop_All_Indicator_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Stop_All_Indicator;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_Stop_All_Indicator_specs_1;
|
||||
asn_struct_free_f Stop_All_Indicator_free;
|
||||
asn_struct_print_f Stop_All_Indicator_print;
|
||||
asn_constr_check_f Stop_All_Indicator_constraint;
|
||||
per_type_decoder_f Stop_All_Indicator_decode_aper;
|
||||
per_type_encoder_f Stop_All_Indicator_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_Stop_All_Indicator_specs_1;
|
||||
asn_struct_free_f SBcAP_Stop_All_Indicator_free;
|
||||
asn_struct_print_f SBcAP_Stop_All_Indicator_print;
|
||||
asn_constr_check_f SBcAP_Stop_All_Indicator_constraint;
|
||||
per_type_decoder_f SBcAP_Stop_All_Indicator_decode_aper;
|
||||
per_type_encoder_f SBcAP_Stop_All_Indicator_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct SBcAP_Stop_Warning_Indication {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Stop_Warning_Indication;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Indication_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Indication_1[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct SBcAP_Stop_Warning_Request {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Stop_Warning_Request;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Request_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Request_1[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct SBcAP_Stop_Warning_Response {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Stop_Warning_Response;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Response_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Response_1[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ typedef long SBcAP_TriggeringMessage_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_TriggeringMessage_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_TriggeringMessage;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_TriggeringMessage_specs_1;
|
||||
asn_struct_free_f TriggeringMessage_free;
|
||||
asn_struct_print_f TriggeringMessage_print;
|
||||
asn_constr_check_f TriggeringMessage_constraint;
|
||||
per_type_decoder_f TriggeringMessage_decode_aper;
|
||||
per_type_encoder_f TriggeringMessage_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_TriggeringMessage_specs_1;
|
||||
asn_struct_free_f SBcAP_TriggeringMessage_free;
|
||||
asn_struct_print_f SBcAP_TriggeringMessage_print;
|
||||
asn_constr_check_f SBcAP_TriggeringMessage_constraint;
|
||||
per_type_decoder_f SBcAP_TriggeringMessage_decode_aper;
|
||||
per_type_encoder_f SBcAP_TriggeringMessage_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ typedef long SBcAP_TypeOfError_t;
|
||||
/* Implementation */
|
||||
extern asn_per_constraints_t asn_PER_type_SBcAP_TypeOfError_constr_1;
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_TypeOfError;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_TypeOfError_specs_1;
|
||||
asn_struct_free_f TypeOfError_free;
|
||||
asn_struct_print_f TypeOfError_print;
|
||||
asn_constr_check_f TypeOfError_constraint;
|
||||
per_type_decoder_f TypeOfError_decode_aper;
|
||||
per_type_encoder_f TypeOfError_encode_aper;
|
||||
extern const asn_INTEGER_specifics_t asn_SPC_SBcAP_TypeOfError_specs_1;
|
||||
asn_struct_free_f SBcAP_TypeOfError_free;
|
||||
asn_struct_print_f SBcAP_TypeOfError_print;
|
||||
asn_constr_check_f SBcAP_TypeOfError_constraint;
|
||||
per_type_decoder_f SBcAP_TypeOfError_decode_aper;
|
||||
per_type_encoder_f SBcAP_TypeOfError_encode_aper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct SBcAP_Write_Replace_Warning_Indication {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Write_Replace_Warning_Indication;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Indication_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Indication_1[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct SBcAP_Write_Replace_Warning_Request {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Write_Replace_Warning_Request;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Request_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Request_1[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef struct SBcAP_Write_Replace_Warning_Response {
|
||||
|
||||
/* Implementation */
|
||||
extern asn_TYPE_descriptor_t asn_DEF_SBcAP_Write_Replace_Warning_Response;
|
||||
extern asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Response_specs_1;
|
||||
extern asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Response_1[2];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -118,8 +118,8 @@
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
extern int _sbcap_DSBCAP;
|
||||
#define SBC_AP_DEBUG(x, args ...) DEBUGP(_sbcap_DSBCAP, x, ## args)
|
||||
extern int _sbcap_DASN1C;
|
||||
#define SBC_AP_DEBUG(x, args ...) DEBUGP(_sbcap_DASN1C, x, ## args)
|
||||
|
||||
extern int asn1_xer_print;
|
||||
|
||||
@@ -137,12 +137,22 @@ void sbcap_pdu_free(SBcAP_SBC_AP_PDU_t *pdu);
|
||||
struct msgb *sbcap_encode(SBcAP_SBC_AP_PDU_t *pdu);
|
||||
SBcAP_SBC_AP_PDU_t *sbcap_decode(const struct msgb *msg);
|
||||
|
||||
const char *sbcap_procedure_code_str(SBcAP_ProcedureCode_t pc);
|
||||
const char *sbcap_cause_str(SBcAP_Cause_t cause);
|
||||
|
||||
void sbcap_set_log_area(int log_area);
|
||||
void sbcap_set_log_area(int log_area_sbcap, int log_area_asn1c);
|
||||
|
||||
SBcAP_ProcedureCode_t sbcap_pdu_get_procedure_code(const SBcAP_SBC_AP_PDU_t *pdu);
|
||||
SBcAP_Criticality_t sbcap_pdu_get_criticality(const SBcAP_SBC_AP_PDU_t *pdu);
|
||||
const char *sbcap_pdu_get_name(const SBcAP_SBC_AP_PDU_t *pdu);
|
||||
|
||||
void *sbcap_as_find_ie(void *void_list, SBcAP_ProtocolIE_ID_t ie_id);
|
||||
|
||||
SBcAP_Write_Replace_Warning_Request_IEs_t *sbcap_alloc_Write_Replace_Warning_Request_IE(
|
||||
long id, SBcAP_Criticality_t criticality, SBcAP_Write_Replace_Warning_Request_IEs__value_PR present);
|
||||
|
||||
SBcAP_Stop_Warning_Request_IEs_t *sbcap_alloc_Stop_Warning_Request_IE(
|
||||
long id, SBcAP_Criticality_t criticality, SBcAP_Stop_Warning_Request_IEs__value_PR present);
|
||||
|
||||
SBcAP_ErrorIndicationIEs_t *sbcap_alloc_Error_Indication_IE(
|
||||
long id, SBcAP_Criticality_t criticality, SBcAP_Stop_Warning_Request_IEs__value_PR present);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
extern int _sbcap_DSBCAP;
|
||||
#define SBC_AP_ASN_DEBUG(x, args ...) DEBUGP(_sbcap_DSBCAP, x "\n", ## args)
|
||||
extern int _sbcap_DASN1C;
|
||||
#define SBC_AP_ASN_DEBUG(x, args ...) DEBUGP(_sbcap_DASN1C, x "\n", ## args)
|
||||
|
||||
#define ASN_DEBUG SBC_AP_ASN_DEBUG
|
||||
|
||||
@@ -17,21 +17,30 @@ osmo_cbc_SOURCES = \
|
||||
cbc_vty.c \
|
||||
cbsp_link.c \
|
||||
cbsp_link_fsm.c \
|
||||
cbsp_msg.c \
|
||||
cbsp_smscb_peer_fsm.c \
|
||||
rest_api.c \
|
||||
charset.c \
|
||||
message_handling.c \
|
||||
rest_it_op.c \
|
||||
sbcap_msg.c \
|
||||
sbcap_link.c \
|
||||
sbcap_link_fsm.c \
|
||||
smscb_peer_fsm.c \
|
||||
sbcap_smscb_peer_fsm.c \
|
||||
smscb_message_fsm.c \
|
||||
smscb_peer_fsm.c \
|
||||
$(NULL)
|
||||
|
||||
osmo_cbc_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
$(ULFIUS_LIBS) $(JANSSON_LIBS) $(ORCANIA_LIBS) $(LIBSCTP_LIBS) \
|
||||
sbcap/libosmo-sbcap.la
|
||||
osmo_cbc_LDADD = \
|
||||
sbcap/libosmo-sbcap.la \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
$(ULFIUS_LIBS) \
|
||||
$(JANSSON_LIBS) \
|
||||
$(ORCANIA_LIBS) \
|
||||
$(LIBSCTP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
regen:
|
||||
$(MAKE) -C sbcap regen
|
||||
|
||||
@@ -35,6 +35,46 @@
|
||||
#include <osmocom/cbc/rest_it_op.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
|
||||
const char *cbc_cell_id2str(const struct cbc_cell_id *cid)
|
||||
{
|
||||
static char buf[256];
|
||||
|
||||
switch (cid->id_discr) {
|
||||
case CBC_CELL_ID_NONE:
|
||||
snprintf(buf, sizeof(buf), "NONE");
|
||||
break;
|
||||
case CBC_CELL_ID_BSS:
|
||||
snprintf(buf, sizeof(buf), "BSS");
|
||||
break;
|
||||
case CBC_CELL_ID_CGI:
|
||||
snprintf(buf, sizeof(buf), "CGI %s", osmo_cgi_name(&cid->u.cgi));
|
||||
break;
|
||||
case CBC_CELL_ID_LAC_CI:
|
||||
snprintf(buf, sizeof(buf), "LAC %u CI %u", cid->u.lac_and_ci.lac, cid->u.lac_and_ci.ci);
|
||||
break;
|
||||
case CBC_CELL_ID_LAI:
|
||||
snprintf(buf, sizeof(buf), "LAI %s", osmo_lai_name(&cid->u.lai));
|
||||
break;
|
||||
case CBC_CELL_ID_LAC:
|
||||
snprintf(buf, sizeof(buf), "LAC %u", cid->u.lac);
|
||||
break;
|
||||
case CBC_CELL_ID_CI:
|
||||
snprintf(buf, sizeof(buf), "CI %u", cid->u.ci);
|
||||
break;
|
||||
case CBC_CELL_ID_ECGI:
|
||||
snprintf(buf, sizeof(buf), "ECGI %s-%05X-%02X", osmo_plmn_name(&cid->u.ecgi.plmn),
|
||||
cid->u.ecgi.eci >> 8, cid->u.ecgi.eci & 0xff);
|
||||
break;
|
||||
case CBC_CELL_ID_TAI:
|
||||
snprintf(buf, sizeof(buf), "TAI %s-%u", osmo_plmn_name(&cid->u.tai.plmn), cid->u.tai.tac);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "<invalid>");
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct cbc *cbc_alloc(void *ctx)
|
||||
{
|
||||
struct cbc *cbc;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/stats.h>
|
||||
@@ -44,9 +45,12 @@
|
||||
#include <osmocom/vty/logging.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
|
||||
#include <osmocom/sbcap/sbcap_common.h>
|
||||
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/cbc_data.h>
|
||||
#include <osmocom/cbc/cbc_vty.h>
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
|
||||
static void *tall_cbc_ctx;
|
||||
struct cbc *g_cbc;
|
||||
@@ -59,6 +63,13 @@ static const struct log_info_cat log_info_cat[] = {
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DSMSCB] = {
|
||||
.name = "DSMSCB",
|
||||
.description = "SMS Cell Broadcast handling",
|
||||
.color = "\033[1;35m",
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DCBSP] = {
|
||||
.name = "DCBSP",
|
||||
.description = "Cell Broadcast Service Protocol (CBC-BSC)",
|
||||
@@ -73,6 +84,13 @@ static const struct log_info_cat log_info_cat[] = {
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DASN1C] = {
|
||||
.name = "DASN1C",
|
||||
.description = "SBc-AP ASN1C enc/dec",
|
||||
.color = "\033[1;34m",
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DREST] = {
|
||||
.name = "DREST",
|
||||
.description = "REST interface",
|
||||
@@ -90,12 +108,21 @@ static const struct log_info log_info = {
|
||||
static int cbc_vty_go_parent(struct vty *vty)
|
||||
{
|
||||
switch (vty->node) {
|
||||
case CBSP_NODE:
|
||||
g_cbc->config.cbsp.configured = true;
|
||||
break;
|
||||
case SBcAP_NODE:
|
||||
/* If no local addr set, add a default one: */
|
||||
if (g_cbc->config.sbcap.num_local_host == 0) {
|
||||
g_cbc->config.sbcap.local_host[0] = talloc_strdup(g_cbc, "127.0.0.1");
|
||||
g_cbc->config.sbcap.num_local_host = 1;
|
||||
}
|
||||
g_cbc->config.sbcap.configured = true;
|
||||
vty->node = CONFIG_NODE;
|
||||
vty->index = NULL;
|
||||
break;
|
||||
case PEER_NODE:
|
||||
cbc_peer_apply_cfg_chg((struct cbc_peer *)vty->index);
|
||||
vty->node = CONFIG_NODE;
|
||||
vty->index = NULL;
|
||||
break;
|
||||
@@ -244,7 +271,9 @@ int main(int argc, char **argv)
|
||||
msgb_talloc_ctx_init(tall_cbc_ctx, 0);
|
||||
osmo_init_logging2(tall_cbc_ctx, &log_info);
|
||||
log_enable_multithread();
|
||||
sbcap_set_log_area(DSBcAP, DASN1C);
|
||||
osmo_stats_init(tall_cbc_ctx);
|
||||
osmo_fsm_log_timeouts(true);
|
||||
vty_init(&vty_info);
|
||||
|
||||
g_cbc = cbc_alloc(tall_cbc_ctx);
|
||||
@@ -263,7 +292,7 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rc = telnet_init_dynif(tall_cbc_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_CBC);
|
||||
rc = telnet_init_default(tall_cbc_ctx, NULL, OSMO_VTY_PORT_CBC);
|
||||
if (rc < 0) {
|
||||
perror("Error binding VTY port");
|
||||
exit(1);
|
||||
|
||||
@@ -27,8 +27,146 @@
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <osmocom/cbc/cbsp_msg.h>
|
||||
#include <osmocom/cbc/cbsp_link.h>
|
||||
#include <osmocom/cbc/sbcap_msg.h>
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/cbc_message.h>
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/rest_it_op.h>
|
||||
#include <osmocom/cbc/smscb_message_fsm.h>
|
||||
|
||||
/* determine if peer is within scope of cbc_msg */
|
||||
static bool is_peer_in_scope(const struct cbc_peer *peer, const struct cbc_message *cbcmsg)
|
||||
{
|
||||
switch (cbcmsg->scope) {
|
||||
case CBC_MSG_SCOPE_PLMN:
|
||||
return true;
|
||||
/* FIXME: differnt scopes */
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* send given new message to given peer */
|
||||
int peer_new_cbc_message(struct cbc_peer *peer, struct cbc_message *cbcmsg)
|
||||
{
|
||||
struct osmo_cbsp_decoded *cbsp;
|
||||
SBcAP_SBC_AP_PDU_t *sbcap;
|
||||
|
||||
switch (peer->proto) {
|
||||
case CBC_PEER_PROTO_CBSP:
|
||||
/* skip peers without any current CBSP connection */
|
||||
if (!peer->link.cbsp) {
|
||||
LOGP(DCBSP, LOGL_NOTICE, "[%s] Tx CBSP: not connected\n",
|
||||
peer->name);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (!(cbsp = cbsp_gen_write_replace_req(peer, cbcmsg))) {
|
||||
LOGP(DCBSP, LOGL_ERROR, "[%s] Tx CBSP: msg gen failed\n",
|
||||
peer->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
return cbc_cbsp_link_tx(peer->link.cbsp, cbsp);
|
||||
|
||||
case CBC_PEER_PROTO_SBcAP:
|
||||
/* skip peers without any current SBc-AP connection */
|
||||
if (!peer->link.sbcap) {
|
||||
LOGP(DSBcAP, LOGL_NOTICE, "[%s] Tx SBc-AP: not connected\n",
|
||||
peer->name);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (!(sbcap = sbcap_gen_write_replace_warning_req(peer, cbcmsg))) {
|
||||
LOGP(DSBcAP, LOGL_ERROR, "[%s] Tx SBc-AP: msg gen failed\n",
|
||||
peer->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
return cbc_sbcap_link_tx(peer->link.sbcap, sbcap);
|
||||
|
||||
case CBC_PEER_PROTO_SABP:
|
||||
LOGP(DLGLOBAL, LOGL_ERROR, "Sending message to peer proto %s not implemented!\n",
|
||||
get_value_string(cbc_peer_proto_name, peer->proto));
|
||||
return -1;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* receive a new CBC message from the user (REST). Allocates new memory,
|
||||
* a FSM, copies data from 'orig', routes to all peers and starts FSMs.
|
||||
* Once the operation is complete (success, error, timeout) we must
|
||||
* notify osmo_it_q of the completion */
|
||||
int cbc_message_new(const struct cbc_message *orig, struct rest_it_op *op)
|
||||
{
|
||||
struct cbc_message *cbcmsg = cbc_message_alloc(g_cbc, orig);
|
||||
struct cbc_peer *peer;
|
||||
|
||||
if (!cbcmsg) {
|
||||
rest_it_op_set_http_result(op, 409, "Could not allocate");
|
||||
rest_it_op_complete(op);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
OSMO_ASSERT(llist_empty(&cbcmsg->peers));
|
||||
|
||||
/* iterate over all peers */
|
||||
llist_for_each_entry(peer, &g_cbc->peers, list) {
|
||||
struct cbc_message_peer *mp;
|
||||
|
||||
if (!is_peer_in_scope(peer, cbcmsg))
|
||||
continue;
|
||||
|
||||
/* allocate new cbc_mesage_peer + related FSM */
|
||||
mp = smscb_peer_fsm_alloc(peer, cbcmsg);
|
||||
if (!mp) {
|
||||
LOGP(DCBSP, LOGL_ERROR, "Cannot allocate cbc_message_peer\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* kick off the state machine[s] */
|
||||
if (osmo_fsm_inst_dispatch(cbcmsg->fi, SMSCB_MSG_E_CREATE, op) < 0) {
|
||||
rest_it_op_set_http_result(op, 500, "Illegal FSM event");
|
||||
rest_it_op_complete(op);
|
||||
}
|
||||
|
||||
/* we continue in the FSM after the WRITE_ACK event was received */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cbc_message_delete(struct cbc_message *cbcmsg, struct rest_it_op *op)
|
||||
{
|
||||
if (osmo_fsm_inst_dispatch(cbcmsg->fi, SMSCB_MSG_E_DELETE, op) < 0) {
|
||||
rest_it_op_set_http_result(op, 500, "Illegal FSM event");
|
||||
rest_it_op_complete(op);
|
||||
}
|
||||
/* we continue in the FSM after the DELETE_ACK event was received */
|
||||
}
|
||||
|
||||
struct cbc_message *cbc_message_by_id(uint16_t message_id)
|
||||
{
|
||||
struct cbc_message *cbc_msg;
|
||||
llist_for_each_entry(cbc_msg, &g_cbc->messages, list) {
|
||||
if (cbc_msg->msg.message_id == message_id)
|
||||
return cbc_msg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cbc_message *cbc_message_expired_by_id(uint16_t message_id)
|
||||
{
|
||||
struct cbc_message *cbc_msg;
|
||||
llist_for_each_entry(cbc_msg, &g_cbc->expired_messages, list) {
|
||||
if (cbc_msg->msg.message_id == message_id)
|
||||
return cbc_msg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* remove a peer from the message */
|
||||
int cbc_message_del_peer(struct cbc_message *cbcmsg, struct cbc_peer *peer)
|
||||
|
||||
116
src/cbc_peer.c
116
src/cbc_peer.c
@@ -32,6 +32,7 @@
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
#include <osmocom/cbc/cbsp_link.h>
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
|
||||
const struct value_string cbc_peer_proto_name[] = {
|
||||
{ CBC_PEER_PROTO_CBSP, "CBSP" },
|
||||
@@ -40,6 +41,14 @@ const struct value_string cbc_peer_proto_name[] = {
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
const struct value_string cbc_peer_link_mode_names[] = {
|
||||
{ CBC_PEER_LINK_MODE_DISABLED, "disabled" },
|
||||
{ CBC_PEER_LINK_MODE_SERVER, "server" },
|
||||
{ CBC_PEER_LINK_MODE_CLIENT, "client" },
|
||||
{}
|
||||
};
|
||||
|
||||
/* create a new cbc_peer */
|
||||
struct cbc_peer *cbc_peer_create(const char *name, enum cbc_peer_protocol proto)
|
||||
{
|
||||
@@ -120,3 +129,110 @@ struct cbc_peer *cbc_peer_by_addr_proto(const char *remote_host, uint16_t remote
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int cbc_peer_apply_cfg_chg_cbsp(struct cbc_peer *peer)
|
||||
{
|
||||
struct cbc_cbsp_link *link = peer->link.cbsp;
|
||||
int rc = 0;
|
||||
|
||||
switch (peer->link_mode) {
|
||||
case CBC_PEER_LINK_MODE_DISABLED:
|
||||
if (link) {
|
||||
LOGPCC(link, LOGL_NOTICE,
|
||||
"link mode changed to 'disabled', closing active link\n");
|
||||
cbc_cbsp_link_close(link);
|
||||
}
|
||||
/* Nothing to be done, cbc_cbsp_mgr->srv_link will refuse
|
||||
* accepting() disabled peers. */
|
||||
OSMO_ASSERT(!peer->link.cbsp);
|
||||
break;
|
||||
case CBC_PEER_LINK_MODE_SERVER:
|
||||
if (link && link->is_client) {
|
||||
LOGPCC(link, LOGL_NOTICE,
|
||||
"link mode changed 'client' -> 'server', closing active link\n");
|
||||
cbc_cbsp_link_close(link);
|
||||
}
|
||||
/* Nothing to be done, cbc_cbsp_mgr->srv_link will accept() and
|
||||
* recreate the link */
|
||||
OSMO_ASSERT(!peer->link.cbsp);
|
||||
break;
|
||||
case CBC_PEER_LINK_MODE_CLIENT:
|
||||
if (link) {
|
||||
if (link->is_client) {
|
||||
/* nothing to be done, cli link already created */
|
||||
break;
|
||||
}
|
||||
LOGPCC(link, LOGL_NOTICE,
|
||||
"link mode changed 'server' -> 'client', closing active link\n");
|
||||
cbc_cbsp_link_close(link);
|
||||
}
|
||||
OSMO_ASSERT(!peer->link.cbsp);
|
||||
link = cbc_cbsp_link_alloc(g_cbc->cbsp.mgr, peer);
|
||||
peer->link.cbsp = link;
|
||||
rc = cbc_cbsp_link_open_cli(link);
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cbc_peer_apply_cfg_chg_sbcap(struct cbc_peer *peer)
|
||||
{
|
||||
struct cbc_sbcap_link *link = peer->link.sbcap;
|
||||
int rc = 0;
|
||||
|
||||
switch (peer->link_mode) {
|
||||
case CBC_PEER_LINK_MODE_DISABLED:
|
||||
if (link) {
|
||||
LOGPSBCAPC(link, LOGL_NOTICE,
|
||||
"link mode changed to 'disabled', closing active link\n");
|
||||
cbc_sbcap_link_close(link);
|
||||
}
|
||||
/* Nothing to be done, cbc_sbcap_mgr->srv_link will refuse
|
||||
* accepting() disabled peers. */
|
||||
OSMO_ASSERT(!peer->link.sbcap);
|
||||
break;
|
||||
case CBC_PEER_LINK_MODE_SERVER:
|
||||
if (link && link->is_client) {
|
||||
LOGPSBCAPC(link, LOGL_NOTICE,
|
||||
"link mode changed 'client' -> 'server', closing active link\n");
|
||||
cbc_sbcap_link_close(link);
|
||||
}
|
||||
/* Nothing to be done, cbc_sbcap_mgr->srv_link will accept() and
|
||||
* recreate the link */
|
||||
OSMO_ASSERT(!peer->link.sbcap);
|
||||
break;
|
||||
case CBC_PEER_LINK_MODE_CLIENT:
|
||||
if (link) {
|
||||
if (link->is_client) {
|
||||
/* nothing to be done, cli link already created */
|
||||
break;
|
||||
}
|
||||
LOGPSBCAPC(link, LOGL_NOTICE,
|
||||
"link mode changed 'server' -> 'client', closing active link\n");
|
||||
cbc_sbcap_link_close(link);
|
||||
}
|
||||
OSMO_ASSERT(!peer->link.sbcap);
|
||||
link = cbc_sbcap_link_alloc(g_cbc->sbcap.mgr, peer);
|
||||
peer->link.sbcap = link;
|
||||
rc = cbc_sbcap_link_open_cli(link);
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cbc_peer_apply_cfg_chg(struct cbc_peer *peer)
|
||||
{
|
||||
int rc = -ENOTSUP;
|
||||
|
||||
switch (peer->proto) {
|
||||
case CBC_PEER_PROTO_CBSP:
|
||||
rc = cbc_peer_apply_cfg_chg_cbsp(peer);
|
||||
break;
|
||||
case CBC_PEER_PROTO_SBcAP:
|
||||
rc = cbc_peer_apply_cfg_chg_sbcap(peer);
|
||||
break;
|
||||
case CBC_PEER_PROTO_SABP:
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
131
src/cbc_vty.c
131
src/cbc_vty.c
@@ -102,13 +102,26 @@ DEFUN(show_peers, show_peers_cmd,
|
||||
static void dump_one_cbc_msg(struct vty *vty, const struct cbc_message *cbc_msg)
|
||||
{
|
||||
const struct smscb_message *smscb = &cbc_msg->msg;
|
||||
char str_created[32], str_expired[32];
|
||||
struct tm tm_created = {0};
|
||||
struct tm tm_expired = {0};
|
||||
|
||||
OSMO_ASSERT(!smscb->is_etws);
|
||||
|
||||
vty_out(vty, "| %04X| %04X|%-20s|%-13s| %-4u|%c| %02x|%s",
|
||||
localtime_r(&cbc_msg->time.created, &tm_created);
|
||||
strftime(str_created, sizeof(str_created), "%Y-%m-%dT%H:%M:%SZ", &tm_created);
|
||||
if (cbc_msg->time.expired > 0) {
|
||||
localtime_r(&cbc_msg->time.expired, &tm_expired);
|
||||
strftime(str_expired, sizeof(str_expired), "%Y-%m-%dT%H:%M:%SZ", &tm_expired);
|
||||
} else {
|
||||
OSMO_STRLCPY_ARRAY(str_expired, "active");
|
||||
}
|
||||
|
||||
vty_out(vty, "| %04X| %04X|%-20s|%-13s| %-4u|%c| %02x|%-20s|%-20s|%s",
|
||||
smscb->message_id, smscb->serial_nr, cbc_msg->cbe_name,
|
||||
get_value_string(cbsp_category_names, cbc_msg->priority), cbc_msg->rep_period,
|
||||
cbc_msg->extended_cbch ? 'E' : 'N', smscb->cbs.dcs,
|
||||
str_created, str_expired,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
@@ -119,9 +132,11 @@ DEFUN(show_messages_cbs, show_messages_cbs_cmd,
|
||||
struct cbc_message *cbc_msg;
|
||||
|
||||
vty_out(vty,
|
||||
"|MsgId|SerNo| CBE Name | Category |Period|E|DCS|%s", VTY_NEWLINE);
|
||||
"|MsgId|SerNo| CBE Name | Category |Period|E|DCS| Created | Expired |%s",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty,
|
||||
"|-----|-----|--------------------|-------------|------|-|---|%s", VTY_NEWLINE);
|
||||
"|-----|-----|--------------------|-------------|------|-|---|--------------------|--------------------|%s",
|
||||
VTY_NEWLINE);
|
||||
|
||||
llist_for_each_entry(cbc_msg, &g_cbc->messages, list) {
|
||||
if (cbc_msg->msg.is_etws)
|
||||
@@ -138,37 +153,25 @@ DEFUN(show_messages_cbs, show_messages_cbs_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static const char *cbc_cell_id2str(const struct cbc_cell_id *cid)
|
||||
DEFUN(delete_message_expired, delete_message_expired_cmd,
|
||||
"delete message expired id <0-65535>",
|
||||
"Delete message from the local expired list\n"
|
||||
"Delete message from the local expired list\n"
|
||||
"Delete message from the local expired list\n"
|
||||
"Message ID\n" "Message ID\n")
|
||||
{
|
||||
static char buf[256];
|
||||
|
||||
switch (cid->id_discr) {
|
||||
case CBC_CELL_ID_NONE:
|
||||
snprintf(buf, sizeof(buf), "NONE");
|
||||
break;
|
||||
case CBC_CELL_ID_BSS:
|
||||
snprintf(buf, sizeof(buf), "BSS");
|
||||
break;
|
||||
case CBC_CELL_ID_CGI:
|
||||
snprintf(buf, sizeof(buf), "CGI %s", osmo_cgi_name(&cid->u.cgi));
|
||||
break;
|
||||
case CBC_CELL_ID_LAC_CI:
|
||||
snprintf(buf, sizeof(buf), "LAC %u CI %u", cid->u.lac_and_ci.lac, cid->u.lac_and_ci.ci);
|
||||
break;
|
||||
case CBC_CELL_ID_LAI:
|
||||
snprintf(buf, sizeof(buf), "LAI %s", osmo_lai_name(&cid->u.lai));
|
||||
break;
|
||||
case CBC_CELL_ID_LAC:
|
||||
snprintf(buf, sizeof(buf), "LAC %u", cid->u.lac);
|
||||
break;
|
||||
case CBC_CELL_ID_CI:
|
||||
snprintf(buf, sizeof(buf), "CI %u", cid->u.ci);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "<invalid>");
|
||||
break;
|
||||
struct cbc_message *cbc_msg;
|
||||
uint16_t msgid = atoi(argv[0]);
|
||||
cbc_msg = cbc_message_expired_by_id(msgid);
|
||||
if (!cbc_msg) {
|
||||
if (cbc_message_by_id(msgid))
|
||||
vty_out(vty, "Message ID %s has not yet expired!%s", argv[0], VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, "Unknown expired Message ID %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return buf;
|
||||
cbc_message_free(cbc_msg);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void dump_one_msg_peer(struct vty *vty, const struct cbc_message_peer *msg_peer, const char *pfx)
|
||||
@@ -205,10 +208,13 @@ DEFUN(show_message_cbs, show_message_cbs_cmd,
|
||||
const struct smscb_message *smscb;
|
||||
struct cbc_message_peer *msg_peer;
|
||||
char *timestr;
|
||||
uint16_t msgid = atoi(argv[0]);
|
||||
|
||||
cbc_msg = cbc_message_by_id(atoi(argv[0]));
|
||||
cbc_msg = cbc_message_by_id(msgid);
|
||||
if (!cbc_msg)
|
||||
cbc_msg = cbc_message_expired_by_id(msgid);
|
||||
if (!cbc_msg) {
|
||||
vty_out(vty, "Unknown Messsage ID %s%s", argv[0], VTY_NEWLINE);
|
||||
vty_out(vty, "Unknown Message ID %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
smscb = &cbc_msg->msg;
|
||||
@@ -251,13 +257,26 @@ DEFUN(show_message_cbs, show_message_cbs_cmd,
|
||||
static void dump_one_etws_msg(struct vty *vty, const struct cbc_message *cbc_msg)
|
||||
{
|
||||
const struct smscb_message *smscb = &cbc_msg->msg;
|
||||
char str_created[32], str_expired[32];
|
||||
struct tm tm_created = {0};
|
||||
struct tm tm_expired = {0};
|
||||
|
||||
OSMO_ASSERT(smscb->is_etws);
|
||||
|
||||
vty_out(vty, "| %04X| %04X|%-20s|%-13s| %-4u|%c| %04d|%s",
|
||||
localtime_r(&cbc_msg->time.created, &tm_created);
|
||||
strftime(str_created, sizeof(str_created), "%Y-%m-%dT%H:%M:%SZ", &tm_created);
|
||||
if (cbc_msg->time.expired > 0) {
|
||||
localtime_r(&cbc_msg->time.expired, &tm_expired);
|
||||
strftime(str_expired, sizeof(str_expired), "%Y-%m-%dT%H:%M:%SZ", &tm_expired);
|
||||
} else {
|
||||
OSMO_STRLCPY_ARRAY(str_expired, "active");
|
||||
}
|
||||
|
||||
vty_out(vty, "| %04X| %04X|%-20s|%-13s| %-4u|%c| %04d|%-20s|%-20s|%s",
|
||||
smscb->message_id, smscb->serial_nr, cbc_msg->cbe_name,
|
||||
get_value_string(cbsp_category_names, cbc_msg->priority), cbc_msg->rep_period,
|
||||
cbc_msg->extended_cbch ? 'E' : 'N', smscb->etws.warning_type,
|
||||
str_created, str_expired,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
@@ -268,9 +287,11 @@ DEFUN(show_messages_etws, show_messages_etws_cmd,
|
||||
struct cbc_message *cbc_msg;
|
||||
|
||||
vty_out(vty,
|
||||
"|MsgId|SerNo| CBE Name | Category |Period|E|Warning Type|%s", VTY_NEWLINE);
|
||||
"|MsgId|SerNo| CBE Name | Category |Period|E|Warning Type| Created | Expired |%s",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty,
|
||||
"|-----|-----|--------------------|-------------|------|-|------------|%s", VTY_NEWLINE);
|
||||
"|-----|-----|--------------------|-------------|------|-|------------|--------------------|--------------------|%s",
|
||||
VTY_NEWLINE);
|
||||
|
||||
llist_for_each_entry(cbc_msg, &g_cbc->messages, list) {
|
||||
if (!cbc_msg->msg.is_etws)
|
||||
@@ -555,6 +576,26 @@ DEFUN(cfg_cbc_peer, cfg_cbc_peer_cmd,
|
||||
enum cbc_peer_protocol proto;
|
||||
|
||||
proto = get_string_value(cbc_peer_proto_name_vty, argv[0]);
|
||||
switch (proto) {
|
||||
case CBC_PEER_PROTO_CBSP:
|
||||
if (!g_cbc->config.cbsp.configured) {
|
||||
vty_out(vty, "%% Node '%s' must be configured before configuring node 'peer'!%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
break;
|
||||
case CBC_PEER_PROTO_SBcAP:
|
||||
if (!g_cbc->config.sbcap.configured) {
|
||||
vty_out(vty, "%% Node '%s' must be configured before configuring node 'peer'!%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
break;
|
||||
case CBC_PEER_PROTO_SABP:
|
||||
default:
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
peer = cbc_peer_by_name(argv[1]);
|
||||
if (!peer)
|
||||
peer = cbc_peer_create(argv[1], proto);
|
||||
@@ -593,6 +634,19 @@ DEFUN_DEPRECATED(cfg_peer_proto, cfg_peer_proto_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(cfg_peer_mode, cfg_peer_mode_cmd,
|
||||
"mode (server|client|disabled)",
|
||||
"Connect to peer as TCP(CBSP)/SCTP(SBc-AP) server or client\n"
|
||||
"server: listen for inbound TCP (CBSP) / SCTP (SBc-AP) connections from a remote peer\n"
|
||||
"client: establish outbound TCP (CBSP) / SCTP (SBc-AP) connection to a remote peer\n"
|
||||
"Disable CBSP link\n",
|
||||
CMD_ATTR_NODE_EXIT)
|
||||
{
|
||||
struct cbc_peer *peer = (struct cbc_peer *) vty->index;
|
||||
peer->link_mode = get_string_value(cbc_peer_link_mode_names, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_peer_remote_port, cfg_peer_remote_port_cmd,
|
||||
"remote-port <0-65535>",
|
||||
"Configure remote (TCP) port of peer\n"
|
||||
@@ -677,6 +731,7 @@ static void write_one_peer(struct vty *vty, struct cbc_peer *peer)
|
||||
unsigned int i;
|
||||
vty_out(vty, " peer %s %s%s", get_value_string(cbc_peer_proto_name_vty, peer->proto),
|
||||
peer->name, VTY_NEWLINE);
|
||||
vty_out(vty, " mode %s%s", cbc_peer_link_mode_name(peer->link_mode), VTY_NEWLINE);
|
||||
if (peer->remote_port == -1)
|
||||
vty_out(vty, " no remote-port%s", VTY_NEWLINE);
|
||||
else
|
||||
@@ -703,6 +758,7 @@ void cbc_vty_init(void)
|
||||
install_element_ve(&show_message_cbs_cmd);
|
||||
install_element_ve(&show_messages_cbs_cmd);
|
||||
install_element_ve(&show_messages_etws_cmd);
|
||||
install_element_ve(&delete_message_expired_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_cbc_cmd);
|
||||
install_node(&cbc_node, config_write_cbc);
|
||||
@@ -729,6 +785,7 @@ void cbc_vty_init(void)
|
||||
install_element(CBC_NODE, &cfg_cbc_no_peer_cmd);
|
||||
install_node(&peer_node, NULL);
|
||||
install_element(PEER_NODE, &cfg_peer_proto_cmd);
|
||||
install_element(PEER_NODE, &cfg_peer_mode_cmd);
|
||||
install_element(PEER_NODE, &cfg_peer_remote_port_cmd);
|
||||
install_element(PEER_NODE, &cfg_peer_no_remote_port_cmd);
|
||||
install_element(PEER_NODE, &cfg_peer_remote_ip_cmd);
|
||||
|
||||
185
src/cbsp_link.c
185
src/cbsp_link.c
@@ -41,18 +41,23 @@
|
||||
struct cbc_cbsp_link *cbc_cbsp_link_alloc(struct cbc_cbsp_mgr *cbc, struct cbc_peer *peer)
|
||||
{
|
||||
struct cbc_cbsp_link *link;
|
||||
char *name;
|
||||
|
||||
link = talloc_zero(cbc, struct cbc_cbsp_link);
|
||||
OSMO_ASSERT(link);
|
||||
|
||||
link->peer = peer;
|
||||
link->is_client = (peer->link_mode == CBC_PEER_LINK_MODE_CLIENT);
|
||||
|
||||
link->fi = osmo_fsm_inst_alloc(&cbsp_link_fsm, link, link, LOGL_DEBUG, NULL);
|
||||
name = talloc_strdup(link, peer->name);
|
||||
osmo_identifier_sanitize_buf(name, NULL, '_');
|
||||
link->fi = osmo_fsm_inst_alloc(&cbsp_link_fsm, link, link, LOGL_DEBUG, name);
|
||||
if (!link->fi) {
|
||||
LOGPCC(link, LOGL_ERROR, "Unable to allocate FSM\n");
|
||||
talloc_free(link);
|
||||
return NULL;
|
||||
}
|
||||
talloc_free(name);
|
||||
|
||||
llist_add_tail(&link->list, &cbc->links);
|
||||
return link;
|
||||
@@ -70,18 +75,122 @@ void cbc_cbsp_link_free(struct cbc_cbsp_link *link)
|
||||
|
||||
const char *cbc_cbsp_link_name(const struct cbc_cbsp_link *link)
|
||||
{
|
||||
struct osmo_fd *ofd;
|
||||
OSMO_ASSERT(link);
|
||||
|
||||
if (link->peer && link->peer->name) {
|
||||
if (link->peer && link->peer->name)
|
||||
return link->peer->name;
|
||||
} else {
|
||||
struct osmo_fd *ofd = osmo_stream_srv_get_ofd(link->conn);
|
||||
return osmo_sock_get_name2(ofd->fd);
|
||||
}
|
||||
|
||||
if (link->is_client)
|
||||
ofd = osmo_stream_cli_get_ofd(link->cli_conn);
|
||||
else
|
||||
ofd = osmo_stream_srv_get_ofd(link->srv_conn);
|
||||
return osmo_sock_get_name2(ofd->fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* TCP client
|
||||
*/
|
||||
static int cbc_cbsp_link_cli_connect_cb(struct osmo_stream_cli *conn)
|
||||
{
|
||||
struct cbc_cbsp_link *link = osmo_stream_cli_get_data(conn);
|
||||
LOGPCC(link, LOGL_NOTICE, "Connected\n");
|
||||
osmo_fsm_inst_dispatch(link->fi, CBSP_LINK_E_CMD_RESET, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cbc_cbsp_link_cli_disconnect_cb(struct osmo_stream_cli *conn)
|
||||
{
|
||||
struct cbc_cbsp_link *link = osmo_stream_cli_get_data(conn);
|
||||
LOGPCC(link, LOGL_NOTICE, "Disconnected.\n");
|
||||
LOGPCC(link, LOGL_NOTICE, "Reconnecting...\n");
|
||||
osmo_stream_cli_reconnect(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cbc_cbsp_link_cli_read_cb(struct osmo_stream_cli *conn)
|
||||
{
|
||||
struct cbc_cbsp_link *link = osmo_stream_cli_get_data(conn);
|
||||
struct osmo_fd *ofd = osmo_stream_cli_get_ofd(conn);
|
||||
struct osmo_cbsp_decoded *decoded;
|
||||
struct msgb *msg = NULL;
|
||||
int rc;
|
||||
|
||||
LOGPCC(link, LOGL_DEBUG, "read_cb rx_msg=%p\n", link->rx_msg);
|
||||
|
||||
/* message de-segmentation */
|
||||
rc = osmo_cbsp_recv_buffered(conn, ofd->fd, &msg, &link->rx_msg);
|
||||
if (rc <= 0) {
|
||||
if (rc == -EAGAIN || rc == -EINTR) {
|
||||
/* more data needs to be read */
|
||||
return 0;
|
||||
} else if (rc == -EPIPE || rc == -ECONNRESET) {
|
||||
/* lost connection with server */
|
||||
} else if (rc == 0) {
|
||||
/* connection closed with server */
|
||||
}
|
||||
/* destroy connection */
|
||||
cbc_cbsp_link_close(link);
|
||||
return -EBADF;
|
||||
}
|
||||
OSMO_ASSERT(msg);
|
||||
LOGPCC(link, LOGL_DEBUG, "Received CBSP %s\n", msgb_hexdump(msg));
|
||||
/* decode + dispatch message */
|
||||
decoded = osmo_cbsp_decode(link, msg);
|
||||
if (decoded) {
|
||||
LOGPCC(link, LOGL_INFO, "Received CBSP %s\n",
|
||||
get_value_string(cbsp_msg_type_names, decoded->msg_type));
|
||||
g_cbc->cbsp.mgr->rx_cb(link, decoded);
|
||||
} else {
|
||||
LOGPCC(link, LOGL_ERROR, "Unable to decode %s\n", msgb_hexdump(msg));
|
||||
}
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cbc_cbsp_link_open_cli(struct cbc_cbsp_link *link)
|
||||
{
|
||||
struct osmo_stream_cli *conn;
|
||||
struct cbc_peer *peer = link->peer;
|
||||
int rc;
|
||||
|
||||
OSMO_ASSERT(link->is_client);
|
||||
OSMO_ASSERT(peer->link_mode == CBC_PEER_LINK_MODE_CLIENT);
|
||||
|
||||
conn = osmo_stream_cli_create(link);
|
||||
osmo_stream_cli_set_data(conn, link);
|
||||
osmo_stream_cli_set_nodelay(conn, true);
|
||||
osmo_stream_cli_set_reconnect_timeout(conn, 5);
|
||||
osmo_stream_cli_set_proto(conn, IPPROTO_TCP);
|
||||
osmo_stream_cli_set_connect_cb(conn, cbc_cbsp_link_cli_connect_cb);
|
||||
osmo_stream_cli_set_disconnect_cb(conn, cbc_cbsp_link_cli_disconnect_cb);
|
||||
osmo_stream_cli_set_read_cb(conn, cbc_cbsp_link_cli_read_cb);
|
||||
rc = osmo_stream_cli_set_local_addrs(conn, (const char **)&g_cbc->config.cbsp.local_host, 1);
|
||||
if (rc < 0)
|
||||
goto free_ret;
|
||||
/* We assign free local port for client links:
|
||||
* osmo_stream_cli_set_local_port(conn, g_cbc->cbsp.local_port);
|
||||
*/
|
||||
OSMO_ASSERT(peer->num_remote_host > 0);
|
||||
rc = osmo_stream_cli_set_addrs(conn, (const char **)peer->remote_host, peer->num_remote_host);
|
||||
if (rc < 0)
|
||||
goto free_ret;
|
||||
osmo_stream_cli_set_port(conn, peer->remote_port);
|
||||
rc = osmo_stream_cli_open(conn);
|
||||
if (rc < 0)
|
||||
goto free_ret;
|
||||
link->cli_conn = conn;
|
||||
return 0;
|
||||
free_ret:
|
||||
osmo_stream_cli_destroy(conn);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* TCP server
|
||||
*/
|
||||
/* data from BSC has arrived at CBC */
|
||||
static int cbsp_cbc_read_cb(struct osmo_stream_srv *conn)
|
||||
static int cbsp_cbc_srv_read_cb(struct osmo_stream_srv *conn)
|
||||
{
|
||||
struct osmo_stream_srv_link *srv_link = osmo_stream_srv_get_master(conn);
|
||||
struct cbc_cbsp_link *link = osmo_stream_srv_get_data(conn);
|
||||
@@ -125,7 +234,7 @@ static int cbsp_cbc_read_cb(struct osmo_stream_srv *conn)
|
||||
}
|
||||
|
||||
/* connection from BSC to CBC has been closed */
|
||||
static int cbsp_cbc_closed_cb(struct osmo_stream_srv *conn)
|
||||
static int cbsp_cbc_srv_closed_cb(struct osmo_stream_srv *conn)
|
||||
{
|
||||
struct cbc_cbsp_link *link = osmo_stream_srv_get_data(conn);
|
||||
LOGPCC(link, LOGL_NOTICE, "connection closed\n");
|
||||
@@ -170,6 +279,23 @@ static int cbsp_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
||||
peer = cbc_peer_create(NULL, CBC_PEER_PROTO_CBSP);
|
||||
OSMO_ASSERT(peer);
|
||||
peer->unknown_dynamic_peer = true;
|
||||
} else { /* peer is known */
|
||||
switch (peer->link_mode) {
|
||||
case CBC_PEER_LINK_MODE_DISABLED:
|
||||
LOGP(DCBSP, LOGL_NOTICE,
|
||||
"Rejecting conn for disabled CBSP peer %s:%d\n",
|
||||
remote_ip, remote_port);
|
||||
close(fd);
|
||||
return -1;
|
||||
case CBC_PEER_LINK_MODE_CLIENT:
|
||||
LOGP(DCBSP, LOGL_NOTICE,
|
||||
"Rejecting conn for CBSP peer %s:%d configured as 'client'\n",
|
||||
remote_ip, remote_port);
|
||||
close(fd);
|
||||
return -1;
|
||||
default: /* MODE_SERVER */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (peer->link.cbsp) {
|
||||
LOGPCC(peer->link.cbsp, LOGL_ERROR,
|
||||
@@ -179,10 +305,11 @@ static int cbsp_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
||||
}
|
||||
link = cbc_cbsp_link_alloc(cbc, peer);
|
||||
OSMO_ASSERT(link);
|
||||
link->conn = osmo_stream_srv_create(srv_link, srv_link, fd,
|
||||
cbsp_cbc_read_cb, cbsp_cbc_closed_cb,
|
||||
link);
|
||||
if (!link->conn) {
|
||||
|
||||
link->srv_conn = osmo_stream_srv_create(srv_link, srv_link, fd,
|
||||
cbsp_cbc_srv_read_cb, cbsp_cbc_srv_closed_cb,
|
||||
link);
|
||||
if (!link->srv_conn) {
|
||||
LOGPCC(link, LOGL_ERROR,
|
||||
"Unable to create stream server for %s:%u\n",
|
||||
remote_ip, remote_port);
|
||||
@@ -195,14 +322,20 @@ static int cbsp_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cbc_cbsp_link_tx(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *cbsp)
|
||||
int cbc_cbsp_link_tx(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *cbsp)
|
||||
{
|
||||
struct msgb *msg;
|
||||
|
||||
if (!link) {
|
||||
LOGP(DCBSP, LOGL_NOTICE, "Cannot transmit %s: no connection\n",
|
||||
get_value_string(cbsp_msg_type_names, cbsp->msg_type));
|
||||
return ;
|
||||
talloc_free(cbsp);
|
||||
return -ENOLINK;
|
||||
} else if (link->is_client && !osmo_stream_cli_is_connected(link->cli_conn)) {
|
||||
LOGPCC(link, LOGL_NOTICE, "Cannot transmit %s: reconnecting\n",
|
||||
get_value_string(cbsp_msg_type_names, cbsp->msg_type));
|
||||
talloc_free(cbsp);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
LOGPCC(link, LOGL_INFO, "Transmitting %s\n",
|
||||
@@ -213,16 +346,32 @@ void cbc_cbsp_link_tx(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *cbsp
|
||||
LOGPCC(link, LOGL_ERROR, "Failed to encode CBSP %s: %s\n",
|
||||
get_value_string(cbsp_msg_type_names, cbsp->msg_type), osmo_cbsp_errstr);
|
||||
talloc_free(cbsp);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
talloc_free(cbsp);
|
||||
osmo_stream_srv_send(link->conn, msg);
|
||||
if (link->is_client)
|
||||
osmo_stream_cli_send(link->cli_conn, msg);
|
||||
else
|
||||
osmo_stream_srv_send(link->srv_conn, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cbc_cbsp_link_close(struct cbc_cbsp_link *link)
|
||||
{
|
||||
if (link->conn)
|
||||
osmo_stream_srv_destroy(link->conn);
|
||||
if (!link->conn)
|
||||
return;
|
||||
|
||||
if (link->is_client) {
|
||||
osmo_stream_cli_destroy(link->cli_conn);
|
||||
if (link->peer)
|
||||
link->peer->link.cbsp = NULL;
|
||||
link->cli_conn = NULL;
|
||||
if (link->fi)
|
||||
osmo_fsm_inst_dispatch(link->fi, CBSP_LINK_E_CMD_CLOSE, NULL);
|
||||
} else {
|
||||
osmo_stream_srv_destroy(link->srv_conn);
|
||||
/* Same as waht's done for cli is done for srv in closed_cb() */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <osmocom/cbc/cbsp_link.h>
|
||||
#include <osmocom/cbc/cbsp_link_fsm.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/smscb_message_fsm.h>
|
||||
#include <osmocom/cbc/smscb_peer_fsm.h>
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
@@ -339,22 +339,22 @@ int cbc_cbsp_link_rx_cb(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *de
|
||||
switch (dec->msg_type) {
|
||||
case CBSP_MSGT_WRITE_REPLACE_COMPL:
|
||||
if (dec->u.write_replace_compl.old_serial_nr)
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_CBSP_REPLACE_ACK, dec);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_CBSP_REPLACE_ACK, dec);
|
||||
else
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_CBSP_WRITE_ACK, dec);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_CBSP_WRITE_ACK, dec);
|
||||
case CBSP_MSGT_WRITE_REPLACE_FAIL:
|
||||
if (dec->u.write_replace_fail.old_serial_nr)
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_CBSP_REPLACE_NACK, dec);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_CBSP_REPLACE_NACK, dec);
|
||||
else
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_CBSP_WRITE_NACK, dec);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_CBSP_WRITE_NACK, dec);
|
||||
case CBSP_MSGT_KILL_COMPL:
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_CBSP_DELETE_ACK, dec);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_CBSP_DELETE_ACK, dec);
|
||||
case CBSP_MSGT_KILL_FAIL:
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_CBSP_DELETE_NACK, dec);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_CBSP_DELETE_NACK, dec);
|
||||
case CBSP_MSGT_MSG_STATUS_QUERY_COMPL:
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_CBSP_STATUS_ACK, dec);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_CBSP_STATUS_ACK, dec);
|
||||
case CBSP_MSGT_MSG_STATUS_QUERY_FAIL:
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_CBSP_STATUS_NACK, dec);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_CBSP_STATUS_NACK, dec);
|
||||
default:
|
||||
LOGPCC(link, LOGL_ERROR, "unknown message %s\n",
|
||||
get_value_string(cbsp_msg_type_names, dec->msg_type));
|
||||
|
||||
110
src/cbsp_msg.c
Normal file
110
src/cbsp_msg.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/* Osmocom CBC (Cell Broacast Centre) */
|
||||
|
||||
/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* 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/linuxlist.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gsm/cbsp.h>
|
||||
#include <osmocom/cbc/cbsp_msg.h>
|
||||
#include <osmocom/cbc/cbc_message.h>
|
||||
|
||||
/* convert cbc_message to osmo_cbsp_cell_list */
|
||||
static int cbcmsg_to_cbsp_cell_list(const void *ctx, struct osmo_cbsp_cell_list *list,
|
||||
const struct cbc_message *cbcmsg)
|
||||
{
|
||||
struct osmo_cbsp_cell_ent *ent;
|
||||
|
||||
switch (cbcmsg->scope) {
|
||||
case CBC_MSG_SCOPE_PLMN:
|
||||
list->id_discr = CELL_IDENT_BSS;
|
||||
ent = talloc_zero(ctx, struct osmo_cbsp_cell_ent);
|
||||
if (!ent)
|
||||
return -ENOMEM;
|
||||
//ent->cell_id = ?
|
||||
llist_add_tail(&ent->list, &list->list);
|
||||
return 0;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a CBSP WRITE-REPLACE from our internal representation */
|
||||
struct osmo_cbsp_decoded *cbsp_gen_write_replace_req(void *ctx, const struct cbc_message *cbcmsg)
|
||||
{
|
||||
struct osmo_cbsp_write_replace *wrepl;
|
||||
const struct smscb_message *smscb = &cbcmsg->msg;
|
||||
struct osmo_cbsp_decoded *cbsp = osmo_cbsp_decoded_alloc(ctx, CBSP_MSGT_WRITE_REPLACE);
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
if (!cbsp)
|
||||
return NULL;
|
||||
wrepl = &cbsp->u.write_replace;
|
||||
|
||||
wrepl->msg_id = smscb->message_id;
|
||||
wrepl->new_serial_nr = smscb->serial_nr;
|
||||
/* FIXME: old? */
|
||||
/* Cell list */
|
||||
rc = cbcmsg_to_cbsp_cell_list(cbcmsg, &wrepl->cell_list, cbcmsg);
|
||||
if (rc < 0) {
|
||||
talloc_free(cbsp);
|
||||
return NULL;
|
||||
}
|
||||
if (!smscb->is_etws)
|
||||
wrepl->is_cbs = true;
|
||||
if (wrepl->is_cbs) {
|
||||
if (cbcmsg->extended_cbch)
|
||||
wrepl->u.cbs.channel_ind = CBSP_CHAN_IND_EXTENDED;
|
||||
else
|
||||
wrepl->u.cbs.channel_ind = CBSP_CHAN_IND_BASIC;
|
||||
wrepl->u.cbs.category = cbcmsg->priority;
|
||||
wrepl->u.cbs.rep_period = cbcmsg->rep_period;
|
||||
wrepl->u.cbs.num_bcast_req = cbcmsg->num_bcast;
|
||||
wrepl->u.cbs.dcs = smscb->cbs.dcs;
|
||||
INIT_LLIST_HEAD(&wrepl->u.cbs.msg_content);
|
||||
for (i = 0; i < smscb->cbs.num_pages; i++) {
|
||||
struct osmo_cbsp_content *ce = talloc_zero(cbsp, struct osmo_cbsp_content);
|
||||
if (i == smscb->cbs.num_pages - 1)
|
||||
ce->user_len = smscb->cbs.data_user_len - (i * SMSCB_RAW_PAGE_LEN);
|
||||
else
|
||||
ce->user_len = SMSCB_RAW_PAGE_LEN;
|
||||
memcpy(ce->data, smscb->cbs.data[i], SMSCB_RAW_PAGE_LEN);
|
||||
llist_add_tail(&ce->list, &wrepl->u.cbs.msg_content);
|
||||
}
|
||||
} else {
|
||||
wrepl->u.emergency.indicator = 1;
|
||||
wrepl->u.emergency.warning_type = (smscb->etws.warning_type & 0x7f) << 9;
|
||||
if (smscb->etws.user_alert)
|
||||
wrepl->u.emergency.warning_type |= 0x0100;
|
||||
if (smscb->etws.popup_on_display)
|
||||
wrepl->u.emergency.warning_type |= 0x0080;
|
||||
memcpy(wrepl->u.emergency.warning_sec_info, smscb->etws.warning_sec_info,
|
||||
sizeof(wrepl->u.emergency.warning_sec_info));
|
||||
if (cbcmsg->warning_period_sec == 0xffffffff)
|
||||
wrepl->u.emergency.warning_period = 0;
|
||||
else
|
||||
wrepl->u.emergency.warning_period = cbcmsg->warning_period_sec;
|
||||
}
|
||||
return cbsp;
|
||||
}
|
||||
574
src/cbsp_smscb_peer_fsm.c
Normal file
574
src/cbsp_smscb_peer_fsm.c
Normal file
@@ -0,0 +1,574 @@
|
||||
/* SMSCB Peer FSM: Represents state of one SMSCB for one peer (BSC) */
|
||||
|
||||
/* This FSM exists per tuple of (message, bsc peer) */
|
||||
|
||||
/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* 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/utils.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/gsm/protocol/gsm_08_08.h>
|
||||
#include <osmocom/gsm/gsm0808_utils.h>
|
||||
#include <osmocom/gsm/cbsp.h>
|
||||
|
||||
#include <osmocom/sbcap/sbcap_common.h>
|
||||
|
||||
#include <osmocom/cbc/cbc_message.h>
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
#include <osmocom/cbc/cbsp_link.h>
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/sbcap_msg.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/smscb_peer_fsm.h>
|
||||
#include <osmocom/cbc/smscb_message_fsm.h>
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
/***********************************************************************
|
||||
* Helper functions
|
||||
***********************************************************************/
|
||||
|
||||
/* covert TS 08.08 Cell Identity value to CBC internal type */
|
||||
static enum cbc_cell_id_type cci_discr_from_cell_id(enum CELL_IDENT id_discr)
|
||||
{
|
||||
switch (id_discr) {
|
||||
case CELL_IDENT_NO_CELL:
|
||||
return CBC_CELL_ID_NONE;
|
||||
case CELL_IDENT_WHOLE_GLOBAL:
|
||||
return CBC_CELL_ID_CGI;
|
||||
case CELL_IDENT_LAC_AND_CI:
|
||||
return CBC_CELL_ID_LAC_CI;
|
||||
case CELL_IDENT_CI:
|
||||
return CBC_CELL_ID_CI;
|
||||
case CELL_IDENT_LAI:
|
||||
return CBC_CELL_ID_LAI;
|
||||
case CELL_IDENT_LAC:
|
||||
return CBC_CELL_ID_LAC;
|
||||
case CELL_IDENT_BSS:
|
||||
return CBC_CELL_ID_BSS;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* covert CBC internal type to TS 08.08 Cell Identity */
|
||||
static enum CELL_IDENT cell_id_from_ccid_discr(enum cbc_cell_id_type in)
|
||||
{
|
||||
switch (in) {
|
||||
case CBC_CELL_ID_NONE:
|
||||
return CELL_IDENT_NO_CELL;
|
||||
case CBC_CELL_ID_CGI:
|
||||
return CELL_IDENT_WHOLE_GLOBAL;
|
||||
case CBC_CELL_ID_LAC_CI:
|
||||
return CELL_IDENT_LAC_AND_CI;
|
||||
case CBC_CELL_ID_CI:
|
||||
return CELL_IDENT_CI;
|
||||
case CBC_CELL_ID_LAI:
|
||||
return CELL_IDENT_LAI;
|
||||
case CBC_CELL_ID_LAC:
|
||||
return CELL_IDENT_LAC;
|
||||
case CBC_CELL_ID_BSS:
|
||||
return CELL_IDENT_BSS;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert TS 08.08 Cell Identifier Union to CBC internal type */
|
||||
static void cci_from_cbsp(struct cbc_cell_id *cci, enum CELL_IDENT id_discr,
|
||||
const union gsm0808_cell_id_u *u)
|
||||
{
|
||||
cci->id_discr = cci_discr_from_cell_id(id_discr);
|
||||
|
||||
switch (id_discr) {
|
||||
case CELL_IDENT_NO_CELL:
|
||||
break;
|
||||
case CELL_IDENT_WHOLE_GLOBAL:
|
||||
cci->u.cgi = u->global;
|
||||
break;
|
||||
case CELL_IDENT_LAC_AND_CI:
|
||||
cci->u.lac_and_ci = u->lac_and_ci;
|
||||
break;
|
||||
case CELL_IDENT_CI:
|
||||
cci->u.ci = u->ci;
|
||||
break;
|
||||
case CELL_IDENT_LAI:
|
||||
cci->u.lai = u->lai_and_lac;
|
||||
break;
|
||||
case CELL_IDENT_LAC:
|
||||
cci->u.lac = u->lac;
|
||||
break;
|
||||
case CELL_IDENT_BSS:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert TS 08.08 Cell Identifier Union to CBC internal type */
|
||||
static void cbsp_from_cci(union gsm0808_cell_id_u *u, const struct cbc_cell_id *cci)
|
||||
{
|
||||
switch (cci->id_discr) {
|
||||
case CBC_CELL_ID_NONE:
|
||||
break;
|
||||
case CBC_CELL_ID_CGI:
|
||||
u->global = cci->u.cgi;
|
||||
printf("u->gobal: %s\n", osmo_hexdump((uint8_t *) &u->global, sizeof(u->global)));
|
||||
break;
|
||||
case CBC_CELL_ID_LAC_CI:
|
||||
u->lac_and_ci = cci->u.lac_and_ci;
|
||||
break;
|
||||
case CBC_CELL_ID_CI:
|
||||
u->ci = cci->u.ci;
|
||||
break;
|
||||
case CBC_CELL_ID_LAI:
|
||||
u->lai_and_lac = cci->u.lai;
|
||||
break;
|
||||
case CBC_CELL_ID_LAC:
|
||||
u->lac = cci->u.lac;
|
||||
break;
|
||||
case CBC_CELL_ID_BSS:
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* read a single osmo_cbsp_num_compl_ent and add it to cbc_message_peer */
|
||||
static void cci_from_cbsp_compl_ent(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_num_compl_ent *ce, enum CELL_IDENT id_discr)
|
||||
{
|
||||
struct cbc_cell_id *cci;
|
||||
|
||||
cci = NULL; // FIXME: lookup
|
||||
if (!cci) {
|
||||
cci = talloc_zero(mp, struct cbc_cell_id);
|
||||
if (!cci)
|
||||
return;
|
||||
llist_add_tail(&cci->list, &mp->num_compl_list);
|
||||
}
|
||||
cci_from_cbsp(cci, id_discr, &ce->cell_id);
|
||||
cci->num_compl.num_compl += ce->num_compl;
|
||||
cci->num_compl.num_bcast_info += ce->num_bcast_info;
|
||||
LOGPFSML(mp->fi, LOGL_DEBUG, "Appending CellId %s to Broadcast Completed list\n",
|
||||
cbc_cell_id2str(cci));
|
||||
}
|
||||
static void msg_peer_append_cbsp_compl(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_num_compl_list *nclist)
|
||||
{
|
||||
struct osmo_cbsp_num_compl_ent *ce;
|
||||
|
||||
llist_for_each_entry(ce, &nclist->list, list)
|
||||
cci_from_cbsp_compl_ent(mp, ce, nclist->id_discr);
|
||||
}
|
||||
|
||||
/* read a single osmo_cbsp_cell_ent and add it to cbc_message_peer */
|
||||
static void cci_from_cbsp_cell_ent(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_cell_ent *ce, enum CELL_IDENT id_discr)
|
||||
{
|
||||
struct cbc_cell_id *cci;
|
||||
|
||||
cci = NULL; // FIXME: lookup
|
||||
if (!cci) {
|
||||
cci = talloc_zero(mp, struct cbc_cell_id);
|
||||
if (!cci)
|
||||
return;
|
||||
llist_add_tail(&cci->list, &mp->cell_list);
|
||||
}
|
||||
cci_from_cbsp(cci, id_discr, &ce->cell_id);
|
||||
LOGPFSML(mp->fi, LOGL_DEBUG, "Appending CellId %s to Cell list\n",
|
||||
cbc_cell_id2str(cci));
|
||||
}
|
||||
static void msg_peer_append_cbsp_cell(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_cell_list *clist)
|
||||
{
|
||||
struct osmo_cbsp_cell_ent *ce;
|
||||
|
||||
llist_for_each_entry(ce, &clist->list, list)
|
||||
cci_from_cbsp_cell_ent(mp, ce, clist->id_discr);
|
||||
}
|
||||
|
||||
/* read a single osmo_cbsp_fail_ent and add it to cbc_message_peer */
|
||||
static void cci_from_cbsp_fail_ent(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_fail_ent *fe)
|
||||
{
|
||||
struct cbc_cell_id *cci;
|
||||
cci = NULL; // lookup */
|
||||
if (!cci) {
|
||||
cci = talloc_zero(mp, struct cbc_cell_id);
|
||||
if (!cci)
|
||||
return;
|
||||
llist_add_tail(&cci->list, &mp->fail_list);
|
||||
}
|
||||
cci_from_cbsp(cci, fe->id_discr, &fe->cell_id);
|
||||
cci->fail.cause = fe->cause;
|
||||
LOGPFSML(mp->fi, LOGL_DEBUG, "Appending CellId %s (cause: %u) to Failed list\n",
|
||||
cbc_cell_id2str(cci), cci->fail.cause);
|
||||
}
|
||||
static void msg_peer_append_cbsp_fail(struct cbc_message_peer *mp, struct llist_head *flist)
|
||||
{
|
||||
struct osmo_cbsp_fail_ent *fe;
|
||||
|
||||
llist_for_each_entry(fe, flist, list)
|
||||
cci_from_cbsp_fail_ent(mp, fe);
|
||||
}
|
||||
|
||||
/* append all cells from cbc_message_peer to given CBSP cell_list */
|
||||
static void cbsp_append_cell_list(struct osmo_cbsp_cell_list *out, void *ctx,
|
||||
const struct cbc_message_peer *mp)
|
||||
{
|
||||
struct cbc_cell_id *cci;
|
||||
enum cbc_cell_id_type id_discr = CBC_CELL_ID_NONE;
|
||||
|
||||
llist_for_each_entry(cci, &mp->cell_list, list) {
|
||||
struct osmo_cbsp_cell_ent *ent;
|
||||
|
||||
if (id_discr == CBC_CELL_ID_NONE)
|
||||
id_discr = cci->id_discr;
|
||||
else if (id_discr != cci->id_discr) {
|
||||
LOGPFSML(mp->fi, LOGL_ERROR, "Cannot encode CBSP cell_list as not all "
|
||||
"entries are of same type (%u != %u)\n", id_discr, cci->id_discr);
|
||||
continue;
|
||||
}
|
||||
ent = talloc_zero(ctx, struct osmo_cbsp_cell_ent);
|
||||
OSMO_ASSERT(ent);
|
||||
cbsp_from_cci(&ent->cell_id, cci);
|
||||
llist_add_tail(&ent->list, &out->list);
|
||||
}
|
||||
out->id_discr = cell_id_from_ccid_discr(id_discr);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* actual FSM
|
||||
***********************************************************************/
|
||||
|
||||
static void smscb_p_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_CREATE:
|
||||
/* send it to peer */
|
||||
rc = peer_new_cbc_message(mp->peer, mp->cbcmsg);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_WRITE_ACK, 10, T_WAIT_WRITE_ACK);
|
||||
if (rc != 0) /* Immediately timeout the message */
|
||||
fi->fsm->timer_cb(fi);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_write_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *dec = NULL;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_CBSP_WRITE_ACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.write_replace_compl.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.write_replace_compl.cell_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_WRITE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_PEER_E_CBSP_WRITE_NACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.write_replace_fail.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.write_replace_fail.cell_list);
|
||||
msg_peer_append_cbsp_fail(mp, &dec->u.write_replace_fail.fail_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_WRITE_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *cbsp;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_REPLACE: /* send WRITE-REPLACE to BSC */
|
||||
cbsp = osmo_cbsp_decoded_alloc(mp->peer, CBSP_MSGT_WRITE_REPLACE);
|
||||
OSMO_ASSERT(cbsp);
|
||||
cbsp->u.write_replace.msg_id = mp->cbcmsg->msg.message_id;
|
||||
cbsp->u.write_replace.old_serial_nr = &mp->cbcmsg->msg.serial_nr;
|
||||
//cbsp->u.write_replace.new_serial_nr
|
||||
/* TODO: we assume that the replace will always affect all original cells */
|
||||
cbsp_append_cell_list(&cbsp->u.write_replace.cell_list, cbsp, mp);
|
||||
// TODO: ALL OTHER DATA
|
||||
rc = cbc_cbsp_link_tx(mp->peer->link.cbsp, cbsp);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_REPLACE_ACK, 10, T_WAIT_REPLACE_ACK);
|
||||
if (rc != 0) /* Immediately timeout the message */
|
||||
fi->fsm->timer_cb(fi);
|
||||
break;
|
||||
case SMSCB_PEER_E_STATUS: /* send MSG-STATUS-QUERY to BSC */
|
||||
cbsp = osmo_cbsp_decoded_alloc(mp->peer, CBSP_MSGT_MSG_STATUS_QUERY);
|
||||
OSMO_ASSERT(cbsp);
|
||||
cbsp->u.msg_status_query.msg_id = mp->cbcmsg->msg.message_id;
|
||||
cbsp->u.msg_status_query.old_serial_nr = mp->cbcmsg->msg.serial_nr;
|
||||
cbsp_append_cell_list(&cbsp->u.msg_status_query.cell_list, cbsp, mp);
|
||||
cbsp->u.msg_status_query.channel_ind = CBSP_CHAN_IND_BASIC;
|
||||
rc = cbc_cbsp_link_tx(mp->peer->link.cbsp, cbsp);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_STATUS_ACK, 10, T_WAIT_STATUS_ACK);
|
||||
if (rc != 0) /* Immediately timeout the message */
|
||||
fi->fsm->timer_cb(fi);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_status_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *dec = NULL;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_CBSP_STATUS_ACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.msg_status_query_compl.num_compl_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_STATUS_ACK, mp);
|
||||
break;
|
||||
case SMSCB_PEER_E_CBSP_STATUS_NACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.msg_status_query_fail.num_compl_list);
|
||||
msg_peer_append_cbsp_fail(mp, &dec->u.msg_status_query_fail.fail_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_STATUS_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void smscb_p_fsm_wait_replace_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *dec = NULL;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_CBSP_REPLACE_ACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.write_replace_compl.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.write_replace_compl.cell_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_REPLACE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_PEER_E_CBSP_REPLACE_NACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.write_replace_fail.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.write_replace_fail.cell_list);
|
||||
msg_peer_append_cbsp_fail(mp, &dec->u.write_replace_fail.fail_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_REPLACE_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_delete_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *dec = NULL;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_CBSP_DELETE_ACK:
|
||||
dec = data;
|
||||
/* append results */
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.kill_compl.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.kill_compl.cell_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_DELETE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_PEER_E_CBSP_DELETE_NACK:
|
||||
dec = data;
|
||||
/* append results */
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.kill_fail.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.kill_fail.cell_list);
|
||||
msg_peer_append_cbsp_fail(mp, &dec->u.kill_fail.fail_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_DELETE_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int smscb_p_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
switch (fi->T) {
|
||||
case T_WAIT_WRITE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_PEER_E_CBSP_WRITE_NACK, NULL);
|
||||
break;
|
||||
case T_WAIT_REPLACE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_REPLACE_NACK, NULL);
|
||||
break;
|
||||
case T_WAIT_STATUS_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_STATUS_NACK, NULL);
|
||||
break;
|
||||
case T_WAIT_DELETE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_PEER_E_CBSP_DELETE_NACK, NULL);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *cbsp;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_DELETE: /* send KILL to BSC */
|
||||
switch (fi->state) {
|
||||
case SMSCB_S_DELETED:
|
||||
case SMSCB_S_INIT:
|
||||
LOGPFSML(fi, LOGL_ERROR, "Event %s not permitted\n",
|
||||
osmo_fsm_event_name(fi->fsm, event));
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cbsp = osmo_cbsp_decoded_alloc(mp->peer, CBSP_MSGT_KILL);
|
||||
OSMO_ASSERT(cbsp);
|
||||
cbsp->u.kill.msg_id = mp->cbcmsg->msg.message_id;
|
||||
cbsp->u.kill.old_serial_nr = mp->cbcmsg->msg.serial_nr;
|
||||
/* TODO: we assume that the delete will always affect all original cells */
|
||||
cbsp_append_cell_list(&cbsp->u.kill.cell_list, cbsp, mp);
|
||||
if (!mp->cbcmsg->msg.is_etws) {
|
||||
/* Channel Indication IE is only present in CBS, not in ETWS! */
|
||||
cbsp->u.kill.channel_ind = talloc_zero(cbsp, enum cbsp_channel_ind);
|
||||
OSMO_ASSERT(cbsp->u.kill.channel_ind);
|
||||
*(cbsp->u.kill.channel_ind) = CBSP_CHAN_IND_BASIC;
|
||||
}
|
||||
rc = cbc_cbsp_link_tx(mp->peer->link.cbsp, cbsp);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_DELETE_ACK, 10, T_WAIT_DELETE_ACK);
|
||||
if (rc != 0) /* Immediately timeout the message */
|
||||
fi->fsm->timer_cb(fi);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
llist_del(&mp->list);
|
||||
/* memory of mp is child of fi and hence automatically free'd */
|
||||
}
|
||||
|
||||
static const struct osmo_fsm_state smscb_p_fsm_states[] = {
|
||||
[SMSCB_S_INIT] = {
|
||||
.name = "INIT",
|
||||
.in_event_mask = S(SMSCB_PEER_E_CREATE),
|
||||
.out_state_mask = S(SMSCB_S_WAIT_WRITE_ACK) |
|
||||
S(SMSCB_S_ACTIVE),
|
||||
.action = smscb_p_fsm_init,
|
||||
},
|
||||
[SMSCB_S_WAIT_WRITE_ACK] = {
|
||||
.name = "WAIT_WRITE_ACK",
|
||||
.in_event_mask = S(SMSCB_PEER_E_CBSP_WRITE_ACK) |
|
||||
S(SMSCB_PEER_E_CBSP_WRITE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_write_ack,
|
||||
},
|
||||
[SMSCB_S_ACTIVE] = {
|
||||
.name = "ACTIVE",
|
||||
.in_event_mask = S(SMSCB_PEER_E_REPLACE) |
|
||||
S(SMSCB_PEER_E_STATUS),
|
||||
.out_state_mask = S(SMSCB_S_WAIT_REPLACE_ACK) |
|
||||
S(SMSCB_S_WAIT_STATUS_ACK) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_active,
|
||||
},
|
||||
[SMSCB_S_WAIT_STATUS_ACK] = {
|
||||
.name = "WAIT_STATUS_ACK",
|
||||
.in_event_mask = S(SMSCB_PEER_E_CBSP_STATUS_ACK) |
|
||||
S(SMSCB_PEER_E_CBSP_STATUS_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_status_ack,
|
||||
},
|
||||
[SMSCB_S_WAIT_REPLACE_ACK] = {
|
||||
.name = "WAIT_REPLACE_ACK",
|
||||
.in_event_mask = S(SMSCB_PEER_E_CBSP_REPLACE_ACK) |
|
||||
S(SMSCB_PEER_E_CBSP_REPLACE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_replace_ack,
|
||||
},
|
||||
[SMSCB_S_WAIT_DELETE_ACK] = {
|
||||
.name = "WAIT_DELETE_ACK",
|
||||
.in_event_mask = S(SMSCB_PEER_E_CBSP_DELETE_ACK) |
|
||||
S(SMSCB_PEER_E_CBSP_DELETE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_DELETED),
|
||||
.action = smscb_p_fsm_wait_delete_ack,
|
||||
},
|
||||
[SMSCB_S_DELETED] = {
|
||||
.name = "DELETED",
|
||||
},
|
||||
};
|
||||
|
||||
struct osmo_fsm cbsp_smscb_peer_fsm = {
|
||||
.name = "SMSCB-PEER-CBSP",
|
||||
.states = smscb_p_fsm_states,
|
||||
.num_states = ARRAY_SIZE(smscb_p_fsm_states),
|
||||
.allstate_event_mask = S(SMSCB_PEER_E_DELETE),
|
||||
.allstate_action = smscb_p_fsm_allstate,
|
||||
.timer_cb = smscb_p_fsm_timer_cb,
|
||||
.log_subsys = DCBSP,
|
||||
.event_names = smscb_peer_fsm_event_names,
|
||||
.cleanup = smscb_p_fsm_cleanup,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void on_dso_load_smscb_p_fsm(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&cbsp_smscb_peer_fsm) == 0);
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
/* Osmocom CBC (Cell Broacast Centre) */
|
||||
|
||||
/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* 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/linuxlist.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gsm/cbsp.h>
|
||||
|
||||
#include <osmocom/cbc/cbc_data.h>
|
||||
#include <osmocom/cbc/cbsp_link.h>
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/sbcap_msg.h>
|
||||
#include <osmocom/cbc/rest_it_op.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
#include <osmocom/cbc/smscb_message_fsm.h>
|
||||
|
||||
/* convert cbc_message to osmo_cbsp_cell_list */
|
||||
static int cbcmsg_to_cbsp_cell_list(const void *ctx, struct osmo_cbsp_cell_list *list,
|
||||
const struct cbc_message *cbcmsg)
|
||||
{
|
||||
struct osmo_cbsp_cell_ent *ent;
|
||||
|
||||
switch (cbcmsg->scope) {
|
||||
case CBC_MSG_SCOPE_PLMN:
|
||||
list->id_discr = CELL_IDENT_BSS;
|
||||
ent = talloc_zero(ctx, struct osmo_cbsp_cell_ent);
|
||||
if (!ent)
|
||||
return -ENOMEM;
|
||||
//ent->cell_id = ?
|
||||
llist_add_tail(&ent->list, &list->list);
|
||||
return 0;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a CBSP WRITE-REPLACE from our internal representation */
|
||||
struct osmo_cbsp_decoded *cbcmsg_to_cbsp(void *ctx, const struct cbc_message *cbcmsg)
|
||||
{
|
||||
struct osmo_cbsp_write_replace *wrepl;
|
||||
const struct smscb_message *smscb = &cbcmsg->msg;
|
||||
struct osmo_cbsp_decoded *cbsp = osmo_cbsp_decoded_alloc(ctx, CBSP_MSGT_WRITE_REPLACE);
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
if (!cbsp)
|
||||
return NULL;
|
||||
wrepl = &cbsp->u.write_replace;
|
||||
|
||||
wrepl->msg_id = smscb->message_id;
|
||||
wrepl->new_serial_nr = smscb->serial_nr;
|
||||
/* FIXME: old? */
|
||||
/* Cell list */
|
||||
rc = cbcmsg_to_cbsp_cell_list(cbcmsg, &wrepl->cell_list, cbcmsg);
|
||||
if (rc < 0) {
|
||||
talloc_free(cbsp);
|
||||
return NULL;
|
||||
}
|
||||
if (!smscb->is_etws)
|
||||
wrepl->is_cbs = true;
|
||||
if (wrepl->is_cbs) {
|
||||
if (cbcmsg->extended_cbch)
|
||||
wrepl->u.cbs.channel_ind = CBSP_CHAN_IND_EXTENDED;
|
||||
else
|
||||
wrepl->u.cbs.channel_ind = CBSP_CHAN_IND_BASIC;
|
||||
wrepl->u.cbs.category = cbcmsg->priority;
|
||||
wrepl->u.cbs.rep_period = cbcmsg->rep_period;
|
||||
wrepl->u.cbs.num_bcast_req = cbcmsg->num_bcast;
|
||||
wrepl->u.cbs.dcs = smscb->cbs.dcs;
|
||||
INIT_LLIST_HEAD(&wrepl->u.cbs.msg_content);
|
||||
for (i = 0; i < smscb->cbs.num_pages; i++) {
|
||||
struct osmo_cbsp_content *ce = talloc_zero(cbsp, struct osmo_cbsp_content);
|
||||
if (i == smscb->cbs.num_pages - 1)
|
||||
ce->user_len = smscb->cbs.data_user_len - (i * SMSCB_RAW_PAGE_LEN);
|
||||
else
|
||||
ce->user_len = SMSCB_RAW_PAGE_LEN;
|
||||
memcpy(ce->data, smscb->cbs.data[i], SMSCB_RAW_PAGE_LEN);
|
||||
llist_add_tail(&ce->list, &wrepl->u.cbs.msg_content);
|
||||
}
|
||||
} else {
|
||||
wrepl->u.emergency.indicator = 1;
|
||||
wrepl->u.emergency.warning_type = (smscb->etws.warning_type & 0x7f) << 9;
|
||||
if (smscb->etws.user_alert)
|
||||
wrepl->u.emergency.warning_type |= 0x0100;
|
||||
if (smscb->etws.popup_on_display)
|
||||
wrepl->u.emergency.warning_type |= 0x0080;
|
||||
memcpy(wrepl->u.emergency.warning_sec_info, smscb->etws.warning_sec_info,
|
||||
sizeof(wrepl->u.emergency.warning_sec_info));
|
||||
if (cbcmsg->warning_period_sec == 0xffffffff)
|
||||
wrepl->u.emergency.warning_period = 0;
|
||||
else
|
||||
wrepl->u.emergency.warning_period = cbcmsg->warning_period_sec;
|
||||
}
|
||||
return cbsp;
|
||||
}
|
||||
|
||||
/* determine if peer is within scope of cbc_msg */
|
||||
static bool is_peer_in_scope(const struct cbc_peer *peer, const struct cbc_message *cbcmsg)
|
||||
{
|
||||
switch (cbcmsg->scope) {
|
||||
case CBC_MSG_SCOPE_PLMN:
|
||||
return true;
|
||||
/* FIXME: differnt scopes */
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* send given new message to given peer */
|
||||
int peer_new_cbc_message(struct cbc_peer *peer, struct cbc_message *cbcmsg)
|
||||
{
|
||||
struct osmo_cbsp_decoded *cbsp;
|
||||
SBcAP_SBC_AP_PDU_t *sbcap;
|
||||
|
||||
switch (peer->proto) {
|
||||
case CBC_PEER_PROTO_CBSP:
|
||||
/* skip peers without any current CBSP connection */
|
||||
if (!peer->link.cbsp) {
|
||||
LOGP(DCBSP, LOGL_NOTICE, "[%s] Tx CBSP: not connected\n",
|
||||
peer->name);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (!(cbsp = cbcmsg_to_cbsp(peer, cbcmsg))) {
|
||||
LOGP(DCBSP, LOGL_ERROR, "[%s] Tx CBSP: msg gen failed\n",
|
||||
peer->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
cbc_cbsp_link_tx(peer->link.cbsp, cbsp);
|
||||
break;
|
||||
case CBC_PEER_PROTO_SBcAP:
|
||||
/* skip peers without any current SBc-AP connection */
|
||||
if (!peer->link.sbcap) {
|
||||
LOGP(DSBcAP, LOGL_NOTICE, "[%s] Tx SBc-AP: not connected\n",
|
||||
peer->name);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (!(sbcap = cbcmsg_to_sbcap(peer, cbcmsg))) {
|
||||
LOGP(DSBcAP, LOGL_ERROR, "[%s] Tx SBc-AP: msg gen failed\n",
|
||||
peer->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
cbc_sbcap_link_tx(peer->link.sbcap, sbcap);
|
||||
break;
|
||||
case CBC_PEER_PROTO_SABP:
|
||||
LOGP(DLGLOBAL, LOGL_ERROR, "Sending message to peer proto %s not implemented!\n",
|
||||
get_value_string(cbc_peer_proto_name, peer->proto));
|
||||
return -1;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* receive a new CBC message from the user (REST). Allocates new memory,
|
||||
* a FSM, copies data from 'orig', routes to all peers and starts FSMs.
|
||||
* Once the operation is complete (success, error, timeout) we must
|
||||
* notify osmo_it_q of the completion */
|
||||
int cbc_message_new(const struct cbc_message *orig, struct rest_it_op *op)
|
||||
{
|
||||
struct cbc_message *cbcmsg = cbc_message_alloc(g_cbc, orig);
|
||||
struct cbc_peer *peer;
|
||||
|
||||
if (!cbcmsg) {
|
||||
rest_it_op_set_http_result(op, 409, "Could not allocate");
|
||||
rest_it_op_complete(op);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
OSMO_ASSERT(llist_empty(&cbcmsg->peers));
|
||||
|
||||
/* iterate over all peers */
|
||||
llist_for_each_entry(peer, &g_cbc->peers, list) {
|
||||
struct cbc_message_peer *mp;
|
||||
|
||||
if (!is_peer_in_scope(peer, cbcmsg))
|
||||
continue;
|
||||
|
||||
/* allocate new cbc_mesage_peer + related FSM */
|
||||
mp = smscb_peer_fsm_alloc(peer, cbcmsg);
|
||||
if (!mp) {
|
||||
LOGP(DCBSP, LOGL_ERROR, "Cannot allocate cbc_message_peer\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* kick off the state machine[s] */
|
||||
if (osmo_fsm_inst_dispatch(cbcmsg->fi, SMSCB_E_CREATE, op) < 0) {
|
||||
rest_it_op_set_http_result(op, 500, "Illegal FSM event");
|
||||
rest_it_op_complete(op);
|
||||
}
|
||||
|
||||
/* we continue in the FSM after the WRITE_ACK event was received */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cbc_message_delete(struct cbc_message *cbcmsg, struct rest_it_op *op)
|
||||
{
|
||||
if (osmo_fsm_inst_dispatch(cbcmsg->fi, SMSCB_E_DELETE, op) < 0) {
|
||||
rest_it_op_set_http_result(op, 500, "Illegal FSM event");
|
||||
rest_it_op_complete(op);
|
||||
}
|
||||
/* we continue in the FSM after the DELETE_ACK event was received */
|
||||
}
|
||||
|
||||
struct cbc_message *cbc_message_by_id(uint16_t message_id)
|
||||
{
|
||||
struct cbc_message *cbc_msg;
|
||||
llist_for_each_entry(cbc_msg, &g_cbc->messages, list) {
|
||||
if (cbc_msg->msg.message_id == message_id)
|
||||
return cbc_msg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -374,9 +374,9 @@ noinst_LTLIBRARIES=libosmo-asn1-sbcap.la
|
||||
libosmo_asn1_sbcap_la_SOURCES=$(ASN_MODULE_SRC)
|
||||
libosmo_asn1_sbcap_la_LIBADD=$(ASN1C_LDADD)
|
||||
|
||||
sbcap_LIBVERSION=0:0:0
|
||||
sbcap_LIBVERSION=1:0:1
|
||||
lib_LTLIBRARIES = libosmo-sbcap.la
|
||||
libosmo_sbcap_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(sbcap_LIBVERSION)
|
||||
libosmo_sbcap_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(sbcap_LIBVERSION) -no-undefined
|
||||
libosmo_sbcap_la_LIBADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
|
||||
$(ASN1C_LIBS) libosmo-asn1-sbcap.la
|
||||
libosmo_sbcap_la_SOURCES = sbcap_common.c
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_Error-Indication.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_Error_Indication_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_Error_Indication_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_Error_Indication, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -32,7 +32,7 @@ static const ber_tlv_tag_t asn_DEF_SBcAP_Error_Indication_tags_1[] = {
|
||||
static const asn_TYPE_tag2member_t asn_MAP_SBcAP_Error_Indication_tag2el_1[] = {
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* protocolIEs */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Error_Indication_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Error_Indication_specs_1 = {
|
||||
sizeof(struct SBcAP_Error_Indication),
|
||||
offsetof(struct SBcAP_Error_Indication, _asn_ctx),
|
||||
asn_MAP_SBcAP_Error_Indication_tag2el_1,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_PWS-Failure-Indication.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_PWS_Failure_Indication_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_PWS_Failure_Indication_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_PWS_Failure_Indication, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -51,7 +51,7 @@ static const asn_TYPE_tag2member_t asn_MAP_SBcAP_PWS_Failure_Indication_tag2el_1
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocolIEs */
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* protocolExtensions */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_PWS_Failure_Indication_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_PWS_Failure_Indication_specs_1 = {
|
||||
sizeof(struct SBcAP_PWS_Failure_Indication),
|
||||
offsetof(struct SBcAP_PWS_Failure_Indication, _asn_ctx),
|
||||
asn_MAP_SBcAP_PWS_Failure_Indication_tag2el_1,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_PWS-Restart-Indication.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_PWS_Restart_Indication_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_PWS_Restart_Indication_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_PWS_Restart_Indication, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -51,7 +51,7 @@ static const asn_TYPE_tag2member_t asn_MAP_SBcAP_PWS_Restart_Indication_tag2el_1
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocolIEs */
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* protocolExtensions */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_PWS_Restart_Indication_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_PWS_Restart_Indication_specs_1 = {
|
||||
sizeof(struct SBcAP_PWS_Restart_Indication),
|
||||
offsetof(struct SBcAP_PWS_Restart_Indication, _asn_ctx),
|
||||
asn_MAP_SBcAP_PWS_Restart_Indication_tag2el_1,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_Stop-Warning-Indication.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Indication_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Indication_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_Stop_Warning_Indication, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -51,7 +51,7 @@ static const asn_TYPE_tag2member_t asn_MAP_SBcAP_Stop_Warning_Indication_tag2el_
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocolIEs */
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* protocolExtensions */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Indication_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Indication_specs_1 = {
|
||||
sizeof(struct SBcAP_Stop_Warning_Indication),
|
||||
offsetof(struct SBcAP_Stop_Warning_Indication, _asn_ctx),
|
||||
asn_MAP_SBcAP_Stop_Warning_Indication_tag2el_1,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_Stop-Warning-Request.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Request_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Request_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_Stop_Warning_Request, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -51,7 +51,7 @@ static const asn_TYPE_tag2member_t asn_MAP_SBcAP_Stop_Warning_Request_tag2el_1[]
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocolIEs */
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* protocolExtensions */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Request_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Request_specs_1 = {
|
||||
sizeof(struct SBcAP_Stop_Warning_Request),
|
||||
offsetof(struct SBcAP_Stop_Warning_Request, _asn_ctx),
|
||||
asn_MAP_SBcAP_Stop_Warning_Request_tag2el_1,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_Stop-Warning-Response.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Response_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_Stop_Warning_Response_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_Stop_Warning_Response, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -51,7 +51,7 @@ static const asn_TYPE_tag2member_t asn_MAP_SBcAP_Stop_Warning_Response_tag2el_1[
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocolIEs */
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* protocolExtensions */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Response_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Stop_Warning_Response_specs_1 = {
|
||||
sizeof(struct SBcAP_Stop_Warning_Response),
|
||||
offsetof(struct SBcAP_Stop_Warning_Response, _asn_ctx),
|
||||
asn_MAP_SBcAP_Stop_Warning_Response_tag2el_1,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_Write-Replace-Warning-Indication.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Indication_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Indication_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_Write_Replace_Warning_Indication, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -51,7 +51,7 @@ static const asn_TYPE_tag2member_t asn_MAP_SBcAP_Write_Replace_Warning_Indicatio
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocolIEs */
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* protocolExtensions */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Indication_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Indication_specs_1 = {
|
||||
sizeof(struct SBcAP_Write_Replace_Warning_Indication),
|
||||
offsetof(struct SBcAP_Write_Replace_Warning_Indication, _asn_ctx),
|
||||
asn_MAP_SBcAP_Write_Replace_Warning_Indication_tag2el_1,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_Write-Replace-Warning-Request.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Request_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Request_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_Write_Replace_Warning_Request, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -51,7 +51,7 @@ static const asn_TYPE_tag2member_t asn_MAP_SBcAP_Write_Replace_Warning_Request_t
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocolIEs */
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* protocolExtensions */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Request_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Request_specs_1 = {
|
||||
sizeof(struct SBcAP_Write_Replace_Warning_Request),
|
||||
offsetof(struct SBcAP_Write_Replace_Warning_Request, _asn_ctx),
|
||||
asn_MAP_SBcAP_Write_Replace_Warning_Request_tag2el_1,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <osmocom/sbcap/SBcAP_Write-Replace-Warning-Response.h>
|
||||
|
||||
static asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Response_1[] = {
|
||||
asn_TYPE_member_t asn_MBR_SBcAP_Write_Replace_Warning_Response_1[] = {
|
||||
{ ATF_NOFLAGS, 0, offsetof(struct SBcAP_Write_Replace_Warning_Response, protocolIEs),
|
||||
(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
|
||||
-1, /* IMPLICIT tag at current level */
|
||||
@@ -51,7 +51,7 @@ static const asn_TYPE_tag2member_t asn_MAP_SBcAP_Write_Replace_Warning_Response_
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocolIEs */
|
||||
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* protocolExtensions */
|
||||
};
|
||||
static asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Response_specs_1 = {
|
||||
asn_SEQUENCE_specifics_t asn_SPC_SBcAP_Write_Replace_Warning_Response_specs_1 = {
|
||||
sizeof(struct SBcAP_Write_Replace_Warning_Response),
|
||||
offsetof(struct SBcAP_Write_Replace_Warning_Response, _asn_ctx),
|
||||
asn_MAP_SBcAP_Write_Replace_Warning_Response_tag2el_1,
|
||||
|
||||
@@ -432,7 +432,7 @@ asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
|
||||
#endif /* !defined(ASN_DISABLE_XER_SUPPORT) */
|
||||
|
||||
#if !defined(ASN_DISABLE_JER_SUPPORT)
|
||||
case ATS_BASIC_JER:
|
||||
case ATS_JER:
|
||||
if(td->op->jer_encoder) {
|
||||
er = jer_encode(td, sptr, callback, callback_key);
|
||||
if(er.encoded == -1) {
|
||||
|
||||
@@ -53,8 +53,8 @@ CHOICE_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,
|
||||
if(specs->ext_start == -1)
|
||||
ASN__DECODE_FAILED;
|
||||
|
||||
if (ct && ct->upper_bound >= ct->lower_bound) {
|
||||
value = aper_get_nsnnwn(pd, ct->upper_bound - ct->lower_bound + 1);
|
||||
if(specs && specs->tag2el_count > specs->ext_start) {
|
||||
value = aper_get_nsnnwn(pd, specs->tag2el_count - specs->ext_start); /* extension elements range */
|
||||
if(value < 0) ASN__DECODE_STARVED;
|
||||
value += specs->ext_start;
|
||||
if((unsigned)value >= td->elements_count)
|
||||
|
||||
@@ -124,6 +124,8 @@ SEQUENCE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
|
||||
for(edx = 0; edx < td->elements_count; edx++) {
|
||||
asn_TYPE_member_t *elm = &td->elements[edx];
|
||||
const void *memb_ptr;
|
||||
asn_constr_check_f *constr;
|
||||
int ret;
|
||||
|
||||
if(elm->flags & ATF_POINTER) {
|
||||
memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
|
||||
@@ -139,14 +141,12 @@ SEQUENCE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
|
||||
memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
|
||||
}
|
||||
|
||||
if(elm->encoding_constraints.general_constraints) {
|
||||
int ret = elm->encoding_constraints.general_constraints(elm->type, memb_ptr,
|
||||
ctfailcb, app_key);
|
||||
if(ret) return ret;
|
||||
} else {
|
||||
return elm->type->encoding_constraints.general_constraints(elm->type,
|
||||
memb_ptr, ctfailcb, app_key);
|
||||
}
|
||||
constr = elm->encoding_constraints.general_constraints;
|
||||
if(!constr)
|
||||
constr = elm->type->encoding_constraints.general_constraints;
|
||||
|
||||
ret = constr(elm->type, memb_ptr, ctfailcb, app_key);
|
||||
if(ret) return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -28,7 +28,25 @@
|
||||
extern int asn1_xer_print;
|
||||
|
||||
int _sbcap_DSBCAP = 0;
|
||||
int _sbcap_DASN1C = 0;
|
||||
#define DSBCAP _sbcap_DSBCAP
|
||||
#define DASN1C _sbcap_DASN1C
|
||||
|
||||
static const struct value_string sbcap_procedure_code_vals[] = {
|
||||
{ SBcAP_ProcedureId_Write_Replace_Warning, "Write-Replace-Warning" },
|
||||
{ SBcAP_ProcedureId_Stop_Warning, "Stop-Warning" },
|
||||
{ SBcAP_ProcedureId_Error_Indication, "Error-Indication" },
|
||||
{ SBcAP_ProcedureId_Write_Replace_Warning_Indication, "Write-Replace-Warning-Indication" },
|
||||
{ SBcAP_ProcedureId_Stop_Warning_Indication, "Stop-Warning-Indication" },
|
||||
{ SBcAP_ProcedureId_PWS_Restart_Indication, "PWS-Restart-Indication" },
|
||||
{ SBcAP_ProcedureId_PWS_Failure_Indication, "PWS-Failure-Indication" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const char *sbcap_procedure_code_str(SBcAP_ProcedureCode_t pc)
|
||||
{
|
||||
return get_value_string(sbcap_procedure_code_vals, pc);
|
||||
}
|
||||
|
||||
static const struct value_string sbcap_cause_vals[] = {
|
||||
{ SBcAP_Cause_message_accepted, "message accepted" },
|
||||
@@ -36,7 +54,7 @@ static const struct value_string sbcap_cause_vals[] = {
|
||||
{ SBcAP_Cause_parameter_value_invalid, "parameter value invalid" },
|
||||
{ SBcAP_Cause_valid_message_not_identified, "valid message not identified" },
|
||||
{ SBcAP_Cause_tracking_area_not_valid, "Tracking Area not valid" },
|
||||
{ SBcAP_Cause_unrecognised_message, "unrecoznied message" },
|
||||
{ SBcAP_Cause_unrecognised_message, "unrecognised message" },
|
||||
{ SBcAP_Cause_missing_mandatory_element, "missing mandatory element" },
|
||||
{ SBcAP_Cause_mME_capacity_exceeded, "MME capacity exceeded" },
|
||||
{ SBcAP_Cause_mME_memory_exceeded, "MME memory exceeded" },
|
||||
@@ -75,7 +93,8 @@ struct msgb *sbcap_encode(SBcAP_SBC_AP_PDU_t *pdu)
|
||||
rval = aper_encode_to_buffer(&asn_DEF_SBcAP_SBC_AP_PDU, NULL, pdu,
|
||||
msgb_data(msg), msgb_tailroom(msg));
|
||||
if (rval.encoded < 0) {
|
||||
LOGP(DSBCAP, LOGL_ERROR, "Error encoding type: %s\n",
|
||||
LOGP(DSBCAP, LOGL_ERROR, "%s: Error encoding type: %s\n",
|
||||
sbcap_pdu_get_name(pdu),
|
||||
rval.failed_type->name);
|
||||
msgb_free(msg);
|
||||
return NULL;
|
||||
@@ -96,6 +115,7 @@ SBcAP_SBC_AP_PDU_t *sbcap_decode(const struct msgb *msg)
|
||||
LOGP(DSBCAP, LOGL_ERROR, "Error decoding code=%d\n", rval.code);
|
||||
return NULL;
|
||||
}
|
||||
LOGP(DSBCAP, LOGL_DEBUG, "Decoded %s\n", sbcap_pdu_get_name(pdu));
|
||||
return pdu;
|
||||
}
|
||||
|
||||
@@ -111,9 +131,75 @@ void sbcap_pdu_free(SBcAP_SBC_AP_PDU_t *pdu)
|
||||
ASN_STRUCT_FREE(asn_DEF_SBcAP_SBC_AP_PDU, pdu);
|
||||
}
|
||||
|
||||
void sbcap_set_log_area(int log_area)
|
||||
SBcAP_ProcedureCode_t sbcap_pdu_get_procedure_code(const SBcAP_SBC_AP_PDU_t *pdu)
|
||||
{
|
||||
_sbcap_DSBCAP = log_area;
|
||||
switch (pdu->present) {
|
||||
case SBcAP_SBC_AP_PDU_PR_initiatingMessage:
|
||||
return pdu->choice.initiatingMessage.procedureCode;
|
||||
case SBcAP_SBC_AP_PDU_PR_successfulOutcome:
|
||||
return pdu->choice.successfulOutcome.procedureCode;
|
||||
case SBcAP_SBC_AP_PDU_PR_unsuccessfulOutcome:
|
||||
return pdu->choice.unsuccessfulOutcome.procedureCode;
|
||||
case SBcAP_SBC_AP_PDU_PR_NOTHING:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
SBcAP_Criticality_t sbcap_pdu_get_criticality(const SBcAP_SBC_AP_PDU_t *pdu)
|
||||
{
|
||||
switch (pdu->present) {
|
||||
case SBcAP_SBC_AP_PDU_PR_initiatingMessage:
|
||||
return pdu->choice.initiatingMessage.criticality;
|
||||
case SBcAP_SBC_AP_PDU_PR_successfulOutcome:
|
||||
return pdu->choice.successfulOutcome.criticality;
|
||||
case SBcAP_SBC_AP_PDU_PR_unsuccessfulOutcome:
|
||||
return pdu->choice.unsuccessfulOutcome.criticality;
|
||||
case SBcAP_SBC_AP_PDU_PR_NOTHING:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const char *sbcap_pdu_get_name(const SBcAP_SBC_AP_PDU_t *pdu)
|
||||
{
|
||||
static char pdu_name[256] = "<unknown>";
|
||||
struct osmo_strbuf sb = { .buf = pdu_name, .len = sizeof(pdu_name) };
|
||||
SBcAP_ProcedureCode_t pc = sbcap_pdu_get_procedure_code(pdu);
|
||||
|
||||
OSMO_STRBUF_PRINTF(sb, "%s", sbcap_procedure_code_str(pc));
|
||||
|
||||
switch (pc) {
|
||||
case SBcAP_ProcedureId_Write_Replace_Warning:
|
||||
case SBcAP_ProcedureId_Stop_Warning:
|
||||
OSMO_STRBUF_PRINTF(sb, "%s",
|
||||
pdu->present == SBcAP_SBC_AP_PDU_PR_initiatingMessage
|
||||
? "-Request" : "-Response");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return pdu_name;
|
||||
}
|
||||
|
||||
void *sbcap_as_find_ie(void *void_list, SBcAP_ProtocolIE_ID_t ie_id)
|
||||
{
|
||||
A_SEQUENCE_OF(SBcAP_ProtocolIE_ID_t) *li = (void *)void_list;
|
||||
int i;
|
||||
for (i = 0; i < li->count; i++) {
|
||||
/* "SBcAP_ProtocolIE_ID_t id" is first element in all *_IEs struct */
|
||||
SBcAP_ProtocolIE_ID_t *cur_ie_id = li->array[i];
|
||||
if (*cur_ie_id == ie_id) {
|
||||
return cur_ie_id;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sbcap_set_log_area(int log_area_sbcap, int log_area_asn1c)
|
||||
{
|
||||
_sbcap_DSBCAP = log_area_sbcap;
|
||||
_sbcap_DASN1C = log_area_asn1c;
|
||||
}
|
||||
|
||||
SBcAP_Write_Replace_Warning_Request_IEs_t *sbcap_alloc_Write_Replace_Warning_Request_IE(
|
||||
@@ -135,3 +221,13 @@ SBcAP_Stop_Warning_Request_IEs_t *sbcap_alloc_Stop_Warning_Request_IE(
|
||||
ie->value.present = present;
|
||||
return ie;
|
||||
}
|
||||
|
||||
SBcAP_ErrorIndicationIEs_t *sbcap_alloc_Error_Indication_IE(
|
||||
long id, SBcAP_Criticality_t criticality, SBcAP_Stop_Warning_Request_IEs__value_PR present)
|
||||
{
|
||||
SBcAP_ErrorIndicationIEs_t *ie = CALLOC(1, sizeof(*ie));
|
||||
ie->id = id;
|
||||
ie->criticality = criticality;
|
||||
ie->value.present = present;
|
||||
return ie;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ enum asn_transfer_syntax {
|
||||
*/
|
||||
ATS_BASIC_XER,
|
||||
ATS_CANONICAL_XER,
|
||||
ATS_BASIC_JER,
|
||||
ATS_JER,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -137,8 +137,25 @@ asn__format_to_callback(
|
||||
/*
|
||||
* Check stack against overflow, if limit is set.
|
||||
*/
|
||||
|
||||
/* Since GCC 13, AddressSanitizer started defaulting to
|
||||
* ASAN_OPTIONS="detect_stack_use_after_return=1", which makes this check
|
||||
* fail due to apparently jumping stack pointers.
|
||||
* Hence, disable this check if building with ASan, as documented in:
|
||||
* GCC: https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
|
||||
* Clang: https://clang.llvm.org/docs/AddressSanitizer.html#conditional-compilation-with-has-feature-address-sanitizer
|
||||
*/
|
||||
#if defined(__SANITIZE_ADDRESS__)
|
||||
#define ASN__SANITIZE_ENABLED 1
|
||||
#elif defined(__has_feature)
|
||||
#if __has_feature(address_sanitizer)
|
||||
#define ASN__SANITIZE_ENABLED 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define ASN__DEFAULT_STACK_MAX (30000)
|
||||
#ifdef ASN_DISABLE_STACK_OVERFLOW_CHECK
|
||||
|
||||
#if defined(ASN__SANITIZE_ENABLED) || defined(ASN_DISABLE_STACK_OVERFLOW_CHECK)
|
||||
static int CC_NOTUSED
|
||||
ASN__STACK_OVERFLOW_CHECK(const asn_codec_ctx_t *ctx) {
|
||||
(void)ctx;
|
||||
|
||||
@@ -13,15 +13,20 @@ extern "C" {
|
||||
|
||||
struct asn_TYPE_descriptor_s; /* Forward declaration */
|
||||
|
||||
/* Flags used by the jer_encode() and (*jer_type_encoder_f), defined below */
|
||||
/* Flags used by the jer_encode() and (*jer_type_encoder_f), defined below
|
||||
*
|
||||
* This isn't actually used, it might be used in the future to support
|
||||
* both normal JSON and prettified JSON output or removed.
|
||||
* It came from XER
|
||||
*/
|
||||
enum jer_encoder_flags_e {
|
||||
/* Mode of encoding */
|
||||
JER_F_BASIC = 0x01, /* BASIC-JER (pretty-printing) */
|
||||
JER_F = 0x01, /* JER (pretty-printing) */
|
||||
};
|
||||
|
||||
/*
|
||||
* The JER encoder of any type. May be invoked by the application.
|
||||
* Produces CANONICAL-JER and BASIC-JER depending on the (jer_flags).
|
||||
* Produces JER output.
|
||||
*/
|
||||
asn_enc_rval_t jer_encode(const struct asn_TYPE_descriptor_s *type_descriptor,
|
||||
const void *struct_ptr, /* Structure to be encoded */
|
||||
@@ -30,7 +35,7 @@ asn_enc_rval_t jer_encode(const struct asn_TYPE_descriptor_s *type_descriptor,
|
||||
);
|
||||
|
||||
/*
|
||||
* The variant of the above function which dumps the BASIC-JER (JER_F_BASIC)
|
||||
* The variant of the above function which dumps the JER
|
||||
* output into the chosen file pointer.
|
||||
* RETURN VALUES:
|
||||
* 0: The structure is printed.
|
||||
@@ -42,9 +47,9 @@ int jer_fprint(FILE *stream, const struct asn_TYPE_descriptor_s *td,
|
||||
|
||||
/*
|
||||
* A helper function that uses JER encoding/decoding to verify that:
|
||||
* - Both structures encode into the same BASIC JER.
|
||||
* - Both structures encode into the same JER.
|
||||
* - Both resulting JER byte streams can be decoded back.
|
||||
* - Both decoded structures encode into the same BASIC JER (round-trip).
|
||||
* - Both decoded structures encode into the same JER (round-trip).
|
||||
* All of this verifies equivalence between structures and a round-trip.
|
||||
* ARGUMENTS:
|
||||
* (opt_debug_stream) - If specified, prints ongoing details.
|
||||
|
||||
234
src/sbcap_link.c
234
src/sbcap_link.c
@@ -39,24 +39,30 @@
|
||||
#include <osmocom/cbc/cbc_data.h>
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/sbcap_link_fsm.h>
|
||||
#include <osmocom/cbc/sbcap_msg.h>
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
|
||||
struct cbc_sbcap_link *cbc_sbcap_link_alloc(struct cbc_sbcap_mgr *cbc, struct cbc_peer *peer)
|
||||
{
|
||||
struct cbc_sbcap_link *link;
|
||||
char *name;
|
||||
|
||||
link = talloc_zero(cbc, struct cbc_sbcap_link);
|
||||
OSMO_ASSERT(link);
|
||||
|
||||
link->peer = peer;
|
||||
link->is_client = (peer->link_mode == CBC_PEER_LINK_MODE_CLIENT);
|
||||
|
||||
link->fi = osmo_fsm_inst_alloc(&sbcap_link_fsm, link, link, LOGL_DEBUG, NULL);
|
||||
name = talloc_strdup(link, peer->name);
|
||||
osmo_identifier_sanitize_buf(name, NULL, '_');
|
||||
link->fi = osmo_fsm_inst_alloc(&sbcap_link_fsm, link, link, LOGL_DEBUG, name);
|
||||
if (!link->fi) {
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "Unable to allocate FSM\n");
|
||||
talloc_free(link);
|
||||
return NULL;
|
||||
}
|
||||
talloc_free(name);
|
||||
|
||||
llist_add_tail(&link->list, &cbc->links);
|
||||
return link;
|
||||
@@ -77,16 +83,152 @@ const char *cbc_sbcap_link_name(const struct cbc_sbcap_link *link)
|
||||
struct osmo_fd *ofd;
|
||||
OSMO_ASSERT(link);
|
||||
|
||||
if (link->peer && link->peer->name) {
|
||||
if (link->peer && link->peer->name)
|
||||
return link->peer->name;
|
||||
}
|
||||
|
||||
ofd = osmo_stream_srv_get_ofd(link->conn);
|
||||
if (link->is_client)
|
||||
ofd = osmo_stream_cli_get_ofd(link->cli_conn);
|
||||
else
|
||||
ofd = osmo_stream_srv_get_ofd(link->srv_conn);
|
||||
return osmo_sock_get_name2(ofd->fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* SCTP client
|
||||
*/
|
||||
static int cbc_sbcap_link_cli_connect_cb(struct osmo_stream_cli *conn)
|
||||
{
|
||||
struct cbc_sbcap_link *link = osmo_stream_cli_get_data(conn);
|
||||
LOGPSBCAPC(link, LOGL_NOTICE, "Connected\n");
|
||||
osmo_fsm_inst_dispatch(link->fi, SBcAP_LINK_E_CMD_RESET, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cbc_sbcap_link_cli_disconnect_cb(struct osmo_stream_cli *conn)
|
||||
{
|
||||
struct cbc_sbcap_link *link = osmo_stream_cli_get_data(conn);
|
||||
LOGPSBCAPC(link, LOGL_NOTICE, "Disconnected.\n");
|
||||
LOGPSBCAPC(link, LOGL_NOTICE, "Reconnecting...\n");
|
||||
osmo_stream_cli_reconnect(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cbc_sbcap_link_cli_read_cb(struct osmo_stream_cli *conn)
|
||||
{
|
||||
struct cbc_sbcap_link *link = osmo_stream_cli_get_data(conn);
|
||||
struct osmo_fd *ofd = osmo_stream_cli_get_ofd(conn);
|
||||
SBcAP_SBC_AP_PDU_t *pdu;
|
||||
struct msgb *msg = msgb_alloc_c(g_cbc, 1500, "SBcAP-rx");
|
||||
struct sctp_sndrcvinfo sinfo;
|
||||
int flags = 0;
|
||||
int rc;
|
||||
|
||||
/* read SBc-AP message from socket and process it */
|
||||
rc = sctp_recvmsg(ofd->fd, msgb_data(msg), msgb_tailroom(msg),
|
||||
NULL, NULL, &sinfo, &flags);
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "%s(): sctp_recvmsg() returned %d (flags=0x%x)\n",
|
||||
__func__, rc, flags);
|
||||
if (rc < 0) {
|
||||
osmo_stream_cli_reconnect(conn);
|
||||
goto out;
|
||||
} else if (rc == 0) {
|
||||
osmo_stream_cli_reconnect(conn);
|
||||
} else {
|
||||
msgb_put(msg, rc);
|
||||
}
|
||||
|
||||
if (flags & MSG_NOTIFICATION) {
|
||||
union sctp_notification *notif = (union sctp_notification *) msgb_data(msg);
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "Rx sctp notif %s\n",
|
||||
osmo_sctp_sn_type_str(notif->sn_header.sn_type));
|
||||
switch (notif->sn_header.sn_type) {
|
||||
case SCTP_SHUTDOWN_EVENT:
|
||||
osmo_stream_cli_reconnect(conn);
|
||||
break;
|
||||
case SCTP_ASSOC_CHANGE:
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "Rx sctp notif SCTP_ASSOC_CHANGE: %s\n",
|
||||
osmo_sctp_assoc_chg_str(notif->sn_assoc_change.sac_state));
|
||||
break;
|
||||
default:
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "Rx sctp notif %s (%u)\n",
|
||||
osmo_sctp_sn_type_str(notif->sn_header.sn_type),
|
||||
notif->sn_header.sn_type);
|
||||
break;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
goto out;
|
||||
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "Rx SBc-AP %s\n", msgb_hexdump(msg));
|
||||
|
||||
/* decode + dispatch message */
|
||||
pdu = sbcap_decode(msg);
|
||||
if (pdu) {
|
||||
LOGPSBCAPC(link, LOGL_INFO, "Rx SBc-AP %s\n",
|
||||
sbcap_pdu_get_name(pdu));
|
||||
g_cbc->sbcap.mgr->rx_cb(link, pdu);
|
||||
} else {
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "Unable to decode %s\n", msgb_hexdump(msg));
|
||||
pdu = sbcap_gen_error_ind(link, SBcAP_Cause_unrecognised_message, NULL);
|
||||
if (pdu) {
|
||||
cbc_sbcap_link_tx(link, pdu);
|
||||
} else {
|
||||
LOGPSBCAPC(link, LOGL_ERROR,
|
||||
"Tx SBc-AP Error-Indication: msg gen failed\n");
|
||||
}
|
||||
}
|
||||
out:
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cbc_sbcap_link_open_cli(struct cbc_sbcap_link *link)
|
||||
{
|
||||
struct osmo_stream_cli *conn;
|
||||
struct cbc_peer *peer = link->peer;
|
||||
int rc;
|
||||
|
||||
OSMO_ASSERT(link->is_client);
|
||||
OSMO_ASSERT(peer->link_mode == CBC_PEER_LINK_MODE_CLIENT);
|
||||
|
||||
conn = osmo_stream_cli_create(link);
|
||||
osmo_stream_cli_set_data(conn, link);
|
||||
osmo_stream_cli_set_nodelay(conn, true);
|
||||
osmo_stream_cli_set_reconnect_timeout(conn, 5);
|
||||
osmo_stream_cli_set_proto(conn, IPPROTO_SCTP);
|
||||
osmo_stream_cli_set_connect_cb(conn, cbc_sbcap_link_cli_connect_cb);
|
||||
osmo_stream_cli_set_disconnect_cb(conn, cbc_sbcap_link_cli_disconnect_cb);
|
||||
osmo_stream_cli_set_read_cb(conn, cbc_sbcap_link_cli_read_cb);
|
||||
OSMO_ASSERT(g_cbc->config.sbcap.num_local_host > 0);
|
||||
rc = osmo_stream_cli_set_local_addrs(conn, (const char **)&g_cbc->config.sbcap.local_host,
|
||||
g_cbc->config.sbcap.num_local_host);
|
||||
if (rc < 0)
|
||||
goto free_ret;
|
||||
/* We assign free local port for client links:
|
||||
* osmo_stream_cli_set_local_port(conn, g_cbc->sbcap.local_port);
|
||||
*/
|
||||
OSMO_ASSERT(peer->num_remote_host > 0);
|
||||
rc = osmo_stream_cli_set_addrs(conn, (const char **)peer->remote_host, peer->num_remote_host);
|
||||
if (rc < 0)
|
||||
goto free_ret;
|
||||
osmo_stream_cli_set_port(conn, peer->remote_port);
|
||||
rc = osmo_stream_cli_open(conn);
|
||||
if (rc < 0)
|
||||
goto free_ret;
|
||||
link->cli_conn = conn;
|
||||
return 0;
|
||||
free_ret:
|
||||
osmo_stream_cli_destroy(conn);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* SCTP server
|
||||
*/
|
||||
/* data from MME has arrived at CBC */
|
||||
static int sbcap_cbc_read_cb(struct osmo_stream_srv *conn)
|
||||
static int sbcap_cbc_srv_read_cb(struct osmo_stream_srv *conn)
|
||||
{
|
||||
struct osmo_stream_srv_link *srv_link = osmo_stream_srv_get_master(conn);
|
||||
struct cbc_sbcap_link *link = osmo_stream_srv_get_data(conn);
|
||||
@@ -136,13 +278,13 @@ static int sbcap_cbc_read_cb(struct osmo_stream_srv *conn)
|
||||
if (rc == 0)
|
||||
goto out;
|
||||
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "Received SBc-AP %s\n", msgb_hexdump(msg));
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "Rx SBc-AP %s\n", msgb_hexdump(msg));
|
||||
|
||||
/* decode + dispatch message */
|
||||
pdu = sbcap_decode(msg);
|
||||
if (pdu) {
|
||||
LOGPSBCAPC(link, LOGL_INFO, "Received SBc-AP %d\n",
|
||||
pdu->present);
|
||||
LOGPSBCAPC(link, LOGL_INFO, "Rx SBc-AP %s\n",
|
||||
sbcap_pdu_get_name(pdu));
|
||||
cbc->rx_cb(link, pdu);
|
||||
} else {
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "Unable to decode %s\n", msgb_hexdump(msg));
|
||||
@@ -153,7 +295,7 @@ out:
|
||||
}
|
||||
|
||||
/* connection from MME to CBC has been closed */
|
||||
static int sbcap_cbc_closed_cb(struct osmo_stream_srv *conn)
|
||||
static int sbcap_cbc_srv_closed_cb(struct osmo_stream_srv *conn)
|
||||
{
|
||||
struct cbc_sbcap_link *link = osmo_stream_srv_get_data(conn);
|
||||
LOGPSBCAPC(link, LOGL_NOTICE, "connection closed\n");
|
||||
@@ -198,6 +340,23 @@ static int sbcap_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
||||
peer = cbc_peer_create(NULL, CBC_PEER_PROTO_SBcAP);
|
||||
OSMO_ASSERT(peer);
|
||||
peer->unknown_dynamic_peer = true;
|
||||
} else { /* peer is known */
|
||||
switch (peer->link_mode) {
|
||||
case CBC_PEER_LINK_MODE_DISABLED:
|
||||
LOGP(DSBcAP, LOGL_NOTICE,
|
||||
"Rejecting conn for disabled SBc-AP peer %s:%d\n",
|
||||
remote_ip, remote_port);
|
||||
close(fd);
|
||||
return -1;
|
||||
case CBC_PEER_LINK_MODE_CLIENT:
|
||||
LOGP(DSBcAP, LOGL_NOTICE,
|
||||
"Rejecting conn for SBc-AP peer %s:%d configured as 'client'\n",
|
||||
remote_ip, remote_port);
|
||||
close(fd);
|
||||
return -1;
|
||||
default: /* MODE_SERVER */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (peer->link.sbcap) {
|
||||
LOGPSBCAPC(peer->link.sbcap, LOGL_ERROR,
|
||||
@@ -208,10 +367,10 @@ static int sbcap_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
||||
link = cbc_sbcap_link_alloc(cbc, peer);
|
||||
OSMO_ASSERT(link);
|
||||
|
||||
link->conn = osmo_stream_srv_create(srv_link, srv_link, fd,
|
||||
sbcap_cbc_read_cb, sbcap_cbc_closed_cb,
|
||||
link);
|
||||
if (!link->conn) {
|
||||
link->srv_conn = osmo_stream_srv_create(srv_link, srv_link, fd,
|
||||
sbcap_cbc_srv_read_cb, sbcap_cbc_srv_closed_cb,
|
||||
link);
|
||||
if (!link->srv_conn) {
|
||||
LOGPSBCAPC(link, LOGL_ERROR,
|
||||
"Unable to create stream server for %s:%u\n",
|
||||
remote_ip, remote_port);
|
||||
@@ -224,35 +383,64 @@ static int sbcap_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cbc_sbcap_link_tx(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
int cbc_sbcap_link_tx(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
{
|
||||
struct msgb *msg;
|
||||
int rc = 0;
|
||||
|
||||
if (!pdu) {
|
||||
LOGP(DSBcAP, LOGL_NOTICE, "Cannot transmit msg: no pdu\n");
|
||||
return;
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
if (!link) {
|
||||
LOGP(DSBcAP, LOGL_NOTICE, "Cannot transmit msg: no connection\n");
|
||||
return;
|
||||
LOGP(DSBcAP, LOGL_NOTICE, "Cannot transmit msg %s: no connection\n",
|
||||
sbcap_pdu_get_name(pdu));
|
||||
rc = -ENOLINK;
|
||||
goto ret_free;
|
||||
} else if (link->is_client && !osmo_stream_cli_is_connected(link->cli_conn)) {
|
||||
LOGPSBCAPC(link, LOGL_NOTICE, "Cannot transmit msg %s: reconnecting\n",
|
||||
sbcap_pdu_get_name(pdu));
|
||||
rc = -ENOTCONN;
|
||||
goto ret_free;
|
||||
}
|
||||
|
||||
LOGPSBCAPC(link, LOGL_INFO, "Transmitting msg\n");
|
||||
LOGPSBCAPC(link, LOGL_INFO, "Tx msg %s\n",
|
||||
sbcap_pdu_get_name(pdu));
|
||||
OSMO_ASSERT(link->conn);
|
||||
msg = sbcap_encode(pdu);
|
||||
if (!msg)
|
||||
if (!msg) {
|
||||
rc = -EINVAL;
|
||||
goto ret_free;
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "Encoded message: %s\n", msgb_hexdump(msg));
|
||||
osmo_stream_srv_send(link->conn, msg);
|
||||
}
|
||||
LOGPSBCAPC(link, LOGL_DEBUG, "Encoded message %s: %s\n",
|
||||
sbcap_pdu_get_name(pdu), msgb_hexdump(msg));
|
||||
if (link->is_client)
|
||||
osmo_stream_cli_send(link->cli_conn, msg);
|
||||
else
|
||||
osmo_stream_srv_send(link->srv_conn, msg);
|
||||
ret_free:
|
||||
sbcap_pdu_free(pdu);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cbc_sbcap_link_close(struct cbc_sbcap_link *link)
|
||||
{
|
||||
if (link->conn)
|
||||
osmo_stream_srv_destroy(link->conn);
|
||||
if (!link->conn)
|
||||
return;
|
||||
|
||||
if (link->is_client) {
|
||||
osmo_stream_cli_destroy(link->cli_conn);
|
||||
osmo_stream_cli_destroy(link->cli_conn);
|
||||
if (link->peer)
|
||||
link->peer->link.sbcap = NULL;
|
||||
link->cli_conn = NULL;
|
||||
if (link->fi)
|
||||
osmo_fsm_inst_dispatch(link->fi, SBcAP_LINK_E_CMD_CLOSE, NULL);
|
||||
} else {
|
||||
osmo_stream_srv_destroy(link->srv_conn);
|
||||
/* Same as waht's done for cli is done for srv in closed_cb() */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
#include <osmocom/cbc/cbc_message.h>
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/sbcap_link_fsm.h>
|
||||
#include <osmocom/cbc/sbcap_msg.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
#include <osmocom/cbc/smscb_message_fsm.h>
|
||||
#include <osmocom/cbc/smscb_peer_fsm.h>
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
@@ -42,9 +43,6 @@ enum sbcap_link_state {
|
||||
};
|
||||
|
||||
static const struct value_string sbcap_link_event_names[] = {
|
||||
{ SBcAP_LINK_E_RX_RST_COMPL, "Rx Reset Complete" },
|
||||
{ SBcAP_LINK_E_RX_RST_FAIL, "Rx Reset Failure" },
|
||||
{ SBcAP_LINK_E_RX_KA_COMPL, "Rx Keep-Alive Complete" },
|
||||
{ SBcAP_LINK_E_RX_RESTART, "Rx Restart" },
|
||||
{ SBcAP_LINK_E_CMD_RESET, "RESET.cmd" },
|
||||
{ SBcAP_LINK_E_CMD_CLOSE, "CLOSE.cmd" },
|
||||
@@ -83,7 +81,7 @@ static void sbcap_link_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, vo
|
||||
//pdu = data;
|
||||
/* TODO: delete any CBS state we have for this peer */
|
||||
/* TODO: re-send messages we have matching the scope of the peer */
|
||||
LOGPSBCAPC(link, LOGL_NOTICE, "RESTART but re-sending not implemented yet\n");
|
||||
LOGPSBCAPC(link, LOGL_NOTICE, "Rx PWS Restart Indication not implemented yet\n");
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
@@ -131,20 +129,6 @@ struct osmo_fsm sbcap_link_fsm = {
|
||||
.cleanup = sbcap_link_fsm_cleanup,
|
||||
};
|
||||
|
||||
static void *sbcap_as_find_ie(void *void_list, SBcAP_ProtocolIE_ID_t ie_id)
|
||||
{
|
||||
A_SEQUENCE_OF(SBcAP_ProtocolIE_ID_t) *li = (void *)void_list;
|
||||
int i;
|
||||
for (i = 0; i < li->count; i++) {
|
||||
/* "SBcAP_ProtocolIE_ID_t id" is first element in all *_IEs struct */
|
||||
SBcAP_ProtocolIE_ID_t *cur_ie_id = li->array[i];
|
||||
if (*cur_ie_id == ie_id) {
|
||||
return cur_ie_id;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SBcAP_Message_Identifier_t *get_msg_id_ie(struct cbc_sbcap_link *link,
|
||||
const SBcAP_SBC_AP_PDU_t *pdu)
|
||||
{
|
||||
@@ -209,17 +193,88 @@ static int get_msg_id(struct cbc_sbcap_link *link, const SBcAP_SBC_AP_PDU_t *pdu
|
||||
if (!ie)
|
||||
return -1;
|
||||
if (ie->size != 2) {
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "get_msg_id wrong size %zu\n", ie->size);
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "get_msg_id(%s) wrong size %zu\n",
|
||||
sbcap_pdu_get_name(pdu), ie->size);
|
||||
return -1;
|
||||
}
|
||||
return osmo_load16be(ie->buf);
|
||||
}
|
||||
|
||||
/* message was received from remote SBcAP peer (BSC) */
|
||||
/* Rx Error Indication from peer */
|
||||
static int cbc_sbcap_link_rx_error_ind(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
{
|
||||
A_SEQUENCE_OF(void) *as_pdu = NULL;
|
||||
SBcAP_ErrorIndicationIEs_t *ie;
|
||||
SBcAP_Criticality_Diagnostics_t *ie_diag = NULL;
|
||||
long cause = -1;
|
||||
long proc_code = -1;
|
||||
long trigger_msg = -1;
|
||||
long criticality = -1;
|
||||
int i;
|
||||
|
||||
as_pdu = (void *)&pdu->choice.initiatingMessage.value.choice.Error_Indication.protocolIEs.list;
|
||||
OSMO_ASSERT(as_pdu);
|
||||
|
||||
for (i = 0; i < as_pdu->count; i++) {
|
||||
ie = (SBcAP_ErrorIndicationIEs_t *)(as_pdu->array[i]);
|
||||
OSMO_ASSERT(ie);
|
||||
switch (ie->id) {
|
||||
case SBcAP_ErrorIndicationIEs__value_PR_Cause:
|
||||
cause = ie->value.choice.Cause;
|
||||
break;
|
||||
case SBcAP_ErrorIndicationIEs__value_PR_Criticality_Diagnostics:
|
||||
ie_diag = &ie->value.choice.Criticality_Diagnostics;
|
||||
if (ie_diag->procedureCode)
|
||||
proc_code = *ie_diag->procedureCode;
|
||||
if (ie_diag->triggeringMessage)
|
||||
trigger_msg = *ie_diag->triggeringMessage;
|
||||
if (ie_diag->procedureCriticality)
|
||||
criticality = *ie_diag->procedureCriticality;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "Rx %s (cause=%ld, diagnostics=%d [proc_code=%ld, trigger_msg=%ld criticality=%ld])\n",
|
||||
sbcap_pdu_get_name(pdu), cause, !!ie_diag, proc_code, trigger_msg, criticality);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Rx Write Replace Warning Response from peer */
|
||||
static int cbc_sbcap_link_rx_write_replace_warn_resp(struct cbc_sbcap_link *link,
|
||||
struct cbc_message_peer *mp,
|
||||
SBcAP_SBC_AP_PDU_t *pdu)
|
||||
{
|
||||
A_SEQUENCE_OF(void) *as_pdu;
|
||||
SBcAP_Write_Replace_Warning_Response_IEs_t *ie;
|
||||
SBcAP_SBC_AP_PDU_t *err_ind_pdu;
|
||||
int ev = SMSCB_PEER_E_SBCAP_WRITE_ACK;
|
||||
|
||||
as_pdu = (void *)&pdu->choice.successfulOutcome.value.choice.Write_Replace_Warning_Response.protocolIEs.list;
|
||||
|
||||
/* static const long asn_VAL_19_SBcAP_id_Cause = 1; */
|
||||
ie = sbcap_as_find_ie(as_pdu, 1);
|
||||
if (ie) {
|
||||
if (ie->value.choice.Cause != SBcAP_Cause_message_accepted)
|
||||
ev = SMSCB_PEER_E_SBCAP_WRITE_NACK;
|
||||
} else { /* This shouldn't happen, the IE is Mandatory... */
|
||||
ev = SMSCB_PEER_E_SBCAP_WRITE_NACK;
|
||||
err_ind_pdu = sbcap_gen_error_ind(link,
|
||||
SBcAP_Cause_missing_mandatory_element, pdu);
|
||||
if (err_ind_pdu)
|
||||
cbc_sbcap_link_tx(link, err_ind_pdu);
|
||||
}
|
||||
|
||||
return osmo_fsm_inst_dispatch(mp->fi, ev, pdu);
|
||||
}
|
||||
|
||||
/* message was received from remote SBc-AP peer (MME) */
|
||||
int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
{
|
||||
struct cbc_message *smscb;
|
||||
struct cbc_message_peer *mp;
|
||||
SBcAP_SBC_AP_PDU_t *err_ind_pdu;
|
||||
int msg_id;
|
||||
|
||||
/* messages without reference to a specific SMSCB message */
|
||||
@@ -229,19 +284,31 @@ int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
case SBcAP_ProcedureId_Write_Replace_Warning:
|
||||
case SBcAP_ProcedureId_Stop_Warning:
|
||||
LOGPSBCAPC(link, LOGL_ERROR,
|
||||
"SBcAP initiatingMessage procedure=%ld MME->CBC not expected\n",
|
||||
pdu->choice.initiatingMessage.procedureCode);
|
||||
"SBcAP %s MME->CBC not expected\n",
|
||||
sbcap_pdu_get_name(pdu));
|
||||
return -EINVAL;
|
||||
case SBcAP_ProcedureId_PWS_Restart_Indication:
|
||||
return osmo_fsm_inst_dispatch(link->fi, SBcAP_LINK_E_RX_RESTART, pdu);
|
||||
case SBcAP_ProcedureId_Error_Indication:
|
||||
return cbc_sbcap_link_rx_error_ind(link, pdu);
|
||||
case SBcAP_ProcedureId_PWS_Failure_Indication:
|
||||
LOGPSBCAPC(link, LOGL_NOTICE, "Rx %s not implemented yet\n",
|
||||
sbcap_pdu_get_name(pdu));
|
||||
return 0;
|
||||
case SBcAP_ProcedureId_Stop_Warning_Indication:
|
||||
case SBcAP_ProcedureId_Write_Replace_Warning_Indication:
|
||||
break; /* Handle msg id below */
|
||||
case SBcAP_ProcedureId_Error_Indication:
|
||||
case SBcAP_ProcedureId_PWS_Failure_Indication:
|
||||
default:
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "SBcAP initiatingMessage procedure=%ld not implemented?\n",
|
||||
pdu->choice.initiatingMessage.procedureCode);
|
||||
pdu->choice.initiatingMessage.procedureCode);
|
||||
err_ind_pdu = sbcap_gen_error_ind(link, SBcAP_Cause_valid_message_not_identified, pdu);
|
||||
if (!err_ind_pdu) {
|
||||
LOGPSBCAPC(link, LOGL_ERROR,
|
||||
"Tx SBc-AP Error-Indication: msg gen failed\n");
|
||||
} else if (cbc_sbcap_link_tx(link, err_ind_pdu) < 0) {
|
||||
LOGPSBCAPC(link, LOGL_ERROR,
|
||||
"Tx SBc-AP Error-Indication failed\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@@ -276,8 +343,8 @@ int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
/* look-up smscb_message */
|
||||
smscb = cbc_message_by_id(msg_id);
|
||||
if (!smscb) {
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "Rx SBc-AP msg for unknown message-id 0x%04x\n",
|
||||
msg_id);
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "Rx SBc-AP %s for unknown message-id 0x%04x\n",
|
||||
sbcap_pdu_get_name(pdu), msg_id);
|
||||
/* TODO: inform peer? */
|
||||
return 0;
|
||||
}
|
||||
@@ -285,8 +352,8 @@ int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
/* look-up smscb_message_peer */
|
||||
mp = cbc_message_peer_get(smscb, link->peer);
|
||||
if (!mp) {
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "Rx SBc-AP msg for message-id 0x%04x without peer %s\n",
|
||||
msg_id, link->peer->name);
|
||||
LOGPSBCAPC(link, LOGL_ERROR, "Rx SBc-AP %s for message-id 0x%04x without peer %s\n",
|
||||
sbcap_pdu_get_name(pdu), msg_id, link->peer->name);
|
||||
/* TODO: inform peer? */
|
||||
return 0;
|
||||
}
|
||||
@@ -295,6 +362,8 @@ int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
switch (pdu->present) {
|
||||
case SBcAP_SBC_AP_PDU_PR_initiatingMessage:
|
||||
switch (pdu->choice.initiatingMessage.procedureCode) {
|
||||
case SBcAP_ProcedureId_Write_Replace_Warning_Indication:
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_SBCAP_WRITE_IND, pdu);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -303,11 +372,11 @@ int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
switch (pdu->choice.successfulOutcome.procedureCode) {
|
||||
case SBcAP_ProcedureId_Write_Replace_Warning:
|
||||
//if (dec->u.write_replace_compl.old_serial_nr)
|
||||
// return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_SBcAP_REPLACE_ACK, dec);
|
||||
// return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_SBcAP_REPLACE_ACK, dec);
|
||||
//else
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_SBCAP_WRITE_ACK, pdu);
|
||||
return cbc_sbcap_link_rx_write_replace_warn_resp(link, mp, pdu);
|
||||
case SBcAP_ProcedureId_Stop_Warning:
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_SBCAP_DELETE_ACK, pdu);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_SBCAP_DELETE_ACK, pdu);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -315,7 +384,7 @@ int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
||||
case SBcAP_SBC_AP_PDU_PR_unsuccessfulOutcome:
|
||||
switch (pdu->choice.unsuccessfulOutcome.procedureCode) {
|
||||
case SBcAP_ProcedureId_Stop_Warning:
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_E_SBCAP_DELETE_NACK, pdu);
|
||||
return osmo_fsm_inst_dispatch(mp->fi, SMSCB_PEER_E_SBCAP_DELETE_NACK, pdu);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
158
src/sbcap_msg.c
158
src/sbcap_msg.c
@@ -35,10 +35,13 @@
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
|
||||
/* 3GPP TS 36.413 9.2.1.53 */
|
||||
/* 3GPP TS 36.413 9.2.1.53, 3GPP TS 23.041 9.3.35 */
|
||||
#define SBCAP_WARN_MSG_CONTENTS_IE_MAX_LEN 9600
|
||||
|
||||
#if 0
|
||||
/* Warning Area List
|
||||
* 3GPP TS 36.413 9.2.1.46, 3GPP TS 23.041 9.3.30
|
||||
*/
|
||||
static void msgb_put_sbcap_cell_list(const struct cbc_message *cbcmsg, void *void_li)
|
||||
{
|
||||
static uint8_t ie_plm_id0[] = {0x05, 0xf5, 0x32};
|
||||
@@ -78,13 +81,14 @@ static void msgb_put_sbcap_cell_list(const struct cbc_message *cbcmsg, void *voi
|
||||
}
|
||||
#endif
|
||||
|
||||
/* generate a SBc-AP WRITE-REPLACE WARNING REQUEST from our internal representation */
|
||||
SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg)
|
||||
/* generate a SBc-AP WRITE-REPLACE WARNING REQUEST from our internal representation.
|
||||
* 3GPP TS 36.413 9.1.13.1
|
||||
*/
|
||||
SBcAP_SBC_AP_PDU_t *sbcap_gen_write_replace_warning_req(void *ctx, const struct cbc_message *cbcmsg)
|
||||
{
|
||||
const struct smscb_message *smscb = &cbcmsg->msg;
|
||||
SBcAP_SBC_AP_PDU_t *pdu;
|
||||
SBcAP_Write_Replace_Warning_Request_IEs_t *ie;
|
||||
uint16_t ie_warning_type;
|
||||
unsigned int i;
|
||||
uint8_t *ptr;
|
||||
#if 0
|
||||
@@ -101,7 +105,9 @@ SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg)
|
||||
|
||||
A_SEQUENCE_OF(void) *as_pdu = (void *)&pdu->choice.initiatingMessage.value.choice.Write_Replace_Warning_Request.protocolIEs.list;
|
||||
|
||||
/* static const long asn_VAL_1_SBcAP_id_Message_Identifier = 5; */
|
||||
/* Message Identifier:
|
||||
* 3GPP TS 36.413 9.2.1.44, 3GPP TS 23.041 9.4.1.3.6
|
||||
* static const long asn_VAL_1_SBcAP_id_Message_Identifier = 5; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(5, SBcAP_Criticality_reject,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Message_Identifier);
|
||||
ie->value.choice.Message_Identifier.buf = MALLOC(sizeof(uint16_t));
|
||||
@@ -110,7 +116,9 @@ SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg)
|
||||
osmo_store16be(smscb->message_id, ie->value.choice.Message_Identifier.buf);
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
/* static const long asn_VAL_2_SBcAP_id_Serial_Number = 11; */
|
||||
/* Serial Number
|
||||
* 3GPP TS 36.413 9.2.1.45, 3GPP TS 23.041 9.4.1.2.1
|
||||
* static const long asn_VAL_2_SBcAP_id_Serial_Number = 11; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(11, SBcAP_Criticality_reject,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Serial_Number);
|
||||
ie->value.choice.Serial_Number.buf = MALLOC(sizeof(uint16_t));
|
||||
@@ -124,7 +132,9 @@ SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg)
|
||||
break; /* Nothing to be done :*/
|
||||
#if 0
|
||||
case CBC_MSG_SCOPE_EUTRAN_CGI:
|
||||
/* static const long asn_VAL_25_SBcAP_id_Warning_Area_List = 15; */
|
||||
/* Warning Area List
|
||||
* 3GPP TS 36.413 9.2.1.46, 3GPP TS 23.041 9.3.30
|
||||
* static const long asn_VAL_25_SBcAP_id_Warning_Area_List = 15; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(15, SBcAP_Criticality_ignore,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Warning_Area_List);
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
@@ -136,35 +146,39 @@ SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg)
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
|
||||
/* static const long asn_VAL_5_SBcAP_id_Repetition_Period = 10; */
|
||||
/* Repetition Period
|
||||
* 3GPP TS 36.413 9.2.1.48, 3GPP TS 23.041 9.3.8
|
||||
* static const long asn_VAL_5_SBcAP_id_Repetition_Period = 10; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(10, SBcAP_Criticality_reject,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Repetition_Period);
|
||||
ie->value.choice.Repetition_Period = cbcmsg->rep_period; /*seconds */
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
/* static const long asn_VAL_7_SBcAP_id_Number_of_Broadcasts_Requested = 7; */
|
||||
/* Number of Broadcasts Requested
|
||||
* 3GPP TS 36.413 9.2.1.49, 3GPP TS 23.041 9.3.9
|
||||
* static const long asn_VAL_7_SBcAP_id_Number_of_Broadcasts_Requested = 7; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(7, SBcAP_Criticality_reject,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Number_of_Broadcasts_Requested);
|
||||
ie->value.choice.Number_of_Broadcasts_Requested = cbcmsg->num_bcast;
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
if (smscb->is_etws) {
|
||||
/* Warning Type, 3GPP TS 36.413 sec 9.2.1.50: */
|
||||
ie_warning_type = smscb->etws.warning_type;
|
||||
if (smscb->etws.user_alert)
|
||||
ie_warning_type |= 0x0100;
|
||||
if (smscb->etws.popup_on_display)
|
||||
ie_warning_type |= 0x0080;
|
||||
/* static const long asn_VAL_8_SBcAP_id_Warning_Type = 18; */
|
||||
/* Warning Type
|
||||
* 3GPP TS 36.413 sec 9.2.1.50, 3GPP TS 23.041 9.3.24
|
||||
* static const long asn_VAL_8_SBcAP_id_Warning_Type = 18; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(18, SBcAP_Criticality_ignore,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Warning_Type);
|
||||
ie->value.choice.Warning_Type.buf = MALLOC(sizeof(ie_warning_type));
|
||||
ie->value.choice.Warning_Type.size = sizeof(ie_warning_type);
|
||||
memcpy(ie->value.choice.Warning_Type.buf, &ie_warning_type, sizeof(ie_warning_type));
|
||||
ie->value.choice.Warning_Type.buf = MALLOC(2);
|
||||
ie->value.choice.Warning_Type.size = 2;
|
||||
ie->value.choice.Warning_Type.buf[0] = ((smscb->etws.warning_type & 0x7f) << 1);
|
||||
if (smscb->etws.user_alert)
|
||||
ie->value.choice.Warning_Type.buf[0] |= 0x01;
|
||||
ie->value.choice.Warning_Type.buf[1] = (smscb->etws.popup_on_display) ? 0x80 : 0x0;
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
/* Warning Security Information, 3GPP TS 36.413 sec 9.2.1.51: */
|
||||
/*static const long asn_VAL_9_SBcAP_id_Warning_Security_Information = 17 */
|
||||
/* Warning Security Information
|
||||
* 3GPP TS 36.413 sec 9.2.1.51, 3GPP TS 23.041 9.3.25
|
||||
* static const long asn_VAL_9_SBcAP_id_Warning_Security_Information = 17 */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(17, SBcAP_Criticality_ignore,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Warning_Security_Information);
|
||||
ie->value.choice.Warning_Security_Information.buf = MALLOC(sizeof(smscb->etws.warning_sec_info));
|
||||
@@ -174,7 +188,9 @@ SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg)
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
} else {
|
||||
/* static const long asn_VAL_10_SBcAP_id_Data_Coding_Scheme = 3; */
|
||||
/* Data Coding Scheme
|
||||
* 3GPP TS 36.413 9.2.1.52, 3GPP TS 23.041 9.4.1.2.3
|
||||
* static const long asn_VAL_10_SBcAP_id_Data_Coding_Scheme = 3; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(3, SBcAP_Criticality_ignore,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Data_Coding_Scheme);
|
||||
ie->value.choice.Data_Coding_Scheme.buf = MALLOC(1);
|
||||
@@ -183,8 +199,9 @@ SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg)
|
||||
*ie->value.choice.Data_Coding_Scheme.buf = smscb->cbs.dcs;
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
/* 3GPP TS 36.413 9.2.1.53 Warning Message Contents. Encoded as in S1AP. */
|
||||
/* static const long asn_VAL_11_SBcAP_id_Warning_Message_Content = 16; */
|
||||
/* Warning Message Contents
|
||||
* 3GPP TS 36.413 9.2.1.53, 3GPP TS 23.041 9.3.35
|
||||
* static const long asn_VAL_11_SBcAP_id_Warning_Message_Content = 16; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(16, SBcAP_Criticality_ignore,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Warning_Message_Content);
|
||||
ie->value.choice.Warning_Message_Content.buf = MALLOC(1 + smscb->cbs.num_pages * (SMSCB_RAW_PAGE_LEN+1));
|
||||
@@ -206,8 +223,24 @@ SBcAP_SBC_AP_PDU_t *cbcmsg_to_sbcap(void *ctx, const struct cbc_message *cbcmsg)
|
||||
ptr++;
|
||||
}
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
/* Concurrent Warning Message Indicator
|
||||
* 3GPP TS 36.413 8.12.1.2 and 9.2.1.72, 3GPP TS 23.041 9.3.32
|
||||
* static const long asn_VAL_13_SBcAP_id_Concurrent_Warning_Message_Indicator = 20; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(20, SBcAP_Criticality_reject,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Concurrent_Warning_Message_Indicator);
|
||||
ie->value.choice.Concurrent_Warning_Message_Indicator = SBcAP_Concurrent_Warning_Message_Indicator_true;
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
}
|
||||
|
||||
/* Send Write-Replace-Warning-Indication
|
||||
* 3GPP TS 36.413 4.3.4.3.5, 3GPP TS 23.041 9.3.39
|
||||
* static const long asn_VAL_14_SBcAP_id_Send_Write_Replace_Warning_Indication = 24; */
|
||||
ie = sbcap_alloc_Write_Replace_Warning_Request_IE(24, SBcAP_Criticality_ignore,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Send_Write_Replace_Warning_Indication);
|
||||
ie->value.choice.Send_Write_Replace_Warning_Indication = SBcAP_Send_Write_Replace_Warning_Indication_true;
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
@@ -231,7 +264,9 @@ SBcAP_SBC_AP_PDU_t *sbcap_gen_stop_warning_req(void *ctx, const struct cbc_messa
|
||||
|
||||
A_SEQUENCE_OF(void) *as_pdu = (void *)&pdu->choice.initiatingMessage.value.choice.Stop_Warning_Request.protocolIEs.list;
|
||||
|
||||
/* static const long asn_VAL_1_SBcAP_id_Message_Identifier = 5; */
|
||||
/* Message Identifier:
|
||||
* 3GPP TS 36.413 9.2.1.44, 3GPP TS 23.041 9.4.1.3.6
|
||||
* static const long asn_VAL_1_SBcAP_id_Message_Identifier = 5; */
|
||||
ie = sbcap_alloc_Stop_Warning_Request_IE(5, SBcAP_Criticality_reject,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Message_Identifier);
|
||||
ie->value.choice.Message_Identifier.buf = MALLOC(sizeof(uint16_t));
|
||||
@@ -240,7 +275,9 @@ SBcAP_SBC_AP_PDU_t *sbcap_gen_stop_warning_req(void *ctx, const struct cbc_messa
|
||||
osmo_store16be(smscb->message_id, ie->value.choice.Message_Identifier.buf);
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
/* static const long asn_VAL_2_SBcAP_id_Serial_Number = 11; */
|
||||
/* Serial Number
|
||||
* 3GPP TS 36.413 9.2.1.45, 3GPP TS 23.041 9.4.1.2.1
|
||||
* static const long asn_VAL_2_SBcAP_id_Serial_Number = 11; */
|
||||
ie = sbcap_alloc_Stop_Warning_Request_IE(11, SBcAP_Criticality_reject,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Serial_Number);
|
||||
ie->value.choice.Serial_Number.buf = MALLOC(sizeof(uint16_t));
|
||||
@@ -254,7 +291,9 @@ SBcAP_SBC_AP_PDU_t *sbcap_gen_stop_warning_req(void *ctx, const struct cbc_messa
|
||||
break; /* Nothing to be done :*/
|
||||
#if 0
|
||||
case CBC_MSG_SCOPE_EUTRAN_CGI:
|
||||
/* static const long asn_VAL_25_SBcAP_id_Warning_Area_List = 15; */
|
||||
/* Warning Area List
|
||||
* 3GPP TS 36.413 9.2.1.46, 3GPP TS 23.041 9.3.30
|
||||
* static const long asn_VAL_25_SBcAP_id_Warning_Area_List = 15; */
|
||||
ie = sbcap_alloc_Stop_Warning_Request_IE(15, SBcAP_Criticality_ignore,
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Warning_Area_List);
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
@@ -268,3 +307,68 @@ SBcAP_SBC_AP_PDU_t *sbcap_gen_stop_warning_req(void *ctx, const struct cbc_messa
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/* generate a SBc-AP ERROR INDICATION, 3GPP TS 29.168 4.3.4.2A.1.
|
||||
* rx_pdu can be NULL.
|
||||
*/
|
||||
SBcAP_SBC_AP_PDU_t *sbcap_gen_error_ind(void *ctx, SBcAP_Cause_t cause, SBcAP_SBC_AP_PDU_t *rx_pdu)
|
||||
{
|
||||
SBcAP_SBC_AP_PDU_t *pdu;
|
||||
SBcAP_ErrorIndicationIEs_t *ie;
|
||||
|
||||
pdu = sbcap_pdu_alloc();
|
||||
if (!pdu)
|
||||
return NULL;
|
||||
pdu->present = SBcAP_SBC_AP_PDU_PR_initiatingMessage;
|
||||
pdu->choice.initiatingMessage.procedureCode = SBcAP_ProcedureId_Error_Indication;
|
||||
pdu->choice.initiatingMessage.criticality = SBcAP_Criticality_ignore;
|
||||
pdu->choice.initiatingMessage.value.present = SBcAP_InitiatingMessage__value_PR_Error_Indication;
|
||||
|
||||
A_SEQUENCE_OF(void) *as_pdu = (void *)&pdu->choice.initiatingMessage.value.choice.Error_Indication.protocolIEs.list;
|
||||
|
||||
/* Cause, Optional:
|
||||
* 3GPP TS 36.413 4.3.4.3.2
|
||||
* static const long asn_VAL_19_SBcAP_id_Cause = 1; */
|
||||
ie = sbcap_alloc_Error_Indication_IE(1, SBcAP_Criticality_ignore,
|
||||
SBcAP_ErrorIndicationIEs__value_PR_Cause);
|
||||
ie->value.choice.Cause = cause;
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
if (rx_pdu) {
|
||||
SBcAP_Criticality_Diagnostics_t *diag_ie;
|
||||
/* Criticality Diagnostics, Optional:
|
||||
* 3GPP TS 36.413 4.3.4.3.3
|
||||
* static const long asn_VAL_20_SBcAP_id_Criticality_Diagnostics = 2; */
|
||||
ie = sbcap_alloc_Error_Indication_IE(1, SBcAP_Criticality_ignore,
|
||||
SBcAP_ErrorIndicationIEs__value_PR_Criticality_Diagnostics);
|
||||
diag_ie = &ie->value.choice.Criticality_Diagnostics;
|
||||
diag_ie->procedureCode = MALLOC(sizeof(*diag_ie->procedureCode));
|
||||
*diag_ie->procedureCode = sbcap_pdu_get_procedure_code(rx_pdu);
|
||||
diag_ie->triggeringMessage = MALLOC(sizeof(*diag_ie->triggeringMessage));
|
||||
*diag_ie->triggeringMessage = rx_pdu->present;
|
||||
diag_ie->procedureCriticality = MALLOC(sizeof(*diag_ie->procedureCriticality));
|
||||
*diag_ie->procedureCriticality = sbcap_pdu_get_criticality(rx_pdu);
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
}
|
||||
return pdu;
|
||||
}
|
||||
static void cci_from_sbcap_ecgi(struct cbc_cell_id *cci, const SBcAP_EUTRAN_CGI_t *eCGI)
|
||||
{
|
||||
cci->id_discr = CBC_CELL_ID_ECGI;
|
||||
cci->u.ecgi.eci = (osmo_load32be(&eCGI->cell_ID.buf[0]) >> 4);
|
||||
osmo_plmn_from_bcd(eCGI->pLMNidentity.buf, &cci->u.ecgi.plmn);
|
||||
}
|
||||
|
||||
/* Fill a cbc_cell_id from a SBcAP_CellId_Broadcast_List_Item */
|
||||
void cci_from_sbcap_bcast_cell_id(struct cbc_cell_id *cci, const SBcAP_CellId_Broadcast_List_Item_t *it)
|
||||
{
|
||||
cci_from_sbcap_ecgi(cci, &it->eCGI);
|
||||
}
|
||||
|
||||
/* Fill a cbc_cell_id from a SBcAP_TAI_t */
|
||||
void cci_from_sbcap_tai(struct cbc_cell_id *cci, const SBcAP_TAI_t *tai)
|
||||
{
|
||||
cci->id_discr = CBC_CELL_ID_TAI;
|
||||
cci->u.tai.tac = osmo_load16be(tai->tAC.buf);
|
||||
osmo_plmn_from_bcd(tai->pLMNidentity.buf, &cci->u.tai.plmn);
|
||||
}
|
||||
|
||||
373
src/sbcap_smscb_peer_fsm.c
Normal file
373
src/sbcap_smscb_peer_fsm.c
Normal file
@@ -0,0 +1,373 @@
|
||||
/* SMSCB Peer FSM: Represents state of one SMSCB for one peer (MME) */
|
||||
|
||||
/* This FSM exists per tuple of (message, mme peer) */
|
||||
|
||||
/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* 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/utils.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/gsm/protocol/gsm_08_08.h>
|
||||
#include <osmocom/gsm/gsm0808_utils.h>
|
||||
|
||||
#include <osmocom/sbcap/sbcap_common.h>
|
||||
|
||||
#include <osmocom/cbc/cbc_message.h>
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/sbcap_msg.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/smscb_peer_fsm.h>
|
||||
#include <osmocom/cbc/smscb_message_fsm.h>
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
/***********************************************************************
|
||||
* Helper functions
|
||||
***********************************************************************/
|
||||
|
||||
/* append SBcAP cells to msg_peer compl list */
|
||||
void msg_peer_append_compl_sbcap_bcast_area_list(struct cbc_message_peer *mp,
|
||||
const SBcAP_Broadcast_Scheduled_Area_List_t *bcast)
|
||||
{
|
||||
SBcAP_CellId_Broadcast_List_t *cell_id_bscat = bcast->cellId_Broadcast_List;
|
||||
A_SEQUENCE_OF(struct SBcAP_CellId_Broadcast_List_Item) *as_cell_id_bcast;
|
||||
SBcAP_CellId_Broadcast_List_Item_t *it;
|
||||
unsigned int i;
|
||||
|
||||
if (!cell_id_bscat)
|
||||
return;
|
||||
|
||||
as_cell_id_bcast = (void *) &cell_id_bscat->list;
|
||||
for (i = 0; i < as_cell_id_bcast->count; i++) {
|
||||
it = (SBcAP_CellId_Broadcast_List_Item_t *)(as_cell_id_bcast->array[i]);
|
||||
OSMO_ASSERT(it);
|
||||
struct cbc_cell_id *cci = NULL; // FIXME: lookup
|
||||
if (!cci) {
|
||||
cci = talloc_zero(mp, struct cbc_cell_id);
|
||||
if (!cci)
|
||||
return;
|
||||
llist_add_tail(&cci->list, &mp->num_compl_list);
|
||||
}
|
||||
cci_from_sbcap_bcast_cell_id(cci, it);
|
||||
LOGPFSML(mp->fi, LOGL_DEBUG, "Appending CellId %s to Broadcast Completed list\n",
|
||||
cbc_cell_id2str(cci));
|
||||
cci->num_compl.num_compl += 1;
|
||||
cci->num_compl.num_bcast_info += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* append SBcAP cells to msg_peer fail list */
|
||||
void msg_peer_append_fail_sbcap_tai_list(struct cbc_message_peer *mp,
|
||||
const SBcAP_List_of_TAIs_t *tais)
|
||||
{
|
||||
A_SEQUENCE_OF(List_of_TAIs__Member) *as_tais = (void *)&tais->list;
|
||||
List_of_TAIs__Member *it;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < as_tais->count; i++) {
|
||||
it = (List_of_TAIs__Member *)(as_tais->array[i]);
|
||||
OSMO_ASSERT(it);
|
||||
struct cbc_cell_id *cci = NULL; // FIXME: lookup
|
||||
if (!cci) {
|
||||
cci = talloc_zero(mp, struct cbc_cell_id);
|
||||
if (!cci)
|
||||
return;
|
||||
llist_add_tail(&cci->list, &mp->fail_list);
|
||||
}
|
||||
cci_from_sbcap_tai(cci, &it->tai);
|
||||
cci->fail.cause = SBcAP_Cause_tracking_area_not_valid;
|
||||
LOGPFSML(mp->fi, LOGL_DEBUG, "Appending CellId %s (cause: %s) to Failed list\n",
|
||||
cbc_cell_id2str(cci), sbcap_cause_str(cci->fail.cause));
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* actual FSM
|
||||
***********************************************************************/
|
||||
|
||||
static void smscb_p_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_CREATE:
|
||||
/* send it to peer */
|
||||
rc = peer_new_cbc_message(mp->peer, mp->cbcmsg);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_WRITE_ACK, 10, T_WAIT_WRITE_ACK);
|
||||
if (rc != 0) /* Immediately timeout the message */
|
||||
fi->fsm->timer_cb(fi);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_write_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
SBcAP_SBC_AP_PDU_t *sbcap = NULL;
|
||||
A_SEQUENCE_OF(void) *as_pdu;
|
||||
SBcAP_Write_Replace_Warning_Response_IEs_t *ie;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_SBCAP_WRITE_ACK:
|
||||
sbcap = data;
|
||||
OSMO_ASSERT(sbcap->present == SBcAP_SBC_AP_PDU_PR_successfulOutcome);
|
||||
OSMO_ASSERT(sbcap->choice.successfulOutcome.procedureCode == SBcAP_ProcedureId_Write_Replace_Warning);
|
||||
as_pdu = (void *)&sbcap->choice.successfulOutcome.value.choice.Write_Replace_Warning_Response.protocolIEs.list;
|
||||
/* static const long asn_VAL_21_SBcAP_id_Unknown_Tracking_Area_List = 22; */
|
||||
ie = sbcap_as_find_ie(as_pdu, 22);
|
||||
if (ie) { /* IE is optional */
|
||||
OSMO_ASSERT(ie->value.present == SBcAP_Write_Replace_Warning_Response_IEs__value_PR_List_of_TAIs);
|
||||
msg_peer_append_fail_sbcap_tai_list(mp, &ie->value.choice.List_of_TAIs);
|
||||
}
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_WRITE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_PEER_E_SBCAP_WRITE_NACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_WRITE_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_REPLACE: /* send WRITE-REPLACE to MME */
|
||||
/* NOT IMPLEMENETED */
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_REPLACE_ACK, 10, T_WAIT_REPLACE_ACK);
|
||||
break;
|
||||
case SMSCB_PEER_E_STATUS:
|
||||
/* NOT IMPLEMENETED */
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_STATUS_ACK, 10, T_WAIT_STATUS_ACK);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_status_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
|
||||
switch (event) {
|
||||
/* NOT IMPLEMENETED */
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void smscb_p_fsm_wait_replace_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
|
||||
switch (event) {
|
||||
/* NOT IMPLEMENETED */
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_delete_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_SBCAP_DELETE_ACK:
|
||||
//pdu = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_DELETE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_PEER_E_SBCAP_DELETE_NACK:
|
||||
//pdu = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_DELETE_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int smscb_p_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
switch (fi->T) {
|
||||
case T_WAIT_WRITE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_WRITE_NACK, NULL);
|
||||
break;
|
||||
case T_WAIT_REPLACE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_REPLACE_NACK, NULL);
|
||||
break;
|
||||
case T_WAIT_STATUS_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_STATUS_NACK, NULL);
|
||||
break;
|
||||
case T_WAIT_DELETE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_MSG_E_DELETE_NACK, NULL);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
SBcAP_SBC_AP_PDU_t *sbcap;
|
||||
A_SEQUENCE_OF(void) *as_pdu;
|
||||
SBcAP_Write_Replace_Warning_Indication_IEs_t *ie;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_PEER_E_DELETE: /* send Stop-Warning to MME */
|
||||
switch (fi->state) {
|
||||
case SMSCB_S_DELETED:
|
||||
case SMSCB_S_INIT:
|
||||
LOGPFSML(fi, LOGL_ERROR, "Event %s not permitted\n",
|
||||
osmo_fsm_event_name(fi->fsm, event));
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((sbcap = sbcap_gen_stop_warning_req(mp->peer, mp->cbcmsg))) {
|
||||
rc = cbc_sbcap_link_tx(mp->peer->link.sbcap, sbcap);
|
||||
} else {
|
||||
LOGP(DSBcAP, LOGL_ERROR,
|
||||
"[%s] Tx SBc-AP Stop-Warning-Request: msg gen failed\n",
|
||||
mp->peer->name);
|
||||
rc = -1;
|
||||
}
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_DELETE_ACK, 10, T_WAIT_DELETE_ACK);
|
||||
if (rc != 0) /* Immediately timeout the message */
|
||||
fi->fsm->timer_cb(fi);
|
||||
break;
|
||||
case SMSCB_PEER_E_SBCAP_WRITE_IND:
|
||||
sbcap = (SBcAP_SBC_AP_PDU_t *)data;
|
||||
OSMO_ASSERT(sbcap->present == SBcAP_SBC_AP_PDU_PR_initiatingMessage);
|
||||
OSMO_ASSERT(sbcap->choice.initiatingMessage.procedureCode == SBcAP_ProcedureId_Write_Replace_Warning_Indication);
|
||||
as_pdu = (void *)&sbcap->choice.initiatingMessage.value.choice.Write_Replace_Warning_Indication.protocolIEs.list;
|
||||
/* static const long asn_VAL_36_SBcAP_id_Broadcast_Scheduled_Area_List = 23; */
|
||||
ie = sbcap_as_find_ie(as_pdu, 23);
|
||||
if (!ie)
|
||||
return; /* IE is optional */
|
||||
OSMO_ASSERT(ie->value.present == SBcAP_Write_Replace_Warning_Indication_IEs__value_PR_Broadcast_Scheduled_Area_List);
|
||||
msg_peer_append_compl_sbcap_bcast_area_list(mp, &ie->value.choice.Broadcast_Scheduled_Area_List);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
llist_del(&mp->list);
|
||||
/* memory of mp is child of fi and hence automatically free'd */
|
||||
}
|
||||
|
||||
static const struct osmo_fsm_state smscb_p_fsm_states[] = {
|
||||
[SMSCB_S_INIT] = {
|
||||
.name = "INIT",
|
||||
.in_event_mask = S(SMSCB_PEER_E_CREATE),
|
||||
.out_state_mask = S(SMSCB_S_WAIT_WRITE_ACK) |
|
||||
S(SMSCB_S_ACTIVE),
|
||||
.action = smscb_p_fsm_init,
|
||||
},
|
||||
[SMSCB_S_WAIT_WRITE_ACK] = {
|
||||
.name = "WAIT_WRITE_ACK",
|
||||
.in_event_mask = S(SMSCB_PEER_E_SBCAP_WRITE_ACK) |
|
||||
S(SMSCB_PEER_E_SBCAP_WRITE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_write_ack,
|
||||
},
|
||||
[SMSCB_S_ACTIVE] = {
|
||||
.name = "ACTIVE",
|
||||
.in_event_mask = S(SMSCB_PEER_E_REPLACE) |
|
||||
S(SMSCB_PEER_E_STATUS),
|
||||
.out_state_mask = S(SMSCB_S_WAIT_REPLACE_ACK) |
|
||||
S(SMSCB_S_WAIT_STATUS_ACK) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_active,
|
||||
},
|
||||
[SMSCB_S_WAIT_STATUS_ACK] = {
|
||||
.name = "WAIT_STATUS_ACK",
|
||||
.in_event_mask = 0 /* NOT IMPLEMENTED */,
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_status_ack,
|
||||
},
|
||||
[SMSCB_S_WAIT_REPLACE_ACK] = {
|
||||
.name = "WAIT_REPLACE_ACK",
|
||||
.in_event_mask = 0 /* NOT IMPLEMENTED */,
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_replace_ack,
|
||||
},
|
||||
[SMSCB_S_WAIT_DELETE_ACK] = {
|
||||
.name = "WAIT_DELETE_ACK",
|
||||
.in_event_mask = S(SMSCB_PEER_E_SBCAP_DELETE_ACK) |
|
||||
S(SMSCB_PEER_E_SBCAP_DELETE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_DELETED),
|
||||
.action = smscb_p_fsm_wait_delete_ack,
|
||||
},
|
||||
[SMSCB_S_DELETED] = {
|
||||
.name = "DELETED",
|
||||
},
|
||||
};
|
||||
|
||||
struct osmo_fsm sbcap_smscb_peer_fsm = {
|
||||
.name = "SMSCB-PEER-SBcAP",
|
||||
.states = smscb_p_fsm_states,
|
||||
.num_states = ARRAY_SIZE(smscb_p_fsm_states),
|
||||
.allstate_event_mask = S(SMSCB_PEER_E_DELETE) |
|
||||
S(SMSCB_PEER_E_SBCAP_WRITE_IND),
|
||||
.allstate_action = smscb_p_fsm_allstate,
|
||||
.timer_cb = smscb_p_fsm_timer_cb,
|
||||
.log_subsys = DSBcAP,
|
||||
.event_names = smscb_peer_fsm_event_names,
|
||||
.cleanup = smscb_p_fsm_cleanup,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void on_dso_load_smscb_p_fsm(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&sbcap_smscb_peer_fsm) == 0);
|
||||
}
|
||||
@@ -35,20 +35,38 @@
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/rest_it_op.h>
|
||||
#include <osmocom/cbc/smscb_message_fsm.h>
|
||||
#include <osmocom/cbc/smscb_peer_fsm.h>
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
const struct value_string smscb_message_fsm_event_names[] = {
|
||||
{ SMSCB_MSG_E_CHILD_DIED, "CHILD_DIED" },
|
||||
{ SMSCB_MSG_E_CREATE, "CREATE" },
|
||||
{ SMSCB_MSG_E_REPLACE, "REPLACE" },
|
||||
{ SMSCB_MSG_E_STATUS, "STATUS" },
|
||||
{ SMSCB_MSG_E_DELETE, "DELETE" },
|
||||
{ SMSCB_MSG_E_WRITE_ACK, "WRITE_ACK" },
|
||||
{ SMSCB_MSG_E_WRITE_NACK, "WRITE_NACK" },
|
||||
{ SMSCB_MSG_E_REPLACE_ACK, "REPLACE_ACK" },
|
||||
{ SMSCB_MSG_E_REPLACE_NACK, "REPLACE_NACK" },
|
||||
{ SMSCB_MSG_E_DELETE_ACK, "DELETE_ACK" },
|
||||
{ SMSCB_MSG_E_DELETE_NACK, "DELETE_NACK" },
|
||||
{ SMSCB_MSG_E_STATUS_ACK, "STATUS_ACK" },
|
||||
{ SMSCB_MSG_E_STATUS_NACK, "STATUS_NACK" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static void smscb_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message *cbcmsg = fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CREATE:
|
||||
case SMSCB_MSG_E_CREATE:
|
||||
OSMO_ASSERT(!cbcmsg->it_op);
|
||||
cbcmsg->it_op = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_WRITE_ACK, 15, T_WAIT_WRITE_ACK);
|
||||
/* forward this event to all child FSMs (i.e. all smscb_message_peer) */
|
||||
osmo_fsm_inst_broadcast_children(fi, SMSCB_E_CREATE, NULL);
|
||||
osmo_fsm_inst_broadcast_children(fi, SMSCB_PEER_E_CREATE, NULL);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
@@ -61,14 +79,12 @@ static void smscb_fsm_wait_write_ack(struct osmo_fsm_inst *fi, uint32_t event, v
|
||||
struct osmo_fsm_inst *peer_fi;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CBSP_WRITE_ACK:
|
||||
case SMSCB_E_CBSP_WRITE_NACK:
|
||||
case SMSCB_E_SBCAP_WRITE_ACK:
|
||||
case SMSCB_E_SBCAP_WRITE_NACK:
|
||||
case SMSCB_MSG_E_WRITE_ACK:
|
||||
case SMSCB_MSG_E_WRITE_NACK:
|
||||
/* check if any per-peer children have not yet received the ACK or
|
||||
* timed out */
|
||||
llist_for_each_entry(peer_fi, &fi->proc.children, proc.child) {
|
||||
if (peer_fi->state == SMSCB_S_WAIT_WRITE_ACK)
|
||||
if (peer_fi->state != SMSCB_S_ACTIVE)
|
||||
return;
|
||||
}
|
||||
rest_it_op_set_http_result(cbcmsg->it_op, 201, "Created"); // FIXME: error cases
|
||||
@@ -92,26 +108,26 @@ static void smscb_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *dat
|
||||
struct cbc_message *cbcmsg = fi->priv;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_REPLACE:
|
||||
case SMSCB_MSG_E_REPLACE:
|
||||
OSMO_ASSERT(!cbcmsg->it_op);
|
||||
cbcmsg->it_op = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_REPLACE_ACK, 15, T_WAIT_REPLACE_ACK);
|
||||
/* forward this event to all child FSMs (i.e. all smscb_message_peer) */
|
||||
osmo_fsm_inst_broadcast_children(fi, SMSCB_E_REPLACE, data);
|
||||
osmo_fsm_inst_broadcast_children(fi, SMSCB_PEER_E_REPLACE, data);
|
||||
break;
|
||||
case SMSCB_E_STATUS:
|
||||
case SMSCB_MSG_E_STATUS:
|
||||
OSMO_ASSERT(!cbcmsg->it_op);
|
||||
cbcmsg->it_op = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_STATUS_ACK, 15, T_WAIT_STATUS_ACK);
|
||||
/* forward this event to all child FSMs (i.e. all smscb_message_peer) */
|
||||
osmo_fsm_inst_broadcast_children(fi, SMSCB_E_STATUS, data);
|
||||
osmo_fsm_inst_broadcast_children(fi, SMSCB_PEER_E_STATUS, data);
|
||||
break;
|
||||
case SMSCB_E_DELETE:
|
||||
case SMSCB_MSG_E_DELETE:
|
||||
OSMO_ASSERT(!cbcmsg->it_op);
|
||||
cbcmsg->it_op = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_DELETE_ACK, 15, T_WAIT_DELETE_ACK);
|
||||
/* forward this event to all child FSMs (i.e. all smscb_message_peer) */
|
||||
osmo_fsm_inst_broadcast_children(fi, SMSCB_E_DELETE, data);
|
||||
osmo_fsm_inst_broadcast_children(fi, SMSCB_PEER_E_DELETE, data);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
@@ -124,8 +140,8 @@ static void smscb_fsm_wait_replace_ack(struct osmo_fsm_inst *fi, uint32_t event,
|
||||
struct osmo_fsm_inst *peer_fi;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CBSP_REPLACE_ACK:
|
||||
case SMSCB_E_CBSP_REPLACE_NACK:
|
||||
case SMSCB_MSG_E_REPLACE_ACK:
|
||||
case SMSCB_MSG_E_REPLACE_NACK:
|
||||
llist_for_each_entry(peer_fi, &fi->proc.children, proc.child) {
|
||||
if (peer_fi->state == SMSCB_S_WAIT_REPLACE_ACK)
|
||||
return;
|
||||
@@ -152,8 +168,8 @@ static void smscb_fsm_wait_status_ack(struct osmo_fsm_inst *fi, uint32_t event,
|
||||
struct osmo_fsm_inst *peer_fi;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CBSP_STATUS_ACK:
|
||||
case SMSCB_E_CBSP_STATUS_NACK:
|
||||
case SMSCB_MSG_E_STATUS_ACK:
|
||||
case SMSCB_MSG_E_STATUS_NACK:
|
||||
llist_for_each_entry(peer_fi, &fi->proc.children, proc.child) {
|
||||
if (peer_fi->state == SMSCB_S_WAIT_STATUS_ACK)
|
||||
return;
|
||||
@@ -180,10 +196,8 @@ static void smscb_fsm_wait_delete_ack(struct osmo_fsm_inst *fi, uint32_t event,
|
||||
struct osmo_fsm_inst *peer_fi;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CBSP_DELETE_ACK:
|
||||
case SMSCB_E_CBSP_DELETE_NACK:
|
||||
case SMSCB_E_SBCAP_DELETE_ACK:
|
||||
case SMSCB_E_SBCAP_DELETE_NACK:
|
||||
case SMSCB_MSG_E_DELETE_ACK:
|
||||
case SMSCB_MSG_E_DELETE_NACK:
|
||||
llist_for_each_entry(peer_fi, &fi->proc.children, proc.child) {
|
||||
if (peer_fi->state != SMSCB_S_DELETED)
|
||||
return;
|
||||
@@ -223,25 +237,23 @@ static void smscb_fsm_deleted_onenter(struct osmo_fsm_inst *fi, uint32_t old_sta
|
||||
static struct osmo_fsm_state smscb_fsm_states[] = {
|
||||
[SMSCB_S_INIT] = {
|
||||
.name = "INIT",
|
||||
.in_event_mask = S(SMSCB_E_CREATE),
|
||||
.in_event_mask = S(SMSCB_MSG_E_CREATE),
|
||||
.out_state_mask = S(SMSCB_S_WAIT_WRITE_ACK),
|
||||
.action = smscb_fsm_init,
|
||||
},
|
||||
[SMSCB_S_WAIT_WRITE_ACK] = {
|
||||
.name = "WAIT_WRITE_ACK",
|
||||
.in_event_mask = S(SMSCB_E_CBSP_WRITE_ACK) |
|
||||
S(SMSCB_E_CBSP_WRITE_NACK) |
|
||||
S(SMSCB_E_SBCAP_WRITE_ACK) |
|
||||
S(SMSCB_E_SBCAP_WRITE_NACK),
|
||||
.in_event_mask = S(SMSCB_MSG_E_WRITE_ACK) |
|
||||
S(SMSCB_MSG_E_WRITE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE),
|
||||
.action = smscb_fsm_wait_write_ack,
|
||||
.onleave = smscb_fsm_wait_write_ack_onleave,
|
||||
},
|
||||
[SMSCB_S_ACTIVE] = {
|
||||
.name = "ACTIVE",
|
||||
.in_event_mask = S(SMSCB_E_REPLACE) |
|
||||
S(SMSCB_E_STATUS) |
|
||||
S(SMSCB_E_DELETE),
|
||||
.in_event_mask = S(SMSCB_MSG_E_REPLACE) |
|
||||
S(SMSCB_MSG_E_STATUS) |
|
||||
S(SMSCB_MSG_E_DELETE),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_REPLACE_ACK) |
|
||||
S(SMSCB_S_WAIT_STATUS_ACK) |
|
||||
@@ -250,26 +262,24 @@ static struct osmo_fsm_state smscb_fsm_states[] = {
|
||||
},
|
||||
[SMSCB_S_WAIT_REPLACE_ACK] = {
|
||||
.name = "WAIT_REPLACE_ACK",
|
||||
.in_event_mask = S(SMSCB_E_CBSP_REPLACE_ACK) |
|
||||
S(SMSCB_E_CBSP_REPLACE_NACK),
|
||||
.in_event_mask = S(SMSCB_MSG_E_REPLACE_ACK) |
|
||||
S(SMSCB_MSG_E_REPLACE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE),
|
||||
.action = smscb_fsm_wait_replace_ack,
|
||||
.onleave = smscb_fsm_wait_replace_ack_onleave,
|
||||
},
|
||||
[SMSCB_S_WAIT_STATUS_ACK] = {
|
||||
.name = "WAIT_STATUS_ACK",
|
||||
.in_event_mask = S(SMSCB_E_CBSP_STATUS_ACK) |
|
||||
S(SMSCB_E_CBSP_STATUS_NACK),
|
||||
.in_event_mask = S(SMSCB_MSG_E_STATUS_ACK) |
|
||||
S(SMSCB_MSG_E_STATUS_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE),
|
||||
.action = smscb_fsm_wait_status_ack,
|
||||
.onleave = smscb_fsm_wait_status_ack_onleave,
|
||||
},
|
||||
[SMSCB_S_WAIT_DELETE_ACK] = {
|
||||
.name = "WAIT_DELETE_ACK",
|
||||
.in_event_mask = S(SMSCB_E_CBSP_DELETE_ACK) |
|
||||
S(SMSCB_E_CBSP_DELETE_NACK) |
|
||||
S(SMSCB_E_SBCAP_DELETE_ACK) |
|
||||
S(SMSCB_E_SBCAP_DELETE_NACK),
|
||||
.in_event_mask = S(SMSCB_MSG_E_DELETE_ACK) |
|
||||
S(SMSCB_MSG_E_DELETE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_DELETED),
|
||||
.action = smscb_fsm_wait_delete_ack,
|
||||
.onleave = smscb_fsm_wait_delete_ack_onleave,
|
||||
@@ -287,19 +297,19 @@ static int smscb_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
switch (fi->T) {
|
||||
case T_WAIT_WRITE_ACK:
|
||||
/* onexit will take care of notifying the user */
|
||||
/* onleave will take care of notifying the user */
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
break;
|
||||
case T_WAIT_REPLACE_ACK:
|
||||
/* onexit will take care of notifying the user */
|
||||
/* onleave will take care of notifying the user */
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
break;
|
||||
case T_WAIT_STATUS_ACK:
|
||||
/* onexit will take care of notifying the user */
|
||||
/* onleave will take care of notifying the user */
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
break;
|
||||
case T_WAIT_DELETE_ACK:
|
||||
/* onexit will take care of notifying the user */
|
||||
/* onleave will take care of notifying the user */
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
break;
|
||||
default:
|
||||
@@ -311,7 +321,7 @@ static int smscb_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
static void smscb_fsm_allstate(struct osmo_fsm_inst *Fi, uint32_t event, void *data)
|
||||
{
|
||||
switch (event) {
|
||||
case SMSCB_E_CHILD_DIED:
|
||||
case SMSCB_MSG_E_CHILD_DIED:
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
@@ -332,11 +342,11 @@ static struct osmo_fsm smscb_fsm = {
|
||||
.name = "SMSCB",
|
||||
.states = smscb_fsm_states,
|
||||
.num_states = ARRAY_SIZE(smscb_fsm_states),
|
||||
.allstate_event_mask = S(SMSCB_E_CHILD_DIED),
|
||||
.allstate_event_mask = S(SMSCB_MSG_E_CHILD_DIED),
|
||||
.allstate_action = smscb_fsm_allstate,
|
||||
.timer_cb = smscb_fsm_timer_cb,
|
||||
.log_subsys = DCBSP,
|
||||
.event_names = smscb_fsm_event_names,
|
||||
.log_subsys = DSMSCB,
|
||||
.event_names = smscb_message_fsm_event_names,
|
||||
.cleanup= smscb_fsm_cleanup,
|
||||
};
|
||||
|
||||
@@ -349,7 +359,7 @@ struct cbc_message *cbc_message_alloc(void *ctx, const struct cbc_message *orig_
|
||||
char idbuf[32];
|
||||
|
||||
if (cbc_message_by_id(orig_msg->msg.message_id)) {
|
||||
LOGP(DCBSP, LOGL_ERROR, "Cannot create message_id %u (already exists)\n",
|
||||
LOGP(DSMSCB, LOGL_ERROR, "Cannot create message_id %u (already exists)\n",
|
||||
orig_msg->msg.message_id);
|
||||
return NULL;
|
||||
}
|
||||
@@ -357,13 +367,13 @@ struct cbc_message *cbc_message_alloc(void *ctx, const struct cbc_message *orig_
|
||||
snprintf(idbuf, sizeof(idbuf), "%s-%u", orig_msg->cbe_name, orig_msg->msg.message_id);
|
||||
fi = osmo_fsm_inst_alloc(&smscb_fsm, ctx, NULL, LOGL_INFO, idbuf);
|
||||
if (!fi) {
|
||||
LOGP(DCBSP, LOGL_ERROR, "Cannot allocate cbc_message fsm\n");
|
||||
LOGP(DSMSCB, LOGL_ERROR, "Cannot allocate cbc_message fsm\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
smscb = talloc(fi, struct cbc_message);
|
||||
if (!smscb) {
|
||||
LOGP(DCBSP, LOGL_ERROR, "Cannot allocate cbc_message\n");
|
||||
LOGP(DSMSCB, LOGL_ERROR, "Cannot allocate cbc_message\n");
|
||||
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
|
||||
return NULL;
|
||||
}
|
||||
@@ -384,6 +394,11 @@ struct cbc_message *cbc_message_alloc(void *ctx, const struct cbc_message *orig_
|
||||
return smscb;
|
||||
}
|
||||
|
||||
void cbc_message_free(struct cbc_message *cbcmsg)
|
||||
{
|
||||
osmo_fsm_inst_term(cbcmsg->fi, OSMO_FSM_TERM_REGULAR, NULL);
|
||||
}
|
||||
|
||||
__attribute__((constructor)) void smscb_fsm_constructor(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&smscb_fsm) == 0);
|
||||
|
||||
@@ -27,645 +27,54 @@
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/gsm/protocol/gsm_08_08.h>
|
||||
#include <osmocom/gsm/gsm0808_utils.h>
|
||||
#include <osmocom/gsm/cbsp.h>
|
||||
|
||||
#include <osmocom/sbcap/sbcap_common.h>
|
||||
|
||||
#include <osmocom/cbc/cbc_message.h>
|
||||
#include <osmocom/cbc/cbc_peer.h>
|
||||
#include <osmocom/cbc/cbsp_link.h>
|
||||
#include <osmocom/cbc/sbcap_link.h>
|
||||
#include <osmocom/cbc/sbcap_msg.h>
|
||||
#include <osmocom/cbc/debug.h>
|
||||
#include <osmocom/cbc/smscb_peer_fsm.h>
|
||||
#include <osmocom/cbc/smscb_message_fsm.h>
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
const struct value_string smscb_fsm_event_names[] = {
|
||||
{ SMSCB_E_CHILD_DIED, "CHILD_DIED" },
|
||||
{ SMSCB_E_CREATE, "CREATE" },
|
||||
{ SMSCB_E_REPLACE, "REPLACE" },
|
||||
{ SMSCB_E_STATUS, "STATUS" },
|
||||
{ SMSCB_E_DELETE, "DELETE" },
|
||||
{ SMSCB_E_CBSP_WRITE_ACK, "CBSP_WRITE_ACK" },
|
||||
{ SMSCB_E_CBSP_WRITE_NACK, "CBSP_WRITE_NACK" },
|
||||
{ SMSCB_E_CBSP_REPLACE_ACK, "CBSP_REPLACE_ACK" },
|
||||
{ SMSCB_E_CBSP_REPLACE_NACK, "CBSP_REPLACE_NACK" },
|
||||
{ SMSCB_E_CBSP_DELETE_ACK, "CBSP_DELETE_ACK" },
|
||||
{ SMSCB_E_CBSP_DELETE_NACK, "CBSP_DELETE_NACK" },
|
||||
{ SMSCB_E_CBSP_STATUS_ACK, "CBSP_STATUS_ACK" },
|
||||
{ SMSCB_E_CBSP_STATUS_NACK, "CBSP_STATUS_NACK" },
|
||||
{ SMSCB_E_SBCAP_WRITE_ACK, "SBcAP_WRITE_ACK" },
|
||||
{ SMSCB_E_SBCAP_WRITE_NACK, "SBcAP_WRITE_NACK" },
|
||||
{ SMSCB_E_SBCAP_DELETE_ACK, "SBcAP_DELETE_ACK" },
|
||||
{ SMSCB_E_SBCAP_DELETE_NACK, "SBcAP_DELETE_NACK" },
|
||||
const struct value_string smscb_peer_fsm_event_names[] = {
|
||||
{ SMSCB_PEER_E_CREATE, "CREATE" },
|
||||
{ SMSCB_PEER_E_REPLACE, "REPLACE" },
|
||||
{ SMSCB_PEER_E_STATUS, "STATUS" },
|
||||
{ SMSCB_PEER_E_DELETE, "DELETE" },
|
||||
{ SMSCB_PEER_E_CBSP_WRITE_ACK, "CBSP_WRITE_ACK" },
|
||||
{ SMSCB_PEER_E_CBSP_WRITE_NACK, "CBSP_WRITE_NACK" },
|
||||
{ SMSCB_PEER_E_CBSP_REPLACE_ACK, "CBSP_REPLACE_ACK" },
|
||||
{ SMSCB_PEER_E_CBSP_REPLACE_NACK, "CBSP_REPLACE_NACK" },
|
||||
{ SMSCB_PEER_E_CBSP_DELETE_ACK, "CBSP_DELETE_ACK" },
|
||||
{ SMSCB_PEER_E_CBSP_DELETE_NACK, "CBSP_DELETE_NACK" },
|
||||
{ SMSCB_PEER_E_CBSP_STATUS_ACK, "CBSP_STATUS_ACK" },
|
||||
{ SMSCB_PEER_E_CBSP_STATUS_NACK, "CBSP_STATUS_NACK" },
|
||||
{ SMSCB_PEER_E_SBCAP_WRITE_ACK, "SBcAP_WRITE_ACK" },
|
||||
{ SMSCB_PEER_E_SBCAP_WRITE_NACK, "SBcAP_WRITE_NACK" },
|
||||
{ SMSCB_PEER_E_SBCAP_DELETE_ACK, "SBcAP_DELETE_ACK" },
|
||||
{ SMSCB_PEER_E_SBCAP_DELETE_NACK, "SBcAP_DELETE_NACK" },
|
||||
{ SMSCB_PEER_E_SBCAP_WRITE_IND, "SBcAP_WRITE_IND" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
#if 0
|
||||
static const struct value_string smscb_p_fsm_timer_names[] = {
|
||||
OSMO_VALUE_STRING(T_WAIT_WRITE_ACK),
|
||||
OSMO_VALUE_STRING(T_WAIT_REPLACE_ACK),
|
||||
OSMO_VALUE_STRING(T_WAIT_DELETE_ACK),
|
||||
{ 0, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* Helper functions
|
||||
***********************************************************************/
|
||||
|
||||
/* covert TS 08.08 Cell Identity value to CBC internal type */
|
||||
static enum cbc_cell_id_type cci_discr_from_cell_id(enum CELL_IDENT id_discr)
|
||||
{
|
||||
switch (id_discr) {
|
||||
case CELL_IDENT_NO_CELL:
|
||||
return CBC_CELL_ID_NONE;
|
||||
case CELL_IDENT_WHOLE_GLOBAL:
|
||||
return CBC_CELL_ID_CGI;
|
||||
case CELL_IDENT_LAC_AND_CI:
|
||||
return CBC_CELL_ID_LAC_CI;
|
||||
case CELL_IDENT_CI:
|
||||
return CBC_CELL_ID_CI;
|
||||
case CELL_IDENT_LAI:
|
||||
return CBC_CELL_ID_LAI;
|
||||
case CELL_IDENT_LAC:
|
||||
return CBC_CELL_ID_LAC;
|
||||
case CELL_IDENT_BSS:
|
||||
return CBC_CELL_ID_BSS;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* covert CBC internal type to TS 08.08 Cell Identity */
|
||||
static enum CELL_IDENT cell_id_from_ccid_discr(enum cbc_cell_id_type in)
|
||||
{
|
||||
switch (in) {
|
||||
case CBC_CELL_ID_NONE:
|
||||
return CELL_IDENT_NO_CELL;
|
||||
case CBC_CELL_ID_CGI:
|
||||
return CELL_IDENT_WHOLE_GLOBAL;
|
||||
case CBC_CELL_ID_LAC_CI:
|
||||
return CELL_IDENT_LAC_AND_CI;
|
||||
case CBC_CELL_ID_CI:
|
||||
return CELL_IDENT_CI;
|
||||
case CBC_CELL_ID_LAI:
|
||||
return CELL_IDENT_LAI;
|
||||
case CBC_CELL_ID_LAC:
|
||||
return CELL_IDENT_LAC;
|
||||
case CBC_CELL_ID_BSS:
|
||||
return CELL_IDENT_BSS;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert TS 08.08 Cell Identifier Union to CBC internal type */
|
||||
static void cci_from_cbsp(struct cbc_cell_id *cci, enum CELL_IDENT id_discr,
|
||||
const union gsm0808_cell_id_u *u)
|
||||
{
|
||||
cci->id_discr = cci_discr_from_cell_id(id_discr);
|
||||
|
||||
switch (id_discr) {
|
||||
case CELL_IDENT_NO_CELL:
|
||||
break;
|
||||
case CELL_IDENT_WHOLE_GLOBAL:
|
||||
cci->u.cgi = u->global;
|
||||
break;
|
||||
case CELL_IDENT_LAC_AND_CI:
|
||||
cci->u.lac_and_ci = u->lac_and_ci;
|
||||
break;
|
||||
case CELL_IDENT_CI:
|
||||
cci->u.ci = u->ci;
|
||||
break;
|
||||
case CELL_IDENT_LAI:
|
||||
cci->u.lai = u->lai_and_lac;
|
||||
break;
|
||||
case CELL_IDENT_LAC:
|
||||
cci->u.lac = u->lac;
|
||||
break;
|
||||
case CELL_IDENT_BSS:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert TS 08.08 Cell Identifier Union to CBC internal type */
|
||||
static void cbsp_from_cci(union gsm0808_cell_id_u *u, const struct cbc_cell_id *cci)
|
||||
{
|
||||
switch (cci->id_discr) {
|
||||
case CBC_CELL_ID_NONE:
|
||||
break;
|
||||
case CBC_CELL_ID_CGI:
|
||||
u->global = cci->u.cgi;
|
||||
printf("u->gobal: %s\n", osmo_hexdump((uint8_t *) &u->global, sizeof(u->global)));
|
||||
break;
|
||||
case CBC_CELL_ID_LAC_CI:
|
||||
u->lac_and_ci = cci->u.lac_and_ci;
|
||||
break;
|
||||
case CBC_CELL_ID_CI:
|
||||
u->ci = cci->u.ci;
|
||||
break;
|
||||
case CBC_CELL_ID_LAI:
|
||||
u->lai_and_lac = cci->u.lai;
|
||||
break;
|
||||
case CBC_CELL_ID_LAC:
|
||||
u->lac = cci->u.lac;
|
||||
break;
|
||||
case CBC_CELL_ID_BSS:
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* read a single osmo_cbsp_num_compl_ent and add it to cbc_message_peer */
|
||||
static void cci_from_cbsp_compl_ent(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_num_compl_ent *ce, enum CELL_IDENT id_discr)
|
||||
{
|
||||
struct cbc_cell_id *cci;
|
||||
|
||||
cci = NULL; // FIXME: lookup
|
||||
if (!cci) {
|
||||
cci = talloc_zero(mp, struct cbc_cell_id);
|
||||
if (!cci)
|
||||
return;
|
||||
llist_add_tail(&cci->list, &mp->num_compl_list);
|
||||
}
|
||||
cci_from_cbsp(cci, id_discr, &ce->cell_id);
|
||||
cci->num_compl.num_compl += ce->num_compl;
|
||||
cci->num_compl.num_bcast_info += ce->num_bcast_info;
|
||||
}
|
||||
static void msg_peer_append_cbsp_compl(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_num_compl_list *nclist)
|
||||
{
|
||||
struct osmo_cbsp_num_compl_ent *ce;
|
||||
|
||||
llist_for_each_entry(ce, &nclist->list, list)
|
||||
cci_from_cbsp_compl_ent(mp, ce, nclist->id_discr);
|
||||
}
|
||||
|
||||
/* read a single osmo_cbsp_cell_ent and add it to cbc_message_peer */
|
||||
static void cci_from_cbsp_cell_ent(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_cell_ent *ce, enum CELL_IDENT id_discr)
|
||||
{
|
||||
struct cbc_cell_id *cci;
|
||||
|
||||
cci = NULL; // FIXME: lookup
|
||||
if (!cci) {
|
||||
cci = talloc_zero(mp, struct cbc_cell_id);
|
||||
if (!cci)
|
||||
return;
|
||||
llist_add_tail(&cci->list, &mp->cell_list);
|
||||
}
|
||||
cci_from_cbsp(cci, id_discr, &ce->cell_id);
|
||||
}
|
||||
static void msg_peer_append_cbsp_cell(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_cell_list *clist)
|
||||
{
|
||||
struct osmo_cbsp_cell_ent *ce;
|
||||
|
||||
llist_for_each_entry(ce, &clist->list, list)
|
||||
cci_from_cbsp_cell_ent(mp, ce, clist->id_discr);
|
||||
}
|
||||
|
||||
/* read a single osmo_cbsp_fail_ent and add it to cbc_message_peer */
|
||||
static void cci_from_cbsp_fail_ent(struct cbc_message_peer *mp,
|
||||
struct osmo_cbsp_fail_ent *fe)
|
||||
{
|
||||
struct cbc_cell_id *cci;
|
||||
cci = NULL; // lookup */
|
||||
if (!cci) {
|
||||
cci = talloc_zero(mp, struct cbc_cell_id);
|
||||
if (!cci)
|
||||
return;
|
||||
llist_add_tail(&cci->list, &mp->fail_list);
|
||||
}
|
||||
cci->id_discr = cci_discr_from_cell_id(fe->id_discr);
|
||||
cci->fail.cause = fe->cause;
|
||||
}
|
||||
static void msg_peer_append_cbsp_fail(struct cbc_message_peer *mp, struct llist_head *flist)
|
||||
{
|
||||
struct osmo_cbsp_fail_ent *fe;
|
||||
|
||||
llist_for_each_entry(fe, flist, list)
|
||||
cci_from_cbsp_fail_ent(mp, fe);
|
||||
}
|
||||
|
||||
/* append all cells from cbc_message_peer to given CBSP cell_list */
|
||||
static void cbsp_append_cell_list(struct osmo_cbsp_cell_list *out, void *ctx,
|
||||
const struct cbc_message_peer *mp)
|
||||
{
|
||||
struct cbc_cell_id *cci;
|
||||
enum cbc_cell_id_type id_discr = CBC_CELL_ID_NONE;
|
||||
|
||||
llist_for_each_entry(cci, &mp->cell_list, list) {
|
||||
struct osmo_cbsp_cell_ent *ent;
|
||||
|
||||
if (id_discr == CBC_CELL_ID_NONE)
|
||||
id_discr = cci->id_discr;
|
||||
else if (id_discr != cci->id_discr) {
|
||||
LOGPFSML(mp->fi, LOGL_ERROR, "Cannot encode CBSP cell_list as not all "
|
||||
"entries are of same type (%u != %u)\n", id_discr, cci->id_discr);
|
||||
continue;
|
||||
}
|
||||
ent = talloc_zero(ctx, struct osmo_cbsp_cell_ent);
|
||||
OSMO_ASSERT(ent);
|
||||
cbsp_from_cci(&ent->cell_id, cci);
|
||||
llist_add_tail(&ent->list, &out->list);
|
||||
}
|
||||
out->id_discr = cell_id_from_ccid_discr(id_discr);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* actual FSM
|
||||
***********************************************************************/
|
||||
|
||||
static void smscb_p_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CREATE:
|
||||
/* send it to peer */
|
||||
rc = peer_new_cbc_message(mp->peer, mp->cbcmsg);
|
||||
if (rc == 0) {
|
||||
/* wait for peers' response */
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_WRITE_ACK, 10,
|
||||
T_WAIT_WRITE_ACK);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_write_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *dec = NULL;
|
||||
//SBcAP_SBC_AP_PDU_t *pdu = NULL;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CBSP_WRITE_ACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.write_replace_compl.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.write_replace_compl.cell_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_WRITE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_E_CBSP_WRITE_NACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.write_replace_fail.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.write_replace_fail.cell_list);
|
||||
msg_peer_append_cbsp_fail(mp, &dec->u.write_replace_fail.fail_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_WRITE_NACK, mp);
|
||||
break;
|
||||
case SMSCB_E_SBCAP_WRITE_ACK:
|
||||
//pdu = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_SBCAP_WRITE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_E_SBCAP_WRITE_NACK:
|
||||
//pdu = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_SBCAP_WRITE_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *cbsp;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_REPLACE: /* send WRITE-REPLACE to BSC */
|
||||
cbsp = osmo_cbsp_decoded_alloc(mp->peer, CBSP_MSGT_WRITE_REPLACE);
|
||||
OSMO_ASSERT(cbsp);
|
||||
cbsp->u.write_replace.msg_id = mp->cbcmsg->msg.message_id;
|
||||
cbsp->u.write_replace.old_serial_nr = &mp->cbcmsg->msg.serial_nr;
|
||||
//cbsp->u.write_replace.new_serial_nr
|
||||
/* TODO: we assume that the replace will always affect all original cells */
|
||||
cbsp_append_cell_list(&cbsp->u.write_replace.cell_list, cbsp, mp);
|
||||
// TODO: ALL OTHER DATA
|
||||
cbc_cbsp_link_tx(mp->peer->link.cbsp, cbsp);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_REPLACE_ACK, 10, T_WAIT_REPLACE_ACK);
|
||||
break;
|
||||
case SMSCB_E_STATUS: /* send MSG-STATUS-QUERY to BSC */
|
||||
cbsp = osmo_cbsp_decoded_alloc(mp->peer, CBSP_MSGT_MSG_STATUS_QUERY);
|
||||
OSMO_ASSERT(cbsp);
|
||||
cbsp->u.msg_status_query.msg_id = mp->cbcmsg->msg.message_id;
|
||||
cbsp->u.msg_status_query.old_serial_nr = mp->cbcmsg->msg.serial_nr;
|
||||
cbsp_append_cell_list(&cbsp->u.msg_status_query.cell_list, cbsp, mp);
|
||||
cbsp->u.msg_status_query.channel_ind = CBSP_CHAN_IND_BASIC;
|
||||
cbc_cbsp_link_tx(mp->peer->link.cbsp, cbsp);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_STATUS_ACK, 10, T_WAIT_STATUS_ACK);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_status_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *dec = NULL;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CBSP_STATUS_ACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.msg_status_query_compl.num_compl_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_STATUS_ACK, mp);
|
||||
break;
|
||||
case SMSCB_E_CBSP_STATUS_NACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.msg_status_query_fail.num_compl_list);
|
||||
msg_peer_append_cbsp_fail(mp, &dec->u.msg_status_query_fail.fail_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_STATUS_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void smscb_p_fsm_wait_replace_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *dec = NULL;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CBSP_REPLACE_ACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.write_replace_compl.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.write_replace_compl.cell_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_REPLACE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_E_CBSP_REPLACE_NACK:
|
||||
dec = data;
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.write_replace_fail.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.write_replace_fail.cell_list);
|
||||
msg_peer_append_cbsp_fail(mp, &dec->u.write_replace_fail.fail_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_REPLACE_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_wait_delete_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *dec = NULL;
|
||||
//SBcAP_SBC_AP_PDU_t *pdu = NULL;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_CBSP_DELETE_ACK:
|
||||
dec = data;
|
||||
/* append results */
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.kill_compl.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.kill_compl.cell_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_DELETE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_E_CBSP_DELETE_NACK:
|
||||
dec = data;
|
||||
/* append results */
|
||||
msg_peer_append_cbsp_compl(mp, &dec->u.kill_fail.num_compl_list);
|
||||
msg_peer_append_cbsp_cell(mp, &dec->u.kill_fail.cell_list);
|
||||
msg_peer_append_cbsp_fail(mp, &dec->u.kill_fail.fail_list);
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_DELETE_NACK, mp);
|
||||
break;
|
||||
case SMSCB_E_SBCAP_DELETE_ACK:
|
||||
//pdu = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_SBCAP_DELETE_ACK, mp);
|
||||
break;
|
||||
case SMSCB_E_SBCAP_DELETE_NACK:
|
||||
//pdu = data;
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
/* Signal parent fsm about completion */
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_SBCAP_DELETE_NACK, mp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int smscb_p_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *)fi->priv;
|
||||
int ev;
|
||||
switch (fi->T) {
|
||||
case T_WAIT_WRITE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
switch (mp->peer->proto) {
|
||||
case CBC_PEER_PROTO_CBSP:
|
||||
ev = SMSCB_E_CBSP_WRITE_NACK;
|
||||
break;
|
||||
case CBC_PEER_PROTO_SBcAP:
|
||||
ev = SMSCB_E_SBCAP_WRITE_NACK;
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, ev, NULL);
|
||||
break;
|
||||
case T_WAIT_REPLACE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_REPLACE_NACK, NULL);
|
||||
break;
|
||||
case T_WAIT_STATUS_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_ACTIVE, 0, 0);
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, SMSCB_E_CBSP_STATUS_NACK, NULL);
|
||||
break;
|
||||
case T_WAIT_DELETE_ACK:
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_DELETED, 0, 0);
|
||||
switch (mp->peer->proto) {
|
||||
case CBC_PEER_PROTO_CBSP:
|
||||
ev = SMSCB_E_CBSP_DELETE_NACK;
|
||||
break;
|
||||
case CBC_PEER_PROTO_SBcAP:
|
||||
ev = SMSCB_E_SBCAP_DELETE_NACK;
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
osmo_fsm_inst_dispatch(fi->proc.parent, ev, NULL);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
struct osmo_cbsp_decoded *cbsp;
|
||||
SBcAP_SBC_AP_PDU_t *sbcap;
|
||||
|
||||
switch (event) {
|
||||
case SMSCB_E_DELETE: /* send KILL to BSC */
|
||||
switch (fi->state) {
|
||||
case SMSCB_S_DELETED:
|
||||
case SMSCB_S_INIT:
|
||||
LOGPFSML(fi, LOGL_ERROR, "Event %s not permitted\n",
|
||||
osmo_fsm_event_name(fi->fsm, event));
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (mp->peer->proto) {
|
||||
case CBC_PEER_PROTO_CBSP:
|
||||
cbsp = osmo_cbsp_decoded_alloc(mp->peer, CBSP_MSGT_KILL);
|
||||
OSMO_ASSERT(cbsp);
|
||||
cbsp->u.kill.msg_id = mp->cbcmsg->msg.message_id;
|
||||
cbsp->u.kill.old_serial_nr = mp->cbcmsg->msg.serial_nr;
|
||||
/* TODO: we assume that the delete will always affect all original cells */
|
||||
cbsp_append_cell_list(&cbsp->u.kill.cell_list, cbsp, mp);
|
||||
if (!mp->cbcmsg->msg.is_etws) {
|
||||
/* Channel Indication IE is only present in CBS, not in ETWS! */
|
||||
cbsp->u.kill.channel_ind = talloc_zero(cbsp, enum cbsp_channel_ind);
|
||||
OSMO_ASSERT(cbsp->u.kill.channel_ind);
|
||||
*(cbsp->u.kill.channel_ind) = CBSP_CHAN_IND_BASIC;
|
||||
}
|
||||
cbc_cbsp_link_tx(mp->peer->link.cbsp, cbsp);
|
||||
break;
|
||||
case CBC_PEER_PROTO_SBcAP:
|
||||
if ((sbcap = sbcap_gen_stop_warning_req(mp->peer, mp->cbcmsg))) {
|
||||
cbc_sbcap_link_tx(mp->peer->link.sbcap, sbcap);
|
||||
} else {
|
||||
LOGP(DSBcAP, LOGL_ERROR,
|
||||
"[%s] Tx SBc-AP Stop-Warning-Request: msg gen failed\n",
|
||||
mp->peer->name);
|
||||
}
|
||||
break;
|
||||
case CBC_PEER_PROTO_SABP:
|
||||
default:
|
||||
osmo_panic("SMSCB_E_DELETE not implemented for proto %u", mp->peer->proto);
|
||||
}
|
||||
osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_DELETE_ACK, 10, T_WAIT_DELETE_ACK);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void smscb_p_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
|
||||
{
|
||||
struct cbc_message_peer *mp = (struct cbc_message_peer *) fi->priv;
|
||||
llist_del(&mp->list);
|
||||
/* memory of mp is child of fi and hence automatically free'd */
|
||||
}
|
||||
|
||||
static const struct osmo_fsm_state smscb_p_fsm_states[] = {
|
||||
[SMSCB_S_INIT] = {
|
||||
.name = "INIT",
|
||||
.in_event_mask = S(SMSCB_E_CREATE),
|
||||
.out_state_mask = S(SMSCB_S_WAIT_WRITE_ACK),
|
||||
.action = smscb_p_fsm_init,
|
||||
},
|
||||
[SMSCB_S_WAIT_WRITE_ACK] = {
|
||||
.name = "WAIT_WRITE_ACK",
|
||||
.in_event_mask = S(SMSCB_E_CBSP_WRITE_ACK) |
|
||||
S(SMSCB_E_CBSP_WRITE_NACK) |
|
||||
S(SMSCB_E_SBCAP_WRITE_ACK) |
|
||||
S(SMSCB_E_SBCAP_WRITE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_write_ack,
|
||||
},
|
||||
[SMSCB_S_ACTIVE] = {
|
||||
.name = "ACTIVE",
|
||||
.in_event_mask = S(SMSCB_E_REPLACE) |
|
||||
S(SMSCB_E_STATUS),
|
||||
.out_state_mask = S(SMSCB_S_WAIT_REPLACE_ACK) |
|
||||
S(SMSCB_S_WAIT_STATUS_ACK) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_active,
|
||||
},
|
||||
[SMSCB_S_WAIT_STATUS_ACK] = {
|
||||
.name = "WAIT_STATUS_ACK",
|
||||
.in_event_mask = S(SMSCB_E_CBSP_STATUS_ACK) |
|
||||
S(SMSCB_E_CBSP_STATUS_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_status_ack,
|
||||
},
|
||||
[SMSCB_S_WAIT_REPLACE_ACK] = {
|
||||
.name = "WAIT_REPLACE_ACK",
|
||||
.in_event_mask = S(SMSCB_E_CBSP_REPLACE_ACK) |
|
||||
S(SMSCB_E_CBSP_REPLACE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_ACTIVE) |
|
||||
S(SMSCB_S_WAIT_DELETE_ACK),
|
||||
.action = smscb_p_fsm_wait_replace_ack,
|
||||
},
|
||||
[SMSCB_S_WAIT_DELETE_ACK] = {
|
||||
.name = "WAIT_DELETE_ACK",
|
||||
.in_event_mask = S(SMSCB_E_CBSP_DELETE_ACK) |
|
||||
S(SMSCB_E_CBSP_DELETE_NACK) |
|
||||
S(SMSCB_E_SBCAP_DELETE_ACK) |
|
||||
S(SMSCB_E_SBCAP_DELETE_NACK),
|
||||
.out_state_mask = S(SMSCB_S_DELETED),
|
||||
.action = smscb_p_fsm_wait_delete_ack,
|
||||
},
|
||||
[SMSCB_S_DELETED] = {
|
||||
.name = "DELETED",
|
||||
},
|
||||
};
|
||||
|
||||
struct osmo_fsm smscb_p_fsm = {
|
||||
.name = "SMSCB-PEER",
|
||||
.states = smscb_p_fsm_states,
|
||||
.num_states = ARRAY_SIZE(smscb_p_fsm_states),
|
||||
.allstate_event_mask = S(SMSCB_E_DELETE),
|
||||
.allstate_action = smscb_p_fsm_allstate,
|
||||
.timer_cb = smscb_p_fsm_timer_cb,
|
||||
.log_subsys = DCBSP,
|
||||
.event_names = smscb_fsm_event_names,
|
||||
.cleanup = smscb_p_fsm_cleanup,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void on_dso_load_smscb_p_fsm(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&smscb_p_fsm) == 0);
|
||||
}
|
||||
|
||||
struct cbc_message_peer *smscb_peer_fsm_alloc(struct cbc_peer *peer, struct cbc_message *cbcmsg)
|
||||
{
|
||||
struct cbc_message_peer *mp;
|
||||
struct osmo_fsm_inst *fi;
|
||||
struct osmo_fsm *fsm_def;
|
||||
|
||||
fi = osmo_fsm_inst_alloc_child(&smscb_p_fsm, cbcmsg->fi, SMSCB_E_CHILD_DIED);
|
||||
switch (peer->proto) {
|
||||
case CBC_PEER_PROTO_CBSP:
|
||||
fsm_def = &cbsp_smscb_peer_fsm;
|
||||
break;
|
||||
case CBC_PEER_PROTO_SBcAP:
|
||||
fsm_def = &sbcap_smscb_peer_fsm;
|
||||
break;
|
||||
case CBC_PEER_PROTO_SABP:
|
||||
default:
|
||||
osmo_panic("smscb_peer FSM not implemented for proto %u", peer->proto);
|
||||
}
|
||||
fi = osmo_fsm_inst_alloc_child(fsm_def, cbcmsg->fi, SMSCB_MSG_E_CHILD_DIED);
|
||||
if (!fi)
|
||||
return NULL;
|
||||
/* include the peer name in the ID of the child FSM */
|
||||
|
||||
@@ -19,6 +19,7 @@ AM_CFLAGS = \
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
-no-install \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
@@ -34,6 +35,7 @@ sbcap_test_SOURCES = \
|
||||
$(NULL)
|
||||
|
||||
sbcap_test_LDADD = \
|
||||
$(top_builddir)/src/sbcap/libosmo-sbcap.la \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
@@ -42,5 +44,4 @@ sbcap_test_LDADD = \
|
||||
$(JANSSON_LIBS) \
|
||||
$(ORCANIA_LIBS) \
|
||||
$(LIBSCTP_LIBS) \
|
||||
$(top_builddir)/src/sbcap/libosmo-sbcap.la \
|
||||
$(NULL)
|
||||
|
||||
@@ -14,7 +14,7 @@ void test_asn1c_enc(void)
|
||||
struct msgb *msg;
|
||||
SBcAP_SBC_AP_PDU_t *pdu;
|
||||
SBcAP_Write_Replace_Warning_Request_IEs_t *ie;
|
||||
uint16_t ie_warning_type = 0x01;
|
||||
uint8_t ie_warning_type[2] = {(0x01 << 1) | 0x01, 0x80};
|
||||
uint8_t ie_dcs = 2;
|
||||
uint8_t ie_warning_sec_info[50] = {0x30, 0x40, 0x12, 0x23, 0x45};
|
||||
uint8_t ie_warning_msg_content[SBCAP_WARN_MSG_CONTENTS_IE_MAX_LEN] = {0x30, 0x40, 0x12, 0x23, 0x45};
|
||||
@@ -68,8 +68,6 @@ void test_asn1c_enc(void)
|
||||
SBcAP_Write_Replace_Warning_Request_IEs__value_PR_Warning_Type);
|
||||
ie->value.choice.Warning_Type.buf = MALLOC(sizeof(ie_warning_type));
|
||||
ie->value.choice.Warning_Type.size = sizeof(ie_warning_type);
|
||||
ie_warning_type |= 0x0100;
|
||||
ie_warning_type |= 0x0080;
|
||||
memcpy(ie->value.choice.Warning_Type.buf, &ie_warning_type, sizeof(ie_warning_type));
|
||||
ASN_SEQUENCE_ADD(as_pdu, ie);
|
||||
|
||||
@@ -204,8 +202,8 @@ SBc Application Part
|
||||
|
||||
static const struct log_info_cat log_categories[] = {
|
||||
[0] = {
|
||||
.name = "DSBcAP",
|
||||
.description = "SBc Application Part (CBC-MME)",
|
||||
.name = "DMAIN",
|
||||
.description = "main category",
|
||||
.color = "\033[1;32m",
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_DEBUG,
|
||||
@@ -222,7 +220,7 @@ int main(int argc, char **argv)
|
||||
void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
|
||||
void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
|
||||
osmo_init_logging2(ctx, &log_info);
|
||||
sbcap_set_log_area(0);
|
||||
sbcap_set_log_area(0, 0);
|
||||
log_set_log_level(osmo_stderr_target, LOGL_DEBUG);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 0);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
==== test_asn1c_enc ====
|
||||
Encoded message: 00 00 00 76 00 00 08 00 05 00 02 ab 01 00 0b 00 02 ab cd 00 0a 00 02 00 1e 00 07 00 02 00 59 00 12 40 02 81 01 00 11 40 32 30 40 12 23 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 40 01 02 00 10 40 16 00 13 30 40 12 23 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
Encoded message: 00 00 00 76 00 00 08 00 05 00 02 ab 01 00 0b 00 02 ab cd 00 0a 00 02 00 1e 00 07 00 02 00 59 00 12 40 02 03 80 00 11 40 32 30 40 12 23 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 40 01 02 00 10 40 16 00 13 30 40 12 23 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
==== test_asn1c_dec ====
|
||||
Decoding message: 20 00 00 14 00 00 03 00 05 00 02 00 2b 00 0b 00 02 41 70 00 01 00 01 00
|
||||
Decoded message successfully
|
||||
|
||||
Reference in New Issue
Block a user