aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/gprs/gprs_bssgp.h2
-rw-r--r--src/gb/gprs_bssgp.c78
-rw-r--r--tests/gb/gprs_bssgp_test.c35
-rw-r--r--tests/gb/gprs_bssgp_test.ok4
4 files changed, 103 insertions, 16 deletions
diff --git a/include/osmocom/gprs/gprs_bssgp.h b/include/osmocom/gprs/gprs_bssgp.h
index f229253..e24b563 100644
--- a/include/osmocom/gprs/gprs_bssgp.h
+++ b/include/osmocom/gprs/gprs_bssgp.h
@@ -33,6 +33,7 @@ enum bssgp_prim {
PRIM_NM_BVC_RESET,
PRIM_NM_BVC_BLOCK,
PRIM_NM_BVC_UNBLOCK,
+ PRIM_NM_STATUS,
};
struct osmo_bssgp_prim {
@@ -117,6 +118,7 @@ enum bssgp_ctr {
BSSGP_CTR_BYTES_OUT,
BSSGP_CTR_BLOCKED,
BSSGP_CTR_DISCARDED,
+ BSSGP_CTR_STATUS,
};
diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c
index 8708340..2f23290 100644
--- a/src/gb/gprs_bssgp.c
+++ b/src/gb/gprs_bssgp.c
@@ -46,6 +46,7 @@ static const struct rate_ctr_desc bssgp_ctr_description[] = {
{ "bytes.out", "Bytes at BSSGP Level (Out)" },
{ "blocked", "BVC Blocking count" },
{ "discarded", "BVC LLC Discarded count" },
+ { "status", "BVC Status count" },
};
static const struct rate_ctr_group_desc bssgp_ctrg_desc = {
@@ -516,6 +517,46 @@ static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp,
return bssgp_prim_cb(&nmp.oph, NULL);
}
+int bssgp_rx_status(struct msgb *msg, struct tlv_parsed *tp,
+ uint16_t bvci, struct bssgp_bvc_ctx *bctx)
+{
+ struct osmo_bssgp_prim nmp;
+ enum gprs_bssgp_cause cause;
+
+ if (!TLVP_PRESENT(tp, BSSGP_IE_CAUSE)) {
+ LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx STATUS "
+ "missing mandatory IE\n", bvci);
+ cause = BSSGP_CAUSE_PROTO_ERR_UNSPEC;
+ } else {
+ cause = *TLVP_VAL(tp, BSSGP_IE_CAUSE);
+ }
+
+ LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Rx BVC STATUS, cause=%s\n",
+ bvci, bssgp_cause_str(cause));
+
+ if (cause == BSSGP_CAUSE_BVCI_BLOCKED || cause == BSSGP_CAUSE_UNKNOWN_BVCI) {
+ if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI))
+ LOGP(DBSSGP, LOGL_ERROR,
+ "BSSGP BVCI=%u Rx STATUS cause=%s "
+ "missing conditional BVCI IE\n",
+ bvci, bssgp_cause_str(cause));
+ }
+
+ if (bctx)
+ rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_STATUS]);
+
+ /* send NM_STATUS to NM */
+ memset(&nmp, 0, sizeof(nmp));
+ nmp.nsei = msgb_nsei(msg);
+ nmp.bvci = bvci;
+ nmp.tp = tp;
+ osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_STATUS,
+ PRIM_OP_INDICATION, msg);
+
+ return bssgp_prim_cb(&nmp.oph, NULL);
+}
+
+
/* One element (msgb) in a BSSGP Flow Control queue */
struct bssgp_fc_queue_element {
/* linked list of queue elements */
@@ -807,10 +848,12 @@ static int bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp,
uint8_t pdu_type = bgph->pdu_type;
int rc = 0;
+ OSMO_ASSERT(pdu_type != BSSGP_PDUT_STATUS);
+
/* If traffic is received on a BVC that is marked as blocked, the
* received PDU shall not be accepted and a STATUS PDU (Cause value:
* BVC Blocked) shall be sent to the peer entity on the signalling BVC */
- if (bctx->state & BVC_S_BLOCKED && pdu_type != BSSGP_PDUT_STATUS) {
+ if (bctx->state & BVC_S_BLOCKED) {
uint16_t bvci = msgb_bvci(msg);
return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &bvci, msg);
}
@@ -844,9 +887,7 @@ static int bssgp_rx_ptp(struct msgb *msg, struct tlv_parsed *tp,
/* FIXME: Send FLOW_CONTROL_MS_ACK */
break;
case BSSGP_PDUT_STATUS:
- /* Some exception has occurred */
- DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PTP BVC STATUS\n", bctx->bvci);
- /* FIXME: send NM_STATUS.ind to NM */
+ /* This is already handled in bssgp_rcvmsg() */
break;
case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
@@ -943,9 +984,7 @@ static int bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp,
rc = bssgp_rx_bvc_reset(msg, tp, ns_bvci);
break;
case BSSGP_PDUT_STATUS:
- /* Some exception has occurred */
- DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC STATUS\n", bvci);
- /* FIXME: send NM_STATUS.ind to NM */
+ /* This is already handled in bssgp_rcvmsg() */
break;
/* those only exist in the SGSN -> BSS direction */
case BSSGP_PDUT_PAGING_PS:
@@ -1006,15 +1045,6 @@ int bssgp_rcvmsg(struct msgb *msg)
/* look-up or create the BTS context for this BVC */
bctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg));
- /* Only a RESET PDU can create a new BVC context,
- * otherwise it must be registered if a BVCI is given */
- if (!bctx && bvci != BVCI_SIGNALLING &&
- pdu_type != BSSGP_PDUT_BVC_RESET) {
- LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU "
- "type %u for unknown BVCI\n", msgb_nsei(msg), bvci,
- pdu_type);
- return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci, msg);
- }
if (bctx) {
log_set_context(GPRS_CTX_BVC, bctx);
@@ -1023,6 +1053,22 @@ int bssgp_rcvmsg(struct msgb *msg)
msgb_bssgp_len(msg));
}
+ /* Always handle STATUS PDUs, even if they contain an invalid BVCI or
+ * are otherwise unexpected */
+ if (pdu_type == BSSGP_PDUT_STATUS)
+ /* Some exception has occurred */
+ return bssgp_rx_status(msg, &tp, bvci, bctx);
+
+ /* Only a RESET PDU can create a new BVC context, otherwise it must be
+ * registered if a BVCI is given. */
+ if (!bctx && bvci != BVCI_SIGNALLING &&
+ pdu_type != BSSGP_PDUT_BVC_RESET) {
+ LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU "
+ "type %u for unknown BVCI\n", msgb_nsei(msg), bvci,
+ pdu_type);
+ return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci, msg);
+ }
+
if (ns_bvci == BVCI_SIGNALLING)
rc = bssgp_rx_sign(msg, &tp, bctx);
else if (ns_bvci == BVCI_PTM)
diff --git a/tests/gb/gprs_bssgp_test.c b/tests/gb/gprs_bssgp_test.c
index a247326..3d1384b 100644
--- a/tests/gb/gprs_bssgp_test.c
+++ b/tests/gb/gprs_bssgp_test.c
@@ -125,6 +125,40 @@ static void test_bssgp_suspend_resume(void)
printf("----- %s END\n", __func__);
}
+static void send_bssgp_status(enum gprs_bssgp_cause cause, uint16_t *bvci)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ uint8_t cause_ = cause;
+
+ msgb_v_put(msg, BSSGP_PDUT_STATUS);
+ msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause_);
+ if (bvci) {
+ uint16_t bvci_ = htons(*bvci);
+ msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &bvci_);
+ }
+
+ msgb_bssgp_send_and_free(msg);
+}
+
+static void test_bssgp_status(void)
+{
+ uint16_t bvci;
+
+ printf("----- %s START\n", __func__);
+
+ send_bssgp_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL);
+ OSMO_ASSERT(last_oph.primitive == PRIM_NM_STATUS);
+
+ /* Enforce prim != PRIM_NM_STATUS */
+ last_oph.primitive = PRIM_NM_LLC_DISCARDED;
+
+ bvci = 1234;
+ send_bssgp_status(BSSGP_CAUSE_UNKNOWN_BVCI, &bvci);
+ OSMO_ASSERT(last_oph.primitive == PRIM_NM_STATUS);
+
+ printf("----- %s END\n", __func__);
+}
+
static struct log_info info = {};
int main(int argc, char **argv)
@@ -146,6 +180,7 @@ int main(int argc, char **argv)
printf("===== BSSGP test START\n");
test_bssgp_suspend_resume();
+ test_bssgp_status();
printf("===== BSSGP test END\n\n");
exit(EXIT_SUCCESS);
diff --git a/tests/gb/gprs_bssgp_test.ok b/tests/gb/gprs_bssgp_test.ok
index c9ec83d..0392e6a 100644
--- a/tests/gb/gprs_bssgp_test.ok
+++ b/tests/gb/gprs_bssgp_test.ok
@@ -3,5 +3,9 @@
BSSGP primitive, SAP 16777219, prim = 3, op = 0, msg = 0b 1f 84 f0 12 34 56 1b 86 0f f1 80 20 37 00
BSSGP primitive, SAP 16777219, prim = 4, op = 0, msg = 0e 1f 84 f0 12 34 56 1b 86 0f f1 80 20 37 00 1d 81 01
----- test_bssgp_suspend_resume END
+----- test_bssgp_status START
+BSSGP primitive, SAP 16777221, prim = 11, op = 2, msg = 41 07 81 27
+BSSGP primitive, SAP 16777221, prim = 11, op = 2, msg = 41 07 81 05 04 82 04 d2
+----- test_bssgp_status END
===== BSSGP test END