diff --git a/src/hlr_vty_subscr.c b/src/hlr_vty_subscr.c index 92cfa2a3..998d1bee 100644 --- a/src/hlr_vty_subscr.c +++ b/src/hlr_vty_subscr.c @@ -58,6 +58,15 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr) vty_out(vty, " IMSI: %s%s", *subscr->imsi ? subscr->imsi : "none", VTY_NEWLINE); vty_out(vty, " MSISDN: %s%s", *subscr->msisdn ? subscr->msisdn : "none", VTY_NEWLINE); + + if (*subscr->imei) { + char checksum = osmo_luhn(subscr->imei, 14); + if (checksum == -EINVAL) + vty_out(vty, " IMEI: %s (INVALID LENGTH!)%s", subscr->imei, VTY_NEWLINE); + else + vty_out(vty, " IMEI: %s%c%s", subscr->imei, checksum, VTY_NEWLINE); + } + if (*subscr->vlr_number) vty_out(vty, " VLR number: %s%s", subscr->vlr_number, VTY_NEWLINE); if (*subscr->sgsn_number) @@ -131,6 +140,7 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr) static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id, struct hlr_subscriber *subscr) { + char imei_buf[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1]; int rc = -1; if (strcmp(type, "imsi") == 0) rc = db_subscr_get_by_imsi(g_hlr->dbc, id, subscr); @@ -138,6 +148,17 @@ static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id, rc = db_subscr_get_by_msisdn(g_hlr->dbc, id, subscr); else if (strcmp(type, "id") == 0) rc = db_subscr_get_by_id(g_hlr->dbc, atoll(id), subscr); + else if (strcmp(type, "imei") == 0) { + /* Verify IMEI with checksum digit */ + if (osmo_imei_str_valid(id, true)) { + /* Cut the checksum off */ + osmo_strlcpy(imei_buf, id, sizeof(imei_buf)); + id = imei_buf; + vty_out(vty, "%% Checksum validated and stripped for search: imei = '%s'%s", id, + VTY_NEWLINE); + } + rc = db_subscr_get_by_imei(g_hlr->dbc, id, subscr); + } if (rc) vty_out(vty, "%% No subscriber for %s = '%s'%s", type, id, VTY_NEWLINE); @@ -147,12 +168,13 @@ static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id, #define SUBSCR_CMD "subscriber " #define SUBSCR_CMD_HELP "Subscriber management commands\n" -#define SUBSCR_ID "(imsi|msisdn|id) IDENT" +#define SUBSCR_ID "(imsi|msisdn|id|imei) IDENT" #define SUBSCR_ID_HELP \ "Identify subscriber by IMSI\n" \ "Identify subscriber by MSISDN (phone number)\n" \ "Identify subscriber by database ID\n" \ - "IMSI/MSISDN/ID of the subscriber\n" + "Identify subscriber by IMEI\n" \ + "IMSI/MSISDN/ID/IMEI of the subscriber\n" #define SUBSCR SUBSCR_CMD SUBSCR_ID " " #define SUBSCR_HELP SUBSCR_CMD_HELP SUBSCR_ID_HELP @@ -508,6 +530,54 @@ DEFUN(subscriber_aud3g, return CMD_SUCCESS; } +DEFUN(subscriber_imei, + subscriber_imei_cmd, + SUBSCR_UPDATE "imei (none|IMEI)", + SUBSCR_UPDATE_HELP + "Set IMEI of the subscriber (normally populated from MSC, no need to set this manually)\n" + "Forget IMEI\n" + "Set IMEI (use for debug only!)\n") +{ + struct hlr_subscriber subscr; + const char *id_type = argv[0]; + const char *id = argv[1]; + const char *imei = argv[2]; + char imei_buf[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1]; + + if (strcmp(imei, "none") == 0) + imei = NULL; + else { + /* Verify IMEI with checksum digit */ + if (osmo_imei_str_valid(imei, true)) { + /* Cut the checksum off */ + osmo_strlcpy(imei_buf, imei, sizeof(imei_buf)); + imei = imei_buf; + } else if (!osmo_imei_str_valid(imei, false)) { + vty_out(vty, "%% IMEI invalid: '%s'%s", imei, VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (get_subscr_by_argv(vty, id_type, id, &subscr)) + return CMD_WARNING; + + if (db_subscr_update_imei_by_imsi(g_hlr->dbc, subscr.imsi, imei)) { + vty_out(vty, "%% Error: cannot update IMEI for subscriber IMSI='%s'%s", + subscr.imsi, VTY_NEWLINE); + return CMD_WARNING; + } + + if (imei) + vty_out(vty, "%% Updated subscriber IMSI='%s' to IMEI='%s'%s", + subscr.imsi, imei, VTY_NEWLINE); + else + vty_out(vty, "%% Updated subscriber IMSI='%s': removed IMEI%s", + subscr.imsi, VTY_NEWLINE); + + return CMD_SUCCESS; +} + + void hlr_vty_subscriber_init(void) { install_element_ve(&subscriber_show_cmd); @@ -519,4 +589,5 @@ void hlr_vty_subscriber_init(void) install_element(ENABLE_NODE, &subscriber_aud2g_cmd); install_element(ENABLE_NODE, &subscriber_no_aud3g_cmd); install_element(ENABLE_NODE, &subscriber_aud3g_cmd); + install_element(ENABLE_NODE, &subscriber_imei_cmd); } diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty index 6e72ed0e..ee7885b0 100644 --- a/tests/test_nodes.vty +++ b/tests/test_nodes.vty @@ -17,8 +17,8 @@ OsmoHLR> list show talloc-context (application|all) (full|brief|DEPTH) tree ADDRESS show talloc-context (application|all) (full|brief|DEPTH) filter REGEXP show gsup-connections - subscriber (imsi|msisdn|id) IDENT show - show subscriber (imsi|msisdn|id) IDENT + subscriber (imsi|msisdn|id|imei) IDENT show + show subscriber (imsi|msisdn|id|imei) IDENT OsmoHLR> enable OsmoHLR# list diff --git a/tests/test_subscriber.vty b/tests/test_subscriber.vty index d310eb36..265f8fa6 100644 --- a/tests/test_subscriber.vty +++ b/tests/test_subscriber.vty @@ -2,15 +2,16 @@ OsmoHLR> enable OsmoHLR# list ... - subscriber (imsi|msisdn|id) IDENT show - show subscriber (imsi|msisdn|id) IDENT + subscriber (imsi|msisdn|id|imei) IDENT show + show subscriber (imsi|msisdn|id|imei) IDENT subscriber imsi IDENT create - subscriber (imsi|msisdn|id) IDENT delete - subscriber (imsi|msisdn|id) IDENT update msisdn (none|MSISDN) - subscriber (imsi|msisdn|id) IDENT update aud2g none - subscriber (imsi|msisdn|id) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI - subscriber (imsi|msisdn|id) IDENT update aud3g none - subscriber (imsi|msisdn|id) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>] + subscriber (imsi|msisdn|id|imei) IDENT delete + subscriber (imsi|msisdn|id|imei) IDENT update msisdn (none|MSISDN) + subscriber (imsi|msisdn|id|imei) IDENT update aud2g none + subscriber (imsi|msisdn|id|imei) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI + subscriber (imsi|msisdn|id|imei) IDENT update aud3g none + subscriber (imsi|msisdn|id|imei) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>] + subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI) OsmoHLR# subscriber? subscriber Subscriber management commands @@ -19,13 +20,16 @@ OsmoHLR# subscriber ? imsi Identify subscriber by IMSI msisdn Identify subscriber by MSISDN (phone number) id Identify subscriber by database ID + imei Identify subscriber by IMEI OsmoHLR# subscriber imsi ? - IDENT IMSI/MSISDN/ID of the subscriber + IDENT IMSI/MSISDN/ID/IMEI of the subscriber OsmoHLR# subscriber msisdn ? - IDENT IMSI/MSISDN/ID of the subscriber + IDENT IMSI/MSISDN/ID/IMEI of the subscriber OsmoHLR# subscriber id ? - IDENT IMSI/MSISDN/ID of the subscriber + IDENT IMSI/MSISDN/ID/IMEI of the subscriber +OsmoHLR# subscriber imei ? + IDENT IMSI/MSISDN/ID/IMEI of the subscriber OsmoHLR# subscriber imsi 123456789023000 show % No subscriber for imsi = '123456789023000' @@ -33,6 +37,9 @@ OsmoHLR# subscriber id 101 show % No subscriber for id = '101' OsmoHLR# subscriber msisdn 12345 show % No subscriber for msisdn = '12345' +OsmoHLR# subscriber imei 357613004448485 show +% Checksum validated and stripped for search: imei = '35761300444848' +% No subscriber for imei = '35761300444848' OsmoHLR# show subscriber imsi 123456789023000 % No subscriber for imsi = '123456789023000' @@ -40,6 +47,9 @@ OsmoHLR# show subscriber id 101 % No subscriber for id = '101' OsmoHLR# show subscriber msisdn 12345 % No subscriber for msisdn = '12345' +OsmoHLR# show subscriber imei 357613004448485 +% Checksum validated and stripped for search: imei = '35761300444848' +% No subscriber for imei = '35761300444848' OsmoHLR# subscriber imsi 1234567890230001 create % Not a valid IMSI: 1234567890230001 @@ -118,6 +128,7 @@ OsmoHLR# subscriber imsi 123456789023000 update ? msisdn Set MSISDN (phone number) of the subscriber aud2g Set 2G authentication data aud3g Set UMTS authentication data (3G, and 2G with UMTS AKA) + imei Set IMEI of the subscriber (normally populated from MSC, no need to set this manually) OsmoHLR# subscriber imsi 123456789023000 update msisdn ? none Remove MSISDN (phone number) @@ -374,3 +385,55 @@ OsmoHLR# subscriber imsi 123456789023000 create OsmoHLR# subscriber imsi 123456789023000 delete % Deleted subscriber for IMSI '123456789023000' + +OsmoHLR# subscriber imsi 123456789023000 create +% Created subscriber 123456789023000 + ID: 101 + IMSI: 123456789023000 + MSISDN: none + +OsmoHLR# subscriber imsi 123456789023000 update imei ? + none Forget IMEI + IMEI Set IMEI (use for debug only!) + +OsmoHLR# subscriber imsi 123456789023000 update imei 35761300444848 +% Updated subscriber IMSI='123456789023000' to IMEI='35761300444848' + +OsmoHLR# subscriber imsi 123456789023000 update imei 357613004448484 +% IMEI invalid: '357613004448484' + +OsmoHLR# subscriber imsi 123456789023000 update imei 357613004448485 +% Updated subscriber IMSI='123456789023000' to IMEI='35761300444848' + +OsmoHLR# show subscriber imei 35761300444848 + ID: 101 + IMSI: 123456789023000 + MSISDN: none + IMEI: 357613004448485 + +OsmoHLR# show subscriber imei 357613004448485 +% Checksum validated and stripped for search: imei = '35761300444848' + ID: 101 + IMSI: 123456789023000 + MSISDN: none + IMEI: 357613004448485 + +OsmoHLR# show subscriber imei 357613004448484 +% No subscriber for imei = '357613004448484' + +OsmoHLR# subscriber imsi 123456789023000 update imei none +% Updated subscriber IMSI='123456789023000': removed IMEI + +OsmoHLR# subscriber imsi 123456789023000 show + ID: 101 + IMSI: 123456789023000 + MSISDN: none + +OsmoHLR# subscriber imsi 123456789023000 delete +% Deleted subscriber for IMSI '123456789023000' + +OsmoHLR# show subscriber id 99 + ID: 99 + IMSI: 000000000000099 + MSISDN: none + IMEI: 12345 (INVALID LENGTH!) diff --git a/tests/test_subscriber.vty.sql b/tests/test_subscriber.vty.sql index ff167aa6..e2c1af2a 100644 --- a/tests/test_subscriber.vty.sql +++ b/tests/test_subscriber.vty.sql @@ -1,3 +1,6 @@ +-- Subscriber with invalid IMEI length +INSERT INTO subscriber (id, imsi, imei) VALUES(99, '000000000000099', '12345'); + -- Dummy entry with ID=100 gives all subscribers created in the VTY test an -- ID > 100, so we can pre-fill the database with IDs < 100. INSERT INTO subscriber (id, imsi) VALUES(100, '000000000000100');