summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2011-06-07 20:12:33 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2012-05-02 19:24:29 +0200
commit5b77c752c78051a1ec193dc7f2aa6cf33f2be467 (patch)
treea52ba682f5912139ea64e328049bd94faedcf205
parent68d424a8d44f8928d2ae78f4dc9ed1826c4502c5 (diff)
bsc: Attempt to respond to paging to the MSC that paged
Inspect the message and see if it is a paging response, then try to find the MSC that has paged this subscriber and select this as the target MSC, also move the MSC to the back of the list for 'load balancing'.
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_filter.c71
1 files changed, 67 insertions, 4 deletions
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_filter.c b/openbsc/src/osmo-bsc/osmo_bsc_filter.c
index 7271fc8c3..200360ac9 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_filter.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_filter.c
@@ -53,8 +53,9 @@ static void handle_lu_request(struct gsm_subscriber_connection *conn,
}
}
-/* we will need to stop the paging request */
-static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
+/* extract a subscriber from the paging response */
+static struct gsm_subscriber *extract_sub(struct gsm_subscriber_connection *conn,
+ struct msgb *msg)
{
uint8_t mi_type;
char mi_string[GSM48_MI_SIZE];
@@ -64,7 +65,7 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) {
LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg));
- return -1;
+ return NULL;
}
gh = msgb_l3(msg);
@@ -88,6 +89,14 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
break;
}
+ return subscr;
+}
+
+/* we will need to stop the paging request */
+static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+ struct gsm_subscriber *subscr = extract_sub(conn, msg);
+
if (!subscr) {
LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
return -1;
@@ -100,10 +109,36 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
+ struct gsm48_hdr *gh;
+ int8_t pdisc;
+ uint8_t mtype;
struct osmo_bsc_data *bsc;
- struct osmo_msc_data *msc;
+ struct osmo_msc_data *msc, *pag_msc;
+ struct gsm_subscriber *subscr;
bsc = conn->bts->network->bsc_data;
+
+ if (msgb_l3len(msg) < sizeof(*gh)) {
+ LOGP(DMSC, LOGL_ERROR, "There is no GSM48 header here.\n");
+ return NULL;
+ }
+
+ gh = msgb_l3(msg);
+ pdisc = gh->proto_discr & 0x0f;
+ mtype = gh->msg_type & 0xbf;
+
+ /*
+ * We are asked to select a MSC here but they are not equal. We
+ * want to respond to a paging request on the MSC where we got the
+ * request from. This is where we need to decide where this connection
+ * will go.
+ */
+ if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP)
+ goto paging;
+ else
+ goto round_robin;
+
+round_robin:
llist_for_each_entry(msc, &bsc->mscs, entry) {
if (!msc->msc_con->is_authenticated)
continue;
@@ -114,6 +149,34 @@ struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
}
return NULL;
+
+paging:
+ subscr = extract_sub(conn, msg);
+
+ if (!subscr) {
+ LOGP(DMSC, LOGL_ERROR, "Got paged but no subscriber found.\n");
+ return NULL;
+ }
+
+ pag_msc = paging_get_data(conn->bts, subscr);
+ subscr_put(subscr);
+
+ llist_for_each_entry(msc, &bsc->mscs, entry) {
+ if (msc != pag_msc)
+ continue;
+
+ /*
+ * We don't check if the MSC is connected. In case it
+ * is not the connection will be dropped.
+ */
+
+ /* force round robin by moving it to the end */
+ llist_move_tail(&msc->entry, &bsc->mscs);
+ return msc;
+ }
+
+ LOGP(DMSC, LOGL_ERROR, "Got paged but no request found.\n");
+ return NULL;
}