diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2014-06-06 18:49:23 +0200 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-07-22 16:56:33 +0200 |
commit | 7c101d922e54af3b990a2a8d86ded18c3f3b89c7 (patch) | |
tree | c4ac8dd4f4ac0d7024a81de5f87e89f4bc2f66d7 /openbsc/src | |
parent | 006c038212e1d79938810812c218a4fe4aad737c (diff) |
gprs: Track IMSI/TLLI to control APN patching
This patch adds IMSI/TLLI connection tracking and uses it to control
APN patching based on the IMSI. TLLI entries can expire based on age
and/or by limiting the TLLI list size.
VTY config-gbproxy:
no core-access-point-name disable APN patching
core-access-point-name none remove APN if present
core-access-point-name APN replace APN if present
core-access-point-name none match-imsi RE remove if IMSI matches
core-access-point-name APN match-imsi RE replace if IMSI matches
tlli-list max-age SECONDS expire after SECONDS
no tlli-list max-age don't expire by age
tlli-list max-length N keep N entries only
no tlli-list max-length don't limit list length
RE is an extended regular expression, e.g. ^12345|^23456
Ticket: OW#1192
Sponsored-by: On-Waves ehf
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/gprs/gb_proxy.c | 324 | ||||
-rw-r--r-- | openbsc/src/gprs/gb_proxy_vty.c | 161 |
2 files changed, 444 insertions, 41 deletions
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 4f6ac24be..8fee4acbd 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -29,6 +29,7 @@ #include <sys/fcntl.h> #include <sys/stat.h> #include <arpa/inet.h> +#include <time.h> #include <osmocom/core/talloc.h> #include <osmocom/core/select.h> @@ -39,6 +40,8 @@ #include <osmocom/gprs/gprs_ns.h> #include <osmocom/gprs/gprs_bssgp.h> +#include <osmocom/gsm/gsm_utils.h> + #include <openbsc/signal.h> #include <openbsc/debug.h> #include <openbsc/gb_proxy.h> @@ -128,9 +131,18 @@ static const struct rate_ctr_group_desc peer_ctrg_desc = { .ctr_desc = peer_ctr_description, }; +struct { + int check_imsi; + 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 { @@ -155,6 +167,8 @@ struct gbprox_peer { /* Linked list of all Gb peers (except SGSN) */ static LLIST_HEAD(gbprox_bts_peers); +static void gbprox_delete_tllis(struct gbprox_peer *peer); + /* Find the gbprox_peer by its BVCI */ static struct gbprox_peer *peer_by_bvci(uint16_t bvci) { @@ -237,6 +251,8 @@ static struct gbprox_peer *peer_alloc(uint16_t bvci) llist_add(&peer->list, &gbprox_bts_peers); + INIT_LLIST_HEAD(&peer->patch_state.enabled_tllis); + return peer; } @@ -244,6 +260,9 @@ static void peer_free(struct gbprox_peer *peer) { rate_ctr_group_free(peer->ctrg); llist_del(&peer->list); + + gbprox_delete_tllis(peer); + talloc_free(peer); } @@ -378,6 +397,275 @@ int gbprox_str_to_apn(uint8_t *apn_enc, const char *str, size_t max_chars) return len; } +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) +{ + struct gbprox_tlli_info *tlli_info; + struct gbprox_patch_state *state = &peer->patch_state; + + llist_for_each_entry(tlli_info, &state->enabled_tllis, list) + if (tlli_info->tlli == tlli) + return tlli_info; + + return NULL; +} + +static struct gbprox_tlli_info *gbprox_find_tlli_by_mi( + struct gbprox_peer *peer, + const uint8_t *mi_data, + size_t mi_data_len) +{ + struct gbprox_tlli_info *tlli_info; + struct gbprox_patch_state *state = &peer->patch_state; + + llist_for_each_entry(tlli_info, &state->enabled_tllis, list) { + if (tlli_info->mi_data_len != mi_data_len) + continue; + if (memcmp(tlli_info->mi_data, mi_data, mi_data_len) != 0) + continue; + + return tlli_info; + } + + return NULL; +} + +static void gbprox_delete_tlli(struct gbprox_peer *peer, + struct gbprox_tlli_info *tlli_info) +{ + struct gbprox_patch_state *state = &peer->patch_state; + + llist_del(&tlli_info->list); + talloc_free(tlli_info); + state->enabled_tllis_count -= 1; +} + +static void gbprox_delete_tllis(struct gbprox_peer *peer) +{ + struct gbprox_tlli_info *tlli_info, *nxt; + struct gbprox_patch_state *state = &peer->patch_state; + + llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) { + llist_del(&tlli_info->list); + talloc_free(tlli_info); + } + + OSMO_ASSERT(llist_empty(&state->enabled_tllis)); +} + +int gbprox_set_patch_filter(const char *filter, const char **err_msg) +{ + static char err_buf[300]; + int rc; + + if (gbprox_global_patch_state.check_imsi) { + regfree(&gbprox_global_patch_state.imsi_re_comp); + gbprox_global_patch_state.check_imsi = 0; + } + + if (!filter) + return 0; + + rc = regcomp(&gbprox_global_patch_state.imsi_re_comp, filter, + REG_EXTENDED | REG_NOSUB | REG_ICASE); + + if (rc == 0) { + gbprox_global_patch_state.check_imsi = 1; + return 0; + } + + if (err_msg) { + regerror(rc, &gbprox_global_patch_state.imsi_re_comp, + err_buf, sizeof(err_buf)); + *err_msg = err_buf; + } + + return -1; +} + +static int gbprox_check_imsi(struct gbprox_peer *peer, + const uint8_t *imsi, size_t imsi_len) +{ + char mi_buf[200]; + int rc; + + if (!gbprox_global_patch_state.check_imsi) + return 1; + + rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len); + if (rc < 1) { + LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n", + osmo_hexdump(imsi, imsi_len)); + return -1; + } + + LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc); + + rc = regexec(&gbprox_global_patch_state.imsi_re_comp, mi_buf, 0, NULL, 0); + if (rc == REG_NOMATCH) { + LOGP(DGPRS, LOGL_INFO, + "IMSI '%s' doesn't match pattern '%s'\n", + mi_buf, gbcfg.match_re); + return 0; + } + + return 1; +} + +static 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; + int count = 0; + int deleted_count = 0; + + llist_for_each_entry_safe(tlli_info, nxt, &state->enabled_tllis, list) { + int is_stale = 0; + time_t age = now - tlli_info->timestamp; + + count += 1; + + if (gbcfg.tlli_max_len > 0) + is_stale = is_stale || count > gbcfg.tlli_max_len; + + if (gbcfg.tlli_max_age > 0) + is_stale = is_stale || age > gbcfg.tlli_max_age; + + if (!is_stale) + continue; + + LOGP(DGPRS, LOGL_INFO, + "Removing TLLI %08x from list (stale)\n", + tlli_info->tlli); + + gbprox_delete_tlli(peer, tlli_info); + tlli_info = NULL; + + deleted_count += 1; + } + + return deleted_count; +} + +static void gbprox_register_tlli(struct gbprox_peer *peer, uint32_t tlli, + const uint8_t *imsi, size_t imsi_len) +{ + struct gbprox_patch_state *state = &peer->patch_state; + struct gbprox_tlli_info *tlli_info; + int enable_patching; + time_t now = 0; + + if (gprs_tlli_type(tlli) != TLLI_LOCAL) + return; + + if (!imsi || (imsi[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) + return; + + if (!gbprox_global_patch_state.check_imsi) + return; + + tlli_info = gbprox_find_tlli(peer, tlli); + + /* Check, whether the IMSI matches */ + enable_patching = gbprox_check_imsi(peer, imsi, imsi_len); + + if (enable_patching < 0) + return; + + if (!tlli_info) { + tlli_info = gbprox_find_tlli_by_mi(peer, imsi, imsi_len); + + if (tlli_info) { + /* TLLI has changed somehow, adjust it */ + LOGP(DGPRS, LOGL_INFO, + "The TLLI has changed from %08x to %08x\n", + tlli_info->tlli, tlli); + tlli_info->tlli = tlli; + } + } + + if (!tlli_info) { + if (!enable_patching) + return; + + LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n", tlli); + tlli_info = talloc_zero(peer, struct gbprox_tlli_info); + tlli_info->tlli = tlli; + } else { + llist_del(&tlli_info->list); + OSMO_ASSERT(state->enabled_tllis_count > 0); + state->enabled_tllis_count -= 1; + } + + OSMO_ASSERT(tlli_info != NULL); + + if (enable_patching) { + now = time(NULL); + + tlli_info->timestamp = now; + llist_add(&tlli_info->list, &state->enabled_tllis); + state->enabled_tllis_count += 1; + + gbprox_remove_stale_ttlis(peer, now); + + if (tlli_info != llist_entry(state->enabled_tllis.next, + struct gbprox_tlli_info, list)) { + LOGP(DGPRS, LOGL_ERROR, + "Unexpectedly removed new TLLI entry as stale, " + "TLLI %08x\n", tlli); + tlli_info = NULL; + } + } else { + LOGP(DGPRS, LOGL_INFO, + "Removing TLLI %08x from list (patching no longer enabled)\n", + tlli); + talloc_free(tlli_info); + tlli_info = NULL; + } + + if (tlli_info) { + tlli_info->mi_data_len = imsi_len; + tlli_info->mi_data = + talloc_realloc_size(tlli_info, tlli_info->mi_data, imsi_len); + OSMO_ASSERT(tlli_info->mi_data != NULL); + memcpy(tlli_info->mi_data, imsi, imsi_len); + } +} + +static void gbprox_unregister_tlli(struct gbprox_peer *peer, uint32_t tlli) +{ + struct gbprox_tlli_info *tlli_info; + + tlli_info = gbprox_find_tlli(peer, tlli); + if (tlli_info) { + LOGP(DGPRS, LOGL_INFO, + "Removing TLLI %08x from list\n", + tlli); + llist_del(&tlli_info->list); + talloc_free(tlli_info); + } +} + +static int gbprox_check_tlli(struct gbprox_peer *peer, uint32_t tlli) +{ + LOGP(DGPRS, LOGL_INFO, "Checking TLLI %08x, class: %d\n", + tlli, gprs_tlli_type(tlli)); + if (gprs_tlli_type(tlli) != TLLI_LOCAL) + return 0; + + return !gbprox_global_patch_state.check_imsi || + gbprox_find_tlli(peer, tlli) != NULL; +} + /* check whether patching is enabled at this level */ static int patching_is_enabled(enum gbproxy_patch_mode need_at_least) { @@ -715,7 +1003,7 @@ struct gbprox_peer *peer_by_bssgp_tlv(struct tlv_parsed *tp) static int gbprox_patch_dtap(struct msgb *msg, uint8_t *data, size_t data_len, struct gbprox_peer *peer, int to_bss, - int *len_change) + uint32_t tlli, int *len_change) { struct gsm48_hdr *g48h; @@ -767,8 +1055,16 @@ static int gbprox_patch_dtap(struct msgb *msg, uint8_t *data, size_t data_len, break; if (gbcfg.core_apn == NULL) break; + if (!gbprox_check_tlli(peer, tlli)) + break; return gbprox_patch_gsm_act_pdp_req(msg, data, data_len, peer, to_bss, len_change); + + case GSM48_MT_GMM_DETACH_ACK: + case GSM48_MT_GMM_DETACH_REQ: + gbprox_unregister_tlli(peer, tlli); + break; + default: break; }; @@ -777,7 +1073,9 @@ static int gbprox_patch_dtap(struct msgb *msg, uint8_t *data, size_t data_len, } static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, - struct gbprox_peer *peer, int to_bss) + struct gbprox_peer *peer, int to_bss, + struct bssgp_ud_hdr *budh, + struct tlv_parsed *bssgp_tp) { struct gprs_llc_hdr_parsed ghp = {0}; int rc; @@ -787,6 +1085,7 @@ static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, int len_change = 0; const char *err_info = NULL; int err_ctr = -1; + uint32_t tlli = budh ? ntohl(budh->tlli) : 0; /* parse LLC */ rc = gprs_llc_hdr_parse(&ghp, llc, llc_len); @@ -806,6 +1105,12 @@ static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, if (ghp.sapi != GPRS_SAPI_GMM) return; + if (gbcfg.core_apn && to_bss && tlli && + TLVP_PRESENT(bssgp_tp, BSSGP_IE_IMSI)) + gbprox_register_tlli(peer, tlli, + TLVP_VAL(bssgp_tp, BSSGP_IE_IMSI), + TLVP_LEN(bssgp_tp, BSSGP_IE_IMSI)); + if (ghp.cmd != GPRS_LLC_UI) return; @@ -829,7 +1134,7 @@ static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len, data_len = ghp.data_len; rc = gbprox_patch_dtap(msg, data, data_len, peer, to_bss, - &len_change); + tlli, &len_change); if (rc > 0) { llc_len += len_change; @@ -875,10 +1180,9 @@ static void gbprox_patch_bssgp_message(struct msgb *msg, struct gbprox_peer *peer, int to_bss) { struct bssgp_normal_hdr *bgph; - struct bssgp_ud_hdr *budh; + struct bssgp_ud_hdr *budh = NULL; struct tlv_parsed tp; uint8_t pdu_type; - struct gbprox_patch_state *state = NULL; uint8_t *data; size_t data_len; @@ -886,11 +1190,12 @@ static void gbprox_patch_bssgp_message(struct msgb *msg, return; bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); pdu_type = bgph->pdu_type; if (pdu_type == BSSGP_PDUT_UL_UNITDATA || pdu_type == BSSGP_PDUT_DL_UNITDATA) { + budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); + bgph = NULL; data = budh->data; data_len = msgb_bssgp_len(msg) - sizeof(*budh); } else { @@ -919,11 +1224,6 @@ static void gbprox_patch_bssgp_message(struct msgb *msg, return; } - state = &peer->patch_state; - - if (to_bss && !state->local_mcc && !state->local_mnc) - return; - if (TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) { gbprox_patch_raid((uint8_t *)TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), peer, to_bss, "ROUTING_AREA"); @@ -937,7 +1237,7 @@ static void gbprox_patch_bssgp_message(struct msgb *msg, patching_is_enabled(GBPROX_PATCH_LLC_ATTACH_REQ)) { uint8_t *llc = (uint8_t *)TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); size_t llc_len = TLVP_LEN(&tp, BSSGP_IE_LLC_PDU); - gbprox_patch_llc(msg, llc, llc_len, peer, to_bss); + gbprox_patch_llc(msg, llc, llc_len, peer, to_bss, budh, &tp); /* Note that the tp struct might contain invalid pointers here * if the LLC field has changed its size */ } diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index 6d241653d..36d959a42 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -72,15 +72,24 @@ static int config_write_gbproxy(struct vty *vty) if (g_cfg->core_apn != NULL) { if (g_cfg->core_apn_size > 0) { char str[500] = {0}; - vty_out(vty, " core-access-point-name %s%s", + vty_out(vty, " core-access-point-name %s", gbprox_apn_to_str(str, g_cfg->core_apn, - g_cfg->core_apn_size), - VTY_NEWLINE); + g_cfg->core_apn_size)); } else { - vty_out(vty, " core-access-point-name%s", - VTY_NEWLINE); + vty_out(vty, " core-access-point-name none"); } + if (g_cfg->match_re) + vty_out(vty, " match-imsi %s%s", + g_cfg->match_re, VTY_NEWLINE); + else + vty_out(vty, "%s", VTY_NEWLINE); } + if (g_cfg->tlli_max_age > 0) + vty_out(vty, " tlli-list max-age %d%s", + g_cfg->tlli_max_age, VTY_NEWLINE); + if (g_cfg->tlli_max_len > 0) + vty_out(vty, " tlli-list max-length %d%s", + g_cfg->tlli_max_len, VTY_NEWLINE); if (g_cfg->patch_mode != GBPROX_PATCH_DEFAULT) vty_out(vty, " patch-mode %s%s", @@ -153,50 +162,140 @@ DEFUN(cfg_gbproxy_no_core_mcc, } #define GBPROXY_CORE_APN_STR "Use this access point name (APN) for the backbone\n" +#define GBPROXY_CORE_APN_ARG_STR "Replace APN by this string\n" "Remove APN\n" -DEFUN(cfg_gbproxy_core_apn_remove, - cfg_gbproxy_core_apn_remove_cmd, - "core-access-point-name", - GBPROXY_CORE_APN_STR) +static int set_core_apn(struct vty *vty, const char *apn, const char *filter) { - talloc_free(g_cfg->core_apn); - /* TODO: replace NULL */ - g_cfg->core_apn = talloc_zero_size(NULL, 2); - g_cfg->core_apn_size = 0; - return CMD_SUCCESS; -} + const char *err_msg = NULL; + int apn_len; + + if (!apn) { + talloc_free(g_cfg->core_apn); + g_cfg->core_apn = NULL; + g_cfg->core_apn_size = 0; + gbprox_set_patch_filter(NULL, NULL); + return CMD_SUCCESS; + } -DEFUN(cfg_gbproxy_core_apn, - cfg_gbproxy_core_apn_cmd, - "core-access-point-name APN", - GBPROXY_CORE_APN_STR "Replacement APN\n") -{ - int apn_len = strlen(argv[0]) + 1; + apn_len = strlen(apn); - if (apn_len > 100) { + if (apn_len >= 100) { vty_out(vty, "APN string too long (max 99 chars)%s", VTY_NEWLINE); return CMD_WARNING; } - /* TODO: replace NULL */ - g_cfg->core_apn = talloc_realloc_size(NULL, g_cfg->core_apn, apn_len); - g_cfg->core_apn_size = gbprox_str_to_apn(g_cfg->core_apn, argv[0], apn_len); + if (!filter) { + gbprox_set_patch_filter(NULL, NULL); + } else if (gbprox_set_patch_filter(filter, &err_msg) != 0) { + vty_out(vty, "Match expression invalid: %s%s", + err_msg, VTY_NEWLINE); + return CMD_WARNING; + } + + talloc_free(g_cfg->match_re); + if (filter) + /* TODO: replace NULL */ + g_cfg->match_re = talloc_strdup(NULL, filter); + else + g_cfg->match_re = NULL; + + if (apn_len == 0) { + talloc_free(g_cfg->core_apn); + /* TODO: replace NULL */ + g_cfg->core_apn = talloc_zero_size(NULL, 2); + g_cfg->core_apn_size = 0; + } else { + /* TODO: replace NULL */ + g_cfg->core_apn = + talloc_realloc_size(NULL, g_cfg->core_apn, apn_len + 1); + g_cfg->core_apn_size = + gbprox_str_to_apn(g_cfg->core_apn, apn, apn_len + 1); + } return CMD_SUCCESS; } +DEFUN(cfg_gbproxy_core_apn, + cfg_gbproxy_core_apn_cmd, + "core-access-point-name (APN|none)", + GBPROXY_CORE_APN_STR GBPROXY_CORE_APN_ARG_STR) +{ + if (strcmp(argv[0], "none") == 0) + return set_core_apn(vty, "", NULL); + else + return set_core_apn(vty, argv[0], NULL); +} + +DEFUN(cfg_gbproxy_core_apn_match, + cfg_gbproxy_core_apn_match_cmd, + "core-access-point-name (APN|none) match-imsi .REGEXP", + GBPROXY_CORE_APN_STR GBPROXY_CORE_APN_ARG_STR + "Only modify if the IMSI matches\n" + "Regular expression for the match\n") +{ + if (strcmp(argv[0], "none") == 0) + return set_core_apn(vty, "", argv[1]); + else + return set_core_apn(vty, argv[0], argv[1]); +} + DEFUN(cfg_gbproxy_no_core_apn, cfg_gbproxy_no_core_apn_cmd, "no core-access-point-name", NO_STR GBPROXY_CORE_APN_STR) { - talloc_free(g_cfg->core_apn); - g_cfg->core_apn = NULL; - g_cfg->core_apn_size = 0; + return set_core_apn(vty, NULL, NULL); +} + +#define GBPROXY_TLLI_LIST_STR "Set TLLI list parameters\n" +#define GBPROXY_MAX_AGE_STR "Limit maximum age\n" + +DEFUN(cfg_gbproxy_tlli_list_max_age, + cfg_gbproxy_tlli_list_max_age_cmd, + "tlli-list max-age <1-999999>", + GBPROXY_TLLI_LIST_STR GBPROXY_MAX_AGE_STR + "Maximum age in seconds\n") +{ + g_cfg->tlli_max_age = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_gbproxy_tlli_list_no_max_age, + cfg_gbproxy_tlli_list_no_max_age_cmd, + "no tlli-list max-age", + NO_STR GBPROXY_TLLI_LIST_STR GBPROXY_MAX_AGE_STR) +{ + g_cfg->tlli_max_age = 0; + + return CMD_SUCCESS; +} + +#define GBPROXY_MAX_LEN_STR "Limit list length\n" + +DEFUN(cfg_gbproxy_tlli_list_max_len, + cfg_gbproxy_tlli_list_max_len_cmd, + "tlli-list max-length <1-99999>", + GBPROXY_TLLI_LIST_STR GBPROXY_MAX_LEN_STR + "Maximum number of TLLIs in the list\n") +{ + g_cfg->tlli_max_len = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_gbproxy_tlli_list_no_max_len, + cfg_gbproxy_tlli_list_no_max_len_cmd, + "no tlli-list max-length", + NO_STR GBPROXY_TLLI_LIST_STR GBPROXY_MAX_LEN_STR) +{ + g_cfg->tlli_max_len = 0; + return CMD_SUCCESS; } + DEFUN(cfg_gbproxy_patch_mode, cfg_gbproxy_patch_mode_cmd, "patch-mode (default|bssgp|llc-attach-req|llc-attach|llc-gmm|llc-gsm|llc)", @@ -231,11 +330,15 @@ int gbproxy_vty_init(void) install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_core_mcc_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd); - install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_remove_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_match_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_max_age_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_max_len_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_no_max_age_cmd); + install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_no_max_len_cmd); install_element(GBPROXY_NODE, &cfg_gbproxy_patch_mode_cmd); return 0; |