implement PURGE-MS from VLR/SGSN to HLR

Using this procedure, the VLR/SGSN can set the cs/ps purged
flag for the subscriber.  We might not even need to store this
persistent in the database according to spec, but let's do it anyway, at
least until it turns out to be a performance issue.
This commit is contained in:
Harald Welte 2016-05-05 21:03:03 +02:00
parent 999092790c
commit b18f0e04f3
4 changed files with 92 additions and 0 deletions

View File

@ -32,6 +32,8 @@ CREATE TABLE subscriber (
-- Chapter 2.1.8
lmsi INTEGER,
-- The below purged flags might not even be stored non-volatile,
-- refer to TS 23.012 Chapter 3.6.1.4
-- Chapter 2.7.5
ms_purged_cs BOOLEAN NOT NULL DEFAULT 0,
-- Chapter 2.7.6

View File

@ -9,6 +9,8 @@ enum stmt_idx {
UPD_SGSN_BY_ID = 2,
AUC_BY_IMSI = 3,
AUC_UPD_SQN = 4,
UPD_PURGE_CS_BY_IMSI,
UPD_PURGE_PS_BY_IMSI,
_NUM_STMT
};
@ -71,3 +73,6 @@ int db_subscr_lu(struct db_context *dbc,
const struct hlr_subscriber *subscr,
const char *vlr_or_sgsn_number,
bool lu_is_ps);
int db_subscr_purge(struct db_context *dbc,
const char *imsi, bool is_ps);

View File

@ -135,3 +135,48 @@ out:
return ret;
}
int db_subscr_purge(struct db_context *dbc, const char *imsi, bool is_ps)
{
sqlite3_stmt *stmt = dbc->stmt[UPD_VLR_BY_ID];
int rc, ret = 1;
if (is_ps)
stmt = dbc->stmt[UPD_PURGE_PS_BY_IMSI];
else
stmt = dbc->stmt[UPD_PURGE_CS_BY_IMSI];
rc = sqlite3_bind_int(stmt, 1, 1);
if (rc != SQLITE_OK) {
LOGP(DAUC, LOGL_ERROR, "Error binding Purged: %d\n", rc);
return -1;
}
rc = sqlite3_bind_text(stmt, 2, imsi, -1, SQLITE_STATIC);
if (rc != SQLITE_OK) {
LOGP(DAUC, LOGL_ERROR, "Error binding IMSI: %d\n", rc);
ret = -1;
goto out;
}
/* execute the statement */
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
LOGP(DAUC, LOGL_ERROR, "Error setting Purged: %d\n", rc);
ret = -2;
goto out;
}
/* FIXME: return 0 in case IMSI not known */
out:
/* remove bindings and reset statement to be re-executed */
rc = sqlite3_clear_bindings(stmt);
if (rc != SQLITE_OK) {
LOGP(DAUC, LOGL_ERROR, "Error clearing bindings: %d\n", rc);
}
rc = sqlite3_reset(stmt);
if (rc != SQLITE_OK) {
LOGP(DAUC, LOGL_ERROR, "Error in sqlite3_reset: %d\n", rc);
}
return ret;
}

View File

@ -406,6 +406,43 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
return 0;
}
static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
const struct osmo_gsup_message *gsup)
{
struct osmo_gsup_message gsup_reply = {0};
struct msgb *msg_out;
bool is_ps = false;
int rc;
LOGP(DAUC, LOGL_INFO, "%s: Purge MS (%s)\n", gsup->imsi,
is_ps ? "PS" : "CS");
memcpy(gsup_reply.imsi, gsup->imsi, sizeof(gsup_reply.imsi));
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
is_ps = true;
/* FIXME: check if the VLR that sends the purge is the same that
* we have on record. Only update if yes */
/* Perform the actual update of the DB */
rc = db_subscr_purge(g_dbc, gsup->imsi, is_ps);
if (rc == 1)
gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT;
else if (rc == 0) {
gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;
gsup_reply.cause = GMM_CAUSE_IMSI_UNKNOWN;
} else {
gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;
gsup_reply.cause = GMM_CAUSE_NET_FAIL;
}
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP AUC response");
osmo_gsup_encode(msg_out, &gsup_reply);
return osmo_gsup_conn_send(conn, msg_out);
}
static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
{
static struct osmo_gsup_message gsup;
@ -425,6 +462,9 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
rx_upd_loc_req(conn, &gsup);
break;
case OSMO_GSUP_MSGT_PURGE_MS_REQUEST:
rx_purge_ms_req(conn, &gsup);
break;
/* responses to requests sent by us */
case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
case OSMO_GSUP_MSGT_INSERT_DATA_RESULT: