[PATCH] osmo-hlr[master]: ctrl: completely replace all CTRL commands

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Fri Oct 27 00:19:16 UTC 2017


Hello Max, Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/4311

to look at the new patch set (#7).

ctrl: completely replace all CTRL commands

The previous commands are not conforming to how the CTRL interface is intended
to work:

  SET enable-ps <IMSI>
  SET disable-ps <IMSI>
  SET status-ps <IMSI>

'status-ps' is a write-only command even though it returns the status.
'enable-ps' / 'disable-ps' indicate the value instead of a variable name of an
entity. The entity <IMSI> takes the place of the variable value.

See also https://lists.osmocom.org/pipermail/openbsc/2017-September/011236.html

Instead, replace with

  SET subscriber.by-imsi-123456.ps-enabled {0,1}
  GET subscriber.by-imsi-123456.ps-enabled

and also provide further CTRL functions while at it:

  {SET,GET} subscriber.by-{imsi,msisdn,id}-123456.{cs,ps}-enabled {0,1}
  GET subscriber.by-{imsi,msisdn,id}-123456.{info,info-aud,info-all}

Provide CTRL tests in the form of transcripts.

Adjust tests/test_subscriber.sql to feature nonzero SQN, to see some values for
SQN in the CTRL transcript tests. (This does not affect the VTY tests, because
that creates its own subscribers, and there's no VTY command to set the SQN.)

This is the first time an application uses CTRL_NODE ids that are defined
outside of libosmocore, see 'Depends' below.

Implementation choice: the first idea was to have a '.' between the 'by-xxx'
and the value, like:

  subscriber.by-xxx.123456.function

but the difficulty with subscribers is that they are not in RAM, and I can't
just point node_data at a struct instance that is always there (like, say, a
global bts[0] struct in osmo-bsc). Instead, I want to store the selector and
later decide whether to read from the DB or whatever. With a '.' separating
things, the only way in a ctrl function to obtain both 'by-xxx' and '123456'
for picking a subscriber record would be to parse the entire variable path
string elements, including 'subscriber' and 'function', which would then also
clumsily fix at which node level we hook these commands; there could have been
separate CTRL_NODE_SUBSCR_BY_{IMSI,MSISDN,ID} parent nodes, but we cannot
introspect the current parent node dynamically within a ctrl function handler
(plus I'm not sure whether it's possible and a good idea to have the same
command under multiple parent nodes).

Rather than that, I store the 'by-foo-123' token in the node_data pointer to
have both bits of information pointed at by a single pointer; I use the
incoming command parsing to get this token pre-separated from surrounding node
names, and no need to re-allocate it, since the vector of tokens lives until
after command execution is complete. Each leaf command obtains this token from
cmd->node (aka node_data), and feeds this token to a common static function to
parse selector and value from it and to retrieve a subscriber record as needed.

(BTW, I have mentioned on the mailing list that this way might be necessary to
avoid numeric-only CTRL node names, but we don't need to, and that is not at
all related to this choice of structure.)

Depends: libosmocore I1bd62ae0d4eefde7e1517db15a2155640a1bab58
         libosmocore Ic9dba0e4a1eb5a7dc3cee2f181b9024ed4fc7005
Change-Id: I98ee6a06b3aa6a67adb868e0b63b0e04eb42eb50
---
M src/ctrl.c
M src/ctrl.h
M tests/test_subscriber.ctrl
M tests/test_subscriber.sql
M tests/test_subscriber.vty
A tests/test_subscriber_errors.ctrl
6 files changed, 1,041 insertions(+), 73 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-hlr refs/changes/11/4311/7

diff --git a/src/ctrl.c b/src/ctrl.c
index b49765d..3e81661 100644
--- a/src/ctrl.c
+++ b/src/ctrl.c
@@ -21,77 +21,362 @@
  */
 
 #include <stdbool.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
 
-#include <osmocom/ctrl/control_cmd.h>
-#include <osmocom/ctrl/control_if.h>
+#include <osmocom/gsm/gsm23003.h>
 #include <osmocom/ctrl/ports.h>
 
-#include "gsup_server.h"
-#include "logging.h"
-#include "db.h"
 #include "hlr.h"
-#include "luop.h"
 #include "ctrl.h"
+#include "db.h"
 
-static int handle_cmd_ps(struct hlr *ctx, struct ctrl_cmd *cmd, bool enable)
+#define SEL_BY "by-"
+#define SEL_BY_IMSI SEL_BY "imsi-"
+#define SEL_BY_MSISDN SEL_BY "msisdn-"
+#define SEL_BY_ID SEL_BY "id-"
+
+#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
+
+static bool startswith(const char *str, const char *start)
+{
+	return strncmp(str, start, strlen(start)) == 0;
+}
+
+static int _get_subscriber(struct db_context *dbc,
+			   const char *by_selector,
+			   struct hlr_subscriber *subscr)
+{
+	const char *val;
+	if (startswith(by_selector, SEL_BY_IMSI)) {
+		val = by_selector + strlen(SEL_BY_IMSI);
+		if (!osmo_imsi_str_valid(val))
+			return -EINVAL;
+		return db_subscr_get_by_imsi(dbc, val, subscr);
+	}
+	if (startswith(by_selector, SEL_BY_MSISDN)) {
+		val = by_selector + strlen(SEL_BY_MSISDN);
+		if (!osmo_msisdn_str_valid(val))
+			return -EINVAL;
+		return db_subscr_get_by_msisdn(dbc, val, subscr);
+	}
+	if (startswith(by_selector, SEL_BY_ID)) {
+		int64_t id;
+		char *endptr;
+		val = by_selector + strlen(SEL_BY_ID);
+		if (*val == '+')
+			return -EINVAL;
+		errno = 0;
+		id = strtoll(val, &endptr, 10);
+		if (errno || *endptr)
+			return -EINVAL;
+		return db_subscr_get_by_id(dbc, id, subscr);
+	}
+	return -ENOTSUP;
+}
+
+static bool get_subscriber(struct db_context *dbc,
+			   const char *by_selector,
+			   struct hlr_subscriber *subscr,
+			   struct ctrl_cmd *cmd)
+{
+	int rc = _get_subscriber(dbc, by_selector, subscr);
+	switch (rc) {
+	case 0:
+		return true;
+	case -ENOTSUP:
+		cmd->reply = "Not a known subscriber 'by-xxx-' selector.";
+		return false;
+	case -EINVAL:
+		cmd->reply = "Invalid value part of 'by-xxx-value' selector.";
+		return false;
+	case -ENOENT:
+		cmd->reply = "No such subscriber.";
+		return false;
+	default:
+		cmd->reply = "An unknown error has occured during get_subscriber().";
+		return false;
+	}
+}
+
+/* Optimization: if a subscriber operation is requested by-imsi, just return
+ * the IMSI right back. */
+static const char *get_subscriber_imsi(struct db_context *dbc,
+				       const char *by_selector,
+				       struct ctrl_cmd *cmd)
+{
+	static struct hlr_subscriber subscr;
+
+	if (startswith(by_selector, SEL_BY_IMSI))
+		return by_selector + strlen(SEL_BY_IMSI);
+	if (!get_subscriber(dbc, by_selector, &subscr, cmd))
+		return NULL;
+	return subscr.imsi;
+}
+
+/* printf fmt and arg to completely omit a string if it is empty. */
+#define FMT_S "%s%s%s%s"
+#define ARG_S(name, val) \
+	(val) && *(val) ? "\n" : "", \
+	(val) && *(val) ? name : "", \
+	(val) && *(val) ? "\t" : "", \
+	(val) && *(val) ? (val) : "" \
+
+/* printf fmt and arg to completely omit bool of given value. */
+#define FMT_BOOL "%s"
+#define ARG_BOOL(name, val) \
+	val ? "\n" name "\t1" : "\n" name "\t0"
+
+static void print_subscr_info(struct ctrl_cmd *cmd,
+			      struct hlr_subscriber *subscr)
+{
+	ctrl_cmd_reply_printf(cmd,
+		"\nid\t%"PRIu64
+		FMT_S
+		FMT_S
+		FMT_BOOL
+		FMT_BOOL
+		FMT_S
+		FMT_S
+		FMT_S
+		FMT_BOOL
+		FMT_BOOL
+		"\nperiodic_lu_timer\t%u"
+		"\nperiodic_rau_tau_timer\t%u"
+		"\nlmsi\t%08x"
+		,
+		subscr->id,
+		ARG_S("imsi", subscr->imsi),
+		ARG_S("msisdn", subscr->msisdn),
+		ARG_BOOL("nam_cs", subscr->nam_cs),
+		ARG_BOOL("nam_ps", subscr->nam_ps),
+		ARG_S("vlr_number", subscr->vlr_number),
+		ARG_S("sgsn_number", subscr->sgsn_number),
+		ARG_S("sgsn_address", subscr->sgsn_address),
+		ARG_BOOL("ms_purged_cs", subscr->ms_purged_cs),
+		ARG_BOOL("ms_purged_ps", subscr->ms_purged_ps),
+		subscr->periodic_lu_timer,
+		subscr->periodic_rau_tau_timer,
+		subscr->lmsi
+		);
+}
+
+static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud)
+{
+	if (aud->algo == OSMO_AUTH_ALG_NONE)
+		return;
+	ctrl_cmd_reply_printf(cmd,
+		"\naud2g.algo\t%s"
+		"\naud2g.ki\t%s"
+		,
+		osmo_auth_alg_name(aud->algo),
+		hexdump_buf(aud->u.gsm.ki));
+}
+
+static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud)
+{
+	if (aud->algo == OSMO_AUTH_ALG_NONE)
+		return;
+	ctrl_cmd_reply_printf(cmd,
+		"\naud3g.algo\t%s"
+		"\naud3g.k\t%s"
+		,
+		osmo_auth_alg_name(aud->algo),
+		hexdump_buf(aud->u.umts.k));
+	/* hexdump uses a static string buffer, hence only one hexdump per
+	 * printf(). */
+	ctrl_cmd_reply_printf(cmd,
+		"\naud3g.%s\t%s"
+		"\naud3g.ind_bitlen\t%u"
+		"\naud3g.sqn\t%"PRIu64
+		,
+		aud->u.umts.opc_is_op? "op" : "opc",
+		hexdump_buf(aud->u.umts.opc),
+		aud->u.umts.ind_bitlen,
+		aud->u.umts.sqn);
+}
+
+CTRL_CMD_DEFINE_RO(subscr_info, "info");
+static int get_subscr_info(struct ctrl_cmd *cmd, void *data)
 {
 	struct hlr_subscriber subscr;
+	struct hlr *hlr = data;
+	const char *by_selector = cmd->node;
 
-	if (db_subscr_get_by_imsi(ctx->dbc, cmd->value, &subscr) < 0) {
-		cmd->reply = "Subscriber Unknown in HLR";
+	if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
+		return CTRL_CMD_ERROR;
+
+	print_subscr_info(cmd, &subscr);
+
+	return CTRL_CMD_REPLY;
+}
+
+CTRL_CMD_DEFINE_RO(subscr_info_aud, "info-aud");
+static int get_subscr_info_aud(struct ctrl_cmd *cmd, void *data)
+{
+	const char *imsi;
+	struct osmo_sub_auth_data aud2g;
+	struct osmo_sub_auth_data aud3g;
+	struct hlr *hlr = data;
+	const char *by_selector = cmd->node;
+	int rc;
+
+	imsi = get_subscriber_imsi(hlr->dbc, by_selector, cmd);
+	if (!imsi)
+		return CTRL_CMD_ERROR;
+
+	rc = db_get_auth_data(hlr->dbc, imsi, &aud2g, &aud3g, NULL);
+
+	if (rc == -ENOENT) {
+		/* No auth data found, tell the print*() functions about it. */
+		aud2g.algo = OSMO_AUTH_ALG_NONE;
+		aud3g.algo = OSMO_AUTH_ALG_NONE;
+	} else if (rc) {
+		cmd->reply = "Error retrieving authentication data.";
 		return CTRL_CMD_ERROR;
 	}
 
-	if (hlr_subscr_nam(ctx, &subscr, enable, true) < 0) {
-		cmd->reply = "Error updating DB";
+	print_subscr_info_aud2g(cmd, &aud2g);
+	print_subscr_info_aud3g(cmd, &aud3g);
+
+	return CTRL_CMD_REPLY;
+}
+
+CTRL_CMD_DEFINE_RO(subscr_info_all, "info-all");
+static int get_subscr_info_all(struct ctrl_cmd *cmd, void *data)
+{
+	struct hlr_subscriber subscr;
+	struct osmo_sub_auth_data aud2g;
+	struct osmo_sub_auth_data aud3g;
+	struct hlr *hlr = data;
+	const char *by_selector = cmd->node;
+	int rc;
+
+	if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
+		return CTRL_CMD_ERROR;
+
+	rc = db_get_auth_data(hlr->dbc, subscr.imsi, &aud2g, &aud3g, NULL);
+
+	if (rc == -ENOENT) {
+		/* No auth data found, tell the print*() functions about it. */
+		aud2g.algo = OSMO_AUTH_ALG_NONE;
+		aud3g.algo = OSMO_AUTH_ALG_NONE;
+	} else if (rc) {
+		cmd->reply = "Error retrieving authentication data.";
 		return CTRL_CMD_ERROR;
 	}
 
+	print_subscr_info(cmd, &subscr);
+	print_subscr_info_aud2g(cmd, &aud2g);
+	print_subscr_info_aud3g(cmd, &aud3g);
+
+	return CTRL_CMD_REPLY;
+}
+
+static int verify_subscr_cs_ps_enabled(struct ctrl_cmd *cmd, const char *value, void *data)
+{
+	if (!value || !*value
+	    || (strcmp(value, "0") && strcmp(value, "1")))
+		return 1;
+	return 0;
+}
+
+static int get_subscr_cs_ps_enabled(struct ctrl_cmd *cmd, void *data,
+				    bool is_ps)
+{
+	struct hlr_subscriber subscr;
+	struct hlr *hlr = data;
+	const char *by_selector = cmd->node;
+
+	if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
+		return CTRL_CMD_ERROR;
+
+	cmd->reply = (is_ps ? subscr.nam_ps : subscr.nam_cs)
+		     ? "1" : "0";
+	return CTRL_CMD_REPLY;
+}
+
+static int set_subscr_cs_ps_enabled(struct ctrl_cmd *cmd, void *data,
+				    bool is_ps)
+{
+	const char *imsi;
+	struct hlr *hlr = data;
+	const char *by_selector = cmd->node;
+
+	imsi = get_subscriber_imsi(hlr->dbc, by_selector, cmd);
+	if (!imsi)
+		return CTRL_CMD_ERROR;
+	if (db_subscr_nam(hlr->dbc, imsi, strcmp(cmd->value, "1") == 0, is_ps))
+		return CTRL_CMD_ERROR;
 	cmd->reply = "OK";
 	return CTRL_CMD_REPLY;
 }
 
-CTRL_CMD_DEFINE_WO_NOVRF(enable_ps, "enable-ps");
-static int set_enable_ps(struct ctrl_cmd *cmd, void *data)
+CTRL_CMD_DEFINE(subscr_ps_enabled, "ps-enabled");
+static int verify_subscr_ps_enabled(struct ctrl_cmd *cmd, const char *value, void *data)
 {
-	return handle_cmd_ps(data, cmd, true);
+	return verify_subscr_cs_ps_enabled(cmd, value, data);
+}
+static int get_subscr_ps_enabled(struct ctrl_cmd *cmd, void *data)
+{
+	return get_subscr_cs_ps_enabled(cmd, data, true);
+}
+static int set_subscr_ps_enabled(struct ctrl_cmd *cmd, void *data)
+{
+	return set_subscr_cs_ps_enabled(cmd, data, true);
 }
 
-CTRL_CMD_DEFINE_WO_NOVRF(disable_ps, "disable-ps");
-static int set_disable_ps(struct ctrl_cmd *cmd, void *data)
+CTRL_CMD_DEFINE(subscr_cs_enabled, "cs-enabled");
+static int verify_subscr_cs_enabled(struct ctrl_cmd *cmd, const char *value, void *data)
 {
-	return handle_cmd_ps(data, cmd, false);
+	return verify_subscr_cs_ps_enabled(cmd, value, data);
 }
-
-CTRL_CMD_DEFINE_WO_NOVRF(status_ps, "status-ps");
-static int set_status_ps(struct ctrl_cmd *cmd, void *data)
+static int get_subscr_cs_enabled(struct ctrl_cmd *cmd, void *data)
 {
-	struct hlr *ctx = data;
-	struct lu_operation *luop = lu_op_alloc(ctx->gs);
-	if (!luop) {
-		cmd->reply = "Internal HLR error";
-		return CTRL_CMD_ERROR;
-	}
-
-	if (!lu_op_fill_subscr(luop, ctx->dbc, cmd->value)) {
-		cmd->reply = "Subscriber Unknown in HLR";
-		return CTRL_CMD_ERROR;
-	}
-
-	cmd->reply = luop->subscr.nam_ps ? "1" : "0";
-
-	return CTRL_CMD_REPLY;
+	return get_subscr_cs_ps_enabled(cmd, data, false);
+}
+static int set_subscr_cs_enabled(struct ctrl_cmd *cmd, void *data)
+{
+	return set_subscr_cs_ps_enabled(cmd, data, false);
 }
 
 int hlr_ctrl_cmds_install()
 {
 	int rc = 0;
 
-	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_enable_ps);
-	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_disable_ps);
-	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_status_ps);
+	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info);
+	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_aud);
+	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_all);
+	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_ps_enabled);
+	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_cs_enabled);
 
 	return rc;
+}
+
+static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
+				void **node_data, int *i)
+{
+	const char *token = vector_slot(vline, *i);
+
+	switch (*node_type) {
+	case CTRL_NODE_ROOT:
+		if (strcmp(token, "subscriber") != 0)
+			return 0;
+		*node_data = NULL;
+		*node_type = CTRL_NODE_SUBSCR;
+		break;
+	case CTRL_NODE_SUBSCR:
+		if (!startswith(token, "by-"))
+			return 0;
+		*node_data = (void*)token;
+		*node_type = CTRL_NODE_SUBSCR_BY;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
 }
 
 struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr)
@@ -100,8 +385,8 @@
 	struct ctrl_handle *hdl = ctrl_interface_setup_dynip2(hlr,
 							      hlr->ctrl_bind_addr,
 							      OSMO_CTRL_PORT_HLR,
-							      NULL,
-							      0);
+							      hlr_ctrl_node_lookup,
+							      _LAST_CTRL_NODE_HLR);
 	if (!hdl)
 		return NULL;
 
diff --git a/src/ctrl.h b/src/ctrl.h
index 239deea..3f9ba3f 100644
--- a/src/ctrl.h
+++ b/src/ctrl.h
@@ -24,7 +24,11 @@
 
 #include <osmocom/ctrl/control_if.h>
 
-#include "gsup_server.h"
+enum hlr_ctrl_node {
+	CTRL_NODE_SUBSCR = _LAST_CTRL_NODE,
+	CTRL_NODE_SUBSCR_BY,
+	_LAST_CTRL_NODE_HLR
+};
 
 int hlr_ctrl_cmds_install();
 struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr);
diff --git a/tests/test_subscriber.ctrl b/tests/test_subscriber.ctrl
index 3284ae5..b9be5fe 100644
--- a/tests/test_subscriber.ctrl
+++ b/tests/test_subscriber.ctrl
@@ -1,27 +1,598 @@
-GET 1 invalid
-ERROR 1 Command not found
-SET 2 invalid nonsense
-ERROR 2 Command not found
+GET 1 subscriber.by-imsi-901990000000001.info
+GET_REPLY 1 subscriber.by-imsi-901990000000001.info 
+id	1
+imsi	901990000000001
+msisdn	1
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
 
-SET 3 enable-ps 901990000000001
-SET_REPLY 3 enable-ps OK
-SET 4 status-ps 901990000000001
-SET_REPLY 4 status-ps 1
-SET 5 enable-ps 901990000000001
-SET_REPLY 5 enable-ps OK
-SET 6 status-ps 901990000000001
-SET_REPLY 6 status-ps 1
+GET 2 subscriber.by-imsi-901990000000001.info-aud
+GET_REPLY 2 subscriber.by-imsi-901990000000001.info-aud 
+aud2g.algo	COMP128v1
+aud2g.ki	000102030405060708090a0b0c0d0e0f
 
-SET 7 disable-ps 901990000000001
-SET_REPLY 7 disable-ps OK
-SET 8 status-ps 901990000000001
-SET_REPLY 8 status-ps 0
-SET 9 disable-ps 901990000000001
-SET_REPLY 9 disable-ps OK
-SET 10 status-ps 901990000000001
-SET_REPLY 10 status-ps 0
+GET 3 subscriber.by-imsi-901990000000001.info-all
+GET_REPLY 3 subscriber.by-imsi-901990000000001.info-all 
+id	1
+imsi	901990000000001
+msisdn	1
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+aud2g.algo	COMP128v1
+aud2g.ki	000102030405060708090a0b0c0d0e0f
 
-SET 11 enable-ps 901990000000001
-SET_REPLY 11 enable-ps OK
-SET 12 status-ps 901990000000001
-SET_REPLY 12 status-ps 1
+GET 4 subscriber.by-imsi-901990000000002.info
+GET_REPLY 4 subscriber.by-imsi-901990000000002.info 
+id	2
+imsi	901990000000002
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+GET 5 subscriber.by-imsi-901990000000002.info-aud
+GET_REPLY 5 subscriber.by-imsi-901990000000002.info-aud 
+aud3g.algo	MILENAGE
+aud3g.k	000102030405060708090a0b0c0d0e0f
+aud3g.opc	101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen	5
+aud3g.sqn	4223
+
+GET 6 subscriber.by-imsi-901990000000002.info-all
+GET_REPLY 6 subscriber.by-imsi-901990000000002.info-all 
+id	2
+imsi	901990000000002
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+aud3g.algo	MILENAGE
+aud3g.k	000102030405060708090a0b0c0d0e0f
+aud3g.opc	101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen	5
+aud3g.sqn	4223
+
+GET 7 subscriber.by-imsi-901990000000003.info
+GET_REPLY 7 subscriber.by-imsi-901990000000003.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+GET 8 subscriber.by-imsi-901990000000003.info-aud
+GET_REPLY 8 subscriber.by-imsi-901990000000003.info-aud 
+aud2g.algo	COMP128v1
+aud2g.ki	000102030405060708090a0b0c0d0e0f
+aud3g.algo	MILENAGE
+aud3g.k	000102030405060708090a0b0c0d0e0f
+aud3g.opc	101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen	5
+aud3g.sqn	2342
+
+GET 9 subscriber.by-imsi-901990000000003.info-all
+GET_REPLY 9 subscriber.by-imsi-901990000000003.info-all 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+aud2g.algo	COMP128v1
+aud2g.ki	000102030405060708090a0b0c0d0e0f
+aud3g.algo	MILENAGE
+aud3g.k	000102030405060708090a0b0c0d0e0f
+aud3g.opc	101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen	5
+aud3g.sqn	2342
+
+GET 10 subscriber.by-imsi-901990000000003.ps-enabled
+GET_REPLY 10 subscriber.by-imsi-901990000000003.ps-enabled 1
+
+SET 11 subscriber.by-imsi-901990000000003.ps-enabled 0
+SET_REPLY 11 subscriber.by-imsi-901990000000003.ps-enabled OK
+GET 12 subscriber.by-imsi-901990000000003.ps-enabled
+GET_REPLY 12 subscriber.by-imsi-901990000000003.ps-enabled 0
+
+GET 13 subscriber.by-imsi-901990000000003.info
+GET_REPLY 13 subscriber.by-imsi-901990000000003.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	0
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 14 subscriber.by-imsi-901990000000003.ps-enabled 0
+SET_REPLY 14 subscriber.by-imsi-901990000000003.ps-enabled OK
+GET 15 subscriber.by-imsi-901990000000003.ps-enabled
+GET_REPLY 15 subscriber.by-imsi-901990000000003.ps-enabled 0
+
+SET 16 subscriber.by-imsi-901990000000003.ps-enabled 1
+SET_REPLY 16 subscriber.by-imsi-901990000000003.ps-enabled OK
+GET 17 subscriber.by-imsi-901990000000003.ps-enabled
+GET_REPLY 17 subscriber.by-imsi-901990000000003.ps-enabled 1
+
+GET 18 subscriber.by-imsi-901990000000003.info
+GET_REPLY 18 subscriber.by-imsi-901990000000003.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 19 subscriber.by-imsi-901990000000003.ps-enabled 1
+SET_REPLY 19 subscriber.by-imsi-901990000000003.ps-enabled OK
+GET 20 subscriber.by-imsi-901990000000003.ps-enabled
+GET_REPLY 20 subscriber.by-imsi-901990000000003.ps-enabled 1
+
+GET 21 subscriber.by-imsi-901990000000003.cs-enabled
+GET_REPLY 21 subscriber.by-imsi-901990000000003.cs-enabled 1
+
+SET 22 subscriber.by-imsi-901990000000003.cs-enabled 0
+SET_REPLY 22 subscriber.by-imsi-901990000000003.cs-enabled OK
+GET 23 subscriber.by-imsi-901990000000003.cs-enabled
+GET_REPLY 23 subscriber.by-imsi-901990000000003.cs-enabled 0
+
+GET 24 subscriber.by-imsi-901990000000003.info
+GET_REPLY 24 subscriber.by-imsi-901990000000003.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	0
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 25 subscriber.by-imsi-901990000000003.cs-enabled 0
+SET_REPLY 25 subscriber.by-imsi-901990000000003.cs-enabled OK
+GET 26 subscriber.by-imsi-901990000000003.cs-enabled
+GET_REPLY 26 subscriber.by-imsi-901990000000003.cs-enabled 0
+
+SET 27 subscriber.by-imsi-901990000000003.cs-enabled 1
+SET_REPLY 27 subscriber.by-imsi-901990000000003.cs-enabled OK
+GET 28 subscriber.by-imsi-901990000000003.cs-enabled
+GET_REPLY 28 subscriber.by-imsi-901990000000003.cs-enabled 1
+
+GET 29 subscriber.by-imsi-901990000000003.info
+GET_REPLY 29 subscriber.by-imsi-901990000000003.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 30 subscriber.by-imsi-901990000000003.cs-enabled 1
+SET_REPLY 30 subscriber.by-imsi-901990000000003.cs-enabled OK
+GET 31 subscriber.by-imsi-901990000000003.cs-enabled
+GET_REPLY 31 subscriber.by-imsi-901990000000003.cs-enabled 1
+
+SET 32 subscriber.by-imsi-901990000000003.ps-enabled 0
+SET_REPLY 32 subscriber.by-imsi-901990000000003.ps-enabled OK
+SET 33 subscriber.by-imsi-901990000000003.cs-enabled 0
+SET_REPLY 33 subscriber.by-imsi-901990000000003.cs-enabled OK
+GET 34 subscriber.by-imsi-901990000000003.info
+GET_REPLY 34 subscriber.by-imsi-901990000000003.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	0
+nam_ps	0
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 35 subscriber.by-imsi-901990000000003.ps-enabled 1
+SET_REPLY 35 subscriber.by-imsi-901990000000003.ps-enabled OK
+SET 36 subscriber.by-imsi-901990000000003.cs-enabled 1
+SET_REPLY 36 subscriber.by-imsi-901990000000003.cs-enabled OK
+GET 37 subscriber.by-imsi-901990000000003.info
+GET_REPLY 37 subscriber.by-imsi-901990000000003.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+
+
+GET 38 subscriber.by-msisdn-103.info
+GET_REPLY 38 subscriber.by-msisdn-103.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+GET 39 subscriber.by-msisdn-103.info-aud
+GET_REPLY 39 subscriber.by-msisdn-103.info-aud 
+aud2g.algo	COMP128v1
+aud2g.ki	000102030405060708090a0b0c0d0e0f
+aud3g.algo	MILENAGE
+aud3g.k	000102030405060708090a0b0c0d0e0f
+aud3g.opc	101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen	5
+aud3g.sqn	2342
+
+GET 40 subscriber.by-msisdn-103.info-all
+GET_REPLY 40 subscriber.by-msisdn-103.info-all 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+aud2g.algo	COMP128v1
+aud2g.ki	000102030405060708090a0b0c0d0e0f
+aud3g.algo	MILENAGE
+aud3g.k	000102030405060708090a0b0c0d0e0f
+aud3g.opc	101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen	5
+aud3g.sqn	2342
+
+GET 41 subscriber.by-msisdn-103.ps-enabled
+GET_REPLY 41 subscriber.by-msisdn-103.ps-enabled 1
+
+SET 42 subscriber.by-msisdn-103.ps-enabled 0
+SET_REPLY 42 subscriber.by-msisdn-103.ps-enabled OK
+GET 43 subscriber.by-msisdn-103.ps-enabled
+GET_REPLY 43 subscriber.by-msisdn-103.ps-enabled 0
+
+GET 44 subscriber.by-msisdn-103.info
+GET_REPLY 44 subscriber.by-msisdn-103.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	0
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 45 subscriber.by-msisdn-103.ps-enabled 0
+SET_REPLY 45 subscriber.by-msisdn-103.ps-enabled OK
+GET 46 subscriber.by-msisdn-103.ps-enabled
+GET_REPLY 46 subscriber.by-msisdn-103.ps-enabled 0
+
+SET 47 subscriber.by-msisdn-103.ps-enabled 1
+SET_REPLY 47 subscriber.by-msisdn-103.ps-enabled OK
+GET 48 subscriber.by-msisdn-103.ps-enabled
+GET_REPLY 48 subscriber.by-msisdn-103.ps-enabled 1
+
+GET 49 subscriber.by-msisdn-103.info
+GET_REPLY 49 subscriber.by-msisdn-103.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 50 subscriber.by-msisdn-103.ps-enabled 1
+SET_REPLY 50 subscriber.by-msisdn-103.ps-enabled OK
+GET 51 subscriber.by-msisdn-103.ps-enabled
+GET_REPLY 51 subscriber.by-msisdn-103.ps-enabled 1
+
+GET 52 subscriber.by-msisdn-103.cs-enabled
+GET_REPLY 52 subscriber.by-msisdn-103.cs-enabled 1
+
+SET 53 subscriber.by-msisdn-103.cs-enabled 0
+SET_REPLY 53 subscriber.by-msisdn-103.cs-enabled OK
+GET 54 subscriber.by-msisdn-103.cs-enabled
+GET_REPLY 54 subscriber.by-msisdn-103.cs-enabled 0
+
+GET 55 subscriber.by-msisdn-103.info
+GET_REPLY 55 subscriber.by-msisdn-103.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	0
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 56 subscriber.by-msisdn-103.cs-enabled 0
+SET_REPLY 56 subscriber.by-msisdn-103.cs-enabled OK
+GET 57 subscriber.by-msisdn-103.cs-enabled
+GET_REPLY 57 subscriber.by-msisdn-103.cs-enabled 0
+
+SET 58 subscriber.by-msisdn-103.cs-enabled 1
+SET_REPLY 58 subscriber.by-msisdn-103.cs-enabled OK
+GET 59 subscriber.by-msisdn-103.cs-enabled
+GET_REPLY 59 subscriber.by-msisdn-103.cs-enabled 1
+
+GET 60 subscriber.by-msisdn-103.info
+GET_REPLY 60 subscriber.by-msisdn-103.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 61 subscriber.by-msisdn-103.cs-enabled 1
+SET_REPLY 61 subscriber.by-msisdn-103.cs-enabled OK
+GET 62 subscriber.by-msisdn-103.cs-enabled
+GET_REPLY 62 subscriber.by-msisdn-103.cs-enabled 1
+
+SET 63 subscriber.by-msisdn-103.ps-enabled 0
+SET_REPLY 63 subscriber.by-msisdn-103.ps-enabled OK
+SET 64 subscriber.by-msisdn-103.cs-enabled 0
+SET_REPLY 64 subscriber.by-msisdn-103.cs-enabled OK
+GET 65 subscriber.by-msisdn-103.info
+GET_REPLY 65 subscriber.by-msisdn-103.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	0
+nam_ps	0
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 66 subscriber.by-msisdn-103.ps-enabled 1
+SET_REPLY 66 subscriber.by-msisdn-103.ps-enabled OK
+SET 67 subscriber.by-msisdn-103.cs-enabled 1
+SET_REPLY 67 subscriber.by-msisdn-103.cs-enabled OK
+GET 68 subscriber.by-msisdn-103.info
+GET_REPLY 68 subscriber.by-msisdn-103.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+
+
+GET 69 subscriber.by-id-3.info
+GET_REPLY 69 subscriber.by-id-3.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+GET 70 subscriber.by-id-3.info-aud
+GET_REPLY 70 subscriber.by-id-3.info-aud 
+aud2g.algo	COMP128v1
+aud2g.ki	000102030405060708090a0b0c0d0e0f
+aud3g.algo	MILENAGE
+aud3g.k	000102030405060708090a0b0c0d0e0f
+aud3g.opc	101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen	5
+aud3g.sqn	2342
+
+GET 71 subscriber.by-id-3.info-all
+GET_REPLY 71 subscriber.by-id-3.info-all 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+aud2g.algo	COMP128v1
+aud2g.ki	000102030405060708090a0b0c0d0e0f
+aud3g.algo	MILENAGE
+aud3g.k	000102030405060708090a0b0c0d0e0f
+aud3g.opc	101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen	5
+aud3g.sqn	2342
+
+GET 72 subscriber.by-id-3.ps-enabled
+GET_REPLY 72 subscriber.by-id-3.ps-enabled 1
+
+SET 73 subscriber.by-id-3.ps-enabled 0
+SET_REPLY 73 subscriber.by-id-3.ps-enabled OK
+GET 74 subscriber.by-id-3.ps-enabled
+GET_REPLY 74 subscriber.by-id-3.ps-enabled 0
+
+GET 75 subscriber.by-id-3.info
+GET_REPLY 75 subscriber.by-id-3.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	0
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 76 subscriber.by-id-3.ps-enabled 0
+SET_REPLY 76 subscriber.by-id-3.ps-enabled OK
+GET 77 subscriber.by-id-3.ps-enabled
+GET_REPLY 77 subscriber.by-id-3.ps-enabled 0
+
+SET 78 subscriber.by-id-3.ps-enabled 1
+SET_REPLY 78 subscriber.by-id-3.ps-enabled OK
+GET 79 subscriber.by-id-3.ps-enabled
+GET_REPLY 79 subscriber.by-id-3.ps-enabled 1
+
+GET 80 subscriber.by-id-3.info
+GET_REPLY 80 subscriber.by-id-3.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 81 subscriber.by-id-3.ps-enabled 1
+SET_REPLY 81 subscriber.by-id-3.ps-enabled OK
+GET 82 subscriber.by-id-3.ps-enabled
+GET_REPLY 82 subscriber.by-id-3.ps-enabled 1
+
+GET 83 subscriber.by-id-3.cs-enabled
+GET_REPLY 83 subscriber.by-id-3.cs-enabled 1
+
+SET 84 subscriber.by-id-3.cs-enabled 0
+SET_REPLY 84 subscriber.by-id-3.cs-enabled OK
+GET 85 subscriber.by-id-3.cs-enabled
+GET_REPLY 85 subscriber.by-id-3.cs-enabled 0
+
+GET 86 subscriber.by-id-3.info
+GET_REPLY 86 subscriber.by-id-3.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	0
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 87 subscriber.by-id-3.cs-enabled 0
+SET_REPLY 87 subscriber.by-id-3.cs-enabled OK
+GET 88 subscriber.by-id-3.cs-enabled
+GET_REPLY 88 subscriber.by-id-3.cs-enabled 0
+
+SET 89 subscriber.by-id-3.cs-enabled 1
+SET_REPLY 89 subscriber.by-id-3.cs-enabled OK
+GET 90 subscriber.by-id-3.cs-enabled
+GET_REPLY 90 subscriber.by-id-3.cs-enabled 1
+
+GET 91 subscriber.by-id-3.info
+GET_REPLY 91 subscriber.by-id-3.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 92 subscriber.by-id-3.cs-enabled 1
+SET_REPLY 92 subscriber.by-id-3.cs-enabled OK
+GET 93 subscriber.by-id-3.cs-enabled
+GET_REPLY 93 subscriber.by-id-3.cs-enabled 1
+
+SET 94 subscriber.by-id-3.ps-enabled 0
+SET_REPLY 94 subscriber.by-id-3.ps-enabled OK
+SET 95 subscriber.by-id-3.cs-enabled 0
+SET_REPLY 95 subscriber.by-id-3.cs-enabled OK
+GET 96 subscriber.by-id-3.info
+GET_REPLY 96 subscriber.by-id-3.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	0
+nam_ps	0
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
+
+SET 97 subscriber.by-id-3.ps-enabled 1
+SET_REPLY 97 subscriber.by-id-3.ps-enabled OK
+SET 98 subscriber.by-id-3.cs-enabled 1
+SET_REPLY 98 subscriber.by-id-3.cs-enabled OK
+GET 99 subscriber.by-id-3.info
+GET_REPLY 99 subscriber.by-id-3.info 
+id	3
+imsi	901990000000003
+msisdn	103
+nam_cs	1
+nam_ps	1
+ms_purged_cs	0
+ms_purged_ps	0
+periodic_lu_timer	0
+periodic_rau_tau_timer	0
+lmsi	00000000
diff --git a/tests/test_subscriber.sql b/tests/test_subscriber.sql
index 0767d48..bce0af2 100644
--- a/tests/test_subscriber.sql
+++ b/tests/test_subscriber.sql
@@ -1,13 +1,13 @@
 
 -- 2G only subscriber
-INSERT INTO subscriber (id, imsi) VALUES (1, '901990000000001');
+INSERT INTO subscriber (id, imsi, msisdn) VALUES (1, '901990000000001', '1');
 INSERT INTO auc_2g (subscriber_id, algo_id_2g, ki) VALUES (1, 1, '000102030405060708090a0b0c0d0e0f');
 
 -- 3G only subscriber
 INSERT INTO subscriber (id, imsi) VALUES (2, '901990000000002');
-INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (2, 5, '000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 0);
+INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (2, 5, '000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 4223);
 
 -- 2G + 3G subscriber
-INSERT INTO subscriber (id, imsi) VALUES (3, '901990000000003');
+INSERT INTO subscriber (id, imsi, msisdn) VALUES (3, '901990000000003', '103');
 INSERT INTO auc_2g (subscriber_id, algo_id_2g, ki) VALUES (3, 1, '000102030405060708090a0b0c0d0e0f');
-INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (3, 5, '000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 0);
+INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (3, 5, '000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 2342);
diff --git a/tests/test_subscriber.vty b/tests/test_subscriber.vty
index 2e0bdce..2da455f 100644
--- a/tests/test_subscriber.vty
+++ b/tests/test_subscriber.vty
@@ -305,6 +305,7 @@
              OPC=cededeffacedacefacedbadfadedbeef
              IND-bitlen=23
 
+OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d op C01ffedC1cadaeAc1d1f1edAcac1aB0a
 OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d op CoiffedCicadaeAcidifiedAcaciaBoa
 % Invalid value for OP: 'CoiffedCicadaeAcidifiedAcaciaBoa'
 OsmoHLR# subscriber imsi 123456789023000 show
@@ -313,8 +314,8 @@
     MSISDN: 423
     3G auth: MILENAGE
              K=deaf0ff1ced0d0dabbedd1ced1cef00d
-             OPC=cededeffacedacefacedbadfadedbeef
-             IND-bitlen=23
+             OP=c01ffedc1cadaeac1d1f1edacac1ab0a
+             IND-bitlen=5
 
 OsmoHLR# subscriber id 1 update aud2g comp128v2 ki CededEffacedAceFacedBadFadedBeef
 OsmoHLR# subscriber id 1 show
@@ -325,8 +326,8 @@
              KI=cededeffacedacefacedbadfadedbeef
     3G auth: MILENAGE
              K=deaf0ff1ced0d0dabbedd1ced1cef00d
-             OPC=cededeffacedacefacedbadfadedbeef
-             IND-bitlen=23
+             OP=c01ffedc1cadaeac1d1f1edacac1ab0a
+             IND-bitlen=5
 
 OsmoHLR# subscriber imsi 123456789023000 delete
 % Deleted subscriber for IMSI '123456789023000'
diff --git a/tests/test_subscriber_errors.ctrl b/tests/test_subscriber_errors.ctrl
new file mode 100644
index 0000000..2f64fdb
--- /dev/null
+++ b/tests/test_subscriber_errors.ctrl
@@ -0,0 +1,107 @@
+GET 1 invalid
+ERROR 1 Command not found
+SET 2 invalid nonsense
+ERROR 2 Command not found
+
+GET 3 subscriber.by-imsi-nonsense.info
+ERROR 3 Invalid value part of 'by-xxx-value' selector.
+GET 4 subscriber.by-msisdn-nonsense.info
+ERROR 4 Invalid value part of 'by-xxx-value' selector.
+GET 5 subscriber.by-id-nonsense.info
+ERROR 5 Invalid value part of 'by-xxx-value' selector.
+
+GET 6 subscriber
+ERROR 6 Command not present.
+GET 7 subscriber.
+ERROR 7 Command not present.
+GET 8 subscriber.by-nonsense
+ERROR 8 Command not present.
+GET 9 subscriber.by-nonsense-
+ERROR 9 Command not present.
+GET 10 subscriber.by-nonsense-123456
+ERROR 10 Command not present.
+GET 11 subscriber.by-nonsense-123456.
+ERROR 11 Command not present.
+GET 12 subscriber.by-imsi-
+ERROR 12 Command not present.
+GET 13 subscriber.by-imsi-.
+ERROR 13 Command not present.
+GET 14 subscriber.by-imsi-901990000000003
+ERROR 14 Command not present.
+GET 15 subscriber.by-imsi-901990000000003.
+ERROR 15 Command not present.
+
+GET 16 subscriber.by-nonsense-123456.info
+ERROR 16 Not a known subscriber 'by-xxx-' selector.
+GET 17 subscriber.by-123456.info
+ERROR 17 Not a known subscriber 'by-xxx-' selector.
+
+GET 18 subscriber.by-imsi-.info
+ERROR 18 Invalid value part of 'by-xxx-value' selector.
+GET 19 subscriber.by-imsi--.info
+ERROR 19 Invalid value part of 'by-xxx-value' selector.
+
+GET 20 subscriber.by-imsi-12345678901234567.info
+ERROR 20 Invalid value part of 'by-xxx-value' selector.
+GET 21 subscriber.by-imsi-12345.info
+ERROR 21 Invalid value part of 'by-xxx-value' selector.
+GET 22 subscriber.by-imsi-1234567890123456.info
+ERROR 22 Invalid value part of 'by-xxx-value' selector.
+
+GET 23 subscriber.by-id-99999999999999999999999999.info
+ERROR 23 Invalid value part of 'by-xxx-value' selector.
+GET 24 subscriber.by-id-9223372036854775807.info
+ERROR 24 No such subscriber.
+GET 25 subscriber.by-id-9223372036854775808.info
+ERROR 25 Invalid value part of 'by-xxx-value' selector.
+GET 26 subscriber.by-id--1.info
+ERROR 26 No such subscriber.
+GET 27 subscriber.by-id--9223372036854775808.info
+ERROR 27 No such subscriber.
+GET 28 subscriber.by-id--9223372036854775809.info
+ERROR 28 Invalid value part of 'by-xxx-value' selector.
+
+GET 29 subscriber.by-id-1+1.info
+ERROR 29 Invalid value part of 'by-xxx-value' selector.
+GET 30 subscriber.by-id--.info
+ERROR 30 Invalid value part of 'by-xxx-value' selector.
+GET 31 subscriber.by-id-+1.info
+ERROR 31 Invalid value part of 'by-xxx-value' selector.
+GET 32 subscriber.by-id-+-1.info
+ERROR 32 Invalid value part of 'by-xxx-value' selector.
+GET 33 subscriber.by-id--+1.info
+ERROR 33 Invalid value part of 'by-xxx-value' selector.
+GET 34 subscriber.by-id-++1.info
+ERROR 34 Invalid value part of 'by-xxx-value' selector.
+GET 35 subscriber.by-id---1.info
+ERROR 35 Invalid value part of 'by-xxx-value' selector.
+
+GET 36 subscriber.by-id- 1.info
+ERROR 36 Command not present.
+GET 37 subscriber.by-id-+ 1.info
+ERROR 37 Command not present.
+GET 38 subscriber.by-id-- 1.info
+ERROR 38 Command not present.
+
+
+SET 39 subscriber.by-imsi-901990000000001.info foo
+ERROR 39 Read Only attribute
+SET 40 subscriber.by-imsi-901990000000001.info-aud foo
+ERROR 40 Read Only attribute
+SET 41 subscriber.by-imsi-901990000000001.info-all foo
+ERROR 41 Read Only attribute
+
+SET 42 subscriber.by-imsi-901990000000001.ps-enabled nonsense
+ERROR 42 Value failed verification.
+SET 43 subscriber.by-imsi-901990000000001.cs-enabled nonsense
+ERROR 43 Value failed verification.
+
+SET 44 subscriber.by-imsi-901990000000001.ps-enabled
+ERROR err Command parser error.
+SET 45 subscriber.by-imsi-901990000000001.cs-enabled
+ERROR err Command parser error.
+
+GET 46 subscriber.by-imsi-1234567890123456.ps-enabled
+ERROR 46 Invalid value part of 'by-xxx-value' selector.
+GET 47 subscriber.by-imsi-1234567890123456.cs-enabled
+ERROR 47 Invalid value part of 'by-xxx-value' selector.

-- 
To view, visit https://gerrit.osmocom.org/4311
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I98ee6a06b3aa6a67adb868e0b63b0e04eb42eb50
Gerrit-PatchSet: 7
Gerrit-Project: osmo-hlr
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Max <msuraev at sysmocom.de>
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>


More information about the gerrit-log mailing list