WIP: start handling bss_map_msg_assignment_rqst

Change-Id: I2e43befb9236c1298a166703cbc6dcfc5c54e372
This commit is contained in:
Oliver Smith 2022-03-24 11:12:28 +01:00
parent e168f2d36f
commit dd367ac29d
10 changed files with 477 additions and 27 deletions

View File

@ -6,5 +6,6 @@ noinst_HEADERS = \
logging.h \
msc.h \
subscr_conn.h \
subscr_conn_fsm.h \
vty.h \
$(NULL)

View File

@ -44,6 +44,7 @@ struct bsc_nat {
struct {
struct mgcp_client_pool *pool;
struct osmo_tdef *tdefs;
uint32_t call_id_next;
} mgw;
struct {

View File

@ -21,7 +21,15 @@
#include <osmocom/core/msgb.h>
#include <osmocom/bsc_nat/bsc_nat.h>
#include <osmocom/bsc_nat/subscr_conn.h>
struct subscr_conn;
/* Parsed BSSMAP messages, to be stored inside struct subscr_conn until
* forwarded with slight modification (e.g. different RTP address). */
struct bssmap_assignment_rqst {
char rtp_addr[INET6_ADDRSTRLEN];
uint16_t rtp_port;
};
/* connection-less */
int bssap_handle_udt(struct bsc_nat_sccp_inst *sccp_inst, struct osmo_sccp_addr *addr, struct msgb *msgb,
@ -30,5 +38,5 @@ int bssap_handle_udt(struct bsc_nat_sccp_inst *sccp_inst, struct osmo_sccp_addr
int bssmap_tx_reset(struct bsc_nat_sccp_inst *sccp_inst, struct osmo_sccp_addr *addr);
/* connection-oriented */
int bssap_conn_handle_udt(enum bsc_nat_net net, struct subscr_conn *subscr_conn, struct msgb *msgb,
unsigned int length);
int bssap_conn_handle_dt(enum bsc_nat_net net, struct subscr_conn *subscr_conn, struct msgb *msgb,
unsigned int length);

View File

@ -20,18 +20,25 @@
#pragma once
#include <osmocom/bsc_nat/bsc_nat.h>
#include <osmocom/bsc_nat/bssap.h>
/* connection for one subscriber */
struct subscr_conn {
struct llist_head list;
struct osmo_fsm_inst *fi;
struct osmo_mgcpc_ep *ep;
struct {
uint32_t id;
struct osmo_mgcpc_ep_ci *ci;
struct msc *msc;
struct bssmap_assignment_rqst ass_req;
} cn;
struct {
uint32_t id;
struct osmo_mgcpc_ep_ci *ci;
struct bsc *bsc;
} ran;
};

View File

@ -0,0 +1,41 @@
/* (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Oliver Smith <osmith@sysmocom.de>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/lienses/>.
*
*/
#pragma once
enum subscr_conn_fsm_states {
SUBSCR_CONN_FSM_ST_IDLE,
SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_REQUEST,
SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_REQUEST_WAIT_EP2,
SUBSCR_CONN_FSM_ST_WAITING_FOR_ASSIGNMENT_COMPLETE,
SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_COMPLETE,
SUBSCR_CONN_FSM_ST_WAITING_FOR_CLEAR_COMMAND,
SUBSCR_CONN_FSM_ST_PROCESSING_CLEAR_COMMAND,
SUBSCR_CONN_FSM_ST_WAITING_FOR_CLEAR_COMPLETE,
};
enum subscr_conn_fsm_events {
SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_REQUEST,
SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_COMPLETE,
SUBSCR_CONN_FSM_EV_BSSMAP_CLEAR_COMMAND,
SUBSCR_CONN_FSM_EV_BSSMAP_CLEAR_COMPLETE,
SUBSCR_CONN_FSM_EV_MGCP_EP_OK,
SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL,
SUBSCR_CONN_FSM_EV_MGCP_EP_TERM,
};

View File

@ -36,6 +36,7 @@ osmo_bsc_nat_SOURCES = \
msc.c \
msc_fsm.c \
subscr_conn.c \
subscr_conn_fsm.c \
vty.c \
$(NULL)

View File

@ -126,7 +126,7 @@ static int sccp_sap_up_cn(struct osmo_prim_hdr *oph, void *scu)
goto error;
}
rc = bssap_conn_handle_udt(BSC_NAT_NET_CN, subscr_conn, oph->msg, msgb_l2len(oph->msg));
rc = bssap_conn_handle_dt(BSC_NAT_NET_CN, subscr_conn, oph->msg, msgb_l2len(oph->msg));
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):

View File

@ -23,28 +23,114 @@
#include <osmocom/sigtran/sccp_helpers.h>
#include <osmocom/bsc_nat/logging.h>
#include <osmocom/bsc_nat/subscr_conn.h>
#include <osmocom/bsc_nat/subscr_conn_fsm.h>
static int bssmap_conn_cn_rcvmsg_udt(struct subscr_conn *subscr_conn, struct msgb *msg, unsigned int length)
static int bssap_conn_cn_fwd(struct subscr_conn *subscr_conn, struct msgb *msg, unsigned int length)
{
LOGP(DMAIN, LOGL_DEBUG, "Fwd BSSAP via %s\n", talloc_get_name(subscr_conn));
msgb_pull_to_l2(msg);
return osmo_sccp_tx_data(g_bsc_nat->ran.sccp_inst->scu,
subscr_conn->ran.id,
msg->data,
msgb_length(msg));
}
static int bssmap_cn_handle_assignment_rqst(struct subscr_conn *subscr_conn, struct msgb *msg, unsigned int length)
{
int rc;
unsigned int rc_u;
struct tlv_parsed tp;
uint8_t cause;
struct sockaddr_storage rtp_addr;
struct gsm0808_channel_type ct;
struct bssmap_assignment_rqst *ass_req = &subscr_conn->cn.ass_req;
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, length - 1, 0, 0);
/* Get channel type */
if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) {
LOGP(DMAIN, LOGL_ERROR, "Mandatory channel type not present\n");
cause = GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING;
goto reject;
}
rc = gsm0808_dec_channel_type(&ct, TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE),
TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE));
if (rc < 0) {
LOGP(DMAIN, LOGL_ERROR, "Unable to decode channel type\n");
cause = GSM0808_CAUSE_INCORRECT_VALUE;
goto reject;
}
/* Not speech: fwd directly */
if ((ct.ch_indctr & 0x0f) != GSM0808_CHAN_SPEECH) {
LOGP(DMAIN, LOGL_DEBUG, "Channel type is not speech, forwarding directly\n");
rc = bssap_conn_cn_fwd(subscr_conn, msg, length);
if (rc < 0) {
cause = GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC;
goto reject;
}
return 0;
}
/* Get AoIP transport address */
if (!TLVP_PRESENT(&tp, GSM0808_IE_AOIP_TRASP_ADDR)) {
LOGP(DMAIN, LOGL_ERROR, "AoIP transport address missing in ASSIGN REQ\n");
cause = GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING;
goto reject;
}
rc = gsm0808_dec_aoip_trasp_addr(&rtp_addr,
TLVP_VAL(&tp, GSM0808_IE_AOIP_TRASP_ADDR),
TLVP_LEN(&tp, GSM0808_IE_AOIP_TRASP_ADDR));
if (rc < 0) {
LOGP(DMAIN, LOGL_ERROR, "Unable to decode AoIP transport address\n");
cause = GSM0808_CAUSE_INCORRECT_VALUE;
goto reject;
}
rc_u = osmo_sockaddr_to_str_and_uint(ass_req->rtp_addr, sizeof(ass_req->rtp_addr), &ass_req->rtp_port,
(const struct sockaddr *)&rtp_addr);
if (!rc_u || rc_u >= sizeof(ass_req->rtp_addr)) {
LOGP(DMAIN, LOGL_ERROR, "Assignment request: RTP address is too long\n");
cause = GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_UNAVAIL;
goto reject;
}
/* Get more IEs? */
/* Don't forward the message directly. Instead, let the subscr_conn FSM
* allocate new MGCP connections in the BSCNAT's MGW and then send a
* similar assignment request, but with the RTP address replaced. */
if (osmo_fsm_inst_dispatch(subscr_conn->fi, SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_REQUEST, NULL) < 0) {
cause = GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC;
goto reject;
}
return 0;
reject:
/* FIXME: send error */
LOGP(DMAIN, LOGL_ERROR, "STUB: send error cause %d\n", cause);
return -1;
}
static int bssmap_conn_cn_rcvmsg_dt(struct subscr_conn *subscr_conn, struct msgb *msg, unsigned int length)
{
int ret = 0;
switch (msg->l3h[0]) {
case BSS_MAP_MSG_ASSIGNMENT_RQST:
ret = bssmap_cn_handle_assignment_rqst(subscr_conn, msg, length);
break;
default:
LOGP(DMAIN, LOGL_DEBUG, "Fwd %s via %s\n", gsm0808_bssmap_name(msg->l3h[0]),
talloc_get_name(subscr_conn));
msgb_pull_to_l2(msg);
ret = osmo_sccp_tx_data(g_bsc_nat->ran.sccp_inst->scu,
subscr_conn->ran.id,
msg->data,
msgb_length(msg));
ret = bssap_conn_cn_fwd(subscr_conn, msg, length);
break;
}
return ret;
}
static int bssmap_conn_rcvmsg_udt(enum bsc_nat_net net, struct subscr_conn *subscr_conn, struct msgb *msg,
static int bssmap_conn_rcvmsg_dt(enum bsc_nat_net net, struct subscr_conn *subscr_conn, struct msgb *msg,
unsigned int length)
{
if (length < 1) {
@ -52,40 +138,48 @@ static int bssmap_conn_rcvmsg_udt(enum bsc_nat_net net, struct subscr_conn *subs
return -1;
}
LOGP(DMAIN, LOGL_NOTICE, "Rx UDT BSSMAP %s\n", gsm0808_bssmap_name(msg->l3h[0]));
LOGP(DMAIN, LOGL_NOTICE, "Rx DT BSSMAP %s\n", gsm0808_bssmap_name(msg->l3h[0]));
if (net == BSC_NAT_NET_CN)
return bssmap_conn_cn_rcvmsg_udt(subscr_conn, msg, length);
return bssmap_conn_cn_rcvmsg_dt(subscr_conn, msg, length);
LOGP(DMAIN, LOGL_ERROR, "%s(RAN) is not implemented!\n", __func__);
return -1;
}
int bssap_conn_handle_udt(enum bsc_nat_net net, struct subscr_conn *subscr_conn, struct msgb *msgb, unsigned int length)
int bssap_conn_handle_dt(enum bsc_nat_net net, struct subscr_conn *subscr_conn, struct msgb *msgb, unsigned int length)
{
struct bssmap_header *bs;
int rc = -1;
LOGP(DMAIN, LOGL_DEBUG, "Rx UDT: %s\n", osmo_hexdump(msgb->l2h, length));
LOGP(DMAIN, LOGL_DEBUG, "Rx DT: %s\n", osmo_hexdump(msgb->l2h, length));
if (length < sizeof(*bs)) {
LOGP(DMAIN, LOGL_ERROR, "The header is too short\n");
return -1;
}
bs = (struct bssmap_header *)msgb->l2h;
if (bs->length < length - sizeof(*bs)) {
LOGP(DMAIN, LOGL_ERROR, "Failed to parse BSSMAP header\n");
return -1;
}
switch (bs->type) {
switch (msgb->l2h[0]) {
case BSSAP_MSG_BSS_MANAGEMENT:
bs = (struct bssmap_header *)msgb->l2h;
if (bs->length < length - sizeof(*bs)) {
LOGP(DMAIN, LOGL_ERROR, "Failed to parse BSSMAP header\n");
return -1;
}
msgb->l3h = &msgb->l2h[sizeof(*bs)];
rc = bssmap_conn_rcvmsg_udt(net, subscr_conn, msgb, length - sizeof(*bs));
rc = bssmap_conn_rcvmsg_dt(net, subscr_conn, msgb, length - sizeof(*bs));
break;
case BSSAP_MSG_DTAP:
LOGP(DMAIN, LOGL_DEBUG, "Rx DT DTAP\n");
if (net == BSC_NAT_NET_CN) {
rc = bssap_conn_cn_fwd(subscr_conn, msgb, length);
} else {
LOGP(DMAIN, LOGL_ERROR, "%s(RAN) is not implemented!\n", __func__);
rc = -1;
}
break;
default:
LOGP(DMAIN, LOGL_ERROR, "%s(%s) is not implemented!\n", __func__, gsm0808_bssap_name(bs->type));
LOGP(DMAIN, LOGL_ERROR, "%s(%s) is not implemented!\n", __func__, gsm0808_bssap_name(msgb->l2h[0]));
}
return rc;

View File

@ -26,6 +26,8 @@
#include <osmocom/bsc_nat/subscr_conn.h>
#include <osmocom/bsc_nat/logging.h>
extern struct osmo_fsm subscr_conn_fsm;
/* Get the next available id in either CN or RAN. */
int subscr_conn_get_next_id(enum bsc_nat_net net)
{
@ -67,6 +69,9 @@ struct subscr_conn *subscr_conn_alloc(struct msc *msc, struct bsc *bsc, uint32_t
LOGP(DMAIN, LOGL_DEBUG, "Add %s\n", talloc_get_name(subscr_conn));
subscr_conn->fi = osmo_fsm_inst_alloc(&subscr_conn_fsm, subscr_conn, subscr_conn, LOGL_INFO, NULL);
OSMO_ASSERT(subscr_conn->fi);
subscr_conn->cn.id = id_cn;
subscr_conn->cn.msc = msc;
subscr_conn->ran.id = id_ran;
@ -95,5 +100,6 @@ void subscr_conn_free(struct subscr_conn *subscr_conn)
{
LOGP(DMAIN, LOGL_DEBUG, "Del %s\n", talloc_get_name(subscr_conn));
llist_del(&subscr_conn->list);
osmo_fsm_inst_free(subscr_conn->fi);
talloc_free(subscr_conn);
}

View File

@ -0,0 +1,291 @@
/* (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Oliver Smith <osmith@sysmocom.de>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/lienses/>.
*
*/
#include "config.h"
#include <inttypes.h>
#include <osmocom/core/fsm.h>
#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
#include <osmocom/mgcp_client/mgcp_client_fsm.h>
#include <osmocom/bsc_nat/bsc_nat.h>
#include <osmocom/bsc_nat/bssap.h>
#include <osmocom/bsc_nat/logging.h>
#include <osmocom/bsc_nat/subscr_conn.h>
#include <osmocom/bsc_nat/subscr_conn_fsm.h>
#define X(s) (1 << (s))
static void st_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_REQUEST:
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_REQUEST, 0, 0);
break;
default:
OSMO_ASSERT(false);
}
}
static void st_processing_assignment_request_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_stat)
{
struct mgcp_client *mgcp_client;
struct mgcp_conn_peer crcx_info = {};
struct subscr_conn *subscr_conn = (struct subscr_conn *)fi->priv;
struct bssmap_assignment_rqst *ass_req = &subscr_conn->cn.ass_req;
/* MGCP EP */
mgcp_client = mgcp_client_pool_get(g_bsc_nat->mgw.pool);
OSMO_ASSERT(mgcp_client);
subscr_conn->ep = osmo_mgcpc_ep_alloc(subscr_conn->fi, SUBSCR_CONN_FSM_EV_MGCP_EP_TERM, mgcp_client,
g_bsc_nat->mgw.tdefs, "SUBSCR-CONN-EP",
mgcp_client_rtpbridge_wildcard(mgcp_client));
crcx_info.call_id = subscr_conn->ran.id; /* FIXME: generate unique call id and store in subscr_conn */
/* MGCP CRCX RAN */
subscr_conn->ran.ci = osmo_mgcpc_ep_ci_add(subscr_conn->ep, "CI(%s:%"PRIu32")",
talloc_get_name(subscr_conn->ran.bsc), subscr_conn->ran.id);
osmo_mgcpc_ep_ci_request(subscr_conn->ran.ci, MGCP_VERB_CRCX, &crcx_info, subscr_conn->fi,
SUBSCR_CONN_FSM_EV_MGCP_EP_OK, SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL, NULL);
/* Set RTP addr + port */
osmo_static_assert(sizeof(crcx_info.addr) == sizeof(ass_req->rtp_addr), sizeof_rtp_addr);
memcpy(crcx_info.addr, ass_req->rtp_addr, sizeof(crcx_info.addr));
crcx_info.port = ass_req->rtp_port;
/* MGCP CRCX CN */
subscr_conn->cn.ci = osmo_mgcpc_ep_ci_add(subscr_conn->ep, "CI(%s:%"PRIu32")",
talloc_get_name(subscr_conn->cn.msc), subscr_conn->cn.id);
osmo_mgcpc_ep_ci_request(subscr_conn->cn.ci, MGCP_VERB_CRCX, &crcx_info, subscr_conn->fi,
SUBSCR_CONN_FSM_EV_MGCP_EP_OK, SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL, NULL);
return;
}
static void st_processing_assignment_request(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case SUBSCR_CONN_FSM_EV_MGCP_EP_OK:
LOGP(DMAIN, LOGL_DEBUG, "Rx MGCP EP OK 1/2\n");
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_REQUEST_WAIT_EP2, 0, 0);
break;
case SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL:
LOGP(DMAIN, LOGL_ERROR, "MGCP failure, aborting assignment request processing\n");
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_IDLE, 0, 0);
/* FIXME: do mgcp abort? send bssmap error? */
break;
default:
OSMO_ASSERT(false);
}
}
static void st_processing_assignment_request_wait_ep2(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case SUBSCR_CONN_FSM_EV_MGCP_EP_OK:
LOGP(DMAIN, LOGL_DEBUG, "Rx MGCP EP OK 2/2\n");
/* FIXME: send bssmap assignment request with changed rtp address to bsc */
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_WAITING_FOR_ASSIGNMENT_COMPLETE, 0, 0);
break;
case SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL:
LOGP(DMAIN, LOGL_ERROR, "MGCP failure, aborting assignment request processing\n");
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_IDLE, 0, 0);
/* FIXME: do mgcp abort? send bssmap error? */
break;
default:
OSMO_ASSERT(false);
}
}
static void st_waiting_for_assignment_complete(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_COMPLETE:
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_COMPLETE, 0, 0);
break;
default:
OSMO_ASSERT(false);
}
}
static void st_processing_assignment_complete(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case SUBSCR_CONN_FSM_EV_MGCP_EP_OK:
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_WAITING_FOR_CLEAR_COMMAND, 0, 0);
break;
case SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL:
LOGP(DMAIN, LOGL_ERROR, "MGCP failure, aborting assignment complete processing\n");
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_IDLE, 0, 0);
break;
default:
OSMO_ASSERT(false);
}
}
static void st_waiting_for_clear_command(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case SUBSCR_CONN_FSM_EV_BSSMAP_CLEAR_COMMAND:
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_PROCESSING_CLEAR_COMMAND, 0, 0);
break;
default:
OSMO_ASSERT(false);
}
}
static void st_processing_clear_command(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case SUBSCR_CONN_FSM_EV_MGCP_EP_OK:
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_WAITING_FOR_CLEAR_COMPLETE, 0, 0);
break;
case SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL:
LOGP(DMAIN, LOGL_ERROR, "MGCP failure, aborting clear command processing\n");
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_IDLE, 0, 0);
break;
default:
OSMO_ASSERT(false);
}
}
static void st_waiting_for_clear_complete(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case SUBSCR_CONN_FSM_EV_BSSMAP_CLEAR_COMPLETE:
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_FSM_ST_IDLE, 0, 0);
break;
default:
OSMO_ASSERT(false);
}
}
static struct osmo_fsm_state subscr_conn_fsm_states[] = {
[SUBSCR_CONN_FSM_ST_IDLE] = {
.name = "IDLE",
.in_event_mask = 0
| X(SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_REQUEST)
,
.out_state_mask = 0
| X(SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_REQUEST)
,
.action = st_idle,
},
[SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_REQUEST] = {
.name = "PROCESSING_ASSIGNMENT_REQUEST",
.in_event_mask = 0
| X(SUBSCR_CONN_FSM_EV_MGCP_EP_OK)
| X(SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL)
,
.out_state_mask = 0
| X(SUBSCR_CONN_FSM_ST_IDLE)
| X(SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_REQUEST_WAIT_EP2)
,
.action = st_processing_assignment_request,
.onenter = st_processing_assignment_request_on_enter,
},
[SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_REQUEST_WAIT_EP2] = {
.name = "PROCESSING_ASSIGNMENT_REQUEST_WAIT_EP2",
.in_event_mask = 0
| X(SUBSCR_CONN_FSM_EV_MGCP_EP_OK)
| X(SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL)
,
.out_state_mask = 0
| X(SUBSCR_CONN_FSM_ST_IDLE)
| X(SUBSCR_CONN_FSM_ST_WAITING_FOR_ASSIGNMENT_COMPLETE)
,
.action = st_processing_assignment_request_wait_ep2,
},
[SUBSCR_CONN_FSM_ST_WAITING_FOR_ASSIGNMENT_COMPLETE] = {
.name = "WAITING_FOR_ASSIGNMENT_COMPLETE",
.in_event_mask = 0
| X(SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_COMPLETE)
,
.out_state_mask = 0
| X(SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_COMPLETE)
,
.action = st_waiting_for_assignment_complete,
},
[SUBSCR_CONN_FSM_ST_PROCESSING_ASSIGNMENT_COMPLETE] = {
.name = "PROCESSING_ASSIGNMENT_COMPLETE",
.in_event_mask = 0
| X(SUBSCR_CONN_FSM_EV_MGCP_EP_OK)
| X(SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL)
,
.out_state_mask = 0
| X(SUBSCR_CONN_FSM_ST_IDLE)
| X(SUBSCR_CONN_FSM_ST_WAITING_FOR_CLEAR_COMMAND)
,
.action = st_processing_assignment_complete,
},
[SUBSCR_CONN_FSM_ST_WAITING_FOR_CLEAR_COMMAND] = {
.name = "WAITING_FOR_CLEAR_COMMAND",
.in_event_mask = 0
| X(SUBSCR_CONN_FSM_EV_BSSMAP_CLEAR_COMMAND)
,
.out_state_mask = 0
| X(SUBSCR_CONN_FSM_ST_PROCESSING_CLEAR_COMMAND)
,
.action = st_waiting_for_clear_command,
},
[SUBSCR_CONN_FSM_ST_PROCESSING_CLEAR_COMMAND] = {
.name = "PROCESSING_CLEAR_COMMAND",
.in_event_mask = 0
| X(SUBSCR_CONN_FSM_EV_MGCP_EP_OK)
| X(SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL)
,
.out_state_mask = 0
| X(SUBSCR_CONN_FSM_ST_IDLE)
| X(SUBSCR_CONN_FSM_ST_WAITING_FOR_CLEAR_COMPLETE)
,
.action = st_processing_clear_command,
},
[SUBSCR_CONN_FSM_ST_WAITING_FOR_CLEAR_COMPLETE] = {
.name = "WAITING_FOR_CLEAR_COMPLETE",
.in_event_mask = 0
| X(SUBSCR_CONN_FSM_EV_BSSMAP_CLEAR_COMPLETE)
,
.out_state_mask = 0
| X(SUBSCR_CONN_FSM_ST_IDLE)
,
.action = st_waiting_for_clear_complete,
},
};
const struct value_string subscr_conn_fsm_event_names[] = {
OSMO_VALUE_STRING(SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_REQUEST),
OSMO_VALUE_STRING(SUBSCR_CONN_FSM_EV_BSSMAP_ASSIGNMENT_COMPLETE),
OSMO_VALUE_STRING(SUBSCR_CONN_FSM_EV_BSSMAP_CLEAR_COMMAND),
OSMO_VALUE_STRING(SUBSCR_CONN_FSM_EV_BSSMAP_CLEAR_COMPLETE),
OSMO_VALUE_STRING(SUBSCR_CONN_FSM_EV_MGCP_EP_OK),
OSMO_VALUE_STRING(SUBSCR_CONN_FSM_EV_MGCP_EP_FAIL),
OSMO_VALUE_STRING(SUBSCR_CONN_FSM_EV_MGCP_EP_TERM),
{ 0, NULL }
};
struct osmo_fsm subscr_conn_fsm = {
.name = "SUBSCR_CONN",
.states = subscr_conn_fsm_states,
.num_states = ARRAY_SIZE(subscr_conn_fsm_states),
.log_subsys = DMAIN,
.event_names = subscr_conn_fsm_event_names,
};
static __attribute__((constructor)) void subscr_conn_fsm_init(void)
{
OSMO_ASSERT(osmo_fsm_register(&subscr_conn_fsm) == 0);
}