Hi Caleb,

On Fri, Jun 21, 2013 at 05:05:22PM -0700, Caleb Pal wrote:
 
> Program received signal SIGFPE, Arithmetic exception.
> fc_queue_timer_cfg (fc=fc@entry=0x808def0) at gprs_bssgp.c:596
> 596             msecs = (fcqe->llc_pdu_len * 1000) / fc->bucket_leak_rate;
> (gdb)

What you should always do when reporting crashes is to include a full
backtrace (bt full) as well as 'list' to show some surrounding lines of
code.

However, in this case it is quite obvious.  Please try the attached
(untested) patch against libosmocore.

What happens is basically that the BTS wants the SGSN to stop all
downlink GPRS transmission.

-- 
- Harald Welte <[email protected]>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)
>From 819429a218744bb47161db8a90e1a0e524db8022 Mon Sep 17 00:00:00 2001
From: Harald Welte <[email protected]>
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 e41c7ef..5ef1887 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));
-- 
1.8.3.1

Reply via email to