From 36f34ab21ad7f4f0a51b3a4c53967128109923aa Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Mon, 30 Apr 2018 14:16:37 +0200 Subject: wip Change-Id: I0973c3c993996cb97239e26251575644eaf49e79 --- include/osmocom/bsc/gsm_data.h | 12 ++ src/libbsc/abis_nm.c | 2 +- src/libbsc/abis_rsl.c | 48 ------ src/libbsc/bsc_api.c | 104 ----------- src/libbsc/bsc_subscr_conn_fsm.c | 352 ++++++++++++++++++++++++++++++++++---- src/libbsc/bts_ipaccess_nanobts.c | 3 + 6 files changed, 339 insertions(+), 182 deletions(-) diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index f113904d7..e89d746d0 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -188,6 +188,18 @@ struct gsm_subscriber_connection { enum gsm48_chan_mode chan_mode; } user_plane; + + struct { + enum gscon_fsm_states next_state; + unsigned int timeout_secs; + int T; + uint32_t success_event; + uint32_t failure_event; + enum gsm0808_cause cause; + struct gsm_lchan *new_lchan; + enum gsm48_chan_mode chan_mode; + bool full_rate; + } lchan_alloc; }; diff --git a/src/libbsc/abis_nm.c b/src/libbsc/abis_nm.c index b2cfa531d..e7070d639 100644 --- a/src/libbsc/abis_nm.c +++ b/src/libbsc/abis_nm.c @@ -1868,7 +1868,7 @@ int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb) foh = fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR, NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr); - DEBUGPFOH(DNM, foh, "Set Chan Attr %s\n", gsm_ts_name(ts)); + DEBUGPFOH(DNM, foh, "Set Chan Attr %s chan_comb=0x%x\n", gsm_ts_name(ts), chan_comb); if (verify_chan_comb(ts, chan_comb, &reason) < 0) { msgb_free(msg); LOGPFOH(DNM, LOGL_ERROR, foh, "Invalid Channel Combination %d on %s. Reason: %s\n", diff --git a/src/libbsc/abis_rsl.c b/src/libbsc/abis_rsl.c index 10bef6eb2..66b9c94e1 100644 --- a/src/libbsc/abis_rsl.c +++ b/src/libbsc/abis_rsl.c @@ -544,54 +544,6 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type, struct rsl_ie_chan_mode cm; struct gsm48_chan_desc cd; - /* If a TCH_F/PDCH TS is in PDCH mode, deactivate PDCH first. */ - if (lchan->ts->pchan == GSM_PCHAN_TCH_F_PDCH - && (lchan->ts->flags & TS_F_PDCH_ACTIVE)) { - /* store activation type and handover reference */ - lchan->dyn.act_type = act_type; - lchan->dyn.ho_ref = ho_ref; - return rsl_ipacc_pdch_activate(lchan->ts, 0); - } - - /* - * If necessary, release PDCH on dynamic TS. Note that sending a - * release here is only necessary when in PDCH mode; for TCH types, an - * RSL RF Chan Release is initiated by the BTS when a voice call ends, - * so when we reach this, it will already be released. If a dyn TS is - * in PDCH mode, it is still active and we need to initiate a release - * from the BSC side here. - * - * If pchan_is != pchan_want, the PDCH has already been taken down and - * the switchover now needs to enable the TCH lchan. - * - * To switch a dyn TS between TCH/H and TCH/F, it is sufficient to send - * a chan activ with the new lchan type, because it will already be - * released. - */ - if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH - && lchan->ts->dyn.pchan_is == lchan->ts->dyn.pchan_want) { - enum gsm_phys_chan_config pchan_want; - pchan_want = pchan_for_lchant(lchan->type); - if (lchan->ts->dyn.pchan_is != pchan_want) { - /* - * Make sure to record on lchan[0] so that we'll find - * it after the PDCH release. - */ - struct gsm_lchan *lchan0 = lchan->ts->lchan; - lchan0->dyn.act_type = act_type, - lchan0->dyn.ho_ref = ho_ref; - lchan0->dyn.rqd_ref = lchan->rqd_ref; - lchan0->dyn.rqd_ta = lchan->rqd_ta; - lchan->rqd_ref = NULL; - lchan->rqd_ta = 0; - DEBUGP(DRSL, "%s saved rqd_ref=%p ta=%u\n", - gsm_lchan_name(lchan0), lchan0->rqd_ref, - lchan0->rqd_ta); - return dyn_ts_switchover_start(lchan->ts, pchan_want); - } - } - DEBUGP(DRSL, "%s Tx RSL Channel Activate with act_type=%s\n", gsm_ts_and_pchan_name(lchan->ts), rsl_act_type_name(act_type)); diff --git a/src/libbsc/bsc_api.c b/src/libbsc/bsc_api.c index 142efef02..2cec60e52 100644 --- a/src/libbsc/bsc_api.c +++ b/src/libbsc/bsc_api.c @@ -92,74 +92,6 @@ static void handle_mr_config(struct gsm_subscriber_connection *conn, gsm48_multirate_config(lchan->mr_bts_lv, mr, mr->bts_mode); } -/* - * Start a new assignment and make sure that it is completed within T10 either - * positively, negatively or by the timeout. - * - * 1.) allocate a new lchan - * 2.) copy the encryption key and other data from the - * old to the new channel. - * 3.) RSL Channel Activate this channel and wait - * - * -> Signal handler for the LCHAN - * 4.) Send GSM 04.08 assignment command to the MS - * - * -> Assignment Complete/Assignment Failure - * 5.) Release the SDCCH, continue signalling on the new link - */ -static int handle_new_assignment(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate) -{ - struct gsm_lchan *new_lchan; - enum gsm_chan_t chan_type; - - chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H; - - new_lchan = lchan_alloc(conn_get_bts(conn), chan_type, 0); - - if (!new_lchan) { - LOGP(DMSC, LOGL_NOTICE, "No free channel.\n"); - return -1; - } - - /* check if we are on TCH/F and requested TCH/H, but got TCH/F */ - if (conn->lchan->type == new_lchan->type - && chan_type != new_lchan->type) { - LOGP(DHO, LOGL_NOTICE, "%s -> %s Will not re-assign to identical channel type," - " %s was requested\n", - gsm_lchan_name(conn->lchan), gsm_lchan_name(new_lchan), - gsm_lchant_name(chan_type)); - lchan_free(new_lchan); - return -1; - } - - /* copy old data to the new channel */ - memcpy(&new_lchan->encr, &conn->lchan->encr, sizeof(new_lchan->encr)); - new_lchan->ms_power = conn->lchan->ms_power; - new_lchan->bs_power = conn->lchan->bs_power; - new_lchan->rqd_ta = conn->lchan->rqd_ta; - - /* copy new data to it */ - new_lchan->tch_mode = chan_mode; - new_lchan->rsl_cmode = (chan_mode == GSM48_CMODE_SIGN) ? - RSL_CMOD_SPD_SIGN : RSL_CMOD_SPD_SPEECH; - - /* handle AMR correctly */ - if (chan_mode == GSM48_CMODE_SPEECH_AMR) - handle_mr_config(conn, new_lchan, full_rate); - - if (rsl_chan_activate_lchan(new_lchan, 0x1, 0) < 0) { - LOGP(DHO, LOGL_ERROR, "could not activate channel\n"); - lchan_free(new_lchan); - return -1; - } - - /* remember that we have the channel */ - conn->secondary_lchan = new_lchan; - new_lchan->conn = conn; - - rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ); - return 0; -} static void ho_dtap_cache_add(struct gsm_subscriber_connection *conn, struct msgb *msg, int link_id, bool allow_sacch) @@ -296,42 +228,6 @@ static int chan_compat_with_mode(struct gsm_lchan *lchan, int chan_mode, int ful } } -/** - * Send a GSM08.08 Assignment Request. Right now this does not contain the - * audio codec type or the allowed rates for the config. It is assumed that - * this is for audio handling only. In case the current channel does not allow - * the selected mode a new one will be allocated. - * - * TODO: Add multirate configuration, make it work for more than audio. - */ -int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate) -{ - struct bsc_api *api; - api = conn->network->bsc_api; - - if (!chan_compat_with_mode(conn->lchan, chan_mode, full_rate)) { - if (handle_new_assignment(conn, chan_mode, full_rate) != 0) - goto error; - } else { - if (chan_mode == GSM48_CMODE_SPEECH_AMR) - handle_mr_config(conn, conn->lchan, full_rate); - - LOGP(DMSC, LOGL_NOTICE, - "Sending %s ChanModify for speech: %s on channel %s\n", - gsm_lchan_name(conn->lchan), - get_value_string(gsm48_chan_mode_names, chan_mode), - get_value_string(gsm_chan_t_names, conn->lchan->type)); - gsm48_lchan_modify(conn->lchan, chan_mode); - } - - /* we expect the caller will manage T10 */ - return 0; - -error: - api->assign_fail(conn, 0, NULL); - return -1; -} - int gsm0808_page(struct gsm_bts *bts, unsigned int page_group, unsigned int mi_len, uint8_t *mi, int chan_type) { diff --git a/src/libbsc/bsc_subscr_conn_fsm.c b/src/libbsc/bsc_subscr_conn_fsm.c index 91d4e5984..6991a2de3 100644 --- a/src/libbsc/bsc_subscr_conn_fsm.c +++ b/src/libbsc/bsc_subscr_conn_fsm.c @@ -54,6 +54,8 @@ enum gscon_fsm_states { ST_WAIT_CC, /* active connection */ ST_ACTIVE, + /* when allocating an lchan, it may be necessary to deactivate PDCH on a dyn ts first. */ + ST_WAIT_DYN_TS_SWITCHOVER, /* during assignment; waiting for ASS_CMPL */ ST_WAIT_ASS_CMPL, /* during assignment; waiting for MODE_MODIFY_ACK */ @@ -386,6 +388,22 @@ static void gscon_fsm_wait_cc(struct osmo_fsm_inst *fi, uint32_t event, void *da } } +#define assignment_failed(fi, cause) \ + _assignment_failed(fi, cause, __FILE__, __LINE__) +static void _assignment_failed(struct osmo_fsm_inst *fi, enum gsm0808_cause cause, + const char *file, int line) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct msgb *resp = NULL; + + LOGPFSMLSRC(fi, LOGL_ERROR, file, line, "Assignment failed: %s\n", gsm0808_cause_name(cause)); + + resp = gsm0808_create_assignment_failure(cause, NULL); + sigtran_send(conn, resp, fi); + if (fi->state != ST_ACTIVE) + osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); +} + /* We're on an active subscriber connection, passing DTAP back and forth */ static void gscon_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data) { @@ -424,8 +442,7 @@ static void gscon_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *dat mgcp_conn_create(conn->network->mgw.client, fi, GSCON_EV_MGW_FAIL_BTS, GSCON_EV_MGW_CRCX_RESP_BTS, &conn_peer); if (!conn->user_plane.fi_bts) { - resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL); - sigtran_send(conn, resp, fi); + assignment_failed(fi, GSM0808_CAUSE_EQUIPMENT_FAILURE); return; } break; @@ -439,8 +456,7 @@ static void gscon_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *dat rc = gsm0808_assign_req(conn, conn->user_plane.chan_mode, conn->user_plane.full_rate); if (rc != 0) { - resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL); - sigtran_send(conn, resp, fi); + assignment_failed(fi, GSM0808_CAUSE_EQUIPMENT_FAILURE); return; } @@ -455,8 +471,7 @@ static void gscon_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *dat conn->user_plane.full_rate); /* The requested channel mode is not supported */ - resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP, NULL); - sigtran_send(conn, resp, fi); + assignment_failed(fi, GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP); break; } break; @@ -494,13 +509,304 @@ static void gscon_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *dat } } +/* + * Start a new assignment and make sure that it is completed within T10 either + * positively, negatively or by the timeout. + * + * 1.) allocate a new lchan + * 2.) copy the encryption key and other data from the + * old to the new channel. + * 3.) RSL Channel Activate this channel and wait + * + * -> Signal handler for the LCHAN + * 4.) Send GSM 04.08 assignment command to the MS + * + * -> Assignment Complete/Assignment Failure + * 5.) Release the SDCCH, continue signalling on the new link + */ +static int handle_new_assignment(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate) +{ + struct gsm_lchan *new_lchan; + enum gsm_chan_t chan_type; + + chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H; + + + if (!new_lchan) { + LOGP(DMSC, LOGL_NOTICE, "No free channel.\n"); + return -1; + } + + /* copy old data to the new channel */ + memcpy(&new_lchan->encr, &conn->lchan->encr, sizeof(new_lchan->encr)); + new_lchan->ms_power = conn->lchan->ms_power; + new_lchan->bs_power = conn->lchan->bs_power; + new_lchan->rqd_ta = conn->lchan->rqd_ta; + + /* copy new data to it */ + new_lchan->tch_mode = chan_mode; + new_lchan->rsl_cmode = (chan_mode == GSM48_CMODE_SIGN) ? + RSL_CMOD_SPD_SIGN : RSL_CMOD_SPD_SPEECH; + + /* handle AMR correctly */ + if (chan_mode == GSM48_CMODE_SPEECH_AMR) + handle_mr_config(conn, new_lchan, full_rate); + + + if (rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTRA_NORM_ASS, 0) < 0) { + LOGP(DHO, LOGL_ERROR, "could not activate channel\n"); + lchan_free(new_lchan); + return -1; + } + + /* remember that we have the channel */ + conn->secondary_lchan = new_lchan; + new_lchan->conn = conn; + + rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ); + return 0; +} + +static void allocate_lchan_done(struct osmo_fsm_inst *fi, enum gsm0808_cause cause_or_zero) +{ + struct gsm_subscriber_connection *conn = fi->priv; + + osmo_fsm_inst_state_chg(fi, + conn->lchan_alloc.next_state, + conn->lchan_alloc.timeout_secs, + conn->lchan_alloc.T); + + if (cause_or_zero) { + if (conn->lchan_alloc.new_lchan) { + lchan_free(conn->lchan_alloc.new_lchan); + conn->lchan_alloc.new_lchan = NULL; + } + osmo_fsm_inst_dispatch(fi, conn->lchan_alloc.failure_event, &cause); + } else + osmo_fsm_inst_dispatch(fi, conn->lchan_alloc.success_event, NULL); +} + +static void allocate_lchan_activate(struct osmo_fsm_inst *fi) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct gsm_lchan *new_lchan = conn->lchan_alloc.new_lchan; + enum gsm48_chan_mode; + + if (!new_lchan) { + LOGPFSML(fi, LOGL_ERROR, "cannot activate new lchan: it is NULL\n"); + allocate_lchan_done(fi, GSM0808_CAUSE_EQUIPMENT_FAILURE); + } + + /* copy old data to the new channel */ + if (conn->lchan) { + memcpy(&new_lchan->encr, &conn->lchan->encr, sizeof(new_lchan->encr)); + new_lchan->ms_power = conn->lchan->ms_power; + new_lchan->bs_power = conn->lchan->bs_power; + new_lchan->rqd_ta = conn->lchan->rqd_ta; + } + + /* copy new data to it */ + chan_mode = conn->lchan_alloc.chan_mode; + new_lchan->tch_mode = chan_mode; + new_lchan->rsl_cmode = (chan_mode == GSM48_CMODE_SIGN) ? + RSL_CMOD_SPD_SIGN : RSL_CMOD_SPD_SPEECH; + + /* handle AMR correctly */ + if (chan_mode == GSM48_CMODE_SPEECH_AMR) + handle_mr_config(conn, new_lchan, conn->lchan_alloc.full_rate ? 1 : 0); + + if (rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTRA_NORM_ASS, 0) < 0) { + LOGP(DHO, LOGL_ERROR, "could not activate channel\n"); + lchan_free(new_lchan); + return -1; + } + + /* remember that we have the channel */ + conn->secondary_lchan = new_lchan; + new_lchan->conn = conn; + + rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ); + + allocate_lchan_done(fi, 0); +} + +/* If necessary, release PDCH on dynamic TS. The switch-on of PDCH is handled when a voice call ends, not + * here. Return true if a dyn TS is in PDCH mode, i.e. it is still active and we need to release and + * wait for the release ack. Return false if the caller can carry on right away. + */ +static bool allocate_lchan_disable_dyn_ts_pdch(struct osmo_fsm_inst *fi) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct gsm_lchan *lchan = conn->lchan_alloc.new_lchan; + bool deactivating_pdch = false; + int rc = 0; + + switch (lchan->ts->pchan) { + case GSM_PCHAN_TCH_F_PDCH: + if (lchan->ts->flags & TS_F_PDCH_ACTIVE) { + deactivating_pdch = true; + rc = rsl_ipacc_pdch_activate(lchan->ts, 0); + } + break; + + case GSM_PCHAN_TCH_F_TCH_H_PDCH: + + if (lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH) { + deactivating_pdch = true; + + if (lchan->ts->dyn.pchan_is != lchan->ts->dyn.pchan_want) { + LOGPFSML(fi, LOGL_ERROR, + "%s cannot deactivate PDCH, dyn TS already in transition\n", + gsm_lchan_name(lchan)); + rc = -EINVAL; + break; + } + + rc = dyn_ts_switchover_start(lchan->ts, pchan_for_lchant(lchan->type)); + } + break; + + default: + break; + } + + if (!deactivating_pdch) + return false; + + if (rc) { + allocate_lchan_done(fi, GSM0808_CAUSE_EQUIPMENT_FAILURE); + return true; + } + + osmo_fsm_inst_state_chg(fi, + ST_WAIT_DYN_TS_SWITCHOVER, + conn->lchan_alloc.timeout_secs, + conn->lchan_alloc.T); +} + +static void allocate_lchan(struct osmo_fsm_inst *fi, + struct gsm_bts *on_bts, + enum gsm48_chan_mode chan_mode, + bool full_rate, + bool differ_from_current_lchan, + enum gscon_fsm_states next_state, + unsigned int timeout_secs, int T, + enum gscon_fsm_event success_event, + enum gscon_fsm_event failure_event) +{ + struct gsm_subscriber_connection *conn = fi->priv; + struct gsm_lchan *new_lchan; + enum gsm0808_cause cause = GSM0808_CAUSE_EQUIPMENT_FAILURE; + enum gsm_chan_t chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H; + + if (conn->lchan_alloc.new_lchan) { + LOGPFSML(fi, LOGL_ERROR, "lchan allocation already busy on %s, cannot start another\n", + gsm_lchan_name(conn->lchan_alloc.new_lchan)); + return; + } + + conn->lchan_alloc.next_state = next_state; + conn->lchan_alloc.timeout_secs = timeout_secs; + conn->lchan_alloc.T = T; + conn->lchan_alloc.success_event = success_event; + conn->lchan_alloc.failure_event = failure_event; + + conn->lchan_alloc.chan_mode = chan_mode; + conn->lchan_alloc.full_rate = full_rate; + + switch (chan_mode) { + case GSM48_CMODE_SPEECH_V1: + case GSM48_CMODE_SPEECH_EFR: + case GSM48_CMODE_SPEECH_AMR: + break; + default: + LOGPFSML(fi, LOGL_ERROR, "this code path is not capable of allocating %s\n", + get_value_string(gsm48_chan_mode_names, chan_mode)); + goto failure; + } + + /* About allow_bigger: currently this is only used for TCH, and allow_bigger is about + * allocating SDCCH. So just pass 0. */ + new_lchan = lchan_alloc(on_bts, chan_type, 0); + + if (!new_lchan) { + LOGPFSML(fi, LOGL_NOTICE, "No lchan available for %s\n", + gsm_lchant_name(chan_type)); + cause = GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE; + goto failure; + } + + if (differ_from_current_lchan + && conn->lchan + && conn->lchan->ts->trx->bts == new_lchan->ts->trx->bts + && conn->lchan->type == new_lchan->type) { + LOGPFSML(fi, LOGL_NOTICE, + "%s -> %s Will not re-assign to identical channel type," + " %s was requested\n", + gsm_lchan_name(conn->lchan), gsm_lchan_name(new_lchan), + gsm_lchant_name(chan_type)); + lchan_free(new_lchan); + cause = GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE; + goto failure; + } + + conn->lchan_alloc.new_lchan = new_lchan; + + if (allocate_lchan_disable_dyn_ts_pdch(fi)) + return; + + allocate_lchan_activate(fi); + return; + +failure: + osmo_fsm_inst_state_chg(fi, next_state, timeout_secs, T); + osmo_fsm_inst_dispatch(fi, failure_event, &cause); +} + +static void assignment_request(struct osmo_fsm_inst *fi) +{ + struct gsm_subscriber_connection *conn = fi->priv; + int chan_mode = conn->user_plane.chan_mode; + int full_rate = conn->user_plane.full_rate; + enum gsm0808_cause cause = GSM0808_CAUSE_EQUIPMENT_FAILURE; + + if (conn->lchan && chan_compat_with_mode(conn->lchan, chan_mode, full_rate)) { + /* Already got a compatible lchan, just modify speech */ + if (chan_mode == GSM48_CMODE_SPEECH_AMR) + handle_mr_config(conn, conn->lchan, full_rate); + + LOGPFSML(fi, LOGL_INFO, + "%s: Sending ChanModify for speech: %s\n", + gsm_lchan_name(conn->lchan), + get_value_string(gsm48_chan_mode_names, chan_mode)); + + if (gsm48_lchan_modify(conn->lchan, chan_mode)) { + LOGPFSML(fi, LOGL_ERROR, "Sending ChanModify failed\n"); + goto error; + } + osmo_fsm_inst_state_chg(fi, ST_WAIT_ASS_CMPL, GSM0808_T10_VALUE, GSM0808_T10_TIMER_NR); + osmo_fsm_inst_dispatch(fi, GSCON_EV_RR_ASS_COMPL, NULL); + return; + } + + /* No (suitable) channel available, allocate */ + allocate_lchan(fi, ST_WAIT_ASS_CMPL, GSM0808_T10_VALUE, GSM0808_T10_TIMER_NR, + GSCON_EV_RR_ASS_FAIL); + return; + +error: + osmo_fsm_inst_state_chg(fi, ST_WAIT_ASS_CMPL, GSM0808_T10_VALUE, GSM0808_T10_TIMER_NR); + osmo_fsm_inst_dispatch(fi, GSCON_EV_RR_ASS_FAIL, &cause); + return -1; +} + + /* Before we may start the channel assignment we need to get an IP/Port for the * RTP connection from the MGW */ static void gscon_fsm_wait_crcx_bts(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct gsm_subscriber_connection *conn = fi->priv; struct mgcp_conn_peer *conn_peer = NULL; - struct msgb *resp = NULL; int rc; switch (event) { @@ -510,9 +816,7 @@ static void gscon_fsm_wait_crcx_bts(struct osmo_fsm_inst *fi, uint32_t event, vo /* Check if the MGW has assigned an enpoint to us, otherwise we * can not proceed. */ if (strlen(conn_peer->endpoint) <= 0) { - resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL); - sigtran_send(conn, resp, fi); - osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + assignment_failed(fi, GSM0808_CAUSE_EQUIPMENT_FAILURE); return; } @@ -529,15 +833,8 @@ static void gscon_fsm_wait_crcx_bts(struct osmo_fsm_inst *fi, uint32_t event, vo * then start the channel assignment. */ conn->user_plane.rtp_port = conn_peer->port; conn->user_plane.rtp_ip = osmo_ntohl(inet_addr(conn_peer->addr)); - rc = gsm0808_assign_req(conn, conn->user_plane.chan_mode, conn->user_plane.full_rate); - if (rc != 0) { - resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE, NULL); - sigtran_send(conn, resp, fi); - osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); - return; - } - osmo_fsm_inst_state_chg(fi, ST_WAIT_ASS_CMPL, GSM0808_T10_VALUE, GSM0808_T10_TIMER_NR); + allocate_lchan(fi, ST_WAIT_ASS_CMPL); break; case GSCON_EV_MO_DTAP: forward_dtap(conn, (struct msgb *)data, fi); @@ -561,7 +858,6 @@ static void gscon_fsm_wait_ass_cmpl(struct osmo_fsm_inst *fi, uint32_t event, vo struct gsm_lchan *lchan = conn->lchan; struct mgcp_conn_peer conn_peer; struct in_addr addr; - struct msgb *resp = NULL; int rc; switch (event) { @@ -586,9 +882,7 @@ static void gscon_fsm_wait_ass_cmpl(struct osmo_fsm_inst *fi, uint32_t event, vo osmo_fsm_inst_state_chg(fi, ST_WAIT_MDCX_BTS, MGCP_MGW_TIMEOUT, MGCP_MGW_TIMEOUT_TIMER_NR); rc = mgcp_conn_modify(conn->user_plane.fi_bts, GSCON_EV_MGW_MDCX_RESP_BTS, &conn_peer); if (rc != 0) { - resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL); - sigtran_send(conn, resp, fi); - osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + assignment_failed(fi, GSM0808_CAUSE_EQUIPMENT_FAILURE); return; } break; @@ -610,9 +904,12 @@ static void gscon_fsm_wait_ass_cmpl(struct osmo_fsm_inst *fi, uint32_t event, vo break; case GSCON_EV_RR_ASS_FAIL: - resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE, NULL); - sigtran_send(conn, resp, fi); - osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + { + enum gsm0808_cause cause = GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE; + if (data) + cause = *((enum gsm0808_cause*)data); + assignment_failed(fi, cause); + } break; case GSCON_EV_MO_DTAP: forward_dtap(conn, (struct msgb *)data, fi); @@ -635,7 +932,6 @@ static void gscon_fsm_wait_mdcx_bts(struct osmo_fsm_inst *fi, uint32_t event, vo struct gsm_subscriber_connection *conn = fi->priv; struct mgcp_conn_peer conn_peer; struct sockaddr_in *sin = NULL; - struct msgb *resp = NULL; switch (event) { case GSCON_EV_MGW_MDCX_RESP_BTS: @@ -658,9 +954,7 @@ static void gscon_fsm_wait_mdcx_bts(struct osmo_fsm_inst *fi, uint32_t event, vo mgcp_conn_create(conn->network->mgw.client, fi, GSCON_EV_MGW_FAIL_MSC, GSCON_EV_MGW_CRCX_RESP_MSC, &conn_peer); if (!conn->user_plane.fi_bts) { - resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL); - sigtran_send(conn, resp, fi); - osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0); + assignment_failed(fi, GSM0808_CAUSE_EQUIPMENT_FAILURE); return; } diff --git a/src/libbsc/bts_ipaccess_nanobts.c b/src/libbsc/bts_ipaccess_nanobts.c index 3eb7e0e4d..fda4cc55c 100644 --- a/src/libbsc/bts_ipaccess_nanobts.c +++ b/src/libbsc/bts_ipaccess_nanobts.c @@ -166,6 +166,9 @@ static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd) new_state->availability == NM_AVSTATE_DEPENDENCY) { enum abis_nm_chan_comb ccomb = abis_nm_chcomb4pchan(ts->pchan); + LOGP(DNM, LOGL_ERROR, "%s pchan=%s Channel state chg, ccomb=0x%x\n", + gsm_ts_name(ts), gsm_pchan_name(ts->pchan), ccomb); + if (abis_nm_set_channel_attr(ts, ccomb) == -EINVAL) { ipaccess_drop_oml(trx->bts); return -1; -- cgit v1.2.3