gbproxy: Avoid sending STATUS on unexpected BLOCK_ACK
Handle SGSN BVCs that are gone from the BSS differently.
The previous patch removed the gbproxy_bvc on the SGSN-side after it was
gone on the BSS-side. This caused a STATUS response to BVC_BLOCK_ACK messages
that should be valid. Instead of removing the BVC this patch marks it as
inactive so we can still handle BVC_BLOCK_ACK correctly, but ignore
other messages - especially BVC_RESET from the SGSN.
Related: SYS#5628. OS#5236
Change-Id: Ic9f34a27412d6e15ca1198ee140f66a076b5c6b6
diff --git a/include/osmocom/gbproxy/gb_proxy.h b/include/osmocom/gbproxy/gb_proxy.h
index 1e73a1d..07373ad 100644
--- a/include/osmocom/gbproxy/gb_proxy.h
+++ b/include/osmocom/gbproxy/gb_proxy.h
@@ -139,6 +139,9 @@
/* PTP BVCI of this BVC */
uint16_t bvci;
+ /* Whether this BVC is inactive (removed from BSS-side) */
+ bool inactive;
+
/* Routing Area that this BVC is part of */
struct gprs_ra_id raid;
@@ -279,6 +282,7 @@
#define NSE_F_BSS 0x0002
struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_nse *nse, uint16_t bvci);
+struct gbproxy_bvc *gbproxy_bvc_by_bvci_inactive(struct gbproxy_nse *nse, uint16_t bvci);
struct gbproxy_bvc *gbproxy_bvc_alloc(struct gbproxy_nse *nse, uint16_t bvci);
void gbproxy_bvc_free(struct gbproxy_bvc *bvc);
int gbproxy_cleanup_bvcs(struct gbproxy_nse *nse, uint16_t bvci);
diff --git a/src/gb_proxy.c b/src/gb_proxy.c
index be075d6..e24f468 100644
--- a/src/gb_proxy.c
+++ b/src/gb_proxy.c
@@ -701,6 +701,8 @@
* Removing and reallocating is needed becaus the ra_id/cell_id might have changed */
hash_for_each(cfg->sgsn_nses, i, sgsn_nse, list) {
struct gbproxy_bvc *sgsn_bvc = gbproxy_bvc_by_bvci(sgsn_nse, bvci);
+ if (!sgsn_bvc)
+ sgsn_bvc = gbproxy_bvc_by_bvci_inactive(sgsn_nse, bvci);
if (sgsn_bvc)
gbproxy_bvc_free(sgsn_bvc);
@@ -1374,8 +1376,12 @@
case BSSGP_PDUT_BVC_BLOCK_ACK:
bvci = ntohs(tlvp_val16_unal(&tp[0], BSSGP_IE_BVCI));
sgsn_bvc = gbproxy_bvc_by_bvci(nse, bvci);
- if (!sgsn_bvc)
- goto err_no_bvc;
+ if (!sgsn_bvc) {
+ /* Check if BVC was blocked before */
+ sgsn_bvc = gbproxy_bvc_by_bvci_inactive(nse, bvci);
+ if (!sgsn_bvc)
+ goto err_no_bvc;
+ }
rc = osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_RX_BLOCK_ACK, msg);
break;
case BSSGP_PDUT_BVC_UNBLOCK_ACK:
@@ -1627,7 +1633,7 @@
/* Block BVC, indicate BSS equipment failure */
uint8_t cause = BSSGP_CAUSE_EQUIP_FAIL;
osmo_fsm_inst_dispatch(sgsn_bvc->fi, BSSGP_BVCFSM_E_REQ_BLOCK, &cause);
- gbproxy_bvc_free(sgsn_bvc);
+ sgsn_bvc->inactive = true;
}
}
diff --git a/src/gb_proxy_peer.c b/src/gb_proxy_peer.c
index abbfa50..f59cf9e 100644
--- a/src/gb_proxy_peer.c
+++ b/src/gb_proxy_peer.c
@@ -62,7 +62,18 @@
{
struct gbproxy_bvc *bvc;
hash_for_each_possible(nse->bvcs, bvc, list, bvci) {
- if (bvc->bvci == bvci)
+ if (bvc->bvci == bvci && bvc->inactive == false)
+ return bvc;
+ }
+ return NULL;
+}
+
+/* Find the gbproxy_bvc by its BVCI. There can only be one match */
+struct gbproxy_bvc *gbproxy_bvc_by_bvci_inactive(struct gbproxy_nse *nse, uint16_t bvci)
+{
+ struct gbproxy_bvc *bvc;
+ hash_for_each_possible(nse->bvcs, bvc, list, bvci) {
+ if (bvc->bvci == bvci && bvc->inactive == true)
return bvc;
}
return NULL;
@@ -84,6 +95,7 @@
nse->nsei);
osmo_identifier_sanitize_buf(idbuf, NULL, '_');
bvc->bvci = bvci;
+ bvc->inactive = false;
bvc->ctrg = rate_ctr_group_alloc(bvc, &bvc_ctrg_desc, (nse->nsei << 16) | bvci);
if (!bvc->ctrg) {
talloc_free(bvc);