diff options
Diffstat (limited to 'src/gb/gprs_bssgp.c')
-rw-r--r-- | src/gb/gprs_bssgp.c | 78 |
1 files changed, 62 insertions, 16 deletions
diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c index 87083408..2f23290b 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) |