aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bts.cpp84
-rw-r--r--src/bts.h16
-rw-r--r--src/bts_pch_timer.c49
-rw-r--r--src/bts_pch_timer.h9
-rw-r--r--src/csn1_dec.c2
-rw-r--r--src/gprs_bssgp_pcu.c29
-rw-r--r--src/gprs_ms.c12
-rw-r--r--src/gprs_ms.h6
-rw-r--r--src/gprs_ms_storage.cpp6
-rw-r--r--src/gprs_pcu.c19
-rw-r--r--src/gprs_pcu.h6
-rw-r--r--src/gprs_rlcmac.cpp2
-rw-r--r--src/gprs_rlcmac_ts_alloc.cpp30
-rw-r--r--src/pcu_main.cpp40
-rw-r--r--src/pcu_vty.c57
-rw-r--r--src/pcu_vty_functions.cpp17
-rw-r--r--src/pdch.cpp81
-rw-r--r--src/pdch.h1
-rw-r--r--src/tbf.cpp23
-rw-r--r--src/tbf.h3
-rw-r--r--src/tbf_dl.cpp14
-rw-r--r--src/tbf_dl_ass_fsm.c18
-rw-r--r--src/tbf_fsm.c8
-rw-r--r--src/tbf_ul.cpp21
-rw-r--r--src/tbf_ul_ass_fsm.c9
25 files changed, 423 insertions, 139 deletions
diff --git a/src/bts.cpp b/src/bts.cpp
index 50df92e2..5c870afb 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -79,10 +79,23 @@ void bts_trx_free_all_tbf(struct gprs_rlcmac_trx *trx)
static struct osmo_tdef T_defs_bts[] = {
{ .T=3142, .default_val=20, .unit=OSMO_TDEF_S, .desc="Wait Indication used in Imm Ass Reject during TBF Establishment (CCCH)", .val=0, .min_val = 0, .max_val = 255 }, /* TS 44.018 10.5.2.43, TS 44.060 7.1.3.2.1 (T3172) */
{ .T=3169, .default_val=5, .unit=OSMO_TDEF_S, .desc="Reuse of USF and TFI(s) after the MS uplink TBF assignment is invalid", .val=0 },
- { .T=3172, .default_val=5000,.unit=OSMO_TDEF_MS, .desc="Wait Indication used in Imm Ass Reject during TBF Establishment (PACCH)", .val=0, .min_val = 0, .max_val = 255000 }, /* TS 44.060 7.1.3.2.1 */
{ .T=3191, .default_val=5, .unit=OSMO_TDEF_S, .desc="Reuse of TFI(s) after sending (1) last RLC Data Block on TBF(s), or (2) PACKET TBF RELEASE for an MBMS radio bearer", .val=0 },
{ .T=3193, .default_val=100, .unit=OSMO_TDEF_MS, .desc="Reuse of TFI(s) after reception of final PACKET DOWNLINK ACK/NACK from MS for TBF", .val=0 },
{ .T=3195, .default_val=5, .unit=OSMO_TDEF_S, .desc="Reuse of TFI(s) upon no response from the MS (radio failure or cell change) for TBF/MBMS radio bearer", .val=0 },
+ { .T = -16, .default_val = 1000, .unit = OSMO_TDEF_MS,
+ .desc = "Granularity for *:all_allocated rate counters: amount of milliseconds that one counter increment"
+ " represents. See also X17, X18" },
+ { .T = -17, .default_val = 0, .unit = OSMO_TDEF_MS,
+ .desc = "Rounding threshold for *:all_allocated rate counters: round up to the next counter increment"
+ " after this many milliseconds. If set to half of X16 (or 0), employ the usual round() behavior:"
+ " round up after half of a granularity period. If set to 1, behave like ceil(): already"
+ " increment the counter immediately when all channels are allocated. If set >= X16, behave like"
+ " floor(): only increment after a full X16 period of all channels being occupied."
+ " See also X16, X18" },
+ { .T = -18, .default_val = 60000, .unit = OSMO_TDEF_MS,
+ .desc = "Forget-sum period for *:all_allocated rate counters:"
+ " after this amount of idle time, forget internally cumulated time remainders. Zero to always"
+ " keep remainders. See also X16, X17." },
{ .T=0, .default_val=0, .unit=OSMO_TDEF_S, .desc=NULL, .val=0 } /* empty item at the end */
};
@@ -92,6 +105,7 @@ static struct osmo_tdef T_defs_bts[] = {
* the code below.
*/
static const struct rate_ctr_desc bts_ctr_description[] = {
+ { "pdch:all_allocated", "Cumulative counter of seconds where all enabled PDCH resources were allocated"},
{ "tbf:dl:alloc", "TBF DL Allocated "},
{ "tbf:dl:freed", "TBF DL Freed "},
{ "tbf:dl:aborted", "TBF DL Aborted "},
@@ -134,14 +148,21 @@ static const struct rate_ctr_desc bts_ctr_description[] = {
{ "llc:dl_bytes", "RLC encapsulated PDUs"},
{ "llc:ul_bytes", "full PDUs received "},
{ "pch:requests", "PCH requests sent "},
+ { "pch:requests:already", "PCH requests on subscriber already being paged"},
{ "pch:requests:timeout", "PCH requests timeout "},
{ "rach:requests", "RACH requests received"},
- { "11bit_rach:requests", "11BIT_RACH requests received"},
+ { "rach:requests:11bit", "11BIT_RACH requests received"},
+ { "rach:requests:one_phase", "One phase packet access with request for single TS UL"}, /* TS 52.402 B.2.1.49 */
+ { "rach:requests:two_phase", "Single block packet request for two phase packet access"}, /* TS 52.402 B.2.1.49 */
+ { "rach:requests:unexpected", "RACH Request with unexpected content received"},
{ "spb:uplink_first_segment", "First seg of UL SPB "},
{ "spb:uplink_second_segment", "Second seg of UL SPB "},
{ "spb:downlink_first_segment", "First seg of DL SPB "},
{ "spb:downlink_second_segment","Second seg of DL SPB "},
{ "immediate:assignment_UL", "Immediate Assign UL "},
+ { "immediate:assignment_ul:one_phase", "Immediate Assign UL (one phase packet access)"}, /* TS 52.402 B.2.1.50 */
+ { "immediate:assignment_ul:two_phase", "Immediate Assign UL (two phase packet access)"}, /* TS 52.402 B.2.1.50 */
+ { "immediate:assignment_ul:contention_resolution_success", "First RLC Block (PDU) on the PDTCH from the MS received"}, /* TS 52.402 B.2.1.51 */
{ "immediate:assignment_rej", "Immediate Assign Rej "},
{ "immediate:assignment_DL", "Immediate Assign DL "},
{ "channel:request_description","Channel Request Desc "},
@@ -224,6 +245,8 @@ static int bts_talloc_destructor(struct gprs_rlcmac_bts* bts)
bts->ms_store->cleanup();
delete bts->ms_store;
+ osmo_time_cc_cleanup(&bts->all_allocated_pdch);
+
if (bts->ratectrs) {
rate_ctr_group_free(bts->ratectrs);
bts->ratectrs = NULL;
@@ -293,6 +316,16 @@ struct gprs_rlcmac_bts* bts_alloc(struct gprs_pcu *pcu, uint8_t bts_nr)
bts->statg = osmo_stat_item_group_alloc(tall_pcu_ctx, &bts_statg_desc, 0);
OSMO_ASSERT(bts->statg);
+ osmo_time_cc_init(&bts->all_allocated_pdch);
+ struct osmo_time_cc_cfg *cc_cfg = &bts->all_allocated_pdch.cfg;
+ cc_cfg->gran_usec = 1*1000000,
+ cc_cfg->forget_sum_usec = 60*1000000,
+ cc_cfg->rate_ctr = rate_ctr_group_get_ctr(bts->ratectrs, CTR_PDCH_ALL_ALLOCATED),
+ cc_cfg->T_gran = -16,
+ cc_cfg->T_round_threshold = -17,
+ cc_cfg->T_forget_sum = -18,
+ cc_cfg->T_defs = T_defs_bts,
+
llist_add_tail(&bts->list, &pcu->bts_list);
INIT_LLIST_HEAD(&bts->pch_timer);
@@ -880,7 +913,7 @@ int bts_rcv_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip)
bts_do_rate_ctr_inc(bts, CTR_RACH_REQUESTS);
if (rip->is_11bit)
- bts_do_rate_ctr_inc(bts, CTR_11BIT_RACH_REQUESTS);
+ bts_do_rate_ctr_inc(bts, CTR_RACH_REQUESTS_11BIT);
/* Determine full frame number */
uint32_t Fn = bts_rfn_to_fn(bts, rip->rfn);
@@ -894,15 +927,24 @@ int bts_rcv_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip)
/* Parse [EGPRS Packet] Channel Request from RACH.ind */
rc = parse_rach_ind(rip, &chan_req);
- if (rc) /* Send RR Immediate Assignment Reject */
+ if (rc) {
+ bts_do_rate_ctr_inc(bts, CTR_RACH_REQUESTS_UNEXPECTED);
+ /* Send RR Immediate Assignment Reject */
goto send_imm_ass_rej;
+ }
- if (chan_req.single_block)
- LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block allocation\n");
- else if (bts->pcu->vty.force_two_phase) {
- LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block allocation, "
- "but we force two phase access\n");
- chan_req.single_block = true;
+ if (chan_req.single_block) {
+ bts_do_rate_ctr_inc(bts, CTR_RACH_REQUESTS_TWO_PHASE);
+ LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block allocation "
+ "(two phase packet access)\n");
+ } else {
+ bts_do_rate_ctr_inc(bts, CTR_RACH_REQUESTS_ONE_PHASE);
+ LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single TS uplink transmission "
+ "(one phase packet access)\n");
+ if (bts->pcu->vty.force_two_phase) {
+ LOGP(DRLCMAC, LOGL_DEBUG, "Forcing two phase access\n");
+ chan_req.single_block = true;
+ }
}
/* TODO: handle Radio Priority (see 3GPP TS 44.060, table 11.2.5a.5) */
@@ -925,6 +967,7 @@ int bts_rcv_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip)
sb_fn = sba->fn;
LOGP(DRLCMAC, LOGL_DEBUG, "Allocated a single block at "
"SBFn=%u TRX=%u TS=%u\n", sb_fn, pdch->trx->trx_no, pdch->ts_no);
+ bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_UL_TBF_TWO_PHASE);
} else {
GprsMs *ms = bts_alloc_ms(bts, 0, chan_req.egprs_mslot_class);
tbf = tbf_alloc_ul_ccch(bts, ms);
@@ -936,6 +979,7 @@ int bts_rcv_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip)
tbf->set_ta(ta);
pdch = &tbf->trx->pdch[tbf->first_ts];
usf = tbf->m_usf[pdch->ts_no];
+ bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_UL_TBF_ONE_PHASE);
}
trx = pdch->trx;
@@ -1019,10 +1063,11 @@ int bts_rcv_ptcch_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params
return 0;
}
-void bts_snd_dl_ass(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf, uint16_t pgroup)
+void bts_snd_dl_ass(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf)
{
uint8_t trx_no = tbf->trx->trx_no;
uint8_t ts_no = tbf->first_ts;
+ uint16_t pgroup = ms_paging_group(tbf_ms(tbf));
int plen;
LOGPTBF(tbf, LOGL_INFO, "TX: START Immediate Assignment Downlink (PCH)\n");
@@ -1352,3 +1397,20 @@ uint8_t bts_get_ms_pwr_alpha(const struct gprs_rlcmac_bts *bts)
* B.2 Closed loop control */
return 0;
}
+
+/* Used by counter availablePDCHAllocatedTime, TS 52.402 B.2.1.45 "All available PDCH allocated time" */
+bool bts_all_pdch_allocated(const struct gprs_rlcmac_bts *bts)
+{
+ unsigned trx_no, ts_no;
+ for (trx_no = 0; trx_no < ARRAY_SIZE(bts->trx); trx_no++) {
+ const struct gprs_rlcmac_trx *trx = &bts->trx[trx_no];
+ for (ts_no = 0; ts_no < ARRAY_SIZE(trx->pdch); ts_no++) {
+ const struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts_no];
+ if (!pdch_is_enabled(pdch))
+ continue;
+ if(!pdch_is_full(pdch))
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/src/bts.h b/src/bts.h
index d9a86ebb..6bf62c73 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -32,6 +32,7 @@ extern "C" {
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stat_item.h>
#include <osmocom/core/tdef.h>
+#include <osmocom/core/time_cc.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gsm/l1sap.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
@@ -84,6 +85,7 @@ void bts_update_tbf_ta(struct gprs_rlcmac_bts *bts, const char *p, uint32_t fn,
enum {
+ CTR_PDCH_ALL_ALLOCATED,
CTR_TBF_DL_ALLOCATED,
CTR_TBF_DL_FREED,
CTR_TBF_DL_ABORTED,
@@ -126,14 +128,21 @@ enum {
CTR_LLC_DL_BYTES,
CTR_LLC_UL_BYTES,
CTR_PCH_REQUESTS,
+ CTR_PCH_REQUESTS_ALREADY,
CTR_PCH_REQUESTS_TIMEDOUT,
CTR_RACH_REQUESTS,
- CTR_11BIT_RACH_REQUESTS,
+ CTR_RACH_REQUESTS_11BIT,
+ CTR_RACH_REQUESTS_ONE_PHASE,
+ CTR_RACH_REQUESTS_TWO_PHASE,
+ CTR_RACH_REQUESTS_UNEXPECTED,
CTR_SPB_UL_FIRST_SEGMENT,
CTR_SPB_UL_SECOND_SEGMENT,
CTR_SPB_DL_FIRST_SEGMENT,
CTR_SPB_DL_SECOND_SEGMENT,
CTR_IMMEDIATE_ASSIGN_UL_TBF,
+ CTR_IMMEDIATE_ASSIGN_UL_TBF_ONE_PHASE,
+ CTR_IMMEDIATE_ASSIGN_UL_TBF_TWO_PHASE,
+ CTR_IMMEDIATE_ASSIGN_UL_TBF_CONTENTION_RESOLUTION_SUCCESS,
CTR_IMMEDIATE_ASSIGN_REJ,
CTR_IMMEDIATE_ASSIGN_DL_TBF,
CTR_CHANNEL_REQUEST_DESCRIPTION,
@@ -271,6 +280,8 @@ struct gprs_rlcmac_bts {
/* List of struct bts_pch_timer for active PCH pagings */
struct llist_head pch_timer;
+
+ struct osmo_time_cc all_allocated_pdch;
};
#ifdef __cplusplus
@@ -294,7 +305,7 @@ uint32_t bts_rfn_to_fn(const struct gprs_rlcmac_bts *bts, int32_t rfn);
struct gprs_rlcmac_dl_tbf *bts_dl_tbf_by_tfi(struct gprs_rlcmac_bts *bts, uint8_t tfi, uint8_t trx, uint8_t ts);
struct gprs_rlcmac_ul_tbf *bts_ul_tbf_by_tfi(struct gprs_rlcmac_bts *bts, uint8_t tfi, uint8_t trx, uint8_t ts);
-void bts_snd_dl_ass(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf, uint16_t pgroup);
+void bts_snd_dl_ass(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf);
void bts_set_current_frame_number(struct gprs_rlcmac_bts *bts, uint32_t frame_number);
void bts_set_current_block_frame_number(struct gprs_rlcmac_bts *bts, int frame_number);
@@ -374,6 +385,7 @@ void bts_set_max_mcs_ul(struct gprs_rlcmac_bts *bts, uint8_t mcs_ul);
bool bts_cs_dl_is_supported(const struct gprs_rlcmac_bts *bts, enum CodingScheme cs);
const struct llist_head* bts_ms_list(struct gprs_rlcmac_bts *bts);
uint8_t bts_get_ms_pwr_alpha(const struct gprs_rlcmac_bts *bts);
+bool bts_all_pdch_allocated(const struct gprs_rlcmac_bts *bts);
#ifdef __cplusplus
}
#endif
diff --git a/src/bts_pch_timer.c b/src/bts_pch_timer.c
index 20373ac8..d7211551 100644
--- a/src/bts_pch_timer.c
+++ b/src/bts_pch_timer.c
@@ -26,8 +26,22 @@
#include <gprs_debug.h>
#include <gprs_pcu.h>
#include <bts_pch_timer.h>
+#include <gprs_ms.h>
-static struct bts_pch_timer *bts_pch_timer_get(struct gprs_rlcmac_bts *bts, const char *imsi)
+static struct bts_pch_timer *bts_pch_timer_get_by_ptmsi(struct gprs_rlcmac_bts *bts, uint32_t ptmsi)
+{
+ struct bts_pch_timer *p;
+ OSMO_ASSERT(ptmsi != GSM_RESERVED_TMSI);
+
+ llist_for_each_entry(p, &bts->pch_timer, entry) {
+ if (p->ptmsi != GSM_RESERVED_TMSI && p->ptmsi == ptmsi)
+ return p;
+ }
+
+ return NULL;
+}
+
+struct bts_pch_timer *bts_pch_timer_get_by_imsi(struct gprs_rlcmac_bts *bts, const char *imsi)
{
struct bts_pch_timer *p;
@@ -57,29 +71,42 @@ static void T3113_callback(void *data)
bts_pch_timer_remove(p);
}
-void bts_pch_timer_start(struct gprs_rlcmac_bts *bts, const char *imsi)
+void bts_pch_timer_start(struct gprs_rlcmac_bts *bts, const struct osmo_mobile_identity *mi_paging,
+ const char *imsi)
{
- if (bts_pch_timer_get(bts, imsi))
- return;
-
struct bts_pch_timer *p;
+ struct osmo_tdef *tdef;
+
p = talloc_zero(bts, struct bts_pch_timer);
llist_add_tail(&p->entry, &bts->pch_timer);
- osmo_strlcpy(p->imsi, imsi, sizeof(p->imsi));
p->bts = bts;
+ OSMO_STRLCPY_ARRAY(p->imsi, imsi);
+ p->ptmsi = (mi_paging->type == GSM_MI_TYPE_TMSI) ? mi_paging->tmsi : GSM_RESERVED_TMSI;
- struct osmo_tdef *tdef = osmo_tdef_get_entry(the_pcu->T_defs, 3113);
+ tdef = osmo_tdef_get_entry(the_pcu->T_defs, 3113);
OSMO_ASSERT(tdef);
osmo_timer_setup(&p->T3113, T3113_callback, p);
osmo_timer_schedule(&p->T3113, tdef->val, 0);
- LOGP(DPCU, LOGL_DEBUG, "PCH paging timer started for IMSI=%s\n", p->imsi);
+ if (log_check_level(DPCU, LOGL_DEBUG)) {
+ char str[64];
+ osmo_mobile_identity_to_str_buf(str, sizeof(str), mi_paging);
+ LOGP(DPCU, LOGL_DEBUG, "PCH paging timer started for MI=%s IMSI=%s\n", str, p->imsi);
+ }
}
-void bts_pch_timer_stop(struct gprs_rlcmac_bts *bts, const char *imsi)
+void bts_pch_timer_stop(struct gprs_rlcmac_bts *bts, const struct GprsMs *ms)
{
- struct bts_pch_timer *p = bts_pch_timer_get(bts, imsi);
-
+ struct bts_pch_timer *p = NULL;
+ uint32_t tlli = ms_tlli(ms);
+ const char *imsi = ms_imsi(ms);
+
+ /* First try matching by TMSI if available in MS */
+ if (tlli != GSM_RESERVED_TMSI)
+ p = bts_pch_timer_get_by_ptmsi(bts, tlli);
+ /* Otherwise try matching by IMSI if available in MS */
+ if (!p && imsi[0] != '\0')
+ p = bts_pch_timer_get_by_imsi(bts, imsi);
if (p)
bts_pch_timer_remove(p);
}
diff --git a/src/bts_pch_timer.h b/src/bts_pch_timer.h
index 26b89c80..cc5dcb05 100644
--- a/src/bts_pch_timer.h
+++ b/src/bts_pch_timer.h
@@ -32,12 +32,17 @@ struct bts_pch_timer {
struct llist_head entry;
struct gprs_rlcmac_bts *bts;
struct osmo_timer_list T3113;
+ uint32_t ptmsi; /* GSM_RESERVED_TMSI if not available */
char imsi[OSMO_IMSI_BUF_SIZE];
};
-void bts_pch_timer_start(struct gprs_rlcmac_bts *bts, const char *imsi);
-void bts_pch_timer_stop(struct gprs_rlcmac_bts *bts, const char *imsi);
+struct GprsMs;
+
+void bts_pch_timer_start(struct gprs_rlcmac_bts *bts, const struct osmo_mobile_identity *mi_paging,
+ const char *imsi);
+void bts_pch_timer_stop(struct gprs_rlcmac_bts *bts, const struct GprsMs *ms);
void bts_pch_timer_stop_all(struct gprs_rlcmac_bts *bts);
+struct bts_pch_timer *bts_pch_timer_get_by_imsi(struct gprs_rlcmac_bts *bts, const char *imsi);
#ifdef __cplusplus
}
diff --git a/src/csn1_dec.c b/src/csn1_dec.c
index fa1f0c39..6892dde2 100644
--- a/src/csn1_dec.c
+++ b/src/csn1_dec.c
@@ -996,7 +996,7 @@ csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, struct bitvec *vector
}
}
LOGPC(DCSN1, LOGL_DEBUG, "%s = %u%s | ", pDescr->sz , (unsigned)fExist, fExist && isnull ? " (NULL)" : "");
- *pui8++ = fExist;
+ *pui8++ = !isnull;
remaining_bits_len -= 1;
bit_offset++;
diff --git a/src/gprs_bssgp_pcu.c b/src/gprs_bssgp_pcu.c
index 1fcacdb1..8cb53027 100644
--- a/src/gprs_bssgp_pcu.c
+++ b/src/gprs_bssgp_pcu.c
@@ -39,6 +39,7 @@
#include "tbf_dl.h"
#include "llc.h"
#include "gprs_rlcmac.h"
+#include "bts_pch_timer.h"
/* Tuning parameters for BSSGP flow control */
#define FC_DEFAULT_LIFE_TIME_SECS 10 /* experimental value, 10s */
@@ -107,12 +108,8 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
uint8_t egprs_ms_class = 0;
int rc;
MS_Radio_Access_capability_t rac;
- /* TODO: is it really necessary to initialize this as a "000" IMSI? It seems, the function should just return an
- * error if no IMSI IE was found. */
- struct osmo_mobile_identity mi_imsi = {
- .type = GSM_MI_TYPE_TMSI,
- };
- OSMO_STRLCPY_ARRAY(mi_imsi.imsi, "000");
+ const char *imsi = NULL;
+ struct osmo_mobile_identity mi_imsi;
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg);
tlli = ntohl(budh->tlli);
@@ -143,6 +140,7 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
LOGP(DBSSGP, LOGL_NOTICE, "Failed to parse IMSI IE (rc=%d)\n", rc);
return bssgp_tx_status(BSSGP_CAUSE_COND_IE_ERR, NULL, msg);
}
+ imsi = &mi_imsi.imsi[0];
}
/* parse ms radio access capability */
@@ -179,10 +177,11 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
"TLLI (old) IE\n");
}
- LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, mi_imsi.imsi, len);
+ LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n",
+ tlli, imsi ? : "none", len);
- return dl_tbf_handle(the_pcu->bssgp.bts, tlli, tlli_old, mi_imsi.imsi,
- ms_class, egprs_ms_class, delay_csec, data, len);
+ return dl_tbf_handle(the_pcu->bssgp.bts, tlli, tlli_old, imsi, ms_class,
+ egprs_ms_class, delay_csec, data, len);
}
/* 3GPP TS 48.018 Table 10.3.2. Returns 0 on success, suggested BSSGP cause otherwise */
@@ -319,7 +318,14 @@ static int gprs_bssgp_pcu_rx_paging_ps(struct msgb *msg, const struct tlv_parsed
/* FIXME: look if MS is attached a specific BTS and then only page on that one? */
llist_for_each_entry(bts, &the_pcu->bts_list, list) {
- gprs_rlcmac_paging_request(bts, &paging_mi, pgroup);
+ if (bts_pch_timer_get_by_imsi(bts, mi_imsi.imsi)) {
+ LOGP(DBSSGP, LOGL_INFO, "PS-Paging request already pending for IMSI=%s\n", mi_imsi.imsi);
+ bts_do_rate_ctr_inc(bts, CTR_PCH_REQUESTS_ALREADY);
+ continue;
+ }
+ if (gprs_rlcmac_paging_request(bts, &paging_mi, pgroup) < 0)
+ continue;
+ bts_pch_timer_start(bts, &paging_mi, mi_imsi.imsi);
}
return 0;
}
@@ -1118,7 +1124,8 @@ static int ns_configure_nse(struct gprs_rlcmac_bts *bts,
if (!(valid & (1 << i)))
continue;
- if (!gprs_ns2_ip_bind_by_sockaddr(the_pcu->nsi, &local[i])) {
+ bind[i] = gprs_ns2_ip_bind_by_sockaddr(the_pcu->nsi, &local[i]);
+ if (!bind[i]) {
snprintf(name, sizeof(name), "pcu%u", i);
rc = gprs_ns2_ip_bind(the_pcu->nsi, name, &local[i], 0, &bind[i]);
if (rc < 0) {
diff --git a/src/gprs_ms.c b/src/gprs_ms.c
index 0d6be4d5..5e75d067 100644
--- a/src/gprs_ms.c
+++ b/src/gprs_ms.c
@@ -522,6 +522,18 @@ void ms_set_imsi(struct GprsMs *ms, const char *imsi)
osmo_strlcpy(ms->imsi, imsi, sizeof(ms->imsi));
}
+uint16_t ms_paging_group(struct GprsMs *ms)
+{
+ uint16_t pgroup;
+ if (!ms_imsi_is_valid(ms))
+ return 0; /* 000 is the special "all paging" group */
+ if ((pgroup = imsi2paging_group(ms_imsi(ms))) > 999) {
+ LOGPMS(ms, DRLCMAC, LOGL_ERROR, "IMSI to paging group failed!\n");
+ return 0;
+ }
+ return pgroup;
+}
+
void ms_set_ta(struct GprsMs *ms, uint8_t ta_)
{
if (ta_ == ms->ta)
diff --git a/src/gprs_ms.h b/src/gprs_ms.h
index 4438a4c9..c579cf5a 100644
--- a/src/gprs_ms.h
+++ b/src/gprs_ms.h
@@ -132,6 +132,7 @@ void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);
void ms_set_tlli(struct GprsMs *ms, uint32_t tlli);
bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli);
void ms_set_imsi(struct GprsMs *ms, const char *imsi);
+uint16_t ms_paging_group(struct GprsMs *ms);
void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas);
@@ -186,6 +187,11 @@ static inline const char *ms_imsi(const struct GprsMs *ms)
return ms->imsi;
}
+static inline bool ms_imsi_is_valid(const struct GprsMs *ms)
+{
+ return ms->imsi[0] != '\0';
+}
+
static inline uint8_t ms_ta(const struct GprsMs *ms)
{
return ms->ta;
diff --git a/src/gprs_ms_storage.cpp b/src/gprs_ms_storage.cpp
index 6245ed9f..db3a7f96 100644
--- a/src/gprs_ms_storage.cpp
+++ b/src/gprs_ms_storage.cpp
@@ -29,8 +29,6 @@ extern "C" {
#include <osmocom/gsm/gsm48.h>
}
-#define GPRS_UNDEFINED_IMSI "000"
-
static void ms_storage_ms_idle_cb(struct GprsMs *ms)
{
llist_del(&ms->list);
@@ -89,10 +87,10 @@ GprsMs *GprsMsStorage::get_ms(uint32_t tlli, uint32_t old_tlli, const char *imsi
/* not found by TLLI */
- if (imsi && imsi[0] && strcmp(imsi, GPRS_UNDEFINED_IMSI) != 0) {
+ if (imsi && imsi[0] != '\0') {
llist_for_each(tmp, &m_list) {
ms = llist_entry(tmp, typeof(*ms), list);
- if (strcmp(imsi, ms_imsi(ms)) == 0)
+ if (ms_imsi_is_valid(ms) && strcmp(imsi, ms_imsi(ms)) == 0)
return ms;
}
}
diff --git a/src/gprs_pcu.c b/src/gprs_pcu.c
index 5ed9d7d6..e8dba061 100644
--- a/src/gprs_pcu.c
+++ b/src/gprs_pcu.c
@@ -33,13 +33,14 @@ static struct osmo_tdef T_defs_pcu[] = {
{ .T=3113, .default_val=7, .unit=OSMO_TDEF_S, .desc="Timeout for paging", .val=0 },
{ .T=3190, .default_val=5, .unit=OSMO_TDEF_S, .desc="Return to packet idle mode after Packet DL Assignment on CCCH (s)", .val=0},
{ .T=3141, .default_val=10, .unit=OSMO_TDEF_S, .desc="Timeout for contention resolution procedure (s)", .val=0 },
+ { .T=3172, .default_val=5000, .unit=OSMO_TDEF_MS, .desc="Wait Indication used in Imm Ass Reject during TBF Establishment (PACCH)", .val=0, .min_val = 0, .max_val = 255000 }, /* TS 44.060 7.1.3.2.1 */
{ .T=PCU_TDEF_NEIGH_RESOLVE_TO, .default_val=1000, .unit=OSMO_TDEF_MS, .desc="[ARFCN+BSIC]->[RAC+CI] resolution timeout (ms)", .val=0 },
{ .T=PCU_TDEF_SI_RESOLVE_TO, .default_val=1000, .unit=OSMO_TDEF_MS, .desc="RIM RAN-INFO response timeout (ms)", .val=0 },
{ .T=PCU_TDEF_NEIGH_CACHE_ALIVE, .default_val=5, .unit=OSMO_TDEF_S, .desc="[ARFCN+BSIC]->[RAC+CI] resolution cache entry storage timeout (s)", .val=0 },
{ .T=PCU_TDEF_SI_CACHE_ALIVE, .default_val=5, .unit=OSMO_TDEF_S, .desc="[RAC+CI]->[SI] resolution cache entry storage timeout (s)", .val=0 },
{ .T=-101, .default_val=30, .unit=OSMO_TDEF_S, .desc="BSSGP (un)blocking procedures timer (s)", .val=0 },
{ .T=-102, .default_val=30, .unit=OSMO_TDEF_S, .desc="BSSGP reset procedure timer (s)", .val=0 },
- { .T=-2000, .default_val=2, .unit=OSMO_TDEF_MS, .desc="Delay release of UL TBF after tx Packet Access Reject (PACCH) (ms)", .val=0 },
+ { .T=-2000, .default_val=0, .unit=OSMO_TDEF_MS, .desc="Delay release of UL TBF after tx Packet Access Reject (PACCH) (ms)", .val=0 },
{ .T=-2001, .default_val=2, .unit=OSMO_TDEF_S, .desc="PACCH assignment timeout (s)", .val=0 },
{ .T=-2002, .default_val=200, .unit=OSMO_TDEF_MS, .desc="Waiting after IMM.ASS confirm timer (ms)", .val=0 },
{ .T=-2030, .default_val=60, .unit=OSMO_TDEF_S, .desc="Time to keep an idle MS object alive (s)", .val=0 }, /* slightly above T3314 (default 44s, 24.008, 11.2.2) */
@@ -47,8 +48,21 @@ static struct osmo_tdef T_defs_pcu[] = {
{ .T=0, .default_val=0, .unit=OSMO_TDEF_S, .desc=NULL, .val=0 } /* empty item at the end */
};
+static void _update_stats_timer_cb(void *data)
+{
+ struct gprs_pcu *pcu = (struct gprs_pcu *)data;
+ struct gprs_rlcmac_bts *bts;
+
+ llist_for_each_entry(bts, &pcu->bts_list, list)
+ osmo_time_cc_set_flag(&bts->all_allocated_pdch, bts_all_pdch_allocated(bts));
+
+ osmo_timer_schedule(&pcu->update_stats_timer, 1, 0);
+}
+
static int gprs_pcu_talloc_destructor(struct gprs_pcu *pcu)
{
+ if (osmo_timer_pending(&pcu->update_stats_timer))
+ osmo_timer_del(&pcu->update_stats_timer);
neigh_cache_free(pcu->neigh_cache);
si_cache_free(pcu->si_cache);
return 0;
@@ -125,6 +139,9 @@ struct gprs_pcu *gprs_pcu_alloc(void *ctx)
pcu->neigh_cache = neigh_cache_alloc(pcu, osmo_tdef_get(pcu->T_defs, PCU_TDEF_NEIGH_CACHE_ALIVE, OSMO_TDEF_S, -1));
pcu->si_cache = si_cache_alloc(pcu, osmo_tdef_get(pcu->T_defs, PCU_TDEF_SI_CACHE_ALIVE, OSMO_TDEF_S, -1));
+ osmo_timer_setup(&pcu->update_stats_timer, _update_stats_timer_cb, pcu);
+ osmo_timer_schedule(&pcu->update_stats_timer, 1, 0);
+
return pcu;
}
diff --git a/src/gprs_pcu.h b/src/gprs_pcu.h
index 86fe8eb4..a9e40ea6 100644
--- a/src/gprs_pcu.h
+++ b/src/gprs_pcu.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <osmocom/core/gsmtap_util.h>
+#include <osmocom/core/timer.h>
#include "gprs_bssgp_pcu.h"
#include "coding_scheme.h"
@@ -117,8 +118,9 @@ struct gprs_pcu {
struct gsmtap_inst *gsmtap;
uint32_t gsmtap_categ_mask;
+ char *gsmtap_remote_host;
- struct llist_head bts_list; /* list of gprs_rlcmac_tbf */
+ struct llist_head bts_list; /* list of gprs_rlcmac_bts */
struct gprs_ns2_inst *nsi;
@@ -130,6 +132,8 @@ struct gprs_pcu {
struct neigh_cache *neigh_cache; /* ARFC+BSIC -> CGI PS cache */
struct si_cache *si_cache; /* ARFC+BSIC -> CGI PS cache */
+
+ struct osmo_timer_list update_stats_timer; /* Used to update some time_cc stats periodically */
};
diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp
index 22b12dfc..ffa656c3 100644
--- a/src/gprs_rlcmac.cpp
+++ b/src/gprs_rlcmac.cpp
@@ -26,7 +26,6 @@ extern "C" {
#include <pcu_l1_if.h>
#include <gprs_rlcmac.h>
#include <bts.h>
-#include <bts_pch_timer.h>
#include <encoding.h>
#include <tbf.h>
#include <gprs_debug.h>
@@ -49,7 +48,6 @@ int gprs_rlcmac_paging_request(struct gprs_rlcmac_bts *bts, const struct osmo_mo
return -1;
}
bts_do_rate_ctr_inc(bts, CTR_PCH_REQUESTS);
- bts_pch_timer_start(bts, mi->imsi);
pcu_l1if_tx_pch(bts, paging_request, plen, pgroup);
bitvec_free(paging_request);
diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp
index 5b3b355a..a243d216 100644
--- a/src/gprs_rlcmac_ts_alloc.cpp
+++ b/src/gprs_rlcmac_ts_alloc.cpp
@@ -298,20 +298,21 @@ static bool idle_pdch_avail(const struct gprs_rlcmac_bts *bts)
/*! Return free TFI
*
* \param[in] bts Pointer to BTS struct
- * \param[in] trx Optional pointer to TRX struct
* \param[in] ms Pointer to MS object
* \param[in] dir DL or UL direction
* \param[in] use_trx which TRX to use or -1 if it should be selected based on what MS uses
* \param[out] trx_no_ TRX number on which TFI was found
* \returns negative error code or 0 on success
*/
-static int tfi_find_free(const struct gprs_rlcmac_bts *bts, const gprs_rlcmac_trx *trx, const GprsMs *ms,
+static int tfi_find_free(const struct gprs_rlcmac_bts *bts, const GprsMs *ms,
enum gprs_rlcmac_tbf_direction dir, int8_t use_trx, uint8_t *trx_no_)
{
+ const struct gprs_rlcmac_trx *trx;
int tfi;
uint8_t trx_no;
- if (trx) {
+ /* If MS is already doing stuff on a TRX, set use_trx to it: */
+ if ((trx = ms_current_trx(ms))) {
if (use_trx >= 0 && use_trx != trx->trx_no) {
LOGP(DRLCMAC, LOGL_ERROR, "- Requested incompatible TRX %d (current is %d)\n",
use_trx, trx->trx_no);
@@ -320,9 +321,6 @@ static int tfi_find_free(const struct gprs_rlcmac_bts *bts, const gprs_rlcmac_tr
use_trx = trx->trx_no;
}
- if (use_trx == -1 && ms_current_trx(ms))
- use_trx = ms_current_trx(ms)->trx_no;
-
tfi = bts_tfi_find_free(bts, dir, &trx_no, use_trx);
if (tfi < 0)
return -EBUSY;
@@ -661,12 +659,12 @@ int find_multi_slots(struct gprs_rlcmac_trx *trx, uint8_t mslot_class, uint8_t *
* \param[in] slots Timeslots in use
* \param[in] reserved_slots Reserved timeslots
* \param[out] slotcount Number of TS in use
- * \param[out] avail_count Number of reserved TS
+ * \param[out] reserve_count Number of reserved TS
*/
-static void update_slot_counters(uint8_t slots, uint8_t reserved_slots, uint8_t *slotcount, uint8_t *avail_count)
+static void count_slots(uint8_t slots, uint8_t reserved_slots, uint8_t *slotcount, uint8_t *reserve_count)
{
(*slotcount) = pcu_bitcount(slots);
- (*avail_count) = pcu_bitcount(reserved_slots);
+ (*reserve_count) = pcu_bitcount(reserved_slots);
}
/*! Return slot mask with single TS from a given UL/DL set according to TBF's direction, ts pointer is set to that TS
@@ -869,7 +867,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf,
uint8_t reserved_ul_slots;
int8_t first_common_ts;
uint8_t slotcount = 0;
- uint8_t avail_count = 0, trx_no;
+ uint8_t reserve_count = 0, trx_no;
int first_ts = -1;
int usf[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
int rc;
@@ -884,18 +882,16 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf,
reserved_dl_slots = ms_reserved_dl_slots(ms);
reserved_ul_slots = ms_reserved_ul_slots(ms);
first_common_ts = ms_first_common_ts(ms);
- trx = ms_current_trx(ms);
/* Step 2a: Find usable TRX and TFI */
- tfi = tfi_find_free(bts, trx, ms, tbf->direction, use_trx, &trx_no);
+ tfi = tfi_find_free(bts, ms, tbf->direction, use_trx, &trx_no);
if (tfi < 0) {
LOGPAL(tbf, "B", single, use_trx, LOGL_NOTICE, "failed to allocate a TFI\n");
return tfi;
}
/* Step 2b: Reserve slots on the TRX for the MS */
- if (!trx)
- trx = &bts->trx[trx_no];
+ trx = &bts->trx[trx_no];
if (!reserved_dl_slots || !reserved_ul_slots) {
rc = find_multi_slots(trx, ms_ms_class(ms), &reserved_ul_slots, &reserved_dl_slots);
@@ -914,7 +910,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf,
/* Step 3b: Derive the slot set for a given direction */
if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
dl_slots = rc;
- update_slot_counters(dl_slots, reserved_dl_slots, &slotcount, &avail_count);
+ count_slots(dl_slots, reserved_dl_slots, &slotcount, &reserve_count);
} else {
rc = allocate_usf(trx, rc, dl_slots, usf);
if (rc < 0)
@@ -923,7 +919,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf,
ul_slots = rc;
reserved_ul_slots = ul_slots;
- update_slot_counters(ul_slots, reserved_ul_slots, &slotcount, &avail_count);
+ count_slots(ul_slots, reserved_ul_slots, &slotcount, &reserve_count);
}
first_ts = ffs(rc) - 1;
@@ -940,7 +936,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf,
}
if (single && slotcount) {
- tbf->upgrade_to_multislot = (avail_count > slotcount);
+ tbf->upgrade_to_multislot = (reserve_count > slotcount);
LOGPAL(tbf, "B", single, use_trx, LOGL_INFO, "using single slot at TS %d\n", first_ts);
} else {
tbf->upgrade_to_multislot = false;
diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp
index 003cabb4..fe391b99 100644
--- a/src/pcu_main.cpp
+++ b/src/pcu_main.cpp
@@ -64,7 +64,7 @@ extern void *bv_tall_ctx;
static int quit = 0;
static int rt_prio = -1;
static bool daemonize = false;
-static const char *gsmtap_addr = "localhost"; // FIXME: use gengetopt's default value instead
+static const char *gsmtap_addr;
static void print_help()
{
@@ -74,9 +74,7 @@ static void print_help()
" -m --mcc MCC Use given MCC instead of value provided by BTS\n"
" -n --mnc MNC Use given MNC instead of value provided by BTS\n"
" -V --version Print version\n"
- " -r --realtime PRIO Use SCHED_RR with the specified priority\n"
" -D --daemonize Fork the process into a background daemon\n"
- " -i --gsmtap-ip The destination IP used for GSMTAP\n"
"\nVTY reference generation:\n"
" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n"
" --vty-ref-xml Generate the VTY reference XML output and exit.\n"
@@ -162,9 +160,13 @@ static void handle_options(int argc, char **argv)
break;
case 'i':
gsmtap_addr = optarg;
+ fprintf(stderr, "Command line argument '-i' is deprecated, use VTY "
+ "parameter 'gsmtap-remote-host %s' instead.\n", gsmtap_addr);
break;
case 'r':
rt_prio = atoi(optarg);
+ fprintf(stderr, "Command line argument '-r' is deprecated, use VTY "
+ "cpu-sched node setting 'policy rr %d' instead.\n", rt_prio);
break;
case 'D':
daemonize = true;
@@ -257,13 +259,6 @@ int main(int argc, char *argv[])
exit(0);
}
- pcu->gsmtap = gsmtap_source_init(gsmtap_addr, GSMTAP_UDP_PORT, 1);
-
- if (pcu->gsmtap)
- gsmtap_source_add_sink(pcu->gsmtap);
- else
- fprintf(stderr, "Failed to initialize GSMTAP for %s\n", gsmtap_addr);
-
pcu->nsi = gprs_ns2_instantiate(tall_pcu_ctx, gprs_ns_prim_cb, NULL);
if (!pcu->nsi) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create NS instance\n");
@@ -282,6 +277,31 @@ int main(int argc, char *argv[])
fprintf(stderr, "No config file: '%s' Using default config.\n",
config_file);
+ /* Accept a GSMTAP host from VTY config, but a commandline option overrides that. */
+ if (gsmtap_addr) {
+ if (pcu->gsmtap_remote_host != NULL) {
+ LOGP(DLGLOBAL, LOGL_NOTICE,
+ "Command line argument '-i %s' overrides "
+ "'gsmtap-remote-host %s' from the config file\n",
+ gsmtap_addr, pcu->gsmtap_remote_host);
+ talloc_free(pcu->gsmtap_remote_host);
+ }
+ pcu->gsmtap_remote_host = talloc_strdup(pcu, gsmtap_addr);
+ }
+
+ if (pcu->gsmtap_remote_host) {
+ LOGP(DLGLOBAL, LOGL_NOTICE,
+ "Setting up GSMTAP Um forwarding to '%s:%u'\n",
+ pcu->gsmtap_remote_host, GSMTAP_UDP_PORT);
+ pcu->gsmtap = gsmtap_source_init(pcu->gsmtap_remote_host,
+ GSMTAP_UDP_PORT, 1);
+ if (pcu->gsmtap == NULL) {
+ fprintf(stderr, "Failed during gsmtap_source_init()\n");
+ exit(1);
+ }
+ gsmtap_source_add_sink(pcu->gsmtap);
+ }
+
rc = telnet_init_dynif(tall_pcu_ctx, NULL, vty_get_bind_addr(),
OSMO_VTY_PORT_PCU);
if (rc < 0) {
diff --git a/src/pcu_vty.c b/src/pcu_vty.c
index c85e324b..6b33e297 100644
--- a/src/pcu_vty.c
+++ b/src/pcu_vty.c
@@ -70,6 +70,49 @@ static const struct value_string pcu_gsmtap_categ_help[] = {
{ 0, NULL }
};
+DEFUN(cfg_pcu_gsmtap_remote_host,
+ cfg_pcu_gsmtap_remote_host_cmd,
+ "gsmtap-remote-host [HOSTNAME]",
+ "Enable GSMTAP Um logging (see also 'gsmtap-category')\n"
+ "Remote IP address or hostname ('localhost' if omitted)\n")
+{
+ osmo_talloc_replace_string(the_pcu, &the_pcu->gsmtap_remote_host,
+ argc > 0 ? argv[0] : "localhost");
+
+ if (vty->type != VTY_FILE)
+ vty_out(vty, "%% This command requires restart%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_pcu_no_gsmtap_remote_host,
+ cfg_pcu_no_gsmtap_remote_host_cmd,
+ "no gsmtap-remote-host",
+ NO_STR "Disable GSMTAP Um logging\n")
+{
+ if (the_pcu->gsmtap_remote_host)
+ TALLOC_FREE(the_pcu->gsmtap_remote_host);
+
+ if (vty->type != VTY_FILE)
+ vty_out(vty, "%% This command requires restart%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_pcu_gsmtap_sapi_all, pcucfg_pcu_gsmtap_categ_all_cmd,
+ "gsmtap-category (enable-all|disable-all)",
+ "Enable/disable sending of UL/DL messages over GSMTAP\n"
+ "Enable all kinds of messages (all categories)\n"
+ "Disable all kinds of messages (all categories)\n")
+{
+
+ if (strcmp(argv[0], "enable-all") == 0)
+ the_pcu->gsmtap_categ_mask = UINT32_MAX;
+ else
+ the_pcu->gsmtap_categ_mask = 0x00;
+
+ return CMD_SUCCESS;
+}
DEFUN(cfg_pcu_gsmtap_categ, cfg_pcu_gsmtap_categ_cmd, "HIDDEN", "HIDDEN")
{
@@ -238,11 +281,14 @@ static int config_write_pcu(struct vty *vty)
if (strcmp(the_pcu->pcu_sock_path, PCU_SOCK_DEFAULT))
vty_out(vty, " pcu-socket %s%s", the_pcu->pcu_sock_path, VTY_NEWLINE);
+ if (the_pcu->gsmtap_remote_host)
+ vty_out(vty, " gsmtap-remote-host %s%s", the_pcu->gsmtap_remote_host, VTY_NEWLINE);
for (i = 0; i < 32; i++) {
- uint32_t cs = ((uint32_t)1 << i);
- if (the_pcu->gsmtap_categ_mask & cs) {
- vty_out(vty, " gsmtap-category %s%s",
- get_value_string(pcu_gsmtap_categ_names, i), VTY_NEWLINE);
+ if (the_pcu->gsmtap_categ_mask & ((uint32_t)1 << i)) {
+ const char *category_buf;
+ if (!(category_buf = get_value_string_or_null(pcu_gsmtap_categ_names, i)))
+ continue;
+ vty_out(vty, " gsmtap-category %s%s", category_buf, VTY_NEWLINE);
}
}
@@ -1294,6 +1340,9 @@ int pcu_vty_init(void)
install_element(PCU_NODE, &cfg_pcu_no_dl_tbf_preemptive_retransmission_cmd);
install_element(PCU_NODE, &cfg_pcu_ms_idle_time_cmd);
install_element(PCU_NODE, &cfg_pcu_no_ms_idle_time_cmd);
+ install_element(PCU_NODE, &cfg_pcu_gsmtap_remote_host_cmd);
+ install_element(PCU_NODE, &cfg_pcu_no_gsmtap_remote_host_cmd);
+ install_element(PCU_NODE, &pcucfg_pcu_gsmtap_categ_all_cmd);
install_element(PCU_NODE, &cfg_pcu_gsmtap_categ_cmd);
install_element(PCU_NODE, &cfg_pcu_no_gsmtap_categ_cmd);
install_element(PCU_NODE, &cfg_pcu_sock_cmd);
diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp
index 657e5a16..c2cc9504 100644
--- a/src/pcu_vty_functions.cpp
+++ b/src/pcu_vty_functions.cpp
@@ -54,14 +54,15 @@ static void tbf_print_vty_info(struct vty *vty, struct gprs_rlcmac_tbf *tbf)
tbf->ta(),
tbf->direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
tbf->imsi(), VTY_NEWLINE);
- vty_out(vty, " created=%lu state=%08x [CCCH:%u, PACCH:%u] 1st_TS=%d 1st_cTS=%d ctrl_TS=%d MS_CLASS=%d/%d%s",
- tbf->created_ts(), tbf->state_fsm.state_flags,
+ vty_out(vty, " created=%lu state=%s flags=%08x [CCCH:%u, PACCH:%u] 1st_TS=%d 1st_cTS=%d ctrl_TS=%d MS_CLASS=%d/%d%s",
+ tbf->created_ts(), tbf->state_name(),
+ tbf->state_fsm.state_flags,
tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH),
tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH),
tbf->first_ts,
tbf->first_common_ts, tbf->control_ts,
tbf->ms_class(),
- tbf->ms() ? ms_egprs_ms_class(tbf->ms()) : -1,
+ ms_egprs_ms_class(tbf->ms()),
VTY_NEWLINE);
vty_out(vty, " TS_alloc=");
for (int i = 0; i < 8; i++) {
@@ -79,11 +80,10 @@ static void tbf_print_vty_info(struct vty *vty, struct gprs_rlcmac_tbf *tbf)
ul_tbf->window_size(), win->v_q(), win->v_r());
vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, " TBF Statistics:%s", VTY_NEWLINE);
- if (GPRS == ms_mode(tbf->ms())) {
+ if (ul_tbf->m_ul_gprs_ctrs)
vty_out_rate_ctr_group(vty, " ", ul_tbf->m_ul_gprs_ctrs);
- } else {
+ if (ul_tbf->m_ul_egprs_ctrs)
vty_out_rate_ctr_group(vty, " ", ul_tbf->m_ul_egprs_ctrs);
- }
}
if (dl_tbf) {
gprs_rlc_dl_window *win = static_cast<gprs_rlc_dl_window *>(dl_tbf->window());
@@ -92,11 +92,10 @@ static void tbf_print_vty_info(struct vty *vty, struct gprs_rlcmac_tbf *tbf)
win->window_stalled() ? " STALLED" : "");
vty_out(vty, "%s", VTY_NEWLINE);
vty_out_rate_ctr_group(vty, " ", tbf->m_ctrs);
- if (GPRS == ms_mode(tbf->ms())) {
+ if (dl_tbf->m_dl_gprs_ctrs)
vty_out_rate_ctr_group(vty, " ", dl_tbf->m_dl_gprs_ctrs);
- } else {
+ if (dl_tbf->m_dl_egprs_ctrs)
vty_out_rate_ctr_group(vty, " ", dl_tbf->m_dl_egprs_ctrs);
- }
}
vty_out(vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
}
diff --git a/src/pdch.cpp b/src/pdch.cpp
index 5d8658af..a5eb0804 100644
--- a/src/pdch.cpp
+++ b/src/pdch.cpp
@@ -123,14 +123,40 @@ static inline void sched_ul_ass_or_rej(struct gprs_rlcmac_bts *bts, struct gprs_
/* schedule uplink assignment or reject */
if (ul_tbf) {
- LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack message, so we provide one:\n");
+ LOGPTBFDL(tbf, LOGL_DEBUG, "MS requests UL TBF in ack message, so we provide one:\n");
osmo_fsm_inst_dispatch(tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS, NULL);
} else {
- LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack message, so we packet access reject:\n");
+ LOGPTBFDL(tbf, LOGL_NOTICE, "MS requests UL TBF in ack message, but alloc failed: send PktAssRej\n");
osmo_fsm_inst_dispatch(tbf->ul_ass_fsm.fi, TBF_UL_ASS_EV_SCHED_ASS_REJ, NULL);
}
}
+/* Make sure the PDCH vanished from the mask of reserved PDCHs for all MS, to
+ * avoid alloc_algorithm using it. */
+static void pdch_unreserve_all_ms_reserved_slots(struct gprs_rlcmac_pdch *pdch)
+{
+ struct llist_head *tmp;
+ uint8_t ts_rm_mask = (~(1 << pdch->ts_no));
+ struct gprs_rlcmac_trx *trx = pdch->trx;
+
+ llist_for_each(tmp, bts_ms_list(trx->bts)) {
+ struct GprsMs *ms = llist_entry(tmp, typeof(*ms), list);
+ if (ms->current_trx != trx)
+ continue;
+ uint8_t old_dl_slots = ms_reserved_dl_slots(ms);
+ uint8_t old_ul_slots = ms_reserved_ul_slots(ms);
+ uint8_t new_dl_slots = old_dl_slots & ts_rm_mask;
+ uint8_t new_ul_slots = old_ul_slots & ts_rm_mask;
+ if (old_dl_slots == new_dl_slots && old_ul_slots == new_ul_slots)
+ continue;
+ ms_set_reserved_slots(ms, trx, new_ul_slots, new_dl_slots);
+ }
+ if (pdch->num_reserved(GPRS_RLCMAC_UL_TBF) > 0 || pdch->num_reserved(GPRS_RLCMAC_DL_TBF) > 0)
+ LOGPDCH(pdch, DRLCMAC, LOGL_ERROR,
+ "Reserved TS count not zero after unreserving from all current MS in list! UL=%u DL=%u\n",
+ pdch->num_reserved(GPRS_RLCMAC_UL_TBF), pdch->num_reserved(GPRS_RLCMAC_DL_TBF));
+}
+
void pdch_init(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_trx *trx, uint8_t ts_nr)
{
pdch->ts_no = ts_nr;
@@ -143,6 +169,7 @@ void pdch_init(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_trx *trx, uint8
void gprs_rlcmac_pdch::enable()
{
+ LOGPDCH(this, DRLCMAC, LOGL_INFO, "PDCH state: %s => enabled\n", m_is_enabled ? "enabled" : "disabled");
OSMO_ASSERT(m_is_enabled == 0);
INIT_LLIST_HEAD(&paging_list);
@@ -155,6 +182,7 @@ void gprs_rlcmac_pdch::enable()
void gprs_rlcmac_pdch::disable()
{
+ LOGPDCH(this, DRLCMAC, LOGL_INFO, "PDCH state: %s => disabled\n", m_is_enabled ? "enabled" : "disabled");
OSMO_ASSERT(m_is_enabled == 1);
this->free_resources();
@@ -169,6 +197,8 @@ void gprs_rlcmac_pdch::free_resources()
/* kick all TBF on slot */
pdch_free_all_tbf(this);
+ pdch_unreserve_all_ms_reserved_slots(this);
+
/* flush all pending paging messages */
while ((pag = dequeue_paging()))
talloc_free(pag);
@@ -613,15 +643,16 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
{
struct gprs_rlcmac_sba *sba;
int rc;
+ struct gprs_rlcmac_bts *bts = trx->bts;
if (request->ID.UnionType) {
struct gprs_rlcmac_ul_tbf *ul_tbf = NULL;
struct pdch_ulc_node *item;
uint32_t tlli = request->ID.u.TLLI;
- GprsMs *ms = bts_ms_by_tlli(bts(), tlli, GSM_RESERVED_TMSI);
+ GprsMs *ms = bts_ms_by_tlli(bts, tlli, GSM_RESERVED_TMSI);
if (!ms) {
- ms = bts_alloc_ms(bts(), 0, 0); /* ms class updated later */
+ ms = bts_alloc_ms(bts, 0, 0); /* ms class updated later */
ms_set_tlli(ms, tlli);
}
@@ -649,6 +680,18 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
"MS requests UL TBF throguh SBA\n", fn);
ms_set_ta(ms, sba->ta);
sba_free(sba);
+ /* If MS identified by TLLI sent us a PktResReq through SBA, it means it came
+ * from CCCH, so it's for sure not using previous UL
+ * TBF; drop it if it still exits on our end: */
+ if ((ul_tbf = ms_ul_tbf(ms))) {
+ /* Get rid of previous finished UL TBF before providing a new one */
+ LOGPTBFUL(ul_tbf, LOGL_NOTICE,
+ "Got PACKET RESOURCE REQ while TBF not finished, killing pending UL TBF\n");
+ tbf_free(ul_tbf);
+ ul_tbf = NULL;
+ }
+ /* MS seized the PDCH answering on the SBA: */
+ bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_UL_TBF_CONTENTION_RESOLUTION_SUCCESS);
break;
case PDCH_ULC_NODE_TBF_POLL:
if (item->tbf_poll.poll_tbf->direction != GPRS_RLCMAC_UL_TBF) {
@@ -707,9 +750,9 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
ms_set_egprs_ms_class(ms, egprs_ms_class);
}
- ul_tbf = tbf_alloc_ul_pacch(bts(), ms, trx_no());
+ ul_tbf = tbf_alloc_ul_pacch(bts, ms, trx_no());
if (!ul_tbf) {
- handle_tbf_reject(bts(), ms, trx_no(), ts_no);
+ handle_tbf_reject(bts, ms, trx_no(), ts_no);
goto return_unref;
}
@@ -720,7 +763,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
* sent to tbf_fsm which will call tbf_assign_control_ts(),
* effectively setting back control_ts to
* tbf->initial_common_ts. */
- LOGPTBF(ul_tbf, LOGL_DEBUG, "change control TS %d -> %d until assignment is complete.\n",
+ LOGPTBF(ul_tbf, LOGL_INFO, "change control TS %d -> %d until assignment is complete.\n",
ul_tbf->control_ts, ts_no);
ul_tbf->control_ts = ts_no;
@@ -738,7 +781,7 @@ return_unref:
if (request->ID.u.Global_TFI.UnionType) {
struct gprs_rlcmac_dl_tbf *dl_tbf;
int8_t tfi = request->ID.u.Global_TFI.u.DOWNLINK_TFI;
- dl_tbf = bts_dl_tbf_by_tfi(bts(), tfi, trx_no(), ts_no);
+ dl_tbf = bts_dl_tbf_by_tfi(bts, tfi, trx_no(), ts_no);
if (!dl_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESOURCE REQ unknown downlink TFI=%d\n", tfi);
return;
@@ -751,7 +794,7 @@ return_unref:
} else {
struct gprs_rlcmac_ul_tbf *ul_tbf;
int8_t tfi = request->ID.u.Global_TFI.u.UPLINK_TFI;
- ul_tbf = bts_ul_tbf_by_tfi(bts(), tfi, trx_no(), ts_no);
+ ul_tbf = bts_ul_tbf_by_tfi(bts, tfi, trx_no(), ts_no);
if (!ul_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESOURCE REQ unknown uplink TFI=%d\n", tfi);
return;
@@ -1132,6 +1175,11 @@ void gprs_rlcmac_pdch::detach_tbf(gprs_rlcmac_tbf *tbf)
{
gprs_rlcmac_ul_tbf *ul_tbf;
+ LOGPDCH(this, DRLCMAC, LOGL_INFO, "Detaching %s, %d TBFs, "
+ "USFs = %02x, TFIs = %08x.\n",
+ tbf->name(), num_tbfs(tbf->direction),
+ m_assigned_usf, m_assigned_tfi[tbf->direction]);
+
if (tbf->is_egprs_enabled()) {
OSMO_ASSERT(m_num_tbfs_egprs[tbf->direction] > 0);
} else {
@@ -1147,11 +1195,6 @@ void gprs_rlcmac_pdch::detach_tbf(gprs_rlcmac_tbf *tbf)
m_tbfs[tbf->direction][tbf->tfi()] = NULL;
pdch_ulc_release_tbf(ulc, tbf);
-
- LOGPDCH(this, DRLCMAC, LOGL_INFO, "Detaching %s, %d TBFs, "
- "USFs = %02x, TFIs = %08x.\n",
- tbf->name(), num_tbfs(tbf->direction),
- m_assigned_usf, m_assigned_tfi[tbf->direction]);
}
bool gprs_rlcmac_pdch::has_gprs_only_tbf_attached() const
@@ -1243,3 +1286,13 @@ bool pdch_is_enabled(const struct gprs_rlcmac_pdch *pdch)
{
return pdch->is_enabled();
}
+
+/* To be called only on enabled PDCHs. Used to gather information on whether the
+ * PDCH is currently unable to allocate more TBFs due to any resource being
+ * full. Used by bts_all_pdch_allocated() for counting purposes. */
+bool pdch_is_full(const struct gprs_rlcmac_pdch *pdch)
+{
+ return pdch->assigned_tfi(GPRS_RLCMAC_UL_TBF) == NO_FREE_TFI ||
+ pdch->assigned_tfi(GPRS_RLCMAC_DL_TBF) == NO_FREE_TFI ||
+ find_free_usf(pdch->assigned_usf()) < 0;
+}
diff --git a/src/pdch.h b/src/pdch.h
index 94056069..759d7f97 100644
--- a/src/pdch.h
+++ b/src/pdch.h
@@ -194,6 +194,7 @@ void pdch_init(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_trx *trx, uint8
void pdch_free_all_tbf(struct gprs_rlcmac_pdch *pdch);
void pdch_disable(struct gprs_rlcmac_pdch *pdch);
bool pdch_is_enabled(const struct gprs_rlcmac_pdch *pdch);
+bool pdch_is_full(const struct gprs_rlcmac_pdch *pdch);
#ifdef __cplusplus
}
#endif
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 07732dc4..0b02623a 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -94,14 +94,14 @@ gprs_rlcmac_tbf::Meas::Meas() :
gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_rlcmac_tbf_direction dir) :
direction(dir),
trx(NULL),
- first_ts(0),
- first_common_ts(0),
- control_ts(TBF_CONTROL_TS_UNSET),
+ first_ts(TBF_TS_UNSET),
+ first_common_ts(TBF_TS_UNSET),
+ control_ts(TBF_TS_UNSET),
fT(0),
num_fT_exp(0),
upgrade_to_multislot(false),
bts(bts_),
- m_tfi(0),
+ m_tfi(TBF_TFI_UNSET),
m_created_ts(0),
m_ctrs(NULL),
m_ms(ms),
@@ -137,6 +137,8 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_
m_llc.init();
m_name_buf[0] = '\0';
+
+ m_created_ts = time(NULL);
}
@@ -249,7 +251,7 @@ static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
* confirmation from the MS and goes through the FLOW state. Hence, we
* may have ULC pollings ongoing and we need to make sure we drop all
* reserved nodes there: */
- if (tbf->control_ts != TBF_CONTROL_TS_UNSET && !tbf->pdch[tbf->control_ts])
+ if (tbf->control_ts != TBF_TS_UNSET && !tbf->pdch[tbf->control_ts])
pdch_ulc_release_tbf(tbf->trx->pdch[tbf->control_ts].ulc, tbf);
/* Now simply detach from all attached PDCHs */
@@ -338,7 +340,7 @@ int gprs_rlcmac_tbf::update()
void tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
{
- if (tbf->control_ts == TBF_CONTROL_TS_UNSET)
+ if (tbf->control_ts == TBF_TS_UNSET)
LOGPTBF(tbf, LOGL_INFO, "Setting Control TS %d\n",
tbf->first_common_ts);
else if (tbf->control_ts != tbf->first_common_ts)
@@ -524,7 +526,7 @@ int gprs_rlcmac_tbf::check_polling(uint32_t fn, uint8_t ts,
}
if ((rc = pdch_ulc_get_next_free_rrbp_fn(trx->pdch[ts].ulc, fn, poll_fn_, rrbp_)) < 0) {
- LOGPTBF(this, LOGL_DEBUG,
+ LOGPTBF(this, LOGL_NOTICE,
"(bts=%u,trx=%u,ts=%u) FN=%u No suitable free RRBP offset found!\n",
trx->bts->nr, trx->trx_no, ts, fn);
return rc;
@@ -657,7 +659,6 @@ int gprs_rlcmac_tbf::setup(int8_t use_trx, bool single_slot)
if (ms_mode(m_ms) != GPRS)
enable_egprs();
- m_created_ts = time(NULL);
/* select algorithm */
rc = the_pcu->alloc_algorithm(bts, this, single_slot, use_trx);
/* if no resource */
@@ -718,9 +719,10 @@ const char *tbf_name(const gprs_rlcmac_tbf *tbf)
const char *gprs_rlcmac_tbf::name() const
{
+ int8_t tfi = (m_tfi == TBF_TS_UNSET) ? -1 : m_tfi;
snprintf(m_name_buf, sizeof(m_name_buf) - 1,
"TBF(TFI=%d TLLI=0x%08x DIR=%s STATE=%s%s)",
- m_tfi, tlli(),
+ tfi, tlli(),
direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
state_name(),
is_egprs_enabled() ? " EGPRS" : ""
@@ -732,9 +734,10 @@ const char *gprs_rlcmac_tbf::name() const
void tbf_update_state_fsm_name(struct gprs_rlcmac_tbf *tbf)
{
char buf[64];
+ int8_t tfi = (tbf_tfi(tbf) == TBF_TS_UNSET) ? -1 : tbf_tfi(tbf);
snprintf(buf, sizeof(buf), "%s-TFI_%d",
tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
- tbf_tfi(tbf));
+ tfi);
osmo_identifier_sanitize_buf(buf, NULL, '_');
osmo_fsm_inst_update_id(tbf->state_fsm.fi, buf);
diff --git a/src/tbf.h b/src/tbf.h
index 4013ab05..9ce1813b 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -116,7 +116,8 @@ enum tbf_counters { /* TBF counters from 3GPP TS 44.060 ยง13.4 */
#define GPRS_RLCMAC_FLAG_TO_DL_ACK 3 /* DL TBF: Failed to receive last polled DL ACK/NACK */
#define GPRS_RLCMAC_FLAG_TO_MASK 0xf0 /* timeout bits */
-#define TBF_CONTROL_TS_UNSET 0xff
+#define TBF_TS_UNSET 0xff
+#define TBF_TFI_UNSET 0xff
#define T_START(tbf, t, T, r, f) tbf->t_start(t, T, r, f, __FILE__, __LINE__)
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index 05d5ad36..6e898dad 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -296,7 +296,9 @@ int dl_tbf_handle(struct gprs_rlcmac_bts *bts,
/* check for existing TBF */
ms = bts_ms_store(bts)->get_ms(tlli, tlli_old, imsi);
- if (ms && strlen(ms_imsi(ms)) == 0) {
+ /* If we got MS by TLLI above let's see if we already have another MS
+ * object identified by IMSI and merge them */
+ if (ms && !ms_imsi_is_valid(ms) && imsi) {
ms_old = bts_ms_store(bts)->get_ms(0, 0, imsi);
if (ms_old && ms_old != ms) {
/* The TLLI has changed (RAU), so there are two MS
@@ -310,7 +312,7 @@ int dl_tbf_handle(struct gprs_rlcmac_bts *bts,
if (!ms_dl_tbf(ms) && ms_dl_tbf(ms_old)) {
LOGP(DTBF, LOGL_NOTICE,
"IMSI %s, old TBF %s: moving DL TBF to new MS object\n",
- imsi, ms_dl_tbf(ms_old)->name());
+ imsi ? : "unknown", ms_dl_tbf(ms_old)->name());
dl_tbf = ms_dl_tbf(ms_old);
/* Move the DL TBF to the new MS */
dl_tbf->set_ms(ms);
@@ -323,7 +325,8 @@ int dl_tbf_handle(struct gprs_rlcmac_bts *bts,
if (!ms)
ms = bts_alloc_ms(bts, ms_class, egprs_ms_class);
- ms_set_imsi(ms, imsi);
+ if (imsi)
+ ms_set_imsi(ms, imsi);
ms_confirm_tlli(ms, tlli);
if (!ms_ms_class(ms) && ms_class) {
ms_set_ms_class(ms, ms_class);
@@ -599,7 +602,6 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(uint32_t fn, uint8_t ts,
/* depending on the current TBF, we assign on PACCH or AGCH */
void gprs_rlcmac_dl_tbf::trigger_ass(struct gprs_rlcmac_tbf *old_tbf)
{
- uint16_t pgroup;
/* stop pending timer */
stop_timers("assignment (DL-TBF)");
@@ -618,9 +620,7 @@ void gprs_rlcmac_dl_tbf::trigger_ass(struct gprs_rlcmac_tbf *old_tbf)
osmo_fsm_inst_dispatch(this->state_fsm.fi, TBF_EV_ASSIGN_ADD_CCCH, NULL);
/* send immediate assignment */
- if ((pgroup = imsi2paging_group(imsi())) > 999)
- LOGPTBFDL(this, LOGL_ERROR, "IMSI to paging group failed! (%s)\n", imsi());
- bts_snd_dl_ass(bts, this, pgroup);
+ bts_snd_dl_ass(bts, this);
}
}
diff --git a/src/tbf_dl_ass_fsm.c b/src/tbf_dl_ass_fsm.c
index 37ced616..a5948e7b 100644
--- a/src/tbf_dl_ass_fsm.c
+++ b/src/tbf_dl_ass_fsm.c
@@ -77,9 +77,6 @@ struct msgb *create_packet_dl_assign(const struct tbf_dl_ass_fsm_ctx *ctx,
return NULL;
}
- if (new_dl_tbf == as_dl_tbf(ctx->tbf))
- LOGPTBF(ctx->tbf, LOGL_DEBUG, "New and old TBF are the same.\n");
-
if (old_tfi_is_valid && ms_tlli(ms) == GSM_RESERVED_TMSI) {
LOGPTBF(ctx->tbf, LOGL_ERROR,
"The old TFI is not assigned and there is no TLLI. New TBF %s\n",
@@ -99,7 +96,12 @@ struct msgb *create_packet_dl_assign(const struct tbf_dl_ass_fsm_ctx *ctx,
};
bitvec_unhex(&bv, DUMMY_VEC);
- LOGPTBF((struct gprs_rlcmac_tbf *)new_dl_tbf, LOGL_INFO, "start Packet Downlink Assignment (PACCH)\n");
+ if (ctx->tbf != (struct gprs_rlcmac_tbf *)new_dl_tbf)
+ LOGPTBF(ctx->tbf, LOGL_INFO, "start Packet Downlink Assignment (PACCH) for %s\n",
+ tbf_name((const struct gprs_rlcmac_tbf *)new_dl_tbf));
+ else
+ LOGPTBF(ctx->tbf, LOGL_INFO, "start Packet Downlink Assignment (PACCH)\n");
+
mac_control_block = (RlcMacDownlink_t *)talloc_zero(ctx->tbf, RlcMacDownlink_t);
write_packet_downlink_assignment(mac_control_block, old_tfi_is_valid,
tbf_tfi(ctx->tbf), (tbf_direction(ctx->tbf) == GPRS_RLCMAC_DL_TBF),
@@ -183,11 +185,7 @@ static void st_wait_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
static int tbf_dl_ass_fsm_timer_cb(struct osmo_fsm_inst *fi)
{
- struct tbf_dl_ass_fsm_ctx *ctx = (struct tbf_dl_ass_fsm_ctx *)fi->priv;
switch (fi->T) {
- case -2000:
- tbf_free(ctx->tbf);
- break;
default:
OSMO_ASSERT(0);
}
@@ -206,7 +204,9 @@ static struct osmo_fsm_state tbf_dl_ass_fsm_states[] = {
},
[TBF_DL_ASS_SEND_ASS] = {
.in_event_mask = X(TBF_DL_ASS_EV_CREATE_RLCMAC_MSG),
- .out_state_mask = X(TBF_DL_ASS_WAIT_ACK),
+ .out_state_mask =
+ X(TBF_DL_ASS_WAIT_ACK) |
+ X(TBF_DL_ASS_NONE),
.name = "SEND_ASS",
.action = st_send_ass,
},
diff --git a/src/tbf_fsm.c b/src/tbf_fsm.c
index af2b34ef..39f20805 100644
--- a/src/tbf_fsm.c
+++ b/src/tbf_fsm.c
@@ -214,15 +214,11 @@ static void st_flow(struct osmo_fsm_inst *fi, uint32_t event, void *data)
if ((ctx->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))
&& !(ctx->state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK))) {
struct GprsMs *ms = tbf_ms(ctx->tbf);
- const char *imsi = ms_imsi(ms);
- uint16_t pgroup;
LOGPTBF(ctx->tbf, LOGL_DEBUG, "Re-send downlink assignment on PCH (IMSI=%s)\n",
- imsi);
+ ms_imsi_is_valid(ms) ? ms_imsi(ms) : "");
tbf_fsm_state_chg(fi, TBF_ST_ASSIGN);
/* send immediate assignment */
- if ((pgroup = imsi2paging_group(imsi)) > 999)
- LOGPTBF(ctx->tbf, LOGL_ERROR, "IMSI to paging group failed! (%s)\n", imsi);
- bts_snd_dl_ass(ms->bts, ctx->tbf, pgroup);
+ bts_snd_dl_ass(ms->bts, ctx->tbf);
}
break;
case TBF_EV_LAST_DL_DATA_SENT:
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 74b2636b..02821226 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -151,7 +151,12 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts, GprsMs
return tbf;
}
-/* Alloc a UL TBF to be assigned over PACCH */
+/* Alloc a UL TBF to be assigned over PACCH. Called when an MS requests to
+ * create a new UL TBF during the end of life of a previous UL TBF (or an SBA).
+ * In summary, this TBF is allocated as a consequence of receiving a "Pkt
+ * Resource Req" or "Pkt Ctrl Ack" from the MS.
+ * See TS 44.060 9.3.2.4.2 "Non-extended uplink TBF mode".
+ */
gprs_rlcmac_ul_tbf *tbf_alloc_ul_pacch(struct gprs_rlcmac_bts *bts, GprsMs *ms, int8_t use_trx)
{
struct gprs_rlcmac_ul_tbf *tbf;
@@ -162,13 +167,15 @@ gprs_rlcmac_ul_tbf *tbf_alloc_ul_pacch(struct gprs_rlcmac_bts *bts, GprsMs *ms,
/* Caller will most probably send a Imm Ass Reject after return */
return NULL;
}
+ /* Contention resolution is considered to be done since TLLI is known in MS: */
tbf->m_contention_resolution_done = 1;
osmo_fsm_inst_dispatch(tbf->state_fsm.fi, TBF_EV_ASSIGN_ADD_PACCH, NULL);
return tbf;
}
-/* Alloc a UL TBF to be assigned over CCCH */
+/* Alloc a UL TBF to be assigned over CCCH. Used by request of a "One phase
+ * packet access", where MS requested only 1 PDCH TS (TS 44.018 Table 9.1.8.1). */
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_ccch(struct gprs_rlcmac_bts *bts, struct GprsMs *ms)
{
struct gprs_rlcmac_ul_tbf *tbf;
@@ -203,8 +210,11 @@ struct gprs_rlcmac_ul_tbf *handle_tbf_reject(struct gprs_rlcmac_bts *bts,
talloc_set_destructor(ul_tbf, ul_tbf_dtor);
new (ul_tbf) gprs_rlcmac_ul_tbf(bts, ms);
- ul_tbf->control_ts = ts;
ul_tbf->trx = trx;
+ /* The only one TS is the common, control TS */
+ ul_tbf->first_ts = ts;
+ ul_tbf->first_common_ts = ts;
+ tbf_assign_control_ts(ul_tbf);
ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, next_tbf_ctr_group_id++);
ul_tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(ul_tbf,
&tbf_ul_egprs_ctrg_desc,
@@ -217,6 +227,7 @@ struct gprs_rlcmac_ul_tbf *handle_tbf_reject(struct gprs_rlcmac_bts *bts,
talloc_free(ul_tbf);
return NULL;
}
+ tbf_update_state_fsm_name(ul_tbf);
ms_attach_tbf(ms, ul_tbf);
llist_add(tbf_trx_list((struct gprs_rlcmac_tbf *)ul_tbf), &trx->ul_tbfs);
@@ -321,6 +332,8 @@ void gprs_rlcmac_ul_tbf::contention_resolution_success()
/* now we must set this flag, so we are allowed to assign downlink
* TBF on PACCH. it is only allowed when TLLI is acknowledged. */
m_contention_resolution_done = 1;
+
+ bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_UL_TBF_CONTENTION_RESOLUTION_SUCCESS);
}
/*! \brief receive data from PDCH/L1 */
@@ -430,7 +443,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
"Decoded premier TLLI=0x%08x of UL DATA TFI=%d.\n",
new_tlli, rlc->tfi);
update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
- bts_pch_timer_stop(bts, ms_imsi(ms()));
+ bts_pch_timer_stop(bts, ms());
} else if (new_tlli != GSM_RESERVED_TMSI && new_tlli != tlli()) {
LOGPTBFUL(this, LOGL_NOTICE,
"Decoded TLLI=%08x mismatch on UL DATA TFI=%d. (Ignoring due to contention resolution)\n",
diff --git a/src/tbf_ul_ass_fsm.c b/src/tbf_ul_ass_fsm.c
index ab23fbdb..90fe8280 100644
--- a/src/tbf_ul_ass_fsm.c
+++ b/src/tbf_ul_ass_fsm.c
@@ -64,7 +64,7 @@ static struct msgb *create_packet_access_reject(const struct tbf_ul_ass_fsm_ctx
bitvec_unhex(packet_access_rej, DUMMY_VEC);
write_packet_access_reject(packet_access_rej, ms_tlli(ms),
- osmo_tdef_get(ms->bts->T_defs_bts, 3172, OSMO_TDEF_MS, -1));
+ osmo_tdef_get(ms->bts->pcu->T_defs, 3172, OSMO_TDEF_MS, -1));
bts_do_rate_ctr_inc(ms->bts, CTR_PKT_ACCESS_REJ);
@@ -110,7 +110,12 @@ struct msgb *create_packet_ul_assign(const struct tbf_ul_ass_fsm_ctx *ctx,
};
bitvec_unhex(&bv, DUMMY_VEC);
- LOGPTBFUL((const struct gprs_rlcmac_tbf *)new_tbf, LOGL_INFO, "start Packet Uplink Assignment (PACCH)\n");
+ if (ctx->tbf != (struct gprs_rlcmac_tbf *)new_tbf)
+ LOGPTBF(ctx->tbf, LOGL_INFO, "start Packet Uplink Assignment (PACCH) for %s\n",
+ tbf_name((const struct gprs_rlcmac_tbf *)new_tbf));
+ else
+ LOGPTBF(ctx->tbf, LOGL_INFO, "start Packet Uplink Assignment (PACCH)\n");
+
mac_control_block = (RlcMacDownlink_t *)talloc_zero(ctx->tbf, RlcMacDownlink_t);
tlli = ms_tlli(ms);
write_packet_uplink_assignment(mac_control_block, tbf_tfi(ctx->tbf),