pespin has submitted this change. (
https://gerrit.osmocom.org/c/osmo-cbc/+/28828 )
Change subject: Split smscb_peer_fsm into CBSP and SBcAP specific FSMs
......................................................................
Split smscb_peer_fsm into CBSP and SBcAP specific FSMs
This further simplifies tracking of events and simplifies and clears
code on each of the FSMs.
Change-Id: I0fd00b60cdc6bc6a088be1336d849548ca89c847
---
M include/osmocom/cbc/smscb_peer_fsm.h
M src/Makefile.am
A src/cbsp_smscb_peer_fsm.c
A src/sbcap_smscb_peer_fsm.c
M src/smscb_peer_fsm.c
5 files changed, 952 insertions(+), 665 deletions(-)
Approvals:
pespin: Looks good to me, approved; Verified
osmith: Looks good to me, but someone else must approve
diff --git a/include/osmocom/cbc/smscb_peer_fsm.h b/include/osmocom/cbc/smscb_peer_fsm.h
index 7bf1c54..7ae8968 100644
--- a/include/osmocom/cbc/smscb_peer_fsm.h
+++ b/include/osmocom/cbc/smscb_peer_fsm.h
@@ -35,3 +35,6 @@
};
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;
diff --git a/src/Makefile.am b/src/Makefile.am
index de40dea..ade53d0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,14 +18,16 @@
cbsp_link.c \
cbsp_link_fsm.c \
cbsp_msg.c \
+ cbsp_smscb_peer_fsm.c \
rest_api.c \
charset.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) \
diff --git a/src/cbsp_smscb_peer_fsm.c b/src/cbsp_smscb_peer_fsm.c
new file mode 100644
index 0000000..872008c
--- /dev/null
+++ b/src/cbsp_smscb_peer_fsm.c
@@ -0,0 +1,563 @@
+/* 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(a)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;
+}
+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_PEER_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;
+
+ 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;
+
+ 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
+ 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_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;
+ 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_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;
+
+ 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;
+ }
+ 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);
+ 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),
+ .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);
+}
diff --git a/src/sbcap_smscb_peer_fsm.c b/src/sbcap_smscb_peer_fsm.c
new file mode 100644
index 0000000..706a98f
--- /dev/null
+++ b/src/sbcap_smscb_peer_fsm.c
@@ -0,0 +1,370 @@
+/* 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(a)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);
+ 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;
+ 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;
+
+ 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))) {
+ 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);
+ }
+ osmo_fsm_inst_state_chg(fi, SMSCB_S_WAIT_DELETE_ACK, 10, T_WAIT_DELETE_ACK);
+ 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),
+ .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);
+}
diff --git a/src/smscb_peer_fsm.c b/src/smscb_peer_fsm.c
index 589a832..20eec95 100644
--- a/src/smscb_peer_fsm.c
+++ b/src/smscb_peer_fsm.c
@@ -27,13 +27,6 @@
#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>
@@ -43,8 +36,6 @@
#include <osmocom/cbc/smscb_peer_fsm.h>
#include <osmocom/cbc/smscb_message_fsm.h>
-#define S(x) (1 << (x))
-
const struct value_string smscb_peer_fsm_event_names[] = {
{ SMSCB_PEER_E_CREATE, "CREATE" },
{ SMSCB_PEER_E_REPLACE, "REPLACE" },
@@ -66,666 +57,24 @@
{ 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);
-}
-
-/* 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);
- 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 *sbcap = NULL;
- A_SEQUENCE_OF(void) *as_pdu;
- SBcAP_Write_Replace_Warning_Response_IEs_t *ie;
-
- 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;
- 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;
- struct osmo_cbsp_decoded *cbsp;
-
- 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
- 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_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;
- 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_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;
- //SBcAP_SBC_AP_PDU_t *pdu = 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;
- 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;
- struct osmo_cbsp_decoded *cbsp;
- SBcAP_SBC_AP_PDU_t *sbcap;
- A_SEQUENCE_OF(void) *as_pdu;
- SBcAP_Write_Replace_Warning_Indication_IEs_t *ie;
-
- 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;
- }
- 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_PEER_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;
- 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),
- .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) |
- 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 = 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) |
- 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 smscb_p_fsm = {
- .name = "SMSCB-PEER",
- .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 = 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(&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_MSG_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 */
--
To view, visit
https://gerrit.osmocom.org/c/osmo-cbc/+/28828
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-cbc
Gerrit-Branch: master
Gerrit-Change-Id: I0fd00b60cdc6bc6a088be1336d849548ca89c847
Gerrit-Change-Number: 28828
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged