aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Willmann <daniel@totalueberwachung.de>2013-01-03 17:37:59 +0100
committerHarald Welte <laforge@gnumonks.org>2013-03-24 09:05:04 +0100
commit376183fcf05c84a26e6ccb96d033ed569c84473c (patch)
treea01dcb33e7681bf644eabae29b68d6777db62ad8
parentfb0c9f06132769336ab2f01f6b01e369f48f3575 (diff)
oml: Introduce a SAPI queue for activation and deactivation of SAPIs
Put all SAPI requests into a queue and handle them one after another. Begin with the channel activation. Once the queue is empty the channel activate will be sent. For the BCCH activation we do not want to send a channel activation message and this is why we set the lchan->state to NONE. One change is that we do not attempt to call the ciphering routines on the BCCH anymore. This change is necessary to fix issues with LCHANs staying open and being marked as broken by the BSC and will help in implementing handover support as this requires a re-configuration of the lchan on the fly.
-rw-r--r--src/osmo-bts-sysmo/oml.c192
-rw-r--r--src/osmo-bts-sysmo/sysmobts_vty.c2
2 files changed, 163 insertions, 31 deletions
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index da3b95b5..e9166098 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -38,6 +38,18 @@
#include "l1_if.h"
#include "femtobts.h"
+enum sapi_cmd_type {
+ SAPI_CMD_ACTIVATE,
+};
+
+struct sapi_cmd {
+ struct llist_head entry;
+ GsmL1_Sapi_t sapi;
+ GsmL1_Dir_t dir;
+ enum sapi_cmd_type type;
+ int (*callback)(struct gsm_lchan *lchan, int status);
+};
+
static const enum GsmL1_LogChComb_t pchan_to_logChComb[_GSM_PCHAN_MAX] = {
[GSM_PCHAN_NONE] = GsmL1_LogChComb_0,
[GSM_PCHAN_CCCH] = GsmL1_LogChComb_IV,
@@ -177,7 +189,7 @@ static int compl_cb_send_oml_msg(struct msgb *l1_msg, void *data)
}
#endif
-int lchan_activate(struct gsm_lchan *lchan);
+int lchan_activate(struct gsm_lchan *lchan, enum gsm_lchan_state lchan_state);
static int opstart_compl(struct gsm_abis_mo *mo, struct msgb *l1_msg)
{
@@ -200,7 +212,7 @@ static int opstart_compl(struct gsm_abis_mo *mo, struct msgb *l1_msg)
if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&
mo->obj_inst.ts_nr == 0) {
DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");
- lchan_activate(&mo->bts->c0->ts[0].lchan[4]);
+ lchan_activate(&mo->bts->c0->ts[0].lchan[4], LCHAN_S_NONE);
}
/* Send OPSTART ack */
@@ -452,9 +464,63 @@ static const struct lchan_sapis sapis_for_lchan[_GSM_LCHAN_MAX] = {
},
};
+static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
+
+static void sapi_queue_next(struct gsm_lchan *lchan)
+{
+ struct sapi_cmd *cmd;
+
+ cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
+
+ switch (cmd->type) {
+ case SAPI_CMD_ACTIVATE:
+ mph_send_activate_req(lchan, cmd);
+ break;
+ default:
+ LOGP(DL1C, LOGL_NOTICE,
+ "Unimplemented command type %d\n", cmd->type);
+ abort();
+ break;
+ }
+}
+
+static void sapi_queue_dispatch(struct gsm_lchan *lchan, int status)
+{
+ int end;
+ struct sapi_cmd *cmd = llist_entry(lchan->sapi_cmds.next,
+ struct sapi_cmd, entry);
+ llist_del(&cmd->entry);
+ end = llist_empty(&lchan->sapi_cmds);
+
+ if (cmd->callback)
+ cmd->callback(lchan, status);
+ talloc_free(cmd);
+
+ if (end) {
+ LOGP(DL1C, LOGL_DEBUG,
+ "%s End of queue encountered\n",
+ gsm_lchan_name(lchan));
+ return;
+ }
+
+ sapi_queue_next(lchan);
+}
+
+static void queue_sapi_command(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
+{
+ int start = llist_empty(&lchan->sapi_cmds);
+ llist_add_tail(&cmd->entry, &lchan->sapi_cmds);
+
+ if (!start)
+ return;
+
+ sapi_queue_next(lchan);
+}
+
static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg)
{
- struct gsm_time *time;
+ enum lchan_sapi_state status;
+ struct sapi_cmd *cmd;
struct gsm_lchan *lchan;
GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);
GsmL1_MphActivateCnf_t *ic = &l1p->u.mphActivateCnf;
@@ -476,31 +542,38 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg)
if (ic->status == GsmL1_Status_Success) {
DEBUGP(DL1C, "Successful activation of L1 SAPI %s on TS %u\n",
get_value_string(femtobts_l1sapi_names, ic->sapi), ic->u8Tn);
- lchan_set_state(lchan, LCHAN_S_ACTIVE);
+ status = LCHAN_SAPI_S_ASSIGNED;
} else {
LOGP(DL1C, LOGL_ERROR, "Error activating L1 SAPI %s on TS %u: %s\n",
get_value_string(femtobts_l1sapi_names, ic->sapi), ic->u8Tn,
get_value_string(femtobts_l1status_names, ic->status));
- lchan_set_state(lchan, LCHAN_S_NONE);
+ status = LCHAN_SAPI_S_ERROR;
}
- switch (ic->sapi) {
- case GsmL1_Sapi_Sdcch:
- case GsmL1_Sapi_TchF:
- case GsmL1_Sapi_TchH:
- time = bts_model_get_time(lchan->ts->trx->bts);
- if (lchan->state == LCHAN_S_ACTIVE) {
- /* Hack: we simply only use one direction to
- * avoid sending two ACKs for one activate */
- if (ic->dir == GsmL1_Dir_TxDownlink)
- rsl_tx_chan_act_ack(lchan, time);
- } else
- rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL);
- break;
- default:
- break;
+ if (ic->dir & GsmL1_Dir_TxDownlink)
+ lchan->sapis_dl[ic->sapi] = status;
+ if (ic->dir & GsmL1_Dir_RxUplink)
+ lchan->sapis_ul[ic->sapi] = status;
+
+ if (llist_empty(&lchan->sapi_cmds)) {
+ LOGP(DL1C, LOGL_ERROR,
+ "%s Got activation confirmation with empty queue\n",
+ gsm_lchan_name(lchan));
+ goto err;
}
+ cmd = llist_entry(lchan->sapi_cmds.next, struct sapi_cmd, entry);
+ if (cmd->sapi != ic->sapi || cmd->dir != ic->dir) {
+ LOGP(DL1C, LOGL_ERROR,
+ "%s Confirmation mismatch (%d, %d) (%d, %d)\n",
+ gsm_lchan_name(lchan), cmd->sapi, cmd->dir,
+ ic->sapi, ic->dir);
+ goto err;
+ }
+
+ sapi_queue_dispatch(lchan, ic->status);
+
+err:
msgb_free(l1_msg);
return 0;
@@ -655,10 +728,12 @@ static void lchan2lch_par(GsmL1_LogChParam_t *lch_par, struct gsm_lchan *lchan)
}
}
-static int mph_send_activate_req(struct gsm_lchan *lchan, int sapi, int dir)
+static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd)
{
struct femtol1_hdl *fl1h = trx_femtol1_hdl(lchan->ts->trx);
struct msgb *msg = l1p_msgb_alloc();
+ int sapi = cmd->sapi;
+ int dir = cmd->dir;
GsmL1_MphActivateReq_t *act_req;
GsmL1_LogChParam_t *lch_par;
@@ -716,28 +791,85 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, int sapi, int dir)
return l1if_gsm_req_compl(fl1h, msg, lchan_act_compl_cb);
}
-int lchan_activate(struct gsm_lchan *lchan)
+static void sapi_clear_queue(struct llist_head *queue)
+{
+ struct sapi_cmd *next, *tmp;
+
+ llist_for_each_entry_safe(next, tmp, queue, entry) {
+ llist_del(&next->entry);
+ talloc_free(next);
+ }
+}
+
+static int sapi_activate_cb(struct gsm_lchan *lchan, int status)
+{
+ struct femtol1_hdl *fl1h = trx_femtol1_hdl(lchan->ts->trx);
+
+ /* FIXME: Error handling */
+ if (status != GsmL1_Status_Success) {
+ lchan_set_state(lchan, LCHAN_S_BROKEN);
+ sapi_clear_queue(&lchan->sapi_cmds);
+ rsl_tx_chan_act_nack(lchan, RSL_ERR_EQUIPMENT_FAIL);
+ return -1;
+ }
+
+ if (!llist_empty(&lchan->sapi_cmds))
+ return 0;
+
+ if (lchan->state != LCHAN_S_ACT_REQ)
+ return 0;
+
+ struct gsm_time *time;
+ lchan_set_state(lchan, LCHAN_S_ACTIVE);
+ time = bts_model_get_time(lchan->ts->trx->bts);
+ rsl_tx_chan_act_ack(lchan, time);
+
+#warning "FIXME: Ciphering needs to be enqueued as well"
+ /* set the initial ciphering parameters for both directions */
+ l1if_set_ciphering(fl1h, lchan, 0);
+ l1if_set_ciphering(fl1h, lchan, 1);
+
+ return 0;
+}
+
+static void enqueue_sapi_act_cmd(struct gsm_lchan *lchan, int sapi, int dir)
+{
+ struct sapi_cmd *cmd = talloc_zero(lchan->ts->trx, struct sapi_cmd);
+
+ cmd->sapi = sapi;
+ cmd->dir = dir;
+ cmd->type = SAPI_CMD_ACTIVATE;
+ cmd->callback = sapi_activate_cb;
+ queue_sapi_command(lchan, cmd);
+}
+
+int lchan_activate(struct gsm_lchan *lchan, enum gsm_lchan_state lchan_state)
{
struct gsm_bts_role_bts *btsb = lchan->ts->trx->bts->role;
struct femtol1_hdl *fl1h = trx_femtol1_hdl(lchan->ts->trx);
const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type];
unsigned int i;
+ lchan_set_state(lchan, lchan_state);
+
+ if (!llist_empty(&lchan->sapi_cmds))
+ LOGP(DL1C, LOGL_ERROR,
+ "%s Trying to activate lchan, but commands in queue\n",
+ gsm_lchan_name(lchan));
+
for (i = 0; i < s4l->num_sapis; i++) {
- if (s4l->sapis[i].sapi == GsmL1_Sapi_Sch) {
+ int sapi = s4l->sapis[i].sapi;
+ int dir = s4l->sapis[i].dir;
+
+ if (sapi == GsmL1_Sapi_Sch) {
/* once we activate the SCH, we should get MPH-TIME.ind */
fl1h->alive_timer.cb = alive_timer_cb;
fl1h->alive_timer.data = fl1h;
fl1h->alive_prim_cnt = 0;
osmo_timer_schedule(&fl1h->alive_timer, 5, 0);
}
- mph_send_activate_req(lchan, s4l->sapis[i].sapi, s4l->sapis[i].dir);
+ enqueue_sapi_act_cmd(lchan, sapi, dir);
}
- lchan_set_state(lchan, LCHAN_S_ACT_REQ);
-
- /* set the initial ciphering parameters for both directions */
- l1if_set_ciphering(fl1h, lchan, 0);
- l1if_set_ciphering(fl1h, lchan, 1);
lchan_init_lapdm(lchan);
@@ -1130,7 +1262,7 @@ int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp)
//uint8_t type = *TLVP_VAL(tp, RSL_IE_ACT_TYPE);
lchan->sacch_deact = 0;
- lchan_activate(lchan);
+ lchan_activate(lchan, LCHAN_S_ACT_REQ);
return 0;
}
diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c
index feb271a1..0ecf5858 100644
--- a/src/osmo-bts-sysmo/sysmobts_vty.c
+++ b/src/osmo-bts-sysmo/sysmobts_vty.c
@@ -348,7 +348,7 @@ DEFUN(activate_lchan, activate_lchan_cmd,
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
if (!strcmp(argv[2], "activate"))
- lchan_activate(lchan);
+ lchan_activate(lchan, LCHAN_S_ACT_REQ);
else
lchan_deactivate(lchan);