summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-03-15 00:07:43 +0100
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-03-16 05:51:11 +0100
commitcab2fcd5b5a7276fc9a89e449e9d3ede11790711 (patch)
tree3ac8a5510a7db3bfcc13501ac2ad9d44b467fd1f /src
parentee392bb3b1fdfd45e8b4401622e0ee6cc66f9695 (diff)
UMTS AKA: implement SQN increment according to SEQ and IND
Add ind_bitlen column to auc_3g to record each USIM's IND size according to 3GPP TS 33.102 -- default is 5 bits, as suggested by the spec. Introduce auc_3g_ind to each connecting GSUP client to use as IND index for generating auth tuples sent to this client. With osmo_gsup_server_add_conn(), implement a scheme where clients receive fixed auc_3g_ind indexes based on the order in which they connect; each new connection takes the lowest unused auc_3g_ind, so in case one of the clients restarts, it will most likely receive the same auc_3g_ind, and if one client disconnects, no other clients' auc_3g_ind are affected. Add gsup_server_test.c to test the auc_3g_ind index distribution scheme. Depends: libosmocore I4eac5be0c0b2cede04464c4c3a0873102d952453 for llist_first Related: OS#1969 Change-Id: If4501ed4ff8e923fa6fe8b80c44c5ad647a8ed60
Diffstat (limited to 'src')
-rw-r--r--src/db.c2
-rw-r--r--src/db.h5
-rw-r--r--src/db_auc.c16
-rw-r--r--src/db_test.c2
-rw-r--r--src/gsup_server.c45
-rw-r--r--src/gsup_server.h2
-rw-r--r--src/hlr.c3
7 files changed, 64 insertions, 11 deletions
diff --git a/src/db.c b/src/db.c
index aa4726c..aaf6fe2 100644
--- a/src/db.c
+++ b/src/db.c
@@ -29,7 +29,7 @@ static const char *stmt_sql[] = {
[SEL_BY_IMSI] = "SELECT id,imsi,msisdn,vlr_number,sgsn_number,sgsn_address,periodic_lu_tmr,periodic_rau_tau_tmr,nam_cs,nam_ps,lmsi,ms_purged_cs,ms_purged_ps FROM subscriber WHERE imsi = ?",
[UPD_VLR_BY_ID] = "UPDATE subscriber SET vlr_number = ? WHERE id = ?",
[UPD_SGSN_BY_ID] = "UPDATE subscriber SET sgsn_number = ? WHERE id = ?",
- [AUC_BY_IMSI] = "SELECT id, algo_id_2g, ki, algo_id_3g, k, op, opc, sqn FROM subscriber LEFT JOIN auc_2g ON auc_2g.subscriber_id = subscriber.id LEFT JOIN auc_3g ON auc_3g.subscriber_id = subscriber.id WHERE imsi = ?",
+ [AUC_BY_IMSI] = "SELECT id, algo_id_2g, ki, algo_id_3g, k, op, opc, sqn, ind_bitlen FROM subscriber LEFT JOIN auc_2g ON auc_2g.subscriber_id = subscriber.id LEFT JOIN auc_3g ON auc_3g.subscriber_id = subscriber.id WHERE imsi = ?",
[AUC_UPD_SQN] = "UPDATE auc_3g SET sqn = ? WHERE subscriber_id = ?",
[UPD_PURGE_CS_BY_IMSI] = "UPDATE subscriber SET ms_purged_cs=1 WHERE imsi = ?",
[UPD_PURGE_PS_BY_IMSI] = "UPDATE subscriber SET ms_purged_ps=1 WHERE imsi = ?",
diff --git a/src/db.h b/src/db.h
index 0b3df88..a60cf62 100644
--- a/src/db.h
+++ b/src/db.h
@@ -39,8 +39,9 @@ int db_update_sqn(struct db_context *dbc, uint64_t id,
uint64_t new_sqn);
int db_get_auc(struct db_context *dbc, const char *imsi,
- struct osmo_auth_vector *vec, unsigned int num_vec,
- const uint8_t *rand_auts, const uint8_t *auts);
+ unsigned int auc_3g_ind, struct osmo_auth_vector *vec,
+ unsigned int num_vec, const uint8_t *rand_auts,
+ const uint8_t *auts);
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
diff --git a/src/db_auc.c b/src/db_auc.c
index ac81404..8a369b5 100644
--- a/src/db_auc.c
+++ b/src/db_auc.c
@@ -159,6 +159,7 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
aud3g->u.umts.opc_is_op = 1;
}
aud3g->u.umts.sqn = sqlite3_column_int64(stmt, 7);
+ aud3g->u.umts.ind_bitlen = sqlite3_column_int(stmt, 8);
/* FIXME: amf? */
aud3g->type = OSMO_AUTH_TYPE_UMTS;
} else
@@ -186,8 +187,9 @@ out:
/* return -1 in case of error, 0 for unknown imsi, positive for number
* of vectors generated */
int db_get_auc(struct db_context *dbc, const char *imsi,
- struct osmo_auth_vector *vec, unsigned int num_vec,
- const uint8_t *rand_auts, const uint8_t *auts)
+ unsigned int auc_3g_ind, struct osmo_auth_vector *vec,
+ unsigned int num_vec, const uint8_t *rand_auts,
+ const uint8_t *auts)
{
struct osmo_sub_auth_data aud2g, aud3g;
uint64_t subscr_id;
@@ -198,6 +200,16 @@ int db_get_auc(struct db_context *dbc, const char *imsi,
if (rc <= 0)
return rc;
+ aud3g.u.umts.ind = auc_3g_ind;
+ if (aud3g.type == OSMO_AUTH_TYPE_UMTS
+ && aud3g.u.umts.ind >= (1U << aud3g.u.umts.ind_bitlen)) {
+ LOGAUC(imsi, LOGL_NOTICE, "3G auth: SQN's IND bitlen %u is"
+ " too small to hold an index of %u. Truncating. This"
+ " may cause numerous additional AUTS resyncing.\n",
+ aud3g.u.umts.ind_bitlen, aud3g.u.umts.ind);
+ aud3g.u.umts.ind &= (1U << aud3g.u.umts.ind_bitlen) - 1;
+ }
+
LOGAUC(imsi, LOGL_DEBUG, "Calling to generate %u vectors\n", num_vec);
rc = auc_compute_vectors(vec, num_vec, &aud2g, &aud3g, rand_auts, auts);
if (rc < 0) {
diff --git a/src/db_test.c b/src/db_test.c
index 998a37a..0e823f9 100644
--- a/src/db_test.c
+++ b/src/db_test.c
@@ -20,7 +20,7 @@ static int test(const char *imsi, struct db_context *dbc)
for (i = 0; i < ARRAY_SIZE(vec); i++)
vec[i].res_len = 0;
- rc = db_get_auc(dbc, imsi, vec, ARRAY_SIZE(vec), NULL, NULL);
+ rc = db_get_auc(dbc, imsi, 0, vec, ARRAY_SIZE(vec), NULL, NULL);
if (rc <= 0) {
LOGP(DMAIN, LOGL_ERROR, "Cannot obtain auth tuples for '%s'\n", imsi);
return rc;
diff --git a/src/gsup_server.c b/src/gsup_server.c
index b0e1858..b382c86 100644
--- a/src/gsup_server.c
+++ b/src/gsup_server.c
@@ -211,6 +211,43 @@ static int osmo_gsup_server_closed_cb(struct ipa_server_conn *conn)
return 0;
}
+/* Add conn to the clients list in a way that conn->auc_3g_ind takes the lowest
+ * unused integer and the list of clients remains sorted by auc_3g_ind.
+ * Keep this function non-static to allow linking in a unit test. */
+void osmo_gsup_server_add_conn(struct llist_head *clients,
+ struct osmo_gsup_conn *conn)
+{
+ struct osmo_gsup_conn *c;
+ struct osmo_gsup_conn *prev_conn;
+
+ c = llist_first_entry_or_null(clients, struct osmo_gsup_conn, list);
+
+ /* Is the first index, 0, unused? */
+ if (!c || c->auc_3g_ind > 0) {
+ conn->auc_3g_ind = 0;
+ llist_add(&conn->list, clients);
+ return;
+ }
+
+ /* Look for a gap later on */
+ prev_conn = NULL;
+ llist_for_each_entry(c, clients, list) {
+ /* skip first item, we know it has auc_3g_ind == 0. */
+ if (!prev_conn) {
+ prev_conn = c;
+ continue;
+ }
+ if (c->auc_3g_ind > prev_conn->auc_3g_ind + 1)
+ break;
+ prev_conn = c;
+ }
+
+ OSMO_ASSERT(prev_conn);
+
+ conn->auc_3g_ind = prev_conn->auc_3g_ind + 1;
+ llist_add(&conn->list, &prev_conn->list);
+}
+
/* a client has connected to the server socket and we have accept()ed it */
static int osmo_gsup_server_accept_cb(struct ipa_server_link *link, int fd)
{
@@ -225,15 +262,15 @@ static int osmo_gsup_server_accept_cb(struct ipa_server_link *link, int fd)
conn->conn = ipa_server_conn_create(gsups, link, fd,
osmo_gsup_server_read_cb,
osmo_gsup_server_closed_cb, conn);
- conn->conn->ccm_cb = osmo_gsup_server_ccm_cb;
OSMO_ASSERT(conn->conn);
+ conn->conn->ccm_cb = osmo_gsup_server_ccm_cb;
/* link data structure with server structure */
conn->server = gsups;
- llist_add_tail(&conn->list, &gsups->clients);
+ osmo_gsup_server_add_conn(&gsups->clients, conn);
- LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d\n",
- conn->conn->addr, conn->conn->port);
+ LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d (IND=%u)\n",
+ conn->conn->addr, conn->conn->port, conn->auc_3g_ind);
/* request the identity of the client */
rc = ipa_ccm_send_id_req(fd);
diff --git a/src/gsup_server.h b/src/gsup_server.h
index 885fe52..74062d4 100644
--- a/src/gsup_server.h
+++ b/src/gsup_server.h
@@ -31,6 +31,8 @@ struct osmo_gsup_conn {
struct ipa_server_conn *conn;
//struct oap_state oap_state;
struct tlv_parsed ccm;
+
+ unsigned int auc_3g_ind; /*!< IND index used for UMTS AKA SQN */
};
diff --git a/src/hlr.c b/src/hlr.c
index 00a6459..b5777e2 100644
--- a/src/hlr.c
+++ b/src/hlr.c
@@ -63,7 +63,8 @@ static int rx_send_auth_info(struct osmo_gsup_conn *conn,
memset(&gsup_out, 0, sizeof(gsup_out));
memcpy(&gsup_out.imsi, &gsup->imsi, sizeof(gsup_out.imsi));
- rc = db_get_auc(dbc, gsup->imsi, gsup_out.auth_vectors,
+ rc = db_get_auc(dbc, gsup->imsi, conn->auc_3g_ind,
+ gsup_out.auth_vectors,
ARRAY_SIZE(gsup_out.auth_vectors),
gsup->rand, gsup->auts);
if (rc < 0) {