aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-02-06 13:09:29 +0100
committerHarald Welte <laforge@gnumonks.org>2011-02-06 13:09:29 +0100
commit36f98d9c53e92a19b99a678ae7d713ef0055a8d5 (patch)
tree8c8955d20df88c1b44113b1d115eef7c5436e59f /openbsc/src/gprs
parentb63c3639eb8831e2dce21856ec28e1c574e68755 (diff)
[gb_proxy] Track the state of blocked/unblocked BVC in the proxy
This allows us to reject any additional messages sent by the SGSN after the BVC was blocked (+ acknowledged to be blocked)
Diffstat (limited to 'openbsc/src/gprs')
-rw-r--r--openbsc/src/gprs/gb_proxy.c72
1 files changed, 59 insertions, 13 deletions
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 934ceef68..19f6cbff2 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -47,6 +47,7 @@ struct gbprox_peer {
/* 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];
@@ -202,6 +203,30 @@ static int gbprox_relay2peer(struct msgb *old_msg, struct gbprox_peer *peer,
return gprs_ns_sendmsg(bssgp_nsi, msg);
}
+static int block_unblock_peer(uint16_t ptp_bvci, uint8_t pdu_type)
+{
+ struct gbprox_peer *peer;
+
+ peer = peer_by_bvci(ptp_bvci);
+ if (!peer) {
+ LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n",
+ ptp_bvci);
+ return -ENOENT;
+ }
+
+ switch (pdu_type) {
+ case BSSGP_PDUT_BVC_BLOCK_ACK:
+ peer->blocked = 1;
+ break;
+ case BSSGP_PDUT_BVC_UNBLOCK_ACK:
+ peer->blocked = 0;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
/* Send a message to a peer identified by ptp_bvci but using ns_bvci
* in the NS hdr */
static int gbprox_relay2bvci(struct msgb *msg, uint16_t ptp_bvci,
@@ -428,8 +453,6 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc,
rc = rx_reset_from_sgsn(msg, &tp, nsvc, ns_bvci);
break;
case BSSGP_PDUT_FLUSH_LL:
- case BSSGP_PDUT_BVC_BLOCK_ACK:
- case BSSGP_PDUT_BVC_UNBLOCK_ACK:
case BSSGP_PDUT_BVC_RESET_ACK:
/* simple case: BVCI IE is mandatory */
if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
@@ -474,6 +497,22 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc,
goto err_no_peer;
rc = gbprox_relay2peer(msg, peer, ns_bvci);
break;
+ case BSSGP_PDUT_BVC_BLOCK_ACK:
+ case BSSGP_PDUT_BVC_UNBLOCK_ACK:
+ if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
+ goto err_mand_ie;
+ bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
+ if (bvci == 0) {
+ LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BSSGP "
+ "%sBLOCK_ACK for signalling BVCI ?!?\n", nsvc->nsei,
+ pdu_type == BSSGP_PDUT_BVC_UNBLOCK_ACK ? "UN":"");
+ /* should we send STATUS ? */
+ } else {
+ /* Mark BVC as (un)blocked */
+ block_unblock_peer(bvci, pdu_type);
+ }
+ rc = gbprox_relay2bvci(msg, bvci, ns_bvci);
+ break;
case BSSGP_PDUT_SGSN_INVOKE_TRACE:
LOGP(DGPRS, LOGL_ERROR,
"NSEI=%u(SGSN) BSSGP INVOKE TRACE not supported\n",nsvc->nsei);
@@ -501,6 +540,7 @@ err_no_peer:
int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci)
{
int rc;
+ struct gbprox_peer *peer;
/* Only BVCI=0 messages need special treatment */
if (ns_bvci == 0 || ns_bvci == 1) {
@@ -511,18 +551,24 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci)
} else {
/* All other BVCI are PTP and thus can be simply forwarded */
if (!nsvc->remote_end_is_sgsn) {
- rc = gbprox_relay2sgsn(msg, ns_bvci);
- } else {
- struct gbprox_peer *peer = peer_by_bvci(ns_bvci);
- if (!peer) {
- LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for "
- "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci,
- nsvc->nsvci, nsvc->nsei);
- peer = peer_alloc(ns_bvci);
- peer->nsvc = nsvc;
- }
- rc = gbprox_relay2peer(msg, peer, ns_bvci);
+ return gbprox_relay2sgsn(msg, ns_bvci);
+ }
+ /* else: SGSN -> BSS direction */
+ peer = peer_by_bvci(ns_bvci);
+ if (!peer) {
+ LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for "
+ "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci,
+ nsvc->nsvci, nsvc->nsei);
+ peer = peer_alloc(ns_bvci);
+ peer->nsvc = nsvc;
}
+ if (peer->blocked) {
+ LOGP(DGPRS, LOGL_NOTICE, "Dropping PDU for "
+ "blocked BVCI=%u via NSVC=%u/NSEI=%u\n",
+ ns_bvci, nsvc->nsvci, nsvc->nsei);
+ return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, NULL, msg);
+ }
+ rc = gbprox_relay2peer(msg, peer, ns_bvci);
}
return rc;