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 (#3).

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.

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 src/hlr.c
M tests/test_subscriber.ctrl
M tests/test_subscriber.sql
M tests/test_subscriber.vty
A tests/test_subscriber_errors.ctrl
7 files changed, 871 insertions(+), 78 deletions(-)


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

diff --git a/src/ctrl.c b/src/ctrl.c
index 3bd4d8f..6140a25 100644
--- a/src/ctrl.c
+++ b/src/ctrl.c
@@ -21,87 +21,382 @@
  */
 
 #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 = NULL;
+               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_OMIT_TRUE(name, val) \
+       val ? "" : "\n" name "\t0"
+#define ARG_BOOL_OMIT_FALSE(name, val) \
+       val ? "\n" name "\t1" : ""
+#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
+#if 0
+/* not used yet */
+               FMT_BOOL
+               FMT_BOOL
+               "\nperiodic_lu_timer\t%u"
+               "\nperiodic_rau_tau_timer\t%u"
+               "\nlmsi\t%08x"
+#endif
+               ,
+               subscr->id,
+               ARG_S("imsi", subscr->imsi),
+               ARG_S("msisdn", subscr->msisdn),
+               ARG_BOOL_OMIT_TRUE("nam_cs", subscr->nam_cs),
+               ARG_BOOL_OMIT_TRUE("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)
+#if 0
+               ,
+               ARG_BOOL_OMIT_FALSE("ms_purged_cs", subscr->ms_purged_cs),
+               ARG_BOOL_OMIT_FALSE("ms_purged_ps", subscr->ms_purged_ps),
+               subscr->periodic_lu_timer,
+               subscr->periodic_rau_tau_timer,
+               subscr->lmsi
+#endif
+               );
+}
+
+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) {
+               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) {
+               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;
 }
 
-struct ctrl_handle *hlr_controlif_setup(struct hlr *ctx,
-                                       struct osmo_gsup_server *gs)
+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)
 {
        int rc;
-       struct ctrl_handle *hdl = ctrl_interface_setup_dynip(ctx,
-                                                            
ctx->ctrl_bind_addr,
-                                                            OSMO_CTRL_PORT_HLR,
-                                                            NULL);
+       struct ctrl_handle *hdl;
+
+       hdl = ctrl_interface_setup_dynip2(hlr,
+                                         hlr->ctrl_bind_addr,
+                                         OSMO_CTRL_PORT_HLR,
+                                         hlr_ctrl_node_lookup,
+                                         _LAST_CTRL_NODE_HLR);
        if (!hdl)
                return NULL;
 
diff --git a/src/ctrl.h b/src/ctrl.h
index 663de30..3f9ba3f 100644
--- a/src/ctrl.h
+++ b/src/ctrl.h
@@ -24,8 +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 *ctx,
-                                       struct osmo_gsup_server *gs);
+struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr);
diff --git a/src/hlr.c b/src/hlr.c
index b32f709..6310526 100644
--- a/src/hlr.c
+++ b/src/hlr.c
@@ -474,7 +474,7 @@
        }
 
        g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
-       g_hlr->ctrl = hlr_controlif_setup(g_hlr, g_hlr->gs);
+       g_hlr->ctrl = hlr_controlif_setup(g_hlr);
 
        osmo_init_ignore_signals();
        signal(SIGINT, &signal_hdlr);
diff --git a/tests/test_subscriber.ctrl b/tests/test_subscriber.ctrl
index 3284ae5..30dae00 100644
--- a/tests/test_subscriber.ctrl
+++ b/tests/test_subscriber.ctrl
@@ -1,27 +1,414 @@
-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
 
-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
+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
+
+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      0
+
+GET 6 subscriber.by-imsi-901990000000002.info-all
+GET_REPLY 6 subscriber.by-imsi-901990000000002.info-all 
+id     2
+imsi   901990000000002
+aud3g.algo     MILENAGE
+aud3g.k        000102030405060708090a0b0c0d0e0f
+aud3g.opc      101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen       5
+aud3g.sqn      0
+
+GET 7 subscriber.by-imsi-901990000000003.info
+GET_REPLY 7 subscriber.by-imsi-901990000000003.info 
+id     3
+imsi   901990000000003
+msisdn 103
+
+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      0
+
+GET 9 subscriber.by-imsi-901990000000003.info-all
+GET_REPLY 9 subscriber.by-imsi-901990000000003.info-all 
+id     3
+imsi   901990000000003
+msisdn 103
+aud2g.algo     COMP128v1
+aud2g.ki       000102030405060708090a0b0c0d0e0f
+aud3g.algo     MILENAGE
+aud3g.k        000102030405060708090a0b0c0d0e0f
+aud3g.opc      101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen       5
+aud3g.sqn      0
+
+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_ps 0
+
+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
+
+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
+
+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
+
+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
+
+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
+
+
+
+GET 38 subscriber.by-msisdn-103.info
+GET_REPLY 38 subscriber.by-msisdn-103.info 
+id     3
+imsi   901990000000003
+msisdn 103
+
+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      0
+
+GET 40 subscriber.by-msisdn-103.info-all
+GET_REPLY 40 subscriber.by-msisdn-103.info-all 
+id     3
+imsi   901990000000003
+msisdn 103
+aud2g.algo     COMP128v1
+aud2g.ki       000102030405060708090a0b0c0d0e0f
+aud3g.algo     MILENAGE
+aud3g.k        000102030405060708090a0b0c0d0e0f
+aud3g.opc      101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen       5
+aud3g.sqn      0
+
+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_ps 0
+
+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
+
+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
+
+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
+
+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
+
+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
+
+
+
+GET 69 subscriber.by-id-3.info
+GET_REPLY 69 subscriber.by-id-3.info 
+id     3
+imsi   901990000000003
+msisdn 103
+
+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      0
+
+GET 71 subscriber.by-id-3.info-all
+GET_REPLY 71 subscriber.by-id-3.info-all 
+id     3
+imsi   901990000000003
+msisdn 103
+aud2g.algo     COMP128v1
+aud2g.ki       000102030405060708090a0b0c0d0e0f
+aud3g.algo     MILENAGE
+aud3g.k        000102030405060708090a0b0c0d0e0f
+aud3g.opc      101112131415161718191a1b1c1d1e1f
+aud3g.ind_bitlen       5
+aud3g.sqn      0
+
+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_ps 0
+
+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
+
+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
+
+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
+
+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
+
+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
diff --git a/tests/test_subscriber.sql b/tests/test_subscriber.sql
index 0767d48..decd7d2 100644
--- a/tests/test_subscriber.sql
+++ b/tests/test_subscriber.sql
@@ -1,6 +1,6 @@
 
 -- 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
@@ -8,6 +8,6 @@
 INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (2, 5, 
'000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 0);
 
 -- 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);
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: 3
Gerrit-Project: osmo-hlr
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofm...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Max <msur...@sysmocom.de>
Gerrit-Reviewer: Neels Hofmeyr <nhofm...@sysmocom.de>

Reply via email to