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.
This commit is contained in:
Holger Hans Peter Freyther 2014-08-04 11:10:09 +02:00
parent 035b874fdf
commit 18739ea32d
5 changed files with 308 additions and 294 deletions

View File

@ -7,6 +7,8 @@
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/vty/command.h>
struct rate_ctr_group;
enum gbproxy_patch_mode {
GBPROX_PATCH_DEFAULT,
GBPROX_PATCH_BSSGP, /*!< BSGGP messages only */
@ -24,6 +26,9 @@ struct gbproxy_config {
/* misc */
struct gprs_ns_inst *nsi;
/* Linked list of all Gb peers (except SGSN) */
struct llist_head bts_peers;
/* force mcc/mnc */
int core_mnc;
int core_mcc;
@ -35,12 +40,45 @@ struct gbproxy_config {
int tlli_max_len;
};
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;
};
struct gbprox_tlli_info {
struct llist_head list;
uint32_t tlli;
time_t timestamp;
uint8_t *mi_data;
size_t mi_data_len;
};
extern struct gbproxy_config gbcfg;
extern struct cmd_element show_gbproxy_cmd;
extern struct cmd_element show_gbproxy_tllis_cmd;
extern struct cmd_element delete_gb_bvci_cmd;
extern struct cmd_element delete_gb_nsei_cmd;
extern struct cmd_element delete_gb_tlli_cmd;
/* gb_proxy_vty .c */
@ -49,6 +87,7 @@ int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg);
/* gb_proxy.c */
int gbproxy_init_config(struct gbproxy_config *cfg);
/* Main input function for Gb proxy */
int gbprox_rcvmsg(struct msgb *msg, uint16_t nsei, uint16_t ns_bvci, uint16_t nsvci);
@ -67,4 +106,13 @@ char *gbprox_apn_to_str(char *str, const uint8_t *apn_enc, size_t max_chars);
int gbprox_str_to_apn(uint8_t *apn_enc, const char *str, size_t max_chars);
int gbprox_set_patch_filter(const char *filter, const char **err_msg);
void gbprox_delete_tlli(struct gbprox_peer *peer,
struct gbprox_tlli_info *tlli_info);
int gbprox_remove_stale_ttlis(struct gbprox_peer *peer, time_t now);
int gbprox_cleanup_peers(uint16_t nsei, uint16_t bvci);
/* tmp */
struct rate_ctr_group *get_global_ctrg(void);
struct gbprox_peer *peer_by_nsei(uint16_t nsei);
#endif

View File

@ -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)
int gbproxy_init_config(struct gbproxy_config *cfg)
{
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);
INIT_LLIST_HEAD(&cfg->bts_peers);
return 0;
}
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"
)
{
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;
}

View File

@ -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);

View File

@ -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)
{

View File

@ -1241,6 +1241,7 @@ int main(int argc, char **argv)
setlinebuf(stdout);
printf("===== GbProxy test START\n");
gbproxy_init_config(&gbcfg);
test_tlv_shift_functions();
test_gbproxy();
test_gbproxy_ident_changes();