aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/chan_alloc.h6
-rw-r--r--openbsc/include/openbsc/gsm_data.h3
-rw-r--r--openbsc/include/openbsc/gsm_data_shared.h13
-rw-r--r--openbsc/src/libbsc/abis_rsl.c38
-rw-r--r--openbsc/src/libbsc/bsc_init.c2
-rw-r--r--openbsc/src/libbsc/bsc_vty.c2
-rw-r--r--openbsc/src/libbsc/chan_alloc.c75
-rw-r--r--openbsc/src/libbsc/net_init.c24
-rw-r--r--openbsc/src/libcommon/gsm_data_shared.c3
-rw-r--r--openbsc/tests/channel/Makefile.am5
-rw-r--r--openbsc/tests/channel/channel_test.c11
11 files changed, 153 insertions, 29 deletions
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index 78242e5b7..0ba3f9669 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -37,17 +37,13 @@ void lchan_reset(struct gsm_lchan *lchan);
/* Release the given lchan */
int lchan_release(struct gsm_lchan *lchan, int sacch_deact, enum rsl_rel_mode release_mode);
-struct load_counter {
- unsigned int total;
- unsigned int used;
-};
-
struct pchan_load {
struct load_counter pchan[_GSM_PCHAN_MAX];
};
void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts);
void network_chan_load(struct pchan_load *pl, struct gsm_network *net);
+void bts_update_t3122_chan_load(struct gsm_bts *bts);
int trx_is_usable(struct gsm_bts_trx *trx);
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 39c7458ca..b12c4edc3 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -372,6 +372,9 @@ struct gsm_network {
/* timer to expire old location updates */
struct osmo_timer_list subscr_expire_timer;
+ /* Timer for periodic channel load measurements to maintain each BTS's T3122. */
+ struct osmo_timer_list t3122_chan_load_timer;
+
/* Radio Resource Location Protocol (TS 04.31) */
struct {
enum rrlp_mode mode;
diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h
index 30feedcab..a78e2eb7a 100644
--- a/openbsc/include/openbsc/gsm_data_shared.h
+++ b/openbsc/include/openbsc/gsm_data_shared.h
@@ -674,6 +674,12 @@ struct bts_location {
double height;
};
+/* Channel load counter */
+struct load_counter {
+ unsigned int total;
+ unsigned int used;
+};
+
/* One BTS */
struct gsm_bts {
/* list header in net->bts_list */
@@ -901,6 +907,13 @@ struct gsm_bts {
char *pcu_sock_path;
struct pcu_sock_state *pcu_state;
+ /* BTS-specific overrides for timer values from struct gsm_network. */
+ uint8_t T3122; /* ASSIGMENT REJECT wait indication */
+
+ /* Periodic channel load measurements are used to maintain T3122. */
+ struct load_counter chan_load_samples[7];
+ int chan_load_samples_idx;
+
#endif /* ROLE_BSC */
void *role;
};
diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c
index 0ce27484c..f05344a05 100644
--- a/openbsc/src/libbsc/abis_rsl.c
+++ b/openbsc/src/libbsc/abis_rsl.c
@@ -1744,8 +1744,7 @@ static void t3109_expired(void *data)
/* Format an IMM ASS REJ according to 04.08 Chapter 9.1.20 */
static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
- unsigned int num_req_refs,
- struct gsm48_req_ref *rqd_refs,
+ struct gsm48_req_ref *rqd_ref,
uint8_t wait_ind)
{
uint8_t buf[GSM_MACBLOCK_LEN];
@@ -1757,25 +1756,22 @@ static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
iar->msg_type = GSM48_MT_RR_IMM_ASS_REJ;
iar->page_mode = GSM48_PM_SAME;
- memcpy(&iar->req_ref1, &rqd_refs[0], sizeof(iar->req_ref1));
+ /*
+ * Set all request references and wait indications to the same value.
+ * 3GPP TS 44.018 v4.5.0 release 4 (section 9.1.20.2) requires that
+ * we duplicate reference and wait indication to fill the message.
+ * The BTS will aggregate up to 4 of our ASS REJ messages if possible.
+ */
+ memcpy(&iar->req_ref1, rqd_ref, sizeof(iar->req_ref1));
iar->wait_ind1 = wait_ind;
- if (num_req_refs >= 2)
- memcpy(&iar->req_ref2, &rqd_refs[1], sizeof(iar->req_ref2));
- else
- memcpy(&iar->req_ref2, &rqd_refs[0], sizeof(iar->req_ref2));
+ memcpy(&iar->req_ref2, rqd_ref, sizeof(iar->req_ref2));
iar->wait_ind2 = wait_ind;
- if (num_req_refs >= 3)
- memcpy(&iar->req_ref3, &rqd_refs[2], sizeof(iar->req_ref3));
- else
- memcpy(&iar->req_ref3, &rqd_refs[0], sizeof(iar->req_ref3));
+ memcpy(&iar->req_ref3, rqd_ref, sizeof(iar->req_ref3));
iar->wait_ind3 = wait_ind;
- if (num_req_refs >= 4)
- memcpy(&iar->req_ref4, &rqd_refs[3], sizeof(iar->req_ref4));
- else
- memcpy(&iar->req_ref4, &rqd_refs[0], sizeof(iar->req_ref4));
+ memcpy(&iar->req_ref4, rqd_ref, sizeof(iar->req_ref4));
iar->wait_ind4 = wait_ind;
/* we need to subtract 1 byte from sizeof(*iar) since ia includes the l2_plen field */
@@ -1870,12 +1866,18 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
/* check availability / allocate channel */
lchan = lchan_alloc(bts, lctype, is_lu);
if (!lchan) {
+ uint8_t wait_ind;
LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n",
msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra);
rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]);
- /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */
- if (bts->network->T3122)
- rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff);
+ if (bts->T3122)
+ wait_ind = bts->T3122;
+ else if (bts->network->T3122)
+ wait_ind = bts->network->T3122 & 0xff;
+ else
+ wait_ind = GSM_T3122_DEFAULT;
+ /* The BTS will gather multiple CHAN RQD and reject up to 4 MS at the same time. */
+ rsl_send_imm_ass_rej(bts, rqd_ref, wait_ind);
return 0;
}
diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c
index 36531d2d8..4cfe20a04 100644
--- a/openbsc/src/libbsc/bsc_init.c
+++ b/openbsc/src/libbsc/bsc_init.c
@@ -507,6 +507,8 @@ static int bootstrap_bts(struct gsm_bts *bts)
bts->si_common.ncc_permitted = 0xff;
+ bts->chan_load_samples_idx = 0;
+
/* Initialize the BTS state */
gsm_bts_mo_reset(bts);
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 3daa262c4..fd77fabb0 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -1597,7 +1597,7 @@ DECLARE_TIMER(3113, "Set the time to try paging a subscriber")
DECLARE_TIMER(3115, "Currently not used")
DECLARE_TIMER(3117, "Currently not used")
DECLARE_TIMER(3119, "Currently not used")
-DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT")
+DECLARE_TIMER(3122, "Default waiting time (seconds) after IMM ASS REJECT")
DECLARE_TIMER(3141, "Currently not used")
DEFUN_DEPRECATED(cfg_net_dtx,
diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c
index 33b79a0b2..cf6b708fa 100644
--- a/openbsc/src/libbsc/chan_alloc.c
+++ b/openbsc/src/libbsc/chan_alloc.c
@@ -541,3 +541,78 @@ void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
bts_chan_load(pl, bts);
}
+/* Update T3122 wait indicator based on samples of BTS channel load. */
+void
+bts_update_t3122_chan_load(struct gsm_bts *bts)
+{
+ struct pchan_load pl;
+ uint64_t used = 0;
+ uint32_t total = 0;
+ uint64_t load;
+ uint64_t wait_ind;
+ static const uint8_t min_wait_ind = GSM_T3122_DEFAULT;
+ static const uint8_t max_wait_ind = 128; /* max wait ~2 minutes */
+ int i;
+
+ /* Sum up current load across all channels. */
+ memset(&pl, 0, sizeof(pl));
+ bts_chan_load(&pl, bts);
+ for (i = 0; i < ARRAY_SIZE(pl.pchan); i++) {
+ struct load_counter *lc = &pl.pchan[i];
+
+ /* Ignore samples too large for fixed-point calculations (shouldn't happen). */
+ if (lc->used > UINT16_MAX || lc->total > UINT16_MAX) {
+ LOGP(DRLL, LOGL_NOTICE, "(bts=%d) numbers in channel load sample "
+ "too large (used=%u / total=%u)\n", bts->nr, lc->used, lc->total);
+ continue;
+ }
+
+ used += lc->used;
+ total += lc->total;
+ }
+
+ /* Check for invalid samples (shouldn't happen). */
+ if (total == 0 || used > total) {
+ LOGP(DRLL, LOGL_NOTICE, "(bts=%d) bogus channel load sample (used=%lu / total=%u)\n",
+ bts->nr, used, total);
+ bts->T3122 = 0; /* disable override of network-wide default value */
+ bts->chan_load_samples_idx = 0; /* invalidate other samples collected so far */
+ return;
+ }
+
+ /* If we haven't got enough samples yet, store measurement for later use. */
+ if (bts->chan_load_samples_idx < ARRAY_SIZE(bts->chan_load_samples)) {
+ struct load_counter *sample = &bts->chan_load_samples[bts->chan_load_samples_idx++];
+ sample->total = (unsigned int)total;
+ sample->used = (unsigned int)used;
+ return;
+ }
+
+ /* We have enough samples and will overwrite our current samples later. */
+ bts->chan_load_samples_idx = 0;
+
+ /* Add all previous samples to the current sample. */
+ for (i = 0; i < ARRAY_SIZE(bts->chan_load_samples); i++) {
+ struct load_counter *sample = &bts->chan_load_samples[i];
+ total += sample->total;
+ used += sample->used;
+ }
+
+ used <<= 8; /* convert to fixed-point */
+
+ /* Log channel load average. */
+ load = ((used / total) * 100);
+ LOGP(DRLL, LOGL_DEBUG, "(bts=%d) channel load average is %lu.%.2lu%%\n",
+ bts->nr, (load & 0xffffff00) >> 8, (load & 0xff) / 10);
+
+ /* Calculate new T3122 wait indicator. */
+ wait_ind = ((used / total) * max_wait_ind);
+ wait_ind >>= 8; /* convert from fixed-point to integer */
+ if (wait_ind < min_wait_ind)
+ wait_ind = min_wait_ind;
+ else if (wait_ind > max_wait_ind)
+ wait_ind = max_wait_ind;
+
+ LOGP(DRLL, LOGL_DEBUG, "(bts=%d) T3122 wait indicator set to %lu seconds\n", bts->nr, wait_ind);
+ bts->T3122 = (uint8_t)wait_ind;
+}
diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c
index 9d5431964..08e2bd6c3 100644
--- a/openbsc/src/libbsc/net_init.c
+++ b/openbsc/src/libbsc/net_init.c
@@ -20,6 +20,22 @@
#include <openbsc/common_cs.h>
#include <openbsc/osmo_bsc.h>
#include <openbsc/bsc_msc_data.h>
+#include <openbsc/chan_alloc.h>
+
+/* XXX hard-coded for now */
+#define T3122_CHAN_LOAD_SAMPLE_INTERVAL 1 /* in seconds */
+
+static void update_t3122_chan_load_timer(void *data)
+{
+ struct gsm_network *net = data;
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &net->bts_list, list)
+ bts_update_t3122_chan_load(bts);
+
+ /* Keep this timer ticking. */
+ osmo_timer_schedule(&net->t3122_chan_load_timer, T3122_CHAN_LOAD_SAMPLE_INTERVAL, 0);
+}
struct gsm_network *bsc_network_init(void *ctx,
uint16_t country_code,
@@ -66,6 +82,14 @@ struct gsm_network *bsc_network_init(void *ctx,
INIT_LLIST_HEAD(&net->bts_list);
+ /*
+ * At present all BTS in the network share one channel load timeout.
+ * If this becomes a problem for networks with a lot of BTS, this
+ * code could be refactored to run the timeout individually per BTS.
+ */
+ osmo_timer_setup(&net->t3122_chan_load_timer, update_t3122_chan_load_timer, net);
+ osmo_timer_schedule(&net->t3122_chan_load_timer, T3122_CHAN_LOAD_SAMPLE_INTERVAL, 0);
+
/* init statistics */
net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0);
if (!net->bsc_ctrs) {
diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c
index 26962730a..a1d7a50b4 100644
--- a/openbsc/src/libcommon/gsm_data_shared.c
+++ b/openbsc/src/libcommon/gsm_data_shared.c
@@ -364,6 +364,9 @@ struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
/* si handling */
bts->bcch_change_mark = 1;
+ /* timer overrides */
+ bts->T3122 = 0; /* not overriden by default */
+
return bts;
}
diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am
index ca470ace4..5fec00af4 100644
--- a/openbsc/tests/channel/Makefile.am
+++ b/openbsc/tests/channel/Makefile.am
@@ -23,6 +23,10 @@ channel_test_SOURCES = \
channel_test.c \
$(NULL)
+channel_test_LDFLAGS = \
+ -Wl,--wrap=paging_request \
+ $(NULL)
+
channel_test_LDADD = \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libbsc/libbsc.a \
@@ -30,6 +34,7 @@ channel_test_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOABIS_LIBS) \
$(LIBCRYPTO_LIBS) \
-ldbi \
$(NULL)
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index 049786be7..428182f1e 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -48,8 +48,10 @@ static int subscr_cb(unsigned int hook, unsigned int event, struct msgb *msg, vo
return 0;
}
-/* mock object for testing, directly invoke the cb... maybe later through the timer */
-int paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data)
+/* override, requires '-Wl,--wrap=paging_request'.
+/ mock object for testing, directly invoke the cb... maybe later through the timer */
+int __real_paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data);
+int __wrap_paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, int type, gsm_cbfn *cbfn, void *data)
{
s_data = data;
s_cbfn = cbfn;
@@ -160,13 +162,12 @@ int main(int argc, char **argv)
return EXIT_SUCCESS;
}
-void _abis_nm_sendmsg() {}
void sms_alloc() {}
void sms_free() {}
-void gsm_net_update_ctype(struct gsm_network *network) {}
void gsm48_secure_channel() {}
-void paging_request_stop() {}
void vty_out() {}
+void switch_trau_mux() {}
+void rtp_socket_free() {}
struct tlv_definition nm_att_tlvdef;