aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/abis_nm.c3
-rw-r--r--openbsc/src/bsc_hack.c34
-rw-r--r--openbsc/src/e1_input.c11
-rw-r--r--openbsc/src/gsm_04_08.c34
-rw-r--r--openbsc/src/gsm_subscriber.c119
-rw-r--r--openbsc/src/paging.c49
6 files changed, 209 insertions, 41 deletions
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index 74dba2377..83e6bbb48 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -893,6 +893,9 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
DEBUGPC(DNM, "\n");
+
+ dispatch_signal(SS_NM, S_NM_NACK, (void*) ((long)mt));
+ return 0;
}
#if 0
/* check if last message is to be acked */
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 7aa8b9aef..388840793 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -454,6 +454,18 @@ static int sw_activ_rep(struct msgb *mb)
return 0;
}
+/* Callback function for NACK on the OML NM */
+static int oml_msg_nack(int mt)
+{
+ if (mt == NM_MT_SET_BTS_ATTR_NACK) {
+ fprintf(stderr, "Failed to set BTS attributes. That is fatal. "
+ "Was the bts type and frequency properly specified?\n");
+ exit(-1);
+ }
+
+ return 0;
+}
+
/* Callback function to be called every time we receive a signal from NM */
static int nm_sig_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
@@ -461,6 +473,8 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal,
switch (signal) {
case S_NM_SW_ACTIV_REP:
return sw_activ_rep(signal_data);
+ case S_NM_NACK:
+ return oml_msg_nack((int)signal_data);
default:
break;
}
@@ -960,6 +974,26 @@ static int bootstrap_network(void)
{
struct gsm_bts *bts;
+ switch(BTS_TYPE) {
+ case GSM_BTS_TYPE_NANOBTS_1800:
+ if (ARFCN < 512 || ARFCN > 885) {
+ fprintf(stderr, "GSM1800 channel must be between 512-885.\n");
+ return -EINVAL;
+ }
+ break;
+ case GSM_BTS_TYPE_BS11:
+ case GSM_BTS_TYPE_NANOBTS_900:
+ /* Assume we have a P-GSM900 here */
+ if (ARFCN < 1 || ARFCN > 124) {
+ fprintf(stderr, "GSM900 channel must be between 1-124.\n");
+ return -EINVAL;
+ }
+ break;
+ case GSM_BTS_TYPE_UNKNOWN:
+ fprintf(stderr, "Unknown BTS. Please use the --bts-type switch\n");
+ return -EINVAL;
+ }
+
/* initialize our data structures */
gsmnet = gsm_network_init(2, BTS_TYPE, MCC, MNC);
if (!gsmnet)
diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c
index c3c7c7597..034bd9723 100644
--- a/openbsc/src/e1_input.c
+++ b/openbsc/src/e1_input.c
@@ -140,6 +140,7 @@ static void write_pcap_packet(int direction, int sapi, int tei,
int ret;
time_t cur_time;
struct tm *tm;
+ int mi_head = (direction==PCAP_INPUT) ? MISDN_HEADER_LEN : 0;
struct fake_linux_lapd_header header = {
.pkttype = 4,
@@ -163,13 +164,15 @@ static void write_pcap_packet(int direction, int sapi, int tei,
.ts_usec = 0,
.incl_len = msg->len + sizeof(struct fake_linux_lapd_header)
+ sizeof(struct lapd_header)
- - MISDN_HEADER_LEN,
+ - mi_head,
.orig_len = msg->len + sizeof(struct fake_linux_lapd_header)
+ sizeof(struct lapd_header)
- - MISDN_HEADER_LEN,
+ - mi_head,
};
+ printf("Packet of: %d\n", direction);
+
cur_time = time(NULL);
tm = localtime(&cur_time);
payload_header.ts_sec = mktime(tm);
@@ -177,8 +180,8 @@ static void write_pcap_packet(int direction, int sapi, int tei,
ret = write(pcap_fd, &payload_header, sizeof(payload_header));
ret = write(pcap_fd, &header, sizeof(header));
ret = write(pcap_fd, &lapd_header, sizeof(lapd_header));
- ret = write(pcap_fd, msg->data + MISDN_HEADER_LEN,
- msg->len - MISDN_HEADER_LEN);
+ ret = write(pcap_fd, msg->data + mi_head,
+ msg->len - mi_head);
}
static const char *sign_types[] = {
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index 052991c3b..90b88dfb3 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -1022,11 +1022,6 @@ static int mm_rx_id_resp(struct msgb *msg)
DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
mi_type, mi_string);
- /*
- * Rogue messages could trick us but so is life
- */
- put_lchan(lchan);
-
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
if (!lchan->subscr)
@@ -1116,7 +1111,6 @@ static int mm_rx_loc_upd_req(struct msgb *msg)
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
/* we always want the IMEI, too */
- use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
lchan->loc_operation->waiting_for_imei = 1;
@@ -1125,7 +1119,6 @@ static int mm_rx_loc_upd_req(struct msgb *msg)
break;
case GSM_MI_TYPE_TMSI:
/* we always want the IMEI, too */
- use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
lchan->loc_operation->waiting_for_imei = 1;
@@ -1133,7 +1126,6 @@ static int mm_rx_loc_upd_req(struct msgb *msg)
subscr = subscr_get_by_tmsi(mi_string);
if (!subscr) {
/* send IDENTITY REQUEST message to get IMSI */
- use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
lchan->loc_operation->waiting_for_imsi = 1;
}
@@ -1460,7 +1452,6 @@ static int gsm48_rr_rx_pag_resp(struct msgb *msg)
u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
char mi_string[MI_SIZE];
struct gsm_subscriber *subscr;
- struct gsm_bts *bts;
struct paging_signal_data sig_data;
int rc = 0;
@@ -1508,18 +1499,6 @@ static int gsm48_rr_rx_pag_resp(struct msgb *msg)
/* Stop paging on the bts we received the paging response */
paging_request_stop(msg->trx->bts, subscr, msg->lchan);
- /* Stop paging on all other bts' */
- bts = NULL;
- do {
- bts = gsm_bts_by_lac(msg->trx->bts->network, subscr->lac, bts);
- if (!bts)
- break;
- if (bts == msg->trx->bts)
- continue;
- /* Stop paging */
- paging_request_stop(bts, subscr, NULL);
- } while (1);
-
/* FIXME: somehow signal the completion of the PAGING to
* the entity that requested the paging */
@@ -1754,7 +1733,6 @@ static int gsm48_cc_rx_setup(struct msgb *msg)
struct gsm48_hdr *gh = msgb_l3(msg);
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
struct gsm_subscriber *called_subscr;
- struct gsm_bts *bts;
char called_number[(43-2)*2 + 1] = "\0";
struct tlv_parsed tp;
int ret;
@@ -1798,16 +1776,8 @@ static int gsm48_cc_rx_setup(struct msgb *msg)
call->called_subscr = called_subscr;
/* Start paging subscriber on all BTS in LAC of subscriber */
- bts = NULL;
- do {
- bts = gsm_bts_by_lac(msg->trx->bts->network,
- msg->lchan->subscr->lac, bts);
- if (!bts)
- break;
- /* Trigger paging */
- paging_request(bts, called_subscr, RSL_CHANNEED_TCH_F,
- setup_trig_pag_evt, call);
- } while (1);
+ subscr_get_channel(called_subscr, msg->trx->bts->network, RSL_CHANNEED_TCH_F,
+ setup_trig_pag_evt, call);
/* send a CALL PROCEEDING message to the MO */
ret = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c
index 3f608ec30..3062a6bef 100644
--- a/openbsc/src/gsm_subscriber.c
+++ b/openbsc/src/gsm_subscriber.c
@@ -25,14 +25,77 @@
#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 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_network *network;
+
+ /* the callback data */
+ gsm_cbfn *cbfn;
+ void *param;
+};
+
+/*
+ * 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 *)param;
+
+ 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, data, request->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->network, subscr, request->channel_type,
+ subscr_paging_cb, subscr);
+}
+
struct gsm_subscriber *subscr_alloc(void)
{
struct gsm_subscriber *s;
@@ -45,6 +108,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 +196,42 @@ struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr)
return NULL;
}
+void subscr_get_channel(struct gsm_subscriber *subscr,
+ struct gsm_network *network, int type,
+ gsm_cbfn *cbfn, void *param)
+{
+ struct subscr_request *request;
+
+ request = (struct subscr_request *)malloc(sizeof(*request));
+ if (!request) {
+ if (cbfn)
+ cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_OOM,
+ NULL, NULL, param);
+ return;
+ }
+
+ memset(request, 0, sizeof(*request));
+ request->network = network;
+ request->subscr = subscr;
+ request->channel_type = type;
+ request->cbfn = cbfn;
+ request->param = param;
+
+ /*
+ * 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, from subscr_put_channel */
+ llist_add_tail(&request->entry, &subscr->requests);
+ }
+}
+
void subscr_put_channel(struct gsm_lchan *lchan)
{
/*
@@ -139,5 +240,21 @@ 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);
}
+
diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c
index f3bdf6973..8f15e1640 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -210,8 +210,8 @@ static void paging_T3113_expired(void *data)
paging_remove_request(&req->bts->paging, req);
}
-void paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
- int type, gsm_cbfn *cbfn, void *data)
+static void _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
+ int type, gsm_cbfn *cbfn, void *data)
{
struct gsm_bts_paging_state *bts_entry = &bts->paging;
struct gsm_paging_request *req;
@@ -237,9 +237,25 @@ void paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
bsc_schedule_timer(&bts_entry->work_timer, 1, 0);
}
+void paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
+ int type, gsm_cbfn *cbfn, void *data)
+{
+ struct gsm_bts *bts = NULL;
+
+ do {
+ bts = gsm_bts_by_lac(network, subscr->lac, bts);
+ if (!bts)
+ break;
+
+ /* Trigger paging */
+ _paging_request(bts, subscr, RSL_CHANNEED_TCH_F, cbfn, data);
+ } while (1);
+}
+
+
/* we consciously ignore the type of the request here */
-void paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
- struct gsm_lchan *lchan)
+static void _paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
+ struct gsm_lchan *lchan)
{
struct gsm_bts_paging_state *bts_entry = &bts->paging;
struct gsm_paging_request *req, *req2;
@@ -256,6 +272,31 @@ void paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
}
}
+/* Stop paging on all other bts' */
+void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr,
+ struct gsm_lchan *lchan)
+{
+ struct gsm_bts *bts = NULL;
+
+ _paging_request_stop(_bts, subscr, lchan);
+
+ do {
+ /*
+ * FIXME: Don't use the lac of the subscriber...
+ * as it might have magically changed the lac.. use the
+ * location area of the _bts as reconfiguration of the
+ * network is probably happening less often.
+ */
+ bts = gsm_bts_by_lac(_bts->network, subscr->lac, bts);
+ if (!bts)
+ break;
+
+ /* Stop paging */
+ if (bts != _bts)
+ _paging_request_stop(bts, subscr, NULL);
+ } while (1);
+}
+
void paging_update_buffer_space(struct gsm_bts *bts, u_int16_t free_slots)
{
bts->paging.available_slots = free_slots;