aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Willmann <dwillmann@sysmocom.de>2020-11-26 18:19:21 +0100
committerDaniel Willmann <dwillmann@sysmocom.de>2020-11-30 18:30:35 +0100
commit447ad441e6f60211e6b5582fa82d328fe2f9c8bb (patch)
treea3d6aa21a287c77ef1abf643a9f0d3255bdea917
parentf7a1aed0e6def73335969b7efbfca20d4ea07512 (diff)
gbproxy: Add NSE peer that can have multiple gbproxy_peers
We want this level of indirection to support multiple BVCs per NSE. The current code assumes that an NSE only has one BVC which breaks messages on the signalling BVC which should only be sent once to an NSE regardless of the number of BVCs it contains. Change-Id: I97cc6c8f8c0f1b91577ab8f679c4ae217cc88076 Related: SYS#5226
-rw-r--r--include/osmocom/sgsn/gb_proxy.h42
-rw-r--r--src/gbproxy/gb_proxy.c128
-rw-r--r--src/gbproxy/gb_proxy_ctrl.c36
-rw-r--r--src/gbproxy/gb_proxy_patch.c44
-rw-r--r--src/gbproxy/gb_proxy_peer.c160
-rw-r--r--src/gbproxy/gb_proxy_tlli.c35
-rw-r--r--src/gbproxy/gb_proxy_vty.c124
-rw-r--r--tests/gbproxy/gbproxy_test.c175
-rw-r--r--tests/gbproxy/gbproxy_test.ok36
9 files changed, 495 insertions, 285 deletions
diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h
index 4466f155..54d4548c 100644
--- a/include/osmocom/sgsn/gb_proxy.h
+++ b/include/osmocom/sgsn/gb_proxy.h
@@ -99,7 +99,7 @@ struct gbproxy_config {
struct gprs_ns2_inst *nsi;
/* Linked list of all Gb peers (except SGSN) */
- struct llist_head bts_peers;
+ struct llist_head nse_peers;
/* Counter */
struct rate_ctr_group *ctrg;
@@ -143,24 +143,23 @@ struct gbproxy_patch_state {
int logical_link_count;
};
-/* one peer at NS level that we interact with (BSS/PCU) */
+/* One BVC inside an NSE */
struct gbproxy_peer {
- /* linked to gbproxy_config.bts_peers */
+ /* linked to gbproxy_nse.bts_peers */
struct llist_head list;
- /* point back to the config */
- struct gbproxy_config *cfg;
-
- /* NSEI of the peer entity */
- uint16_t nsei;
+ /* The peer this BVC belongs to */
+ struct gbproxy_nse *nse;
/* BVCI used for Point-to-Point to this peer */
uint16_t bvci;
- bool blocked;
- /* Routeing Area that this peer is part of (raw 04.08 encoding) */
+ /* Routing Area that this peer is part of (raw 04.08 encoding) */
uint8_t ra[6];
+ /* true if this BVC is blocked */
+ bool blocked;
+
/* Counter */
struct rate_ctr_group *ctrg;
@@ -171,6 +170,21 @@ struct gbproxy_peer {
struct osmo_timer_list clean_stale_timer;
};
+/* one peer at NS level that we interact with (BSS/PCU) */
+struct gbproxy_nse {
+ /* linked to gbproxy_config.nse_peers */
+ struct llist_head list;
+
+ /* point back to the config */
+ struct gbproxy_config *cfg;
+
+ /* NSEI of the peer entity */
+ uint16_t nsei;
+
+ /* List of all BVCs in this NSE */
+ struct llist_head bts_peers;
+};
+
struct gbproxy_tlli_state {
/* currently active TLLI */
uint32_t current;
@@ -328,8 +342,14 @@ struct gbproxy_peer *gbproxy_peer_by_lac(
struct gbproxy_config *cfg, const uint8_t *la);
struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(
struct gbproxy_config *cfg, struct tlv_parsed *tp);
-struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci);
+struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_nse *nse, uint16_t bvci);
void gbproxy_peer_free(struct gbproxy_peer *peer);
int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci);
+/* NSE handling */
+struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei);
+void gbproxy_nse_free(struct gbproxy_nse *nse);
+struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei);
+struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei);
+
#endif
diff --git a/src/gbproxy/gb_proxy.c b/src/gbproxy/gb_proxy.c
index 9009651f..736bd7a7 100644
--- a/src/gbproxy/gb_proxy.c
+++ b/src/gbproxy/gb_proxy.c
@@ -84,10 +84,12 @@ static void gbproxy_reset_imsi_acquisition(struct gbproxy_link_info* link_info);
static int check_peer_nsei(struct gbproxy_peer *peer, uint16_t nsei)
{
- if (peer->nsei != nsei) {
+ OSMO_ASSERT(peer->nse);
+
+ if (peer->nse->nsei != nsei) {
LOGP(DGPRS, LOGL_NOTICE, "Peer entry doesn't match current NSEI "
"BVCI=%u via NSEI=%u (expected NSEI=%u)\n",
- peer->bvci, nsei, peer->nsei);
+ peer->bvci, nsei, peer->nse->nsei);
rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_INV_NSEI]);
return 0;
}
@@ -195,6 +197,9 @@ static void gbprox_update_current_raid(uint8_t *raid_enc,
struct gbproxy_patch_state *state = &peer->patch_state;
const struct osmo_plmn_id old_plmn = state->local_plmn;
struct gprs_ra_id raid;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
if (!raid_enc)
return;
@@ -202,15 +207,15 @@ static void gbprox_update_current_raid(uint8_t *raid_enc,
gsm48_parse_ra(&raid, raid_enc);
/* save source side MCC/MNC */
- if (!peer->cfg->core_plmn.mcc || raid.mcc == peer->cfg->core_plmn.mcc) {
+ if (!cfg->core_plmn.mcc || raid.mcc == cfg->core_plmn.mcc) {
state->local_plmn.mcc = 0;
} else {
state->local_plmn.mcc = raid.mcc;
}
- if (!peer->cfg->core_plmn.mnc
+ if (!cfg->core_plmn.mnc
|| !osmo_mnc_cmp(raid.mnc, raid.mnc_3_digits,
- peer->cfg->core_plmn.mnc, peer->cfg->core_plmn.mnc_3_digits)) {
+ cfg->core_plmn.mnc, cfg->core_plmn.mnc_3_digits)) {
state->local_plmn.mnc = 0;
state->local_plmn.mnc_3_digits = false;
} else {
@@ -226,7 +231,7 @@ static void gbprox_update_current_raid(uint8_t *raid_enc,
"" : "de",
log_text,
osmo_plmn_name(&state->local_plmn),
- osmo_plmn_name2(&peer->cfg->core_plmn));
+ osmo_plmn_name2(&cfg->core_plmn));
}
uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer,
@@ -234,7 +239,7 @@ uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer,
{
uint32_t bss_ptmsi;
int max_retries = 23, rc = 0;
- if (!peer->cfg->patch_ptmsi) {
+ if (!peer->nse->cfg->patch_ptmsi) {
bss_ptmsi = sgsn_ptmsi;
} else {
do {
@@ -263,7 +268,7 @@ uint32_t gbproxy_make_sgsn_tlli(struct gbproxy_peer *peer,
{
uint32_t sgsn_tlli;
int max_retries = 23, rc = 0;
- if (!peer->cfg->patch_ptmsi) {
+ if (!peer->nse->cfg->patch_ptmsi) {
sgsn_tlli = bss_tlli;
} else if (link_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI &&
gprs_tlli_type(bss_tlli) == TLLI_FOREIGN) {
@@ -330,6 +335,9 @@ static int gbproxy_flush_stored_messages(struct gbproxy_peer *peer,
{
int rc;
struct msgb *stored_msg;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
/* Patch and flush stored messages towards the SGSN */
while ((stored_msg = msgb_dequeue_count(&link_info->stored_msgs,
@@ -355,7 +363,7 @@ static int gbproxy_flush_stored_messages(struct gbproxy_peer *peer,
return -1;
}
- rc = gbprox_relay2sgsn(peer->cfg, stored_msg,
+ rc = gbprox_relay2sgsn(cfg, stored_msg,
msgb_bvci(stored_msg), link_info->sgsn_nsei);
if (rc < 0)
@@ -425,6 +433,9 @@ static int gbproxy_imsi_acquisition(struct gbproxy_peer *peer,
struct gprs_gb_parse_context *parse_ctx)
{
struct msgb *stored_msg;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
if (!link_info)
return 1;
@@ -493,9 +504,9 @@ static int gbproxy_imsi_acquisition(struct gbproxy_peer *peer,
/* The message cannot be processed since the IMSI is still missing */
/* If queue is getting too large, drop oldest msgb before adding new one */
- if (peer->cfg->stored_msgs_max_len > 0) {
+ if (cfg->stored_msgs_max_len > 0) {
int exceeded_max_len = link_info->stored_msgs_len
- + 1 - peer->cfg->stored_msgs_max_len;
+ + 1 - cfg->stored_msgs_max_len;
for (; exceeded_max_len > 0; exceeded_max_len--) {
struct msgb *msgb_drop;
@@ -806,19 +817,23 @@ static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_peer *peer,
uint16_t ns_bvci)
{
+ struct gbproxy_nse *nse = peer->nse;
+ OSMO_ASSERT(nse);
+ OSMO_ASSERT(nse->cfg);
+
/* create a copy of the message so the old one can
* be free()d safely when we return from gbprox_rcvmsg() */
- struct gprs_ns2_inst *nsi = peer->cfg->nsi;
+ struct gprs_ns2_inst *nsi = nse->cfg->nsi;
struct osmo_gprs_ns2_prim nsp = {};
struct msgb *msg = bssgp_msgb_copy(old_msg, "msgb_relay2peer");
uint32_t tlli;
int rc;
DEBUGP(DGPRS, "NSEI=%u proxying SGSN->BSS (NS_BVCI=%u, NSEI=%u)\n",
- msgb_nsei(msg), ns_bvci, peer->nsei);
+ msgb_nsei(msg), ns_bvci, nse->nsei);
nsp.bvci = ns_bvci;
- nsp.nsei = peer->nsei;
+ nsp.nsei = nse->nsei;
/* Strip the old NS header, it will be replaced with a new one */
strip_ns_hdr(msg);
@@ -1051,16 +1066,33 @@ static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg,
}
from_peer = gbproxy_peer_by_bvci(cfg, bvci);
if (!from_peer) {
+ struct gbproxy_nse *nse = gbproxy_nse_by_nsei_or_new(cfg, nsei);
+ if (!nse) {
+ LOGP(DGPRS, LOGL_ERROR, "Could not allocate NSE for NSEI=%u\n", nsei);
+ return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
+ }
/* if a PTP-BVC is reset, and we don't know that
* PTP-BVCI yet, we should allocate a new peer */
LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for BVCI=%u via NSEI=%u\n", bvci, nsei);
- from_peer = gbproxy_peer_alloc(cfg, bvci);
+ from_peer = gbproxy_peer_alloc(nse, bvci);
OSMO_ASSERT(from_peer);
- from_peer->nsei = nsei;
}
- if (!check_peer_nsei(from_peer, nsei))
- from_peer->nsei = nsei;
+ /* Could have moved to a different NSE */
+ if (!check_peer_nsei(from_peer, nsei)) {
+ struct gbproxy_nse *nse_old = from_peer->nse;
+ struct gbproxy_nse *nse_new = gbproxy_nse_by_nsei_or_new(cfg, nsei);
+ if (!nse_new) {
+ LOGP(DGPRS, LOGL_ERROR, "Could not allocate NSE for NSEI=%u\n", nsei);
+ return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
+ }
+ LOGP(DGPRS, LOGL_NOTICE, "Peer for BVCI=%u moved from NSEI=%u to NSEI=%u\n", bvci, nse_old->nsei, nsei);
+
+ /* Move peer to different NSE */
+ llist_del(&from_peer->list);
+ llist_add(&from_peer->list, &nse_new->bts_peers);
+ from_peer->nse = nse_new;
+ }
if (TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID)) {
struct gprs_ra_id raid;
@@ -1107,10 +1139,13 @@ err_mand_ie:
static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct tlv_parsed *tp,
uint32_t nsei, uint16_t ns_bvci)
{
+ struct gbproxy_nse *nse;
struct gbproxy_peer *peer;
unsigned int n_peers = 0;
int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
+ /* FIXME: Handle paging logic to only page each matching NSE */
+
LOGP(DGPRS, LOGL_INFO, "NSEI=%u(SGSN) BSSGP PAGING ",
nsei);
if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
@@ -1128,29 +1163,35 @@ static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct
} else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
errctr = GBPROX_GLOB_CTR_INV_RAI;
/* iterate over all peers and dispatch the paging to each matching one */
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {
- LOGPC(DGPRS, LOGL_INFO, "routing by RAI to peer BVCI=%u\n", peer->bvci);
- gbprox_relay2peer(msg, peer, ns_bvci);
- n_peers++;
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA), 6)) {
+ LOGPC(DGPRS, LOGL_INFO, "routing by RAI to peer BVCI=%u\n", peer->bvci);
+ gbprox_relay2peer(msg, peer, ns_bvci);
+ n_peers++;
+ }
}
}
} else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
errctr = GBPROX_GLOB_CTR_INV_LAI;
/* iterate over all peers and dispatch the paging to each matching one */
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
- LOGPC(DGPRS, LOGL_INFO, "routing by LAI to peer BVCI=%u\n", peer->bvci);
- gbprox_relay2peer(msg, peer, ns_bvci);
- n_peers++;
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ if (!memcmp(peer->ra, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA), 5)) {
+ LOGPC(DGPRS, LOGL_INFO, "routing by LAI to peer BVCI=%u\n", peer->bvci);
+ gbprox_relay2peer(msg, peer, ns_bvci);
+ n_peers++;
+ }
}
}
} else if (TLVP_PRESENT(tp, BSSGP_IE_BSS_AREA_ID)) {
/* iterate over all peers and dispatch the paging to each matching one */
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- LOGPC(DGPRS, LOGL_INFO, "broadcasting to peer BVCI=%u\n", peer->bvci);
- gbprox_relay2peer(msg, peer, ns_bvci);
- n_peers++;
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ LOGPC(DGPRS, LOGL_INFO, "broadcasting to peer BVCI=%u\n", peer->bvci);
+ gbprox_relay2peer(msg, peer, ns_bvci);
+ n_peers++;
+ }
}
} else {
LOGPC(DGPRS, LOGL_INFO, "\n");
@@ -1174,6 +1215,7 @@ static int rx_reset_from_sgsn(struct gbproxy_config *cfg,
struct msgb *msg, struct tlv_parsed *tp,
uint32_t nsei, uint16_t ns_bvci)
{
+ struct gbproxy_nse *nse;
struct gbproxy_peer *peer;
uint16_t ptp_bvci;
@@ -1204,8 +1246,10 @@ static int rx_reset_from_sgsn(struct gbproxy_config *cfg,
* 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, &cfg->bts_peers, list)
- gbprox_relay2peer(msg, peer, ns_bvci);
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ llist_for_each_entry(peer, &nse->bts_peers, list)
+ gbprox_relay2peer(msg, peer, ns_bvci);
+ }
return 0;
}
@@ -1454,7 +1498,8 @@ void gprs_ns_prim_status_cb(struct gbproxy_config *cfg, struct osmo_gprs_ns2_pri
rate_ctr_inc(&cfg->ctrg->
ctr[GBPROX_GLOB_CTR_RESTART_RESET_SGSN]);
} else {
- /* bss became unavailable */
+ /* bss became unavailable
+ * TODO: Block all BVC belonging to that NSE */
peer = gbproxy_peer_by_nsei(cfg, nsp->nsei);
if (!peer) {
/* TODO: use primitive name + status cause name */
@@ -1525,10 +1570,15 @@ int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
void gbprox_reset(struct gbproxy_config *cfg)
{
- struct gbproxy_peer *peer, *tmp;
+ struct gbproxy_nse *nse, *ntmp;
- llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list)
- gbproxy_peer_free(peer);
+ llist_for_each_entry_safe(nse, ntmp, &cfg->nse_peers, list) {
+ struct gbproxy_peer *peer, *tmp;
+ llist_for_each_entry_safe(peer, tmp, &nse->bts_peers, list)
+ gbproxy_peer_free(peer);
+
+ gbproxy_nse_free(nse);
+ }
rate_ctr_group_free(cfg->ctrg);
gbproxy_init_config(cfg);
@@ -1538,7 +1588,7 @@ int gbproxy_init_config(struct gbproxy_config *cfg)
{
struct timespec tp;
- INIT_LLIST_HEAD(&cfg->bts_peers);
+ INIT_LLIST_HEAD(&cfg->nse_peers);
cfg->ctrg = rate_ctr_group_alloc(tall_sgsn_ctx, &global_ctrg_desc, 0);
if (!cfg->ctrg) {
LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");
diff --git a/src/gbproxy/gb_proxy_ctrl.c b/src/gbproxy/gb_proxy_ctrl.c
index 95773830..482bca01 100644
--- a/src/gbproxy/gb_proxy_ctrl.c
+++ b/src/gbproxy/gb_proxy_ctrl.c
@@ -55,7 +55,7 @@ static int get_nsvc_state(struct ctrl_cmd *cmd, void *data)
struct gbproxy_config *cfg = data;
struct gprs_ns2_inst *nsi = cfg->nsi;
struct gprs_ns2_nse *nse;
- struct gbproxy_peer *peer;
+ struct gbproxy_nse *nse_peer;
cmd->reply = talloc_strdup(cmd, "");
@@ -69,8 +69,8 @@ static int get_nsvc_state(struct ctrl_cmd *cmd, void *data)
gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);
/* NS-VCs for BSS peers */
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- nse = gprs_ns2_nse_by_nsei(nsi, peer->nsei);
+ llist_for_each_entry(nse_peer, &cfg->nse_peers, list) {
+ nse = gprs_ns2_nse_by_nsei(nsi, nse_peer->nsei);
if (nse)
gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);
}
@@ -83,19 +83,22 @@ CTRL_CMD_DEFINE_RO(nsvc_state, "nsvc-state");
static int get_gbproxy_state(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
- struct gbproxy_peer *peer;
+ struct gbproxy_nse *nse_peer;
cmd->reply = talloc_strdup(cmd, "");
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- struct gprs_ra_id raid;
- gsm48_parse_ra(&raid, peer->ra);
-
- cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%u,%u,%u,%u,%u,%s\n",
- peer->nsei, peer->bvci,
- raid.mcc, raid.mnc,
- raid.lac, raid.rac,
- peer->blocked ? "BLOCKED" : "UNBLOCKED");
+ llist_for_each_entry(nse_peer, &cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse_peer->bts_peers, list) {
+ struct gprs_ra_id raid;
+ gsm48_parse_ra(&raid, peer->ra);
+
+ cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%u,%u,%u,%u,%u,%s\n",
+ nse_peer->nsei, peer->bvci,
+ raid.mcc, raid.mnc,
+ raid.lac, raid.rac,
+ peer->blocked ? "BLOCKED" : "UNBLOCKED");
+ }
}
return CTRL_CMD_REPLY;
@@ -106,9 +109,14 @@ CTRL_CMD_DEFINE_RO(gbproxy_state, "gbproxy-state");
static int get_num_peers(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
+ struct gbproxy_nse *nse_peer;
+ uint32_t count = 0;
+
+ llist_for_each_entry(nse_peer, &cfg->nse_peers, list)
+ count += llist_count(&nse_peer->bts_peers);
cmd->reply = talloc_strdup(cmd, "");
- cmd->reply = talloc_asprintf_append(cmd->reply, "%u", llist_count(&cfg->bts_peers));
+ cmd->reply = talloc_asprintf_append(cmd->reply, "%u", count);
return CTRL_CMD_REPLY;
}
diff --git a/src/gbproxy/gb_proxy_patch.c b/src/gbproxy/gb_proxy_patch.c
index 9c70d3f7..66016579 100644
--- a/src/gbproxy/gb_proxy_patch.c
+++ b/src/gbproxy/gb_proxy_patch.c
@@ -44,6 +44,10 @@ static void gbproxy_patch_raid(struct gsm48_ra_id *raid_enc, struct gbproxy_peer
GBPROX_PEER_CTR_RAID_PATCHED_SGSN :
GBPROX_PEER_CTR_RAID_PATCHED_BSS;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
+
if (!state->local_plmn.mcc || !state->local_plmn.mnc)
return;
@@ -58,11 +62,11 @@ static void gbproxy_patch_raid(struct gsm48_ra_id *raid_enc, struct gbproxy_peer
if (!to_bss) {
/* BSS -> SGSN */
if (state->local_plmn.mcc)
- raid.mcc = peer->cfg->core_plmn.mcc;
+ raid.mcc = cfg->core_plmn.mcc;
if (state->local_plmn.mnc) {
- raid.mnc = peer->cfg->core_plmn.mnc;
- raid.mnc_3_digits = peer->cfg->core_plmn.mnc_3_digits;
+ raid.mnc = cfg->core_plmn.mnc;
+ raid.mnc_3_digits = cfg->core_plmn.mnc_3_digits;
}
} else {
/* SGSN -> BSS */
@@ -100,11 +104,14 @@ static void gbproxy_patch_apn_ie(struct msgb *msg,
size_t apn_len = hdr->apn_len;
uint8_t *apn = hdr->apn;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr));
OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102);
- if (peer->cfg->core_apn_size == 0) {
+ if (cfg->core_apn_size == 0) {
char str1[110];
/* Remove the IE */
LOGP(DGPRS, LOGL_DEBUG,
@@ -119,20 +126,20 @@ static void gbproxy_patch_apn_ie(struct msgb *msg,
char str1[110];
char str2[110];
- OSMO_ASSERT(peer->cfg->core_apn_size <= 100);
+ OSMO_ASSERT(cfg->core_apn_size <= 100);
LOGP(DGPRS, LOGL_DEBUG,
"Patching %s to SGSN: "
"Replacing APN '%s' -> '%s'\n",
log_text,
osmo_apn_to_str(str1, apn, apn_len),
- osmo_apn_to_str(str2, peer->cfg->core_apn,
- peer->cfg->core_apn_size));
+ osmo_apn_to_str(str2, cfg->core_apn,
+ cfg->core_apn_size));
- *new_apn_ie_len = peer->cfg->core_apn_size + 2;
- msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size);
- memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size);
- hdr->apn_len = peer->cfg->core_apn_size;
+ *new_apn_ie_len = cfg->core_apn_size + 2;
+ msgb_resize_area(msg, apn, apn_len, cfg->core_apn_size);
+ memcpy(apn, cfg->core_apn, cfg->core_apn_size);
+ hdr->apn_len = cfg->core_apn_size;
}
rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);
@@ -207,10 +214,12 @@ int gbproxy_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
int have_patched = 0;
int fcs;
- struct gbproxy_config *cfg = peer->cfg;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
if (parse_ctx->ptmsi_enc && link_info &&
- !parse_ctx->old_raid_is_foreign && peer->cfg->patch_ptmsi) {
+ !parse_ctx->old_raid_is_foreign && cfg->patch_ptmsi) {
uint32_t ptmsi;
if (parse_ctx->to_bss)
ptmsi = link_info->tlli.ptmsi;
@@ -291,13 +300,16 @@ void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
{
const char *err_info = NULL;
int err_ctr = -1;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
if (parse_ctx->bssgp_raid_enc)
gbproxy_patch_raid((struct gsm48_ra_id *)parse_ctx->bssgp_raid_enc, peer,
parse_ctx->to_bss, "BSSGP");
if (parse_ctx->need_decryption &&
- (peer->cfg->patch_ptmsi || peer->cfg->core_apn)) {
+ (cfg->patch_ptmsi || cfg->core_apn)) {
/* Patching LLC messages has been requested
* explicitly, but the message (including the
* type) is encrypted, so we possibly fail to
@@ -319,7 +331,7 @@ void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
if (!link_info)
return;
- if (parse_ctx->tlli_enc && peer->cfg->patch_ptmsi) {
+ if (parse_ctx->tlli_enc && cfg->patch_ptmsi) {
uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli,
link_info, parse_ctx->to_bss);
@@ -335,7 +347,7 @@ void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
}
}
- if (parse_ctx->bssgp_ptmsi_enc && peer->cfg->patch_ptmsi) {
+ if (parse_ctx->bssgp_ptmsi_enc && cfg->patch_ptmsi) {
uint32_t ptmsi;
if (parse_ctx->to_bss)
ptmsi = link_info->tlli.ptmsi;
diff --git a/src/gbproxy/gb_proxy_peer.c b/src/gbproxy/gb_proxy_peer.c
index cb76a592..920547c9 100644
--- a/src/gbproxy/gb_proxy_peer.c
+++ b/src/gbproxy/gb_proxy_peer.c
@@ -81,25 +81,30 @@ static const struct rate_ctr_group_desc peer_ctrg_desc = {
};
-/* Find the gbprox_peer by its BVCI */
+/* Find the gbproxy_peer by its BVCI. There can only be one match */
struct gbproxy_peer *gbproxy_peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)
{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (peer->bvci == bvci)
- return peer;
+ struct gbproxy_nse *nse;
+
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ if (peer->bvci == bvci)
+ return peer;
+ }
}
return NULL;
}
-/* Find the gbprox_peer by its NSEI */
+/* Find the gbproxy_peer by its NSEI */
+/* FIXME: Only returns the first peer, but we could have multiple on this nsei */
struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg,
uint16_t nsei)
{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (peer->nsei == nsei)
- return peer;
+ struct gbproxy_nse *nse;
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ if (nse->nsei == nsei && !llist_empty(&nse->bts_peers))
+ return llist_first_entry(&nse->bts_peers, struct gbproxy_peer, list);
}
return NULL;
}
@@ -109,11 +114,16 @@ struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg,
struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg,
const uint8_t *ra)
{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra, ra, 6))
- return peer;
+ struct gbproxy_nse *nse;
+
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ if (!memcmp(peer->ra, ra, 6))
+ return peer;
+ }
}
+
return NULL;
}
@@ -122,10 +132,14 @@ struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg,
struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg,
const uint8_t *la)
{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra, la, 5))
- return peer;
+ struct gbproxy_nse *nse;
+
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ if (!memcmp(peer->ra, la, 5))
+ return peer;
+ }
}
return NULL;
}
@@ -135,10 +149,14 @@ struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg,
struct gbproxy_peer *gbproxy_peer_by_lac(struct gbproxy_config *cfg,
const uint8_t *la)
{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra + 3, la + 3, 2))
- return peer;
+ struct gbproxy_nse *nse;
+
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ if (!memcmp(peer->ra + 3, la + 3, 2))
+ return peer;
+ }
}
return NULL;
}
@@ -177,18 +195,25 @@ static void clean_stale_timer_cb(void *data)
time_t now;
struct timespec ts = {0,};
struct gbproxy_peer *peer = (struct gbproxy_peer *) data;
+ OSMO_ASSERT(peer);
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec;
gbproxy_remove_stale_link_infos(peer, now);
- if (peer->cfg->clean_stale_timer_freq != 0)
+ if (cfg->clean_stale_timer_freq != 0)
osmo_timer_schedule(&peer->clean_stale_timer,
- peer->cfg->clean_stale_timer_freq, 0);
+ cfg->clean_stale_timer_freq, 0);
}
-struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
+struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_nse *nse, uint16_t bvci)
{
struct gbproxy_peer *peer;
+ OSMO_ASSERT(nse);
+ struct gbproxy_config *cfg = nse->cfg;
+ OSMO_ASSERT(cfg);
peer = talloc_zero(tall_sgsn_ctx, struct gbproxy_peer);
if (!peer)
@@ -200,22 +225,24 @@ struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvc
talloc_free(peer);
return NULL;
}
- peer->cfg = cfg;
+ peer->nse = nse;
- llist_add(&peer->list, &cfg->bts_peers);
+ llist_add(&peer->list, &nse->bts_peers);
INIT_LLIST_HEAD(&peer->patch_state.logical_links);
osmo_timer_setup(&peer->clean_stale_timer, clean_stale_timer_cb, peer);
- if (peer->cfg->clean_stale_timer_freq != 0)
+ if (cfg->clean_stale_timer_freq != 0)
osmo_timer_schedule(&peer->clean_stale_timer,
- peer->cfg->clean_stale_timer_freq, 0);
+ cfg->clean_stale_timer_freq, 0);
return peer;
}
void gbproxy_peer_free(struct gbproxy_peer *peer)
{
+ OSMO_ASSERT(peer);
+
llist_del(&peer->list);
osmo_timer_del(&peer->clean_stale_timer);
gbproxy_delete_link_infos(peer);
@@ -229,17 +256,78 @@ void gbproxy_peer_free(struct gbproxy_peer *peer)
int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
{
int counter = 0;
- struct gbproxy_peer *peer, *tmp;
+ struct gbproxy_nse *nse, *ntmp;
+ OSMO_ASSERT(cfg);
- llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) {
- if (peer->nsei != nsei)
- continue;
- if (bvci && peer->bvci != bvci)
+ llist_for_each_entry_safe(nse, ntmp, &cfg->nse_peers, list) {
+ struct gbproxy_peer *peer, *tmp;
+ if (nse->nsei != nsei)
continue;
+ llist_for_each_entry_safe(peer, tmp, &nse->bts_peers, list) {
+ if (bvci && peer->bvci != bvci)
+ continue;
- gbproxy_peer_free(peer);
- counter += 1;
+ gbproxy_peer_free(peer);
+ counter += 1;
+ }
}
return counter;
}
+
+struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei)
+{
+ struct gbproxy_nse *nse;
+ OSMO_ASSERT(cfg);
+
+ nse = talloc_zero(tall_sgsn_ctx, struct gbproxy_nse);
+ if (!nse)
+ return NULL;
+
+ nse->nsei = nsei;
+ nse->cfg = cfg;
+
+ llist_add(&nse->list, &cfg->nse_peers);
+
+ INIT_LLIST_HEAD(&nse->bts_peers);
+
+ return nse;
+}
+
+void gbproxy_nse_free(struct gbproxy_nse *nse)
+{
+ struct gbproxy_peer *peer, *tmp;
+ OSMO_ASSERT(nse);
+
+ llist_del(&nse->list);
+
+ llist_for_each_entry_safe(peer, tmp, &nse->bts_peers, list)
+ gbproxy_peer_free(peer);
+
+ talloc_free(nse);
+}
+
+struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei)
+{
+ struct gbproxy_nse *nse;
+ OSMO_ASSERT(cfg);
+
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ if (nse->nsei == nsei)
+ return nse;
+ }
+
+ return NULL;
+}
+
+struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei)
+{
+ struct gbproxy_nse *nse;
+ OSMO_ASSERT(cfg);
+
+ nse = gbproxy_nse_by_nsei(cfg, nsei);
+ if (!nse)
+ nse = gbproxy_nse_alloc(cfg, nsei);
+
+ return nse;
+} \ No newline at end of file
diff --git a/src/gbproxy/gb_proxy_tlli.c b/src/gbproxy/gb_proxy_tlli.c
index e9271c22..94874594 100644
--- a/src/gbproxy/gb_proxy_tlli.c
+++ b/src/gbproxy/gb_proxy_tlli.c
@@ -183,12 +183,15 @@ int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
int exceeded_max_len = 0;
int deleted_count = 0;
int check_for_age;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
- if (peer->cfg->tlli_max_len > 0)
+ if (cfg->tlli_max_len > 0)
exceeded_max_len =
- state->logical_link_count - peer->cfg->tlli_max_len;
+ state->logical_link_count - cfg->tlli_max_len;
- check_for_age = peer->cfg->tlli_max_age > 0;
+ check_for_age = cfg->tlli_max_age > 0;
for (; exceeded_max_len > 0; exceeded_max_len--) {
struct gbproxy_link_info *link_info;
@@ -213,7 +216,7 @@ int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
list);
age = now - link_info->timestamp;
/* age < 0 only happens after system time jumps, discard entry */
- if (age <= peer->cfg->tlli_max_age && age >= 0) {
+ if (age <= cfg->tlli_max_age && age >= 0) {
check_for_age = 0;
continue;
}
@@ -395,6 +398,9 @@ static void gbproxy_assign_imsi(struct gbproxy_peer *peer,
int imsi_matches;
struct gbproxy_link_info *other_link_info;
enum gbproxy_match_id match_id;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
/* Make sure that there is a second entry with the same IMSI */
other_link_info = gbproxy_link_info_by_imsi(
@@ -419,11 +425,11 @@ static void gbproxy_assign_imsi(struct gbproxy_peer *peer,
/* Check, whether the IMSI matches */
OSMO_ASSERT(ARRAY_SIZE(link_info->is_matching) ==
- ARRAY_SIZE(peer->cfg->matches));
+ ARRAY_SIZE(cfg->matches));
for (match_id = 0; match_id < ARRAY_SIZE(link_info->is_matching);
++match_id) {
imsi_matches = gbproxy_check_imsi(
- &peer->cfg->matches[match_id],
+ &cfg->matches[match_id],
parse_ctx->imsi, parse_ctx->imsi_len);
if (imsi_matches >= 0)
link_info->is_matching[match_id] = imsi_matches ? true : false;
@@ -590,6 +596,9 @@ struct gbproxy_link_info *gbproxy_update_link_state_dl(
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info = NULL;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
link_info = gbproxy_get_link_info_dl(peer, parse_ctx);
@@ -613,7 +622,7 @@ struct gbproxy_link_info *gbproxy_update_link_state_dl(
link_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
link_info->tlli.ptmsi = new_bss_ptmsi;
} else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !link_info &&
- !peer->cfg->patch_ptmsi) {
+ !cfg->patch_ptmsi) {
/* A new P-TMSI has been signalled in the message with an unknown
* TLLI, create a new link_info */
/* TODO: Add a test case for this branch */
@@ -631,7 +640,7 @@ struct gbproxy_link_info *gbproxy_update_link_state_dl(
link_info->tlli.ptmsi = new_ptmsi;
gbproxy_attach_link_info(peer, now, link_info);
} else if (parse_ctx->tlli_enc && parse_ctx->llc && !link_info &&
- !peer->cfg->patch_ptmsi) {
+ !cfg->patch_ptmsi) {
/* Unknown SGSN TLLI, create a new link_info */
uint32_t new_ptmsi;
link_info = gbproxy_link_info_alloc(peer);
@@ -677,12 +686,16 @@ int gbproxy_update_link_state_after(
struct gprs_gb_parse_context *parse_ctx)
{
int rc = 0;
+ OSMO_ASSERT(peer->nse);
+ struct gbproxy_config *cfg = peer->nse->cfg;
+ OSMO_ASSERT(cfg);
+
if (parse_ctx->invalidate_tlli && link_info) {
int keep_info =
- peer->cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||
- (peer->cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&
+ cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||
+ (cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&
parse_ctx->await_reattach) ||
- (peer->cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&
+ (cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&
link_info->imsi_len > 0);
if (keep_info) {
LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",
diff --git a/src/gbproxy/gb_proxy_vty.c b/src/gbproxy/gb_proxy_vty.c
index 236d5d3c..caad52e6 100644
--- a/src/gbproxy/gb_proxy_vty.c
+++ b/src/gbproxy/gb_proxy_vty.c
@@ -73,7 +73,7 @@ static void gbprox_vty_print_peer(struct vty *vty, struct gbproxy_peer *peer)
gsm48_parse_ra(&raid, peer->ra);
vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "
- "RAI %s", peer->nsei, peer->bvci, osmo_rai_name(&raid));
+ "RAI %s", peer->nse->nsei, peer->bvci, osmo_rai_name(&raid));
if (peer->blocked)
vty_out(vty, " [BVC-BLOCKED]");
@@ -420,16 +420,19 @@ DEFUN(cfg_gbproxy_link_list_clean_stale_timer,
GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR
"Frequency at which the periodic timer is fired (in seconds)\n")
{
- struct gbproxy_peer *peer;
+ struct gbproxy_nse *nse;
g_cfg->clean_stale_timer_freq = (unsigned int) atoi(argv[0]);
/* Re-schedule running timers soon in case prev frequency was really big
and new frequency is desired to be lower. After initial run, periodic
time is used. Use random() to avoid firing timers for all peers at
the same time */
- llist_for_each_entry(peer, &g_cfg->bts_peers, list)
- osmo_timer_schedule(&peer->clean_stale_timer,
- random() % 5, random() % 1000000);
+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list)
+ osmo_timer_schedule(&peer->clean_stale_timer,
+ random() % 5, random() % 1000000);
+ }
return CMD_SUCCESS;
}
@@ -440,11 +443,14 @@ DEFUN(cfg_gbproxy_link_list_no_clean_stale_timer,
NO_STR GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR)
{
- struct gbproxy_peer *peer;
+ struct gbproxy_nse *nse;
g_cfg->clean_stale_timer_freq = 0;
- llist_for_each_entry(peer, &g_cfg->bts_peers, list)
- osmo_timer_del(&peer->clean_stale_timer);
+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list)
+ osmo_timer_del(&peer->clean_stale_timer);
+ }
return CMD_SUCCESS;
}
@@ -536,17 +542,20 @@ DEFUN(cfg_gbproxy_link_no_stored_msgs_max_len,
DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")
{
- struct gbproxy_peer *peer;
+ struct gbproxy_nse *nse;
int show_stats = argc >= 1;
if (show_stats)
vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
- gbprox_vty_print_peer(vty, peer);
+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ gbprox_vty_print_peer(vty, peer);
- if (show_stats)
- vty_out_rate_ctr_group(vty, " ", peer->ctrg);
+ if (show_stats)
+ vty_out_rate_ctr_group(vty, " ", peer->ctrg);
+ }
}
return CMD_SUCCESS;
}
@@ -554,49 +563,52 @@ DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
{
- struct gbproxy_peer *peer;
+ struct gbproxy_nse *nse;
time_t now;
struct timespec ts = {0,};
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec;
- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
- struct gbproxy_link_info *link_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- gbprox_vty_print_peer(vty, peer);
-
- llist_for_each_entry(link_info, &state->logical_links, list) {
- time_t age = now - link_info->timestamp;
- struct osmo_mobile_identity mi;
- const char *imsi_str;
-
- if (link_info->imsi > 0) {
- if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)
- || mi.type != GSM_MI_TYPE_IMSI)
- imsi_str = "(invalid)";
- else
- imsi_str = mi.imsi;
- } else {
- imsi_str = "(none)";
+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ struct gbproxy_link_info *link_info;
+ struct gbproxy_patch_state *state = &peer->patch_state;
+
+ gbprox_vty_print_peer(vty, peer);
+
+ llist_for_each_entry(link_info, &state->logical_links, list) {
+ time_t age = now - link_info->timestamp;
+ struct osmo_mobile_identity mi;
+ const char *imsi_str;
+
+ if (link_info->imsi > 0) {
+ if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)
+ || mi.type != GSM_MI_TYPE_IMSI)
+ imsi_str = "(invalid)";
+ else
+ imsi_str = mi.imsi;
+ } else {
+ imsi_str = "(none)";
+ }
+ vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",
+ link_info->tlli.current, imsi_str, (int)age);
+
+ if (link_info->stored_msgs_len)
+ vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,
+ link_info->stored_msgs_len,
+ g_cfg->stored_msgs_max_len);
+
+ if (g_cfg->route_to_sgsn2)
+ vty_out(vty, ", SGSN NSEI %d",
+ link_info->sgsn_nsei);
+
+ if (link_info->is_deregistered)
+ vty_out(vty, ", DE-REGISTERED");
+
+ vty_out(vty, "%s", VTY_NEWLINE);
}
- vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",
- link_info->tlli.current, imsi_str, (int)age);
-
- if (link_info->stored_msgs_len)
- vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,
- link_info->stored_msgs_len,
- g_cfg->stored_msgs_max_len);
-
- if (g_cfg->route_to_sgsn2)
- vty_out(vty, ", SGSN NSEI %d",
- link_info->sgsn_nsei);
-
- if (link_info->is_deregistered)
- vty_out(vty, ", DE-REGISTERED");
-
- vty_out(vty, "%s", VTY_NEWLINE);
}
}
return CMD_SUCCESS;
@@ -651,15 +663,17 @@ DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
if (!dry_run)
counter = gbproxy_cleanup_peers(g_cfg, nsei, 0);
else {
+ struct gbproxy_nse *nse;
struct gbproxy_peer *peer;
counter = 0;
- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
- if (peer->nsei != nsei)
+ llist_for_each_entry(nse, &g_cfg->nse_peers, list) {
+ if (nse->nsei != nsei)
continue;
-
- vty_out(vty, "BVC: ");
- gbprox_vty_print_peer(vty, peer);
- counter += 1;
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ vty_out(vty, "BVC: ");
+ gbprox_vty_print_peer(vty, peer);
+ counter += 1;
+ }
}
}
vty_out(vty, "%sDeleted %d BVC%s",
diff --git a/tests/gbproxy/gbproxy_test.c b/tests/gbproxy/gbproxy_test.c
index 78fa8cbd..06734b40 100644
--- a/tests/gbproxy/gbproxy_test.c
+++ b/tests/gbproxy/gbproxy_test.c
@@ -118,7 +118,7 @@ static int dump_global(FILE *stream, int indent)
static int dump_peers(FILE *stream, int indent, time_t now,
struct gbproxy_config *cfg)
{
- struct gbproxy_peer *peer;
+ struct gbproxy_nse *nse;
struct gprs_ra_id raid;
unsigned int i;
const struct rate_ctr_group_desc *desc;
@@ -128,98 +128,101 @@ static int dump_peers(FILE *stream, int indent, time_t now,
if (rc < 0)
return rc;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- struct gbproxy_link_info *link_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
- gsm48_parse_ra(&raid, peer->ra);
- rc = fprintf(stream, "%*s NSEI %u, BVCI %u, %sblocked, RAI %s\n",
- indent, "",
- peer->nsei, peer->bvci,
- peer->blocked ? "" : "not ",
- osmo_rai_name(&raid));
+ llist_for_each_entry(nse, &cfg->nse_peers, list) {
+ struct gbproxy_peer *peer;
+ llist_for_each_entry(peer, &nse->bts_peers, list) {
+ struct gbproxy_link_info *link_info;
+ struct gbproxy_patch_state *state = &peer->patch_state;
+ gsm48_parse_ra(&raid, peer->ra);
- if (rc < 0)
- return rc;
+ rc = fprintf(stream, "%*s NSEI %u, BVCI %u, %sblocked, RAI %s\n",
+ indent, "",
+ nse->nsei, peer->bvci,
+ peer->blocked ? "" : "not ",
+ osmo_rai_name(&raid));
- desc = peer->ctrg->desc;
+ if (rc < 0)
+ return rc;
- for (i = 0; i < desc->num_ctr; i++) {
- struct rate_ctr *ctr = &peer->ctrg->ctr[i];
- if (ctr->current) {
- rc = fprintf(stream, "%*s %s: %llu\n",
- indent, "",
- desc->ctr_desc[i].description,
- (long long)ctr->current);
+ desc = peer->ctrg->desc;
- if (rc < 0)
- return rc;
- }
- }
+ for (i = 0; i < desc->num_ctr; i++) {
+ struct rate_ctr *ctr = &peer->ctrg->ctr[i];
+ if (ctr->current) {
+ rc = fprintf(stream, "%*s %s: %llu\n",
+ indent, "",
+ desc->ctr_desc[i].description,
+ (long long)ctr->current);
- fprintf(stream, "%*s TLLI-Cache: %d\n",
- indent, "", state->logical_link_count);
- llist_for_each_entry(link_info, &state->logical_links, list) {
- struct osmo_mobile_identity mi;
- const char *imsi_str;
- time_t age = now ? now - link_info->timestamp : 0;
- int stored_msgs = 0;
- struct llist_head *iter;
- enum gbproxy_match_id match_id;
- llist_for_each(iter, &link_info->stored_msgs)
- stored_msgs++;
-
- if (link_info->imsi > 0) {
- if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)
- || mi.type != GSM_MI_TYPE_IMSI)
- imsi_str = "(invalid)";
- else
- imsi_str = mi.imsi;
- } else {
- imsi_str = "(none)";
- }
- fprintf(stream, "%*s TLLI %08x",
- indent, "", link_info->tlli.current);
- if (link_info->tlli.assigned)
- fprintf(stream, "/%08x", link_info->tlli.assigned);
- if (link_info->sgsn_tlli.current) {
- fprintf(stream, " -> %08x",
- link_info->sgsn_tlli.current);
- if (link_info->sgsn_tlli.assigned)
- fprintf(stream, "/%08x",
- link_info->sgsn_tlli.assigned);
- }
- fprintf(stream, ", IMSI %s, AGE %d",
- imsi_str, (int)age);
-
- if (stored_msgs)
- fprintf(stream, ", STORED %d", stored_msgs);
-
- for (match_id = 0; match_id < ARRAY_SIZE(cfg->matches);
- ++match_id) {
- if (cfg->matches[match_id].enable &&
- link_info->is_matching[match_id]) {
- fprintf(stream, ", IMSI matches");
- break;
+ if (rc < 0)
+ return rc;
}
}
- if (link_info->imsi_acq_pending)
- fprintf(stream, ", IMSI acquisition in progress");
+ fprintf(stream, "%*s TLLI-Cache: %d\n",
+ indent, "", state->logical_link_count);
+ llist_for_each_entry(link_info, &state->logical_links, list) {
+ struct osmo_mobile_identity mi;
+ const char *imsi_str;
+ time_t age = now ? now - link_info->timestamp : 0;
+ int stored_msgs = 0;
+ struct llist_head *iter;
+ enum gbproxy_match_id match_id;
+ llist_for_each(iter, &link_info->stored_msgs)
+ stored_msgs++;
+
+ if (link_info->imsi > 0) {
+ if (osmo_mobile_identity_decode(&mi, link_info->imsi, link_info->imsi_len, false)
+ || mi.type != GSM_MI_TYPE_IMSI)
+ imsi_str = "(invalid)";
+ else
+ imsi_str = mi.imsi;
+ } else {
+ imsi_str = "(none)";
+ }
+ fprintf(stream, "%*s TLLI %08x",
+ indent, "", link_info->tlli.current);
+ if (link_info->tlli.assigned)
+ fprintf(stream, "/%08x", link_info->tlli.assigned);
+ if (link_info->sgsn_tlli.current) {
+ fprintf(stream, " -> %08x",
+ link_info->sgsn_tlli.current);
+ if (link_info->sgsn_tlli.assigned)
+ fprintf(stream, "/%08x",
+ link_info->sgsn_tlli.assigned);
+ }
+ fprintf(stream, ", IMSI %s, AGE %d",
+ imsi_str, (int)age);
+
+ if (stored_msgs)
+ fprintf(stream, ", STORED %d", stored_msgs);
+
+ for (match_id = 0; match_id < ARRAY_SIZE(cfg->matches);
+ ++match_id) {
+ if (cfg->matches[match_id].enable &&
+ link_info->is_matching[match_id]) {
+ fprintf(stream, ", IMSI matches");
+ break;
+ }
+ }
- if (cfg->route_to_sgsn2)
- fprintf(stream, ", SGSN NSEI %d",
- link_info->sgsn_nsei);
+ if (link_info->imsi_acq_pending)
+ fprintf(stream, ", IMSI acquisition in progress");
- if (link_info->is_deregistered)
- fprintf(stream, ", DE-REGISTERED");
+ if (cfg->route_to_sgsn2)
+ fprintf(stream, ", SGSN NSEI %d",
+ link_info->sgsn_nsei);
- rc = fprintf(stream, "\n");
- if (rc < 0)
- return rc;
+ if (link_info->is_deregistered)
+ fprintf(stream, ", DE-REGISTERED");
+
+ rc = fprintf(stream, "\n");
+ if (rc < 0)
+ return rc;
+ }
}
}
-
return 0;
}
@@ -4210,7 +4213,7 @@ struct gbproxy_link_info *register_tlli(
struct gbproxy_link_info *link_info;
int imsi_matches = -1;
int tlli_already_known = 0;
- struct gbproxy_config *cfg = peer->cfg;
+ struct gbproxy_config *cfg = peer->nse->cfg;
/* Check, whether the IMSI matches */
if (gprs_is_mi_imsi(imsi, imsi_len)) {
@@ -4259,6 +4262,7 @@ struct gbproxy_link_info *register_tlli(
static void test_gbproxy_tlli_expire(void)
{
struct gbproxy_config cfg = {0};
+ struct gbproxy_nse *nse;
struct gbproxy_peer *peer;
const char *err_msg = NULL;
const uint8_t imsi1[] = { GSM_MI_TYPE_IMSI, 0x23, 0x24, 0x25, 0xf6 };
@@ -4273,6 +4277,7 @@ static void test_gbproxy_tlli_expire(void)
printf("Test TLLI info expiry\n\n");
gbproxy_init_config(&cfg);
+ nse = gbproxy_nse_by_nsei_or_new(&cfg, 0);
if (gbproxy_set_patch_filter(&cfg.matches[GBPROX_MATCH_PATCHING],
filter_re, &err_msg) != 0) {
@@ -4288,7 +4293,7 @@ static void test_gbproxy_tlli_expire(void)
cfg.tlli_max_len = 0;
cfg.tlli_max_age = 0;
- peer = gbproxy_peer_alloc(&cfg, 20);
+ peer = gbproxy_peer_alloc(nse, 20);
OSMO_ASSERT(peer->patch_state.logical_link_count == 0);
printf(" Add TLLI 1, IMSI 1\n");
@@ -4327,7 +4332,7 @@ static void test_gbproxy_tlli_expire(void)
cfg.tlli_max_len = 0;
cfg.tlli_max_age = 0;
- peer = gbproxy_peer_alloc(&cfg, 20);
+ peer = gbproxy_peer_alloc(nse, 20);
OSMO_ASSERT(peer->patch_state.logical_link_count == 0);
printf(" Add TLLI 1, IMSI 1\n");
@@ -4367,7 +4372,7 @@ static void test_gbproxy_tlli_expire(void)
cfg.tlli_max_len = 1;
cfg.tlli_max_age = 0;
- peer = gbproxy_peer_alloc(&cfg, 20);
+ peer = gbproxy_peer_alloc(nse, 20);
OSMO_ASSERT(peer->patch_state.logical_link_count == 0);
printf(" Add TLLI 1, IMSI 1\n");
@@ -4405,7 +4410,7 @@ static void test_gbproxy_tlli_expire(void)
cfg.tlli_max_len = 0;
cfg.tlli_max_age = 1;
- peer = gbproxy_peer_alloc(&cfg, 20);
+ peer = gbproxy_peer_alloc(nse, 20);
OSMO_ASSERT(peer->patch_state.logical_link_count == 0);
printf(" Add TLLI 1, IMSI 1 (should expire after timeout)\n");
@@ -4443,7 +4448,7 @@ static void test_gbproxy_tlli_expire(void)
cfg.tlli_max_len = 0;
cfg.tlli_max_age = 1;
- peer = gbproxy_peer_alloc(&cfg, 20);
+ peer = gbproxy_peer_alloc(nse, 20);
OSMO_ASSERT(peer->patch_state.logical_link_count == 0);
printf(" Add TLLI 1, IMSI 1 (should expire)\n");
diff --git a/tests/gbproxy/gbproxy_test.ok b/tests/gbproxy/gbproxy_test.ok
index 74cedb3c..14a2641e 100644
--- a/tests/gbproxy/gbproxy_test.ok
+++ b/tests/gbproxy/gbproxy_test.ok
@@ -96,10 +96,10 @@ Message for SGSN (NSEI=256 BVCI=0):
[L2]> [L3]> 22 04 82 10 12 07 81 08 08 88 11 22 33 40 50 60 10 00
Peers:
- NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96
- TLLI-Cache: 0
NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
+ NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96
+ TLLI-Cache: 0
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
PROCESSING BVC_RESET_ACK from NSEI 256
@@ -131,10 +131,10 @@ Message for SGSN (NSEI=256 BVCI=0):
[L2]> [L3]> 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00
Peers:
- NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96
- TLLI-Cache: 0
NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
+ NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96
+ TLLI-Cache: 0
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
PROCESSING BVC_RESET_ACK from NSEI 256
@@ -166,10 +166,10 @@ Message for SGSN (NSEI=256 BVCI=0):
[L2]> [L3]> 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00
Peers:
- NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96
- TLLI-Cache: 0
NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
+ NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96
+ TLLI-Cache: 0
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
PROCESSING BVC_RESET_ACK from NSEI 256
@@ -285,11 +285,11 @@ Message for SGSN (NSEI=256 BVCI=0):
[L2]> [L3]> 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00
Peers:
- NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96
- TLLI-Cache: 0
NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
+ NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96
+ TLLI-Cache: 0
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
Gbproxy global:
@@ -517,11 +517,11 @@ Message for BSS (NSEI=8192 BVCI=0):
[L2]> [L3]> 23 04 82 10 02
Peers:
- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
- TLLI-Cache: 0
NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
+ TLLI-Cache: 0
--- Setup BVCI 3 ---
Setup BSSGP: BVCI 0x3002(12290)
@@ -553,11 +553,11 @@ Message for BSS (NSEI=8192 BVCI=0):
Peers:
NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
- TLLI-Cache: 0
NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
+ TLLI-Cache: 0
--- Send message from BSS 1 to SGSN and back, BVCI 1 ---
PROCESSING (null) from NSEI 8192
@@ -601,10 +601,10 @@ Message for SGSN (NSEI=256 BVCI=8194):
Peers:
NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
+ NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
- NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96
+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
PROCESSING (null) from NSEI 256
@@ -622,10 +622,10 @@ Message for BSS (NSEI=4096 BVCI=8194):
Peers:
NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96
TLLI-Cache: 0
- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
+ NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
- NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96
+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
--- Send message from BSS 1 to SGSN and back, BVCI 3 ---
@@ -659,10 +659,10 @@ Peers:
NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
- NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
+ NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
- NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96
+ NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96
NSEI mismatch : 1
TLLI-Cache: 0
=== test_gbproxy_ra_patching ===