From 27b2bb7e924161ac087240cfbdf96acf035cba2a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 22 Jun 2013 09:44:00 +0200 Subject: [PATCH] BSSGP: prevent divide-by-zero in flow control If the BTS tells us to not send any data at all anymore (bucket leak rate of 0 bits per second), then we should respect this and not run into a divide-by-zero. However, as this indicates complete overload, we print a log message to that regard. --- src/gb/gprs_bssgp.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c index e41c7efbb..5ef18872e 100644 --- a/src/gb/gprs_bssgp.c +++ b/src/gb/gprs_bssgp.c @@ -590,16 +590,20 @@ static int fc_queue_timer_cfg(struct bssgp_flow_control *fc) fcqe = llist_entry(&fc->queue.next, struct bssgp_fc_queue_element, list); - /* Calculate the point in time at which we will have leaked - * a sufficient number of bytes from the bucket to transmit - * the first PDU in the queue */ - msecs = (fcqe->llc_pdu_len * 1000) / fc->bucket_leak_rate; - /* FIXME: add that time to fc->time_last_pdu and subtract it from - * current time */ - - fc->timer.data = fc; - fc->timer.cb = &fc_timer_cb; - osmo_timer_schedule(&fc->timer, msecs / 1000, (msecs % 1000) * 1000); + if (fc->bucket_leak_rate != 0) { + /* Calculate the point in time at which we will have leaked + * a sufficient number of bytes from the bucket to transmit + * the first PDU in the queue */ + msecs = (fcqe->llc_pdu_len * 1000) / fc->bucket_leak_rate; + /* FIXME: add that time to fc->time_last_pdu and subtract it from + * current time */ + fc->timer.data = fc; + fc->timer.cb = &fc_timer_cb; + osmo_timer_schedule(&fc->timer, msecs / 1000, (msecs % 1000) * 1000); + } else { + /* If the PCU is telling us to not send any more data at all, + * there's no point starting a timer. */ + } return 0; } @@ -742,6 +746,8 @@ int bssgp_fc_ms_init(struct bssgp_flow_control *fc_ms, uint16_t bvci, static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx) { + uint32_t old_leak_rate = bctx->fc->bucket_leak_rate; + uint32_t old_r_def_ms = bctx->r_default_ms; DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx Flow Control BVC\n", bctx->bvci); @@ -769,6 +775,23 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, bctx->r_default_ms = 100 * ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_R_DEFAULT_MS)) / 8; + if (old_leak_rate != 0 && bctx->fc->bucket_leak_rate == 0) + LOGP(DBSSGP, LOGL_NOTICE, "BSS instructs us to bucket leak " + "rate of 0, stopping all DL GPRS!\n"); + else if (old_leak_rate == 0 && bctx->fc->bucket_leak_rate != 0) + LOGP(DBSSGP, LOGL_NOTICE, "BSS instructs us to bucket leak " + "rate of != 0, restarting all DL GPRS!\n"); + + if (old_r_def_ms != 0 && bctx->r_default_ms == 0) + LOGP(DBSSGP, LOGL_NOTICE, "BSS instructs us to MS default " + "bucket leak rate of 0, stopping DL GPRS!\n"); + else if (old_r_def_ms == 0 && bctx->r_default_ms != 0) + LOGP(DBSSGP, LOGL_NOTICE, "BSS instructs us to MS default " + "bucket leak rate != 0, restarting DL GPRS!\n"); + + /* reconfigure the timer for flow control based on new values */ + fc_queue_timer_cfg(bctx->fc); + /* Send FLOW_CONTROL_BVC_ACK */ return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), msgb_bvci(msg));