diff options
author | Harald Welte <laforge@gnumonks.org> | 2009-06-10 23:21:25 +0800 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2009-06-10 23:21:25 +0800 |
commit | ec44e1ff4139f60483dfcaa8329e39b41bfb8c4a (patch) | |
tree | 1336fce24e2c2550993ba4ef20ab76cfe8ca196f /openbsc/src | |
parent | 0c3893078ed3f38f76b0236627bb38a8bd906af6 (diff) | |
parent | 20152a35e35e790ae281cd2445b746e338eb669c (diff) |
Merge commit 'origin/master'
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/abis_nm.c | 3 | ||||
-rw-r--r-- | openbsc/src/bsc_hack.c | 34 | ||||
-rw-r--r-- | openbsc/src/e1_input.c | 11 | ||||
-rw-r--r-- | openbsc/src/gsm_04_08.c | 34 | ||||
-rw-r--r-- | openbsc/src/gsm_subscriber.c | 119 | ||||
-rw-r--r-- | openbsc/src/paging.c | 49 |
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; |