Hey,
I posted some of these patches some time ago and started to rebase them now. The main idea is to make the "paging" layer more internal and only request to open a channel (of a specific type) to a certain subscriber.
The internal handling would find the right bts in the lac ("new" requirement and not yet implemented), will make sure that we assign as many as possible channels to the subscriber but will not lose any request (act as a queue).
I would like to merge the first two patches as I think they are moving in the right direction and are unlikely to break anything and plan to test the third patch later this week (if I get access to a BTS).
So if you will see a regression in call handling, shout at me..
z.
include/openbsc/gsm_data.h | 2 include/openbsc/gsm_subscriber.h | 9 ++ src/bsc_hack.c | 1 src/gsm_04_08.c | 6 - src/gsm_subscriber.c | 139 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 153 insertions(+), 4 deletions(-)
From 6cec523f3c48a6b0d253a9c7405bb6797b044e68 Mon Sep 17 00:00:00 2001 From: Holger Freyther <ich@tamarin.(none)> Date: Tue, 31 Mar 2009 04:35:19 +0200 Subject: [PATCH 1/3] Proposal for a "channel request" interface...
Reuqests for a subscriber a stored within the gsm_subscriber datastructure and it will keep track how many channels are allocated for this user and of which type to decide on policy...
e.g. attempt to submit SMS during a phone call and not doing paging but a simple (immediate) assignment of the channel... --- include/openbsc/gsm_subscriber.h | 8 ++++++++ src/bsc_hack.c | 1 + src/gsm_04_08.c | 6 +++--- src/gsm_subscriber.c | 26 ++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/include/openbsc/gsm_subscriber.h b/include/openbsc/gsm_subscriber.h index 99148b5..abe1fd7 100644 --- a/include/openbsc/gsm_subscriber.h +++ b/include/openbsc/gsm_subscriber.h @@ -23,6 +23,9 @@ struct gsm_subscriber { /* for internal management */ int use_count; struct llist_head entry; + + /* pending requests */ + struct llist_head requests; };
enum gsm_subscriber_field { @@ -43,6 +46,11 @@ struct gsm_subscriber *subscr_get_by_imsi(const char *imsi); struct gsm_subscriber *subscr_get_by_extension(const char *ext); int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason); void subscr_put_channel(struct gsm_lchan *lchan); +void subscr_get_channel(struct gsm_subscriber *subscr, + struct gsm_bts *bts, int type, + gsm_cbfn *cbfn, void *data); + +void subscr_init(struct gsm_network *network);
/* internal */ struct gsm_subscriber *subscr_alloc(void); diff --git a/src/bsc_hack.c b/src/bsc_hack.c index 188ccf6..7821044 100644 --- a/src/bsc_hack.c +++ b/src/bsc_hack.c @@ -983,6 +983,7 @@ static int bootstrap_network(void) printf("DB: Database prepared.\n");
telnet_init(gsmnet, 4242); + subscr_init(gsmnet);
register_signal_handler(SS_NM, nm_sig_cb, NULL);
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c index 83f38dd..040efff 100644 --- a/src/gsm_04_08.c +++ b/src/gsm_04_08.c @@ -1203,10 +1203,10 @@ static int gsm48_cc_rx_setup(struct msgb *msg) call->called_subscr = called_subscr;
/* start paging of the receiving end of the call */ - /* FIXME: we're assuming that the receiver is at the same BTS - * than we are, which is obviously a wrong assumption in multi-BTS + /* FIXME: we're assuming that the receiver is at the same BSC + * than we are, which is obviously a wrong assumption in multi BSC * case */ - paging_request(msg->trx->bts, called_subscr, RSL_CHANNEED_TCH_F, + subscr_get_channel(called_subscr, msg->trx->bts, RSL_CHANNEED_TCH_F, setup_trig_pag_evt, call);
/* send a CALL PROCEEDING message to the MO */ diff --git a/src/gsm_subscriber.c b/src/gsm_subscriber.c index 3f608ec..19de6dc 100644 --- a/src/gsm_subscriber.c +++ b/src/gsm_subscriber.c @@ -27,11 +27,13 @@ #include <string.h>
#include <openbsc/gsm_subscriber.h> +#include <openbsc/paging.h> #include <openbsc/debug.h> #include <openbsc/db.h>
LLIST_HEAD(active_subscribers); +struct gsm_network *gsmnet = NULL;
struct gsm_subscriber *subscr_alloc(void) { @@ -45,6 +47,8 @@ struct gsm_subscriber *subscr_alloc(void) llist_add_tail(&s->entry, &active_subscribers); s->use_count = 1;
+ INIT_LLIST_HEAD(&s->requests); + return s; }
@@ -131,6 +135,23 @@ struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr) return NULL; }
+void subscr_get_channel(struct gsm_subscriber *subscr, + struct gsm_bts *default_bts, int type, + gsm_cbfn *cbfn, void *data) +{ + /* FIXME: Find the right BTS... */ + struct gsm_bts *bts; + if (default_bts) + bts = default_bts; + else + bts = gsm_bts_by_lac(gsmnet, subscr->lac, NULL); + + if (!bts) + return; + + paging_request(bts, subscr, type, cbfn, data); +} + void subscr_put_channel(struct gsm_lchan *lchan) { /* @@ -141,3 +162,8 @@ void subscr_put_channel(struct gsm_lchan *lchan) */ put_lchan(lchan); } + +void subscr_init(struct gsm_network *net) +{ + gsmnet = net; +}
From 6f3d3f1b8ea8ef1e54367a0c8963c7c358addfb8 Mon Sep 17 00:00:00 2001 From: Holger Freyther <ich@tamarin.(none)> Date: Sun, 5 Apr 2009 14:36:33 +0200 Subject: [PATCH 2/3] [paging] Immediately fail if we don't have something like a VLR
If we don't know where to search for a GSM subscriber then do not try to page it at all. Introduce an enum value for this and call the callback from within the get_channel request. --- include/openbsc/gsm_data.h | 1 + src/gsm_subscriber.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h index e85adf8..297d505 100644 --- a/include/openbsc/gsm_data.h +++ b/include/openbsc/gsm_data.h @@ -25,6 +25,7 @@ enum gsm_hooks { enum gsm_paging_event { GSM_PAGING_SUCCEEDED, GSM_PAGING_EXPIRED, + GSM_PAGING_VLR_UNKNOWN, };
struct msgb; diff --git a/src/gsm_subscriber.c b/src/gsm_subscriber.c index 19de6dc..d9e7116 100644 --- a/src/gsm_subscriber.c +++ b/src/gsm_subscriber.c @@ -147,9 +147,15 @@ void subscr_get_channel(struct gsm_subscriber *subscr, bts = gsm_bts_by_lac(gsmnet, subscr->lac, NULL);
if (!bts) - return; + goto error;
paging_request(bts, subscr, type, cbfn, data); + return; + +error: + if (!cbfn) + return; + cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_VLR_UNKNOWN, NULL, NULL, data); }
void subscr_put_channel(struct gsm_lchan *lchan)
From d1e5ef15114ee6071597d4338500c553d9959c87 Mon Sep 17 00:00:00 2001 From: Holger Freyther <ich@tamarin.(none)> Date: Sat, 18 Apr 2009 13:48:55 +0200 Subject: [PATCH 3/3] [channel] Handle and dispatch paging requests in gsm_subscriber
Implement subscr_get_channel to a degree that a pending SMS Submit and a phone call should work. --- include/openbsc/gsm_data.h | 1 + include/openbsc/gsm_subscriber.h | 1 + src/gsm_subscriber.c | 113 ++++++++++++++++++++++++++++++++++++- 3 files changed, 111 insertions(+), 4 deletions(-)
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h index 297d505..9a13b4b 100644 --- a/include/openbsc/gsm_data.h +++ b/include/openbsc/gsm_data.h @@ -26,6 +26,7 @@ enum gsm_paging_event { GSM_PAGING_SUCCEEDED, GSM_PAGING_EXPIRED, GSM_PAGING_VLR_UNKNOWN, + GSM_PAGING_OOM, };
struct msgb; diff --git a/include/openbsc/gsm_subscriber.h b/include/openbsc/gsm_subscriber.h index abe1fd7..d5c2a90 100644 --- a/include/openbsc/gsm_subscriber.h +++ b/include/openbsc/gsm_subscriber.h @@ -25,6 +25,7 @@ struct gsm_subscriber { struct llist_head entry;
/* pending requests */ + int in_callback; struct llist_head requests; };
diff --git a/src/gsm_subscriber.c b/src/gsm_subscriber.c index d9e7116..200ac8f 100644 --- a/src/gsm_subscriber.c +++ b/src/gsm_subscriber.c @@ -25,16 +25,78 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <assert.h>
#include <openbsc/gsm_subscriber.h> #include <openbsc/paging.h> #include <openbsc/debug.h> +#include <openbsc/paging.h> #include <openbsc/db.h>
- LLIST_HEAD(active_subscribers); struct gsm_network *gsmnet = NULL;
+/* + * Struct for pending channel requests. This is managed in the + * llist_head requests of each subscriber. The reference counting + * should work in such a way that a subscriber with a pending request + * remains in memory. + */ +struct subscr_request { + struct llist_head entry; + + /* back reference */ + struct gsm_subscriber *subscr; + + /* the requested channel type */ + int channel_type; + + /* the bts we have decided to use */ + struct gsm_bts *bts; + + /* the callback data */ + gsm_cbfn *cbfn; + void *data; +}; + +/* + * We got the channel assigned and can now hand this channel + * over to one of our callbacks. + */ +static int subscr_paging_cb(unsigned int hooknum, unsigned int event, + struct msgb *msg, void *data, void *param) +{ + struct subscr_request *request; + struct gsm_subscriber *subscr = (struct gsm_subscriber *)data; + + assert(!llist_empty(&subscr->requests)); + + /* + * FIXME: What to do with paging requests coming during + * this callback? We must be sure to not start paging when + * we have an active connection to a subscriber and to make + * the subscr_put_channel work as required... + */ + request = (struct subscr_request *)subscr->requests.next; + llist_del(&request->entry); + subscr->in_callback = 1; + request->cbfn(hooknum, event, msg, request->data, param); + subscr->in_callback = 0; + + free(request); + return 0; +} + +static void subscr_send_paging_request(struct gsm_subscriber *subscr) +{ + struct subscr_request *request; + assert(!llist_empty(&subscr->requests)); + + request = (struct subscr_request *)subscr->requests.next; + paging_request(request->bts, subscr, request->channel_type, + subscr_paging_cb, subscr); +} + struct gsm_subscriber *subscr_alloc(void) { struct gsm_subscriber *s; @@ -139,8 +201,10 @@ void subscr_get_channel(struct gsm_subscriber *subscr, struct gsm_bts *default_bts, int type, gsm_cbfn *cbfn, void *data) { - /* FIXME: Find the right BTS... */ + struct subscr_request *request; struct gsm_bts *bts; + + /* FIXME: Find the right BTS... */ if (default_bts) bts = default_bts; else @@ -149,8 +213,34 @@ void subscr_get_channel(struct gsm_subscriber *subscr, if (!bts) goto error;
- paging_request(bts, subscr, type, cbfn, data); - return; + request = (struct subscr_request *)malloc(sizeof(*request)); + if (!request) { + if (cbfn) + cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_OOM, + NULL, NULL, data); + return; + } + + memset(request, 0, sizeof(*request)); + request->bts = bts; + request->subscr = subscr; + request->channel_type = type; + request->cbfn = cbfn; + request->data = data; + + /* + * FIXME: We might be able to assign more than one + * channel, e.g. voice and SMS submit at the same + * time. + */ + if (!subscr->in_callback && llist_empty(&subscr->requests)) { + /* add to the list, send a request */ + llist_add_tail(&request->entry, &subscr->requests); + subscr_send_paging_request(subscr); + } else { + /* this will be picked up later */ + llist_add_tail(&request->entry, &subscr->requests); + }
error: if (!cbfn) @@ -166,7 +256,22 @@ void subscr_put_channel(struct gsm_lchan *lchan) * of the lchan after having asked the next requestee to handle * the channel. */ + /* + * FIXME: is the lchan is of a different type we could still + * issue an immediate assignment for another channel and then + * close this one. + */ + /* + * Currently we will drop the last ref of the lchan which + * will result in a channel release on RSL and we will start + * the paging. This should work most of the time as the MS + * will listen to the paging requests before we timeout + */ + put_lchan(lchan); + + if (lchan->subscr && !llist_empty(&lchan->subscr->requests)) + subscr_send_paging_request(lchan->subscr); }
void subscr_init(struct gsm_network *net)