diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 012481a5f..b21f8aa05 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -194,6 +194,10 @@ struct gsm_lchan { /* use count. how many users use this channel */ unsigned int use_count; + /* cache of last measurement reports on this lchan */ + struct gsm_meas_rep meas_rep[6]; + int meas_rep_idx; + struct { u_int32_t bound_ip; u_int16_t bound_port; @@ -564,4 +568,6 @@ const char *rrlp_mode_name(enum rrlp_mode mode); void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked); +struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan); + #endif diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index c6675c840..51d524459 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -998,14 +998,12 @@ static int rsl_rx_meas_res(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; - struct gsm_meas_rep mr; + struct gsm_meas_rep *mr = lchan_next_meas_rep(msg->lchan); u_int8_t len; const u_int8_t *val; int rc; - memset(&mr, 0, sizeof(mr)); - - mr.lchan = msg->lchan; + memset(mr, 0, sizeof(*mr)); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1015,44 +1013,44 @@ static int rsl_rx_meas_res(struct msgb *msg) return -EIO; /* Mandatory Parts */ - mr.nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); + mr->nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS); val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS); if (len >= 3) { if (val[0] & 0x40) - mr.flags |= MEAS_REP_F_DL_DTX; - mr.ul.full.rx_lev = val[0] & 0x3f; - mr.ul.sub.rx_lev = val[1] & 0x3f; - mr.ul.full.rx_qual = val[2]>>3 & 0x7; - mr.ul.sub.rx_qual = val[2] & 0x7; + mr->flags |= MEAS_REP_F_DL_DTX; + mr->ul.full.rx_lev = val[0] & 0x3f; + mr->ul.sub.rx_lev = val[1] & 0x3f; + mr->ul.full.rx_qual = val[2]>>3 & 0x7; + mr->ul.sub.rx_qual = val[2] & 0x7; } - mr.bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); + mr->bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); /* Optional Parts */ if (TLVP_PRESENT(&tp, RSL_IE_MS_TIMING_OFFSET)) - mr.ms_timing_offset = + mr->ms_timing_offset = *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET); if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) { val = TLVP_VAL(&tp, RSL_IE_L1_INFO); - mr.flags |= MEAS_REP_F_MS_L1; - mr.ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3); + mr->flags |= MEAS_REP_F_MS_L1; + mr->ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3); if (val[0] & 0x04) - mr.flags |= MEAS_REP_F_FPC; - mr.ms_l1.ta = val[1]; + mr->flags |= MEAS_REP_F_FPC; + mr->ms_l1.ta = val[1]; } if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) { msg->l3h = (u_int8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO); - rc = gsm48_parse_meas_rep(&mr, msg); + rc = gsm48_parse_meas_rep(mr, msg); if (rc < 0) return rc; } - print_meas_rep(&mr); + print_meas_rep(mr); - dispatch_signal(SS_LCHAN, S_LCHAN_MEAS_REP, &mr); + dispatch_signal(SS_LCHAN, S_LCHAN_MEAS_REP, mr); return 0; } diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 2f0d7b93f..0a2984773 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -235,6 +235,8 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) /* Free a logical channel */ void lchan_free(struct gsm_lchan *lchan) { + int i; + lchan->type = GSM_LCHAN_NONE; if (lchan->subscr) { subscr_put(lchan->subscr); @@ -250,6 +252,13 @@ void lchan_free(struct gsm_lchan *lchan) /* stop the timer */ bsc_del_timer(&lchan->release_timer); + /* clear cached measuement reports */ + lchan->meas_rep_idx = 0; + for (i = 0; i < ARRAY_SIZE(lchan->meas_rep); i++) { + lchan->meas_rep[i].flags = 0; + lchan->meas_rep[i].nr = 0; + } + /* FIXME: ts_free() the timeslot, if we're the last logical * channel using it */ } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 6d05a20ad..ef29b29cc 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1558,13 +1558,13 @@ static int gsm48_rx_rr_status(struct msgb *msg) static int gsm48_rx_rr_meas_rep(struct msgb *msg) { - static struct gsm_meas_rep meas_rep; + struct gsm_meas_rep *meas_rep = lchan_next_meas_rep(msg->lchan); /* This shouldn't actually end up here, as RSL treats * L3 Info of 08.58 MEASUREMENT REPORT different by calling * directly into gsm48_parse_meas_rep */ DEBUGP(DMEAS, "DIRECT GSM48 MEASUREMENT REPORT ?!? "); - gsm48_parse_meas_rep(&meas_rep, msg); + gsm48_parse_meas_rep(meas_rep, msg); return 0; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 91a854f46..94ed91ba5 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -415,3 +415,16 @@ const char *rrlp_mode_name(enum rrlp_mode mode) return "none"; return rrlp_mode_names[mode]; } + +struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) +{ + struct gsm_meas_rep *meas_rep; + + meas_rep = &lchan->meas_rep[lchan->meas_rep_idx]; + memset(meas_rep, 0, sizeof(*meas_rep)); + meas_rep->lchan = lchan; + lchan->meas_rep_idx = (lchan->meas_rep_idx + 1) + % ARRAY_SIZE(lchan->meas_rep); + + return meas_rep; +}