aboutsummaryrefslogtreecommitdiffstats
path: root/src/gprs_bssgp_pcu.cpp
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-03-16 12:27:11 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2015-03-17 10:44:07 +0100
commit39645b824a08b355fa48361491d5a1c3e9e6bd4d (patch)
treef5e04dd4d38d9954c385a4e8860e4db7982e60fe /src/gprs_bssgp_pcu.cpp
parent1e96af63259272b73625e1aa40f1b935aece7c29 (diff)
bssgp: Handle BSSGP STATUS messages
Currently incoming BSSGP STATUS messages are just logged and apart from that ignored. Since it is possible that the gbproxy can eventually send both valid replies (from the primary SGSN) and STATUS(unknown BVCI) messages (from the secondary SGSN). Since the PCU assumes in this case that the BVC has been successfully reset and unblocked, it will not send a BVC RESET message after receiving an NS_UNBLOCK. This commit changes gprs_bssgp_pcu_rcvmsg to pass BSSGP STATUS messages to bssgp_rcvmsg() which will in turn call bssgp_prim_cb() with primitive NM_STATUS. Then the BVC RESET or UNBLOCK procedure will be started if the IE in the message matches and the PCU assumes that the BVC should have been successfully reset and unblocked respectively while the STATUS message tells otherwise. Note that bssgp_rcvmsg() from libosmocore is otherwise used for the SGSN side only, albeit it generally just decodes messages, does basic protocol handling and eventually invokes PRIM indications. The only exception here is the handling of BVC RESET, which is implemented specifically for the SGSN. Ticket: OW#1414 Sponsored-by: On-Waves ehf
Diffstat (limited to 'src/gprs_bssgp_pcu.cpp')
-rw-r--r--src/gprs_bssgp_pcu.cpp67
1 files changed, 62 insertions, 5 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index daadc635..09047203 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -303,11 +303,10 @@ static int gprs_bssgp_pcu_rcvmsg(struct msgb *msg)
int rc = 0;
struct bssgp_bvc_ctx *bctx;
- if (pdu_type == BSSGP_PDUT_STATUS) {
- LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u received STATUS\n",
- msgb_nsei(msg), ns_bvci);
- return 0;
- }
+ if (pdu_type == BSSGP_PDUT_STATUS)
+ /* Pass the message to the generic BSSGP parser, which handles
+ * STATUS message in either direction. */
+ return bssgp_rcvmsg(msg);
/* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */
@@ -362,8 +361,66 @@ static int gprs_bssgp_pcu_rcvmsg(struct msgb *msg)
return rc;
}
+static void handle_nm_status(struct osmo_bssgp_prim *bp)
+{
+ enum gprs_bssgp_cause cause;
+
+ LOGP(DPCU, LOGL_DEBUG,
+ "Got NM-STATUS.ind, BVCI=%d, NSEI=%d\n",
+ bp->bvci, bp->nsei);
+
+ if (!TLVP_PRESENT(bp->tp, BSSGP_IE_CAUSE))
+ return;
+
+ cause = (enum gprs_bssgp_cause)*TLVP_VAL(bp->tp, BSSGP_IE_CAUSE);
+
+ if (cause != BSSGP_CAUSE_BVCI_BLOCKED &&
+ cause != BSSGP_CAUSE_UNKNOWN_BVCI)
+ return;
+
+ if (!TLVP_PRESENT(bp->tp, BSSGP_IE_BVCI))
+ return;
+
+ if (gprs_bssgp_pcu_current_bctx()->bvci != bp->bvci) {
+ LOGP(DPCU, LOGL_NOTICE,
+ "Received BSSGP STATUS message for an unknown BVCI (%d), "
+ "ignored\n",
+ bp->bvci);
+ return;
+ }
+
+ switch (cause) {
+ case BSSGP_CAUSE_BVCI_BLOCKED:
+ if (the_pcu.bvc_unblocked) {
+ the_pcu.bvc_unblocked = 0;
+ bvc_timeout(NULL);
+ }
+ break;
+
+ case BSSGP_CAUSE_UNKNOWN_BVCI:
+ if (the_pcu.bvc_reset) {
+ the_pcu.bvc_reset = 0;
+ bvc_timeout(NULL);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
+ struct osmo_bssgp_prim *bp;
+ bp = container_of(oph, struct osmo_bssgp_prim, oph);
+
+ switch (oph->sap) {
+ case SAP_BSSGP_NM:
+ if (oph->primitive == PRIM_NM_STATUS)
+ handle_nm_status(bp);
+ break;
+ default:
+ break;
+ }
return 0;
}