tbf: Handle TLLI change on DL

When doing an RA Update the network can request to change the TLLI.
In this case, there can be 2 MS objects with different TLLI for a
single real MS. The first is associated with the old TLLI and the
IMSI, while the second is associated with the new TLLI and no IMSI if
it had been created for the uplink TBF. When the first message with
the new TLLI and the IMSI arrives from the network, the PCU is able
to detect this.

Currently this is not handled properly. The TBFs of the old MS object
are not cleaned up properly, keeping the old MS from being deleted.

This patch modifies gprs_rlcmac_dl_tbf::handle to check for this and
if neccessary to move an existing DL TBF and to clean up the old MS
object to ensure its deletion.

Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2015-08-14 12:50:54 +02:00
parent 04e72d34f5
commit ac28905082
3 changed files with 56 additions and 18 deletions

View File

@ -297,6 +297,20 @@ void GprsMs::update_status()
}
}
void GprsMs::reset()
{
LOGP(DRLCMAC, LOGL_INFO,
"Clearing MS object, TLLI: 0x%08x, IMSI: '%s'\n",
tlli(), imsi());
stop_timer();
m_tlli = 0;
m_new_dl_tlli = 0;
m_new_ul_tlli = 0;
m_imsi[0] = '\0';
}
void GprsMs::set_tlli(uint32_t tlli)
{
if (tlli == m_tlli || tlli == m_new_ul_tlli)

View File

@ -71,6 +71,8 @@ public:
bool confirm_tlli(uint32_t tlli);
bool check_tlli(uint32_t tlli);
void reset();
const char *imsi() const;
void set_imsi(const char *imsi);

View File

@ -124,17 +124,6 @@ int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class,
return 0;
}
static struct gprs_rlcmac_dl_tbf *tbf_lookup_dl(BTS *bts,
const uint32_t tlli, const uint32_t tlli_old,
const char *imsi)
{
GprsMs *ms = bts->ms_store().get_ms(tlli, tlli_old, imsi);
if (!ms)
return NULL;
return ms->dl_tbf();
}
static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
const char *imsi,
const uint32_t tlli, const uint32_t tlli_old,
@ -203,12 +192,48 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
const uint8_t ms_class, const uint16_t delay_csec,
const uint8_t *data, const uint16_t len)
{
struct gprs_rlcmac_dl_tbf *dl_tbf;
struct gprs_rlcmac_dl_tbf *dl_tbf = NULL;
int rc;
GprsMs *ms;
GprsMs *ms, *ms_old;
/* check for existing TBF */
dl_tbf = tbf_lookup_dl(bts->bts, tlli, tlli_old, imsi);
ms = bts->bts->ms_store().get_ms(tlli, tlli_old, imsi);
if (ms)
dl_tbf = ms->dl_tbf();
if (ms && strlen(ms->imsi()) == 0) {
ms_old = bts->bts->ms_store().get_ms(0, 0, imsi);
if (ms_old && ms_old != ms) {
/* The TLLI has changed (RAU), so there are two MS
* objects for the same MS */
LOGP(DRLCMAC, LOGL_NOTICE,
"There is a new MS object for the same MS: "
"(0x%08x, '%s') -> (0x%08x, '%s')\n",
ms_old->tlli(), ms_old->imsi(),
ms->tlli(), ms->imsi());
GprsMs::Guard guard_old(ms_old);
if (!dl_tbf && ms_old->dl_tbf()) {
LOGP(DRLCMAC, LOGL_NOTICE,
"%s IMSI %s: "
"moving DL TBF to new MS object\n",
dl_tbf->name(), imsi);
dl_tbf = ms_old->dl_tbf();
/* Move the DL TBF to the new MS */
dl_tbf->set_ms(ms);
}
/* Clean up the old MS object */
/* TODO: Put this into a separate function, use timer? */
if (ms_old->ul_tbf() && ms_old->ul_tbf()->T == 0)
tbf_free(ms_old->ul_tbf());
if (ms_old->dl_tbf() && ms_old->dl_tbf()->T == 0)
tbf_free(ms_old->dl_tbf());
ms_old->reset();
}
}
if (!dl_tbf) {
rc = tbf_new_dl_assignment(bts, imsi, tlli, tlli_old, ms_class,
&dl_tbf);
@ -221,11 +246,8 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
GprsMs::Guard guard(ms);
rc = dl_tbf->append_data(ms_class, delay_csec, data, len);
dl_tbf = ms->dl_tbf();
dl_tbf->assign_imsi(imsi);
ms->confirm_tlli(tlli);
dl_tbf->assign_imsi(imsi);
return rc;
}