aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-08-04 11:10:09 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-08-04 11:37:28 +0200
commit18739ea32d5030f5080158fbdd2c3bf8ab6d01e2 (patch)
tree50eccd73aade98678a48da4f9d995774f455778c /openbsc/src
parent035b874fdfaad62b3035b3ff3b8d7d3011629893 (diff)
gbproxy: Move the VTY code into the vty file and create public API
Create public accessors to the core of the peer to allow to simplify the test and separate concerns. Done with Jacob.
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/gprs/gb_proxy.c307
-rw-r--r--openbsc/src/gprs/gb_proxy_main.c1
-rw-r--r--openbsc/src/gprs/gb_proxy_vty.c235
3 files changed, 254 insertions, 289 deletions
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index d4b5e0e40..3e5afa485 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -35,8 +35,6 @@
#include <osmocom/core/select.h>
#include <osmocom/core/rate_ctr.h>
-#include <osmocom/vty/misc.h>
-
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_bssgp.h>
@@ -89,7 +87,7 @@ static const struct rate_ctr_group_desc global_ctrg_desc = {
static struct rate_ctr_group *global_ctrg = NULL;
-static struct rate_ctr_group *get_global_ctrg()
+struct rate_ctr_group *get_global_ctrg(void)
{
if (global_ctrg)
return global_ctrg;
@@ -142,36 +140,6 @@ struct {
regex_t imsi_re_comp;
} gbprox_global_patch_state = {0,};
-struct gbprox_patch_state {
- int local_mnc;
- int local_mcc;
-
- /* List of TLLIs for which patching is enabled */
- struct llist_head enabled_tllis;
- int enabled_tllis_count;
-};
-
-struct gbprox_peer {
- struct llist_head list;
-
- /* NSEI of the peer entity */
- uint16_t nsei;
-
- /* BVCI used for Point-to-Point to this peer */
- uint16_t bvci;
- int blocked;
-
- /* Routeing Area that this peer is part of (raw 04.08 encoding) */
- uint8_t ra[6];
-
- /* Counter */
- struct rate_ctr_group *ctrg;
-
- struct gbprox_patch_state patch_state;
-};
-
-/* Linked list of all Gb peers (except SGSN) */
-static LLIST_HEAD(gbprox_bts_peers);
static void gbprox_delete_tllis(struct gbprox_peer *peer);
@@ -179,7 +147,7 @@ static void gbprox_delete_tllis(struct gbprox_peer *peer);
static struct gbprox_peer *peer_by_bvci(uint16_t bvci)
{
struct gbprox_peer *peer;
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
if (peer->bvci == bvci)
return peer;
}
@@ -187,10 +155,10 @@ static struct gbprox_peer *peer_by_bvci(uint16_t bvci)
}
/* Find the gbprox_peer by its NSEI */
-static struct gbprox_peer *peer_by_nsei(uint16_t nsei)
+struct gbprox_peer *peer_by_nsei(uint16_t nsei)
{
struct gbprox_peer *peer;
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
if (peer->nsei == nsei)
return peer;
}
@@ -201,7 +169,7 @@ static struct gbprox_peer *peer_by_nsei(uint16_t nsei)
static struct gbprox_peer *peer_by_rai(const uint8_t *ra)
{
struct gbprox_peer *peer;
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
if (!memcmp(peer->ra, ra, 6))
return peer;
}
@@ -212,7 +180,7 @@ static struct gbprox_peer *peer_by_rai(const uint8_t *ra)
static struct gbprox_peer *peer_by_lai(const uint8_t *la)
{
struct gbprox_peer *peer;
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
if (!memcmp(peer->ra, la, 5))
return peer;
}
@@ -223,7 +191,7 @@ static struct gbprox_peer *peer_by_lai(const uint8_t *la)
static struct gbprox_peer *peer_by_lac(const uint8_t *la)
{
struct gbprox_peer *peer;
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
if (!memcmp(peer->ra + 3, la + 3, 2))
return peer;
}
@@ -255,7 +223,7 @@ static struct gbprox_peer *peer_alloc(uint16_t bvci)
peer->bvci = bvci;
peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci);
- llist_add(&peer->list, &gbprox_bts_peers);
+ llist_add(&peer->list, &gbcfg.bts_peers);
INIT_LLIST_HEAD(&peer->patch_state.enabled_tllis);
@@ -551,15 +519,6 @@ struct gbprox_parse_context {
uint32_t new_ptmsi;
};
-struct gbprox_tlli_info {
- struct llist_head list;
-
- uint32_t tlli;
- time_t timestamp;
- uint8_t *mi_data;
- size_t mi_data_len;
-};
-
static struct gbprox_tlli_info *gbprox_find_tlli(struct gbprox_peer *peer,
uint32_t tlli)
{
@@ -593,7 +552,7 @@ static struct gbprox_tlli_info *gbprox_find_tlli_by_mi(
return NULL;
}
-static void gbprox_delete_tlli(struct gbprox_peer *peer,
+void gbprox_delete_tlli(struct gbprox_peer *peer,
struct gbprox_tlli_info *tlli_info)
{
struct gbprox_patch_state *state = &peer->patch_state;
@@ -676,7 +635,7 @@ static int gbprox_check_imsi(struct gbprox_peer *peer,
return 1;
}
-static int gbprox_remove_stale_ttlis(struct gbprox_peer *peer, time_t now)
+int gbprox_remove_stale_ttlis(struct gbprox_peer *peer, time_t now)
{
struct gbprox_patch_state *state = &peer->patch_state;
struct gbprox_tlli_info *tlli_info = NULL, *nxt;
@@ -1740,7 +1699,7 @@ static int rx_reset_from_sgsn(struct msgb *msg, struct tlv_parsed *tp,
* from the SGSN. As the signalling BVCI is shared
* among all the BSS's that we multiplex, it needs to
* be relayed */
- llist_for_each_entry(peer, &gbprox_bts_peers, list)
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list)
gbprox_relay2peer(msg, peer, ns_bvci);
return 0;
@@ -2050,7 +2009,7 @@ int gbprox_dump_peers(FILE *stream, int indent)
if (rc < 0)
return rc;
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
struct gbprox_tlli_info *tlli_info;
struct gbprox_patch_state *state = &peer->patch_state;
gsm48_parse_ra(&raid, peer->ra);
@@ -2105,19 +2064,19 @@ void gbprox_reset()
{
struct gbprox_peer *peer, *tmp;
- llist_for_each_entry_safe(peer, tmp, &gbprox_bts_peers, list)
+ llist_for_each_entry_safe(peer, tmp, &gbcfg.bts_peers, list)
peer_free(peer);
rate_ctr_group_free(global_ctrg);
global_ctrg = NULL;
}
-static int gbprox_cleanup_peers(uint16_t nsei, uint16_t bvci)
+int gbprox_cleanup_peers(uint16_t nsei, uint16_t bvci)
{
int counter = 0;
struct gbprox_peer *peer, *tmp;
- llist_for_each_entry_safe(peer, tmp, &gbprox_bts_peers, list) {
+ llist_for_each_entry_safe(peer, tmp, &gbcfg.bts_peers, list) {
if (peer->nsei != nsei)
continue;
if (bvci && peer->bvci != bvci)
@@ -2130,238 +2089,8 @@ static int gbprox_cleanup_peers(uint16_t nsei, uint16_t bvci)
return counter;
}
-#include <osmocom/vty/command.h>
-
-static void gbprox_vty_print_peer(struct vty *vty, struct gbprox_peer *peer)
-{
- struct gprs_ra_id raid;
- gsm48_parse_ra(&raid, peer->ra);
-
- vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "
- "RAI %u-%u-%u-%u",
- peer->nsei, peer->bvci,
- raid.mcc, raid.mnc, raid.lac, raid.rac);
- if (peer->blocked)
- vty_out(vty, " [BVC-BLOCKED]");
-
- vty_out(vty, "%s", VTY_NEWLINE);
-}
-
-gDEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
- SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")
-{
- struct gbprox_peer *peer;
- int show_stats = argc >= 1;
-
- if (show_stats)
- vty_out_rate_ctr_group(vty, "", get_global_ctrg());
-
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
- gbprox_vty_print_peer(vty, peer);
-
- if (show_stats)
- vty_out_rate_ctr_group(vty, " ", peer->ctrg);
- }
- return CMD_SUCCESS;
-}
-
-gDEFUN(show_gbproxy_tllis, show_gbproxy_tllis_cmd, "show gbproxy tllis",
- SHOW_STR "Display information about the Gb proxy\n" "Show TLLIs\n")
-{
- struct gbprox_peer *peer;
- char mi_buf[200];
- time_t now = time(NULL);
-
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
- struct gbprox_tlli_info *tlli_info;
- struct gbprox_patch_state *state = &peer->patch_state;
-
- gbprox_vty_print_peer(vty, peer);
-
- llist_for_each_entry(tlli_info, &state->enabled_tllis, list) {
- time_t age = now - tlli_info->timestamp;
- snprintf(mi_buf, sizeof(mi_buf), "(invalid)");
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- tlli_info->mi_data,
- tlli_info->mi_data_len);
- vty_out(vty, " TLLI %08x, IMSI %s, AGE %d%s",
- tlli_info->tlli, mi_buf, (int)age,
- VTY_NEWLINE);
- }
- }
- return CMD_SUCCESS;
-}
-
-gDEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
- "delete-gbproxy-peer <0-65534> bvci <2-65534>",
- "Delete a GBProxy peer by NSEI and optionally BVCI\n"
- "NSEI number\n"
- "Only delete peer with a matching BVCI\n"
- "BVCI number\n")
-{
- const uint16_t nsei = atoi(argv[0]);
- const uint16_t bvci = atoi(argv[1]);
- int counter;
-
- counter = gbprox_cleanup_peers(nsei, bvci);
-
- if (counter == 0) {
- vty_out(vty, "BVC not found%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-gDEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
- "delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
- "Delete a GBProxy peer by NSEI and optionally BVCI\n"
- "NSEI number\n"
- "Only delete BSSGP connections (BVC)\n"
- "Only delete dynamic NS connections (NS-VC)\n"
- "Delete BVC and dynamic NS connections\n"
- "Show what would be deleted instead of actually deleting\n"
- )
+int gbproxy_init_config(struct gbproxy_config *cfg)
{
- const uint16_t nsei = atoi(argv[0]);
- const char *mode = argv[1];
- int dry_run = argc > 2;
- int delete_bvc = 0;
- int delete_nsvc = 0;
- int counter;
-
- if (strcmp(mode, "only-bvc") == 0)
- delete_bvc = 1;
- else if (strcmp(mode, "only-nsvc") == 0)
- delete_nsvc = 1;
- else
- delete_bvc = delete_nsvc = 1;
-
- if (delete_bvc) {
- if (!dry_run)
- counter = gbprox_cleanup_peers(nsei, 0);
- else {
- struct gbprox_peer *peer;
- counter = 0;
- llist_for_each_entry(peer, &gbprox_bts_peers, list) {
- if (peer->nsei != nsei)
- continue;
-
- vty_out(vty, "BVC: ");
- gbprox_vty_print_peer(vty, peer);
- counter += 1;
- }
- }
- vty_out(vty, "%sDeleted %d BVC%s",
- dry_run ? "Not " : "", counter, VTY_NEWLINE);
- }
-
- if (delete_nsvc) {
- struct gprs_ns_inst *nsi = gbcfg.nsi;
- struct gprs_nsvc *nsvc, *nsvc2;
-
- counter = 0;
- llist_for_each_entry_safe(nsvc, nsvc2, &nsi->gprs_nsvcs, list) {
- if (nsvc->nsei != nsei)
- continue;
- if (nsvc->persistent)
- continue;
-
- if (!dry_run)
- gprs_nsvc_delete(nsvc);
- else
- vty_out(vty, "NS-VC: NSEI %5u, NS-VCI %5u, "
- "remote %s%s",
- nsvc->nsei, nsvc->nsvci,
- gprs_ns_ll_str(nsvc), VTY_NEWLINE);
- counter += 1;
- }
- vty_out(vty, "%sDeleted %d NS-VC%s",
- dry_run ? "Not " : "", counter, VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-gDEFUN(delete_gb_tlli, delete_gb_tlli_cmd,
- "delete-gbproxy-tlli <0-65534> (tlli|imsi|stale) [IDENT]",
- "Delete a GBProxy TLLI entry by NSEI and identification\n"
- "NSEI number\n"
- "Delete entries with a matching TLLI (hex)\n"
- "Delete entries with a matching IMSI\n"
- "Identification to match\n")
-{
- const uint16_t nsei = atoi(argv[0]);
- enum {MATCH_TLLI = 't', MATCH_IMSI = 'i', MATCH_STALE = 's'} match;
- uint32_t tlli = 0;
- const char *imsi = NULL;
- struct gbprox_peer *peer = 0;
- struct gbprox_tlli_info *tlli_info, *nxt;
- struct gbprox_patch_state *state;
- char mi_buf[200];
- int found = 0;
-
- match = argv[1][0];
-
- switch (match) {
- case MATCH_TLLI:
- if (argc < 2 || !argv[2][0]) {
- vty_out(vty, "%% Missing TLLI%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- tlli = strtoll(argv[2], NULL, 16);
- break;
- case MATCH_IMSI:
- if (argc < 2 || !argv[2][0]) {
- vty_out(vty, "%% Missing IMSI%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- imsi = argv[2];
- break;
- default:
- break;
- }
-
- peer = peer_by_nsei(nsei);
- if (!peer) {
- vty_out(vty, "Didn't find peer with NSEI %d%s",
- nsei, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- state = &peer->patch_state;
-
- if (match == MATCH_STALE) {
- found = gbprox_remove_stale_ttlis(peer, time(NULL));
- if (found)
- vty_out(vty, "Deleted %d stale TLLI%s%s",
- found, found == 1 ? "" : "s", VTY_NEWLINE);
- return CMD_SUCCESS;
- }
-
- llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) {
- if (match == MATCH_TLLI && tlli_info->tlli != tlli)
- continue;
-
- if (match == MATCH_IMSI) {
- mi_buf[0] = '\0';
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- tlli_info->mi_data,
- tlli_info->mi_data_len);
-
- if (strcmp(mi_buf, imsi) != 0)
- continue;
- }
- vty_out(vty, "Deleting TLLI %08x%s", tlli_info->tlli, VTY_NEWLINE);
- gbprox_delete_tlli(peer, tlli_info);
- found += 1;
- }
-
- if (!found && argc >= 2) {
- vty_out(vty, "Didn't find TLLI entry with %s %s%s",
- argv[1], argv[2], VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
+ INIT_LLIST_HEAD(&cfg->bts_peers);
+ return 0;
}
-
diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c
index 1f140d48d..773c98336 100644
--- a/openbsc/src/gprs/gb_proxy_main.c
+++ b/openbsc/src/gprs/gb_proxy_main.c
@@ -259,6 +259,7 @@ int main(int argc, char **argv)
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
exit(1);
}
+ gbproxy_init_config(&gbcfg);
gbcfg.nsi = bssgp_nsi;
gprs_ns_vty_init(bssgp_nsi);
gprs_ns_set_log_ss(DNS);
diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c
index e7506fc3e..16d8ceeb1 100644
--- a/openbsc/src/gprs/gb_proxy_vty.c
+++ b/openbsc/src/gprs/gb_proxy_vty.c
@@ -22,9 +22,12 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
+#include <time.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/core/rate_ctr.h>
+#include <openbsc/gsm_04_08.h>
#include <osmocom/gprs/gprs_ns.h>
#include <openbsc/debug.h>
@@ -33,6 +36,7 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/vty.h>
+#include <osmocom/vty/misc.h>
static struct gbproxy_config *g_cfg = NULL;
@@ -56,6 +60,21 @@ static const struct value_string patch_modes[] = {
{0, NULL}
};
+static void gbprox_vty_print_peer(struct vty *vty, struct gbprox_peer *peer)
+{
+ struct gprs_ra_id raid;
+ gsm48_parse_ra(&raid, peer->ra);
+
+ vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "
+ "RAI %u-%u-%u-%u",
+ peer->nsei, peer->bvci,
+ raid.mcc, raid.mnc, raid.lac, raid.rac);
+ if (peer->blocked)
+ vty_out(vty, " [BVC-BLOCKED]");
+
+ vty_out(vty, "%s", VTY_NEWLINE);
+}
+
static int config_write_gbproxy(struct vty *vty)
{
vty_out(vty, "gbproxy%s", VTY_NEWLINE);
@@ -315,7 +334,223 @@ DEFUN(cfg_gbproxy_patch_mode,
return CMD_SUCCESS;
}
+DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
+ SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")
+{
+ struct gbprox_peer *peer;
+ int show_stats = argc >= 1;
+
+ if (show_stats)
+ vty_out_rate_ctr_group(vty, "", get_global_ctrg());
+
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
+ gbprox_vty_print_peer(vty, peer);
+
+ if (show_stats)
+ vty_out_rate_ctr_group(vty, " ", peer->ctrg);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_gbproxy_tllis, show_gbproxy_tllis_cmd, "show gbproxy tllis",
+ SHOW_STR "Display information about the Gb proxy\n" "Show TLLIs\n")
+{
+ struct gbprox_peer *peer;
+ char mi_buf[200];
+ time_t now = time(NULL);
+
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
+ struct gbprox_tlli_info *tlli_info;
+ struct gbprox_patch_state *state = &peer->patch_state;
+
+ gbprox_vty_print_peer(vty, peer);
+
+ llist_for_each_entry(tlli_info, &state->enabled_tllis, list) {
+ time_t age = now - tlli_info->timestamp;
+ snprintf(mi_buf, sizeof(mi_buf), "(invalid)");
+ gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
+ tlli_info->mi_data,
+ tlli_info->mi_data_len);
+ vty_out(vty, " TLLI %08x, IMSI %s, AGE %d%s",
+ tlli_info->tlli, mi_buf, (int)age,
+ VTY_NEWLINE);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
+ "delete-gbproxy-peer <0-65534> bvci <2-65534>",
+ "Delete a GBProxy peer by NSEI and optionally BVCI\n"
+ "NSEI number\n"
+ "Only delete peer with a matching BVCI\n"
+ "BVCI number\n")
+{
+ const uint16_t nsei = atoi(argv[0]);
+ const uint16_t bvci = atoi(argv[1]);
+ int counter;
+
+ counter = gbprox_cleanup_peers(nsei, bvci);
+
+ if (counter == 0) {
+ vty_out(vty, "BVC not found%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
+ "delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
+ "Delete a GBProxy peer by NSEI and optionally BVCI\n"
+ "NSEI number\n"
+ "Only delete BSSGP connections (BVC)\n"
+ "Only delete dynamic NS connections (NS-VC)\n"
+ "Delete BVC and dynamic NS connections\n"
+ "Show what would be deleted instead of actually deleting\n"
+ )
+{
+ const uint16_t nsei = atoi(argv[0]);
+ const char *mode = argv[1];
+ int dry_run = argc > 2;
+ int delete_bvc = 0;
+ int delete_nsvc = 0;
+ int counter;
+
+ if (strcmp(mode, "only-bvc") == 0)
+ delete_bvc = 1;
+ else if (strcmp(mode, "only-nsvc") == 0)
+ delete_nsvc = 1;
+ else
+ delete_bvc = delete_nsvc = 1;
+
+ if (delete_bvc) {
+ if (!dry_run)
+ counter = gbprox_cleanup_peers(nsei, 0);
+ else {
+ struct gbprox_peer *peer;
+ counter = 0;
+ llist_for_each_entry(peer, &gbcfg.bts_peers, list) {
+ if (peer->nsei != nsei)
+ continue;
+
+ vty_out(vty, "BVC: ");
+ gbprox_vty_print_peer(vty, peer);
+ counter += 1;
+ }
+ }
+ vty_out(vty, "%sDeleted %d BVC%s",
+ dry_run ? "Not " : "", counter, VTY_NEWLINE);
+ }
+
+ if (delete_nsvc) {
+ struct gprs_ns_inst *nsi = gbcfg.nsi;
+ struct gprs_nsvc *nsvc, *nsvc2;
+
+ counter = 0;
+ llist_for_each_entry_safe(nsvc, nsvc2, &nsi->gprs_nsvcs, list) {
+ if (nsvc->nsei != nsei)
+ continue;
+ if (nsvc->persistent)
+ continue;
+
+ if (!dry_run)
+ gprs_nsvc_delete(nsvc);
+ else
+ vty_out(vty, "NS-VC: NSEI %5u, NS-VCI %5u, "
+ "remote %s%s",
+ nsvc->nsei, nsvc->nsvci,
+ gprs_ns_ll_str(nsvc), VTY_NEWLINE);
+ counter += 1;
+ }
+ vty_out(vty, "%sDeleted %d NS-VC%s",
+ dry_run ? "Not " : "", counter, VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(delete_gb_tlli, delete_gb_tlli_cmd,
+ "delete-gbproxy-tlli <0-65534> (tlli|imsi|stale) [IDENT]",
+ "Delete a GBProxy TLLI entry by NSEI and identification\n"
+ "NSEI number\n"
+ "Delete entries with a matching TLLI (hex)\n"
+ "Delete entries with a matching IMSI\n"
+ "Identification to match\n")
+{
+ const uint16_t nsei = atoi(argv[0]);
+ enum {MATCH_TLLI = 't', MATCH_IMSI = 'i', MATCH_STALE = 's'} match;
+ uint32_t tlli = 0;
+ const char *imsi = NULL;
+ struct gbprox_peer *peer = 0;
+ struct gbprox_tlli_info *tlli_info, *nxt;
+ struct gbprox_patch_state *state;
+ char mi_buf[200];
+ int found = 0;
+
+ match = argv[1][0];
+
+ switch (match) {
+ case MATCH_TLLI:
+ if (argc < 2 || !argv[2][0]) {
+ vty_out(vty, "%% Missing TLLI%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ tlli = strtoll(argv[2], NULL, 16);
+ break;
+ case MATCH_IMSI:
+ if (argc < 2 || !argv[2][0]) {
+ vty_out(vty, "%% Missing IMSI%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ imsi = argv[2];
+ break;
+ default:
+ break;
+ }
+
+ peer = peer_by_nsei(nsei);
+ if (!peer) {
+ vty_out(vty, "Didn't find peer with NSEI %d%s",
+ nsei, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ state = &peer->patch_state;
+
+ if (match == MATCH_STALE) {
+ found = gbprox_remove_stale_ttlis(peer, time(NULL));
+ if (found)
+ vty_out(vty, "Deleted %d stale TLLI%s%s",
+ found, found == 1 ? "" : "s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) {
+ if (match == MATCH_TLLI && tlli_info->tlli != tlli)
+ continue;
+
+ if (match == MATCH_IMSI) {
+ mi_buf[0] = '\0';
+ gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
+ tlli_info->mi_data,
+ tlli_info->mi_data_len);
+
+ if (strcmp(mi_buf, imsi) != 0)
+ continue;
+ }
+ vty_out(vty, "Deleting TLLI %08x%s", tlli_info->tlli, VTY_NEWLINE);
+ gbprox_delete_tlli(peer, tlli_info);
+ found += 1;
+ }
+
+ if (!found && argc >= 2) {
+ vty_out(vty, "Didn't find TLLI entry with %s %s%s",
+ argv[1], argv[2], VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
int gbproxy_vty_init(void)
{