fix Classmark Update without VLR subscriber

This recent patch moves Classmark storage to the VLR subscriber, and introduced
a segfault when a Classmark Update is received during IMSI detach:

commit 986fe7ed18
change-id I27081bf6e9e017923b2d02607f7ea06beddad82a
Mon Sep 17 01:12:13 2018 +0200
"store classmark in vlr_subscr, not conn"

It assumed that we would never accept any Classmark Update messages unless we
also have a valid subscriber for it. Well, that is proven wrong by the
ttcn3-msc-test TC_imsi_detach_by_imsi(), which brings osmo-msc to its knees.

Fix: in case of no valid vlr_subscr being present, store Classmark in the conn
temporarily, and copy any received Classmark to VLR subscriber as soon as it
gets associated with the conn (if at all).

Change-Id: Ib2a2ae6bf86e8f29fc6751a8b5cdb7187cd70290
This commit is contained in:
Neels Hofmeyr 2018-09-18 15:52:58 +02:00
parent 3117b701c8
commit 68cf957bfd
3 changed files with 31 additions and 1 deletions

View File

@ -181,6 +181,10 @@ struct gsm_subscriber_connection {
bool waiting_for_clear_complete;
} a;
/* Temporary storage for Classmark Information for times when a connection has no VLR subscriber
* associated yet. It will get copied to the VLR subscriber upon msc_vlr_subscr_assoc(). */
struct gsm_classmark temporary_classmark;
};

View File

@ -1739,6 +1739,22 @@ static void msc_vlr_subscr_update(struct vlr_subscr *subscr)
subscr->imsi, subscr->msisdn, subscr->use_count);
}
static void update_classmark(const struct gsm_classmark *src, struct gsm_classmark *dst)
{
if (src->classmark1_set) {
dst->classmark1 = src->classmark1;
dst->classmark1_set = true;
}
if (src->classmark2_len) {
dst->classmark2_len = src->classmark2_len;
memcpy(dst->classmark2, src->classmark2, sizeof(dst->classmark2));
}
if (src->classmark3_len) {
dst->classmark3_len = src->classmark3_len;
memcpy(dst->classmark3, src->classmark3, sizeof(dst->classmark3));
}
}
/* VLR informs us that the subscriber has been associated with a conn */
static void msc_vlr_subscr_assoc(void *msc_conn_ref,
struct vlr_subscr *vsub)
@ -1749,6 +1765,11 @@ static void msc_vlr_subscr_assoc(void *msc_conn_ref,
conn->vsub = vlr_subscr_get(vsub);
OSMO_ASSERT(conn->vsub);
conn->vsub->cs.attached_via_ran = conn->via_ran;
/* In case we have already received Classmark Information before the VLR Subscriber was
* associated with the conn: merge the new Classmark into vsub->classmark. Don't overwrite valid
* vsub->classmark with unset classmark, though. */
update_classmark(&conn->temporary_classmark, &conn->vsub->classmark);
}
static int msc_vlr_route_gsup_msg(struct vlr_subscr *vsub,

View File

@ -147,7 +147,12 @@ void msc_classmark_chg(struct gsm_subscriber_connection *conn,
const uint8_t *cm2, uint8_t cm2_len,
const uint8_t *cm3, uint8_t cm3_len)
{
struct gsm_classmark *cm = &conn->vsub->classmark;
struct gsm_classmark *cm;
if (!conn->vsub)
cm = &conn->temporary_classmark;
else
cm = &conn->vsub->classmark;
if (cm2 && cm2_len) {
if (cm2_len > sizeof(cm->classmark2)) {