aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-04-30 14:16:37 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2018-04-30 14:16:49 +0200
commit36f34ab21ad7f4f0a51b3a4c53967128109923aa (patch)
tree4b28e2690797ba0d69d7e460453cc6ec27ac800b
parent3413cd01d944885e5ae841826d033a777b667987 (diff)
-rw-r--r--include/osmocom/bsc/gsm_data.h12
-rw-r--r--src/libbsc/abis_nm.c2
-rw-r--r--src/libbsc/abis_rsl.c48
-rw-r--r--src/libbsc/bsc_api.c104
-rw-r--r--src/libbsc/bsc_subscr_conn_fsm.c352
-rw-r--r--src/libbsc/bts_ipaccess_nanobts.c3
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;