summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2013-06-17 11:58:30 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2013-07-29 12:44:58 +0200
commit01cee5dd20b801dd52cafc03ccbe60265db93e84 (patch)
treed41b5de971b02967afae7382a93b99d14e7c2ba2
parentfd3a41f145746f1ab3cd6d3208f59ed2e1d145f3 (diff)
Add a queue to bsc_api to queue DTAP messages during handover/assignment
-rw-r--r--openbsc/include/openbsc/gsm_data.h1
-rw-r--r--openbsc/src/libbsc/bsc_api.c66
2 files changed, 67 insertions, 0 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 9c2737e56..52937cc57 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -138,6 +138,7 @@ struct gsm_subscriber_connection {
/* for assignment handling */
struct osmo_timer_list T10;
struct gsm_lchan *secondary_lchan;
+ struct llist_head assignment_queue;
/* penalty timers for handover */
struct llist_head ho_penalty_timers;
diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c
index db3d1bb5f..271eb4a7b 100644
--- a/openbsc/src/libbsc/bsc_api.c
+++ b/openbsc/src/libbsc/bsc_api.c
@@ -46,6 +46,13 @@ static void handle_release(struct gsm_subscriber_connection *conn, struct bsc_ap
static void handle_chan_ack(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan);
static void handle_chan_nack(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan);
+struct assignment_queue {
+ struct llist_head entry;
+ struct msgb *msg;
+ int link_id;
+ int allow_sacch;
+};
+
/* GSM 08.08 3.2.2.33 */
static uint8_t lchan_to_chosen_channel(struct gsm_lchan *lchan)
{
@@ -258,10 +265,36 @@ struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
conn->bts = lchan->ts->trx->bts;
lchan->conn = conn;
INIT_LLIST_HEAD(&conn->ho_penalty_timers);
+ INIT_LLIST_HEAD(&conn->assignment_queue);
llist_add_tail(&conn->entry, &sub_connections);
return conn;
}
+static void flush_assignment_queue(struct gsm_subscriber_connection *conn,
+ int send)
+{
+ struct assignment_queue *ass_queue;
+
+ if (conn->secondary_lchan || conn->ho_lchan) {
+ LOGP(DNM, LOGL_ERROR, "Cannot send queued messages, because "
+ "handover/assignment is still ongoing, please fix!\n");
+ send = 0;
+ }
+
+ while (!llist_empty(&conn->assignment_queue)) {
+ ass_queue = llist_entry(conn->assignment_queue.next,
+ struct assignment_queue, entry);
+ llist_del(&ass_queue->entry);
+ if (send) {
+ LOGP(DNM, LOGL_DEBUG, "Sending pending DTAP message\n");
+ gsm0808_submit_dtap(conn, ass_queue->msg,
+ ass_queue->link_id, ass_queue->allow_sacch);
+ } else
+ msgb_free(ass_queue->msg);
+ talloc_free(ass_queue);
+ }
+}
+
/* TODO: move subscriber put here... */
void subscr_con_free(struct gsm_subscriber_connection *conn)
{
@@ -300,6 +333,9 @@ void subscr_con_free(struct gsm_subscriber_connection *conn)
talloc_free(penalty);
}
+ /* flush pending messages */
+ flush_assignment_queue(conn, 0);
+
llist_del(&conn->entry);
talloc_free(conn);
}
@@ -324,6 +360,18 @@ int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
return -1;
}
+ /* buffer message during assignment / handover */
+ if (conn->secondary_lchan || conn->ho_lchan) {
+ struct assignment_queue *ass_queue;
+ LOGP(DNM, LOGL_DEBUG, "Queing DTAP message during ho/ass\n");
+ ass_queue = talloc_zero(tall_bsc_ctx, struct assignment_queue);
+ ass_queue->msg = msg;
+ ass_queue->link_id = link_id;
+ ass_queue->allow_sacch = allow_sacch;
+ llist_add_tail(&ass_queue->entry, &conn->assignment_queue);
+ return 0;
+ }
+
sapi = link_id & 0x7;
msg->lchan = conn->lchan;
msg->dst = msg->lchan->ts->trx->rsl_link;
@@ -455,6 +503,9 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
osmo_signal_dispatch(SS_LCHAN, S_LCHAN_ASSIGNMENT_COMPL, &sig);
/* FIXME: release old channel */
+ /* send pending messages, if any */
+ flush_assignment_queue(conn, 1);
+
return;
}
@@ -477,6 +528,9 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
conn->lchan = conn->secondary_lchan;
conn->secondary_lchan = NULL;
+ /* send pending messages, if any */
+ flush_assignment_queue(conn, 1);
+
if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
rsl_ipacc_crcx(conn->lchan);
@@ -514,6 +568,9 @@ static void handle_ass_fail(struct gsm_subscriber_connection *conn,
osmo_signal_dispatch(SS_LCHAN, S_LCHAN_ASSIGNMENT_FAIL, &sig);
/* FIXME: release allocated new channel */
+ /* send pending messages, if any */
+ flush_assignment_queue(conn, 1);
+
return;
}
@@ -529,6 +586,9 @@ static void handle_ass_fail(struct gsm_subscriber_connection *conn,
conn->secondary_lchan = NULL;
}
+ /* send pending messages, if any */
+ flush_assignment_queue(conn, 1);
+
gh = msgb_l3(msg);
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
LOGP(DMSC, LOGL_ERROR, "assignemnt failure unhandled: %u\n",
@@ -594,6 +654,9 @@ static void handle_rr_ho_compl(struct msgb *msg)
sig.mr = NULL;
osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, &sig);
/* FIXME: release old channel */
+
+ /* send pending messages, if any */
+ flush_assignment_queue(msg->lchan->conn, 1);
}
/* Chapter 9.1.17 Handover Failure */
@@ -609,6 +672,9 @@ static void handle_rr_ho_fail(struct msgb *msg)
sig.mr = NULL;
osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, &sig);
/* FIXME: release allocated new channel */
+
+ /* send pending messages, if any */
+ flush_assignment_queue(msg->lchan->conn, 1);
}