aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/dccp/ccids/ccid3.h19
-rw-r--r--net/dccp/ccids/lib/tfrc.h23
-rw-r--r--net/dccp/ccids/lib/tfrc_equation.c28
3 files changed, 35 insertions, 35 deletions
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index cd4fc542f73..da0ca3c0a7b 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -171,23 +171,4 @@ static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk)
return ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid);
}
-static inline u64 scaled_div(u64 a, u32 b)
-{
- BUG_ON(b==0);
- a *= 1000000;
- do_div(a, b);
- return a;
-}
-
-static inline u32 scaled_div32(u64 a, u32 b)
-{
- u64 result = scaled_div(a, b);
-
- if (result > UINT_MAX) {
- DCCP_CRIT("Overflow: a(%llu)/b(%u) > ~0U",
- (unsigned long long)a, b);
- return UINT_MAX;
- }
- return result;
-}
#endif /* _DCCP_CCID3_H_ */
diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h
index 45f30f59ea2..faf5f7e219e 100644
--- a/net/dccp/ccids/lib/tfrc.h
+++ b/net/dccp/ccids/lib/tfrc.h
@@ -13,8 +13,29 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-
#include <linux/types.h>
+#include <asm/div64.h>
+
+/* integer-arithmetic divisions of type (a * 1000000)/b */
+static inline u64 scaled_div(u64 a, u32 b)
+{
+ BUG_ON(b==0);
+ a *= 1000000;
+ do_div(a, b);
+ return a;
+}
+
+static inline u32 scaled_div32(u64 a, u32 b)
+{
+ u64 result = scaled_div(a, b);
+
+ if (result > UINT_MAX) {
+ DCCP_CRIT("Overflow: a(%llu)/b(%u) > ~0U",
+ (unsigned long long)a, b);
+ return UINT_MAX;
+ }
+ return result;
+}
extern u32 tfrc_calc_x(u16 s, u32 R, u32 p);
extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue);
diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c
index ddac2c511e2..90009fd77e1 100644
--- a/net/dccp/ccids/lib/tfrc_equation.c
+++ b/net/dccp/ccids/lib/tfrc_equation.c
@@ -13,7 +13,6 @@
*/
#include <linux/module.h>
-#include <asm/div64.h>
#include "../../dccp.h"
#include "tfrc.h"
@@ -616,15 +615,12 @@ static inline u32 tfrc_binsearch(u32 fval, u8 small)
* @R: RTT scaled by 1000000 (i.e., microseconds)
* @p: loss ratio estimate scaled by 1000000
* Returns X_calc in bytes per second (not scaled).
- *
- * Note: DO NOT alter this code unless you run test cases against it,
- * as the code has been optimized to stop underflow/overflow.
*/
u32 tfrc_calc_x(u16 s, u32 R, u32 p)
{
- int index;
+ u16 index;
u32 f;
- u64 tmp1, tmp2;
+ u64 result;
/* check against invalid parameters and divide-by-zero */
BUG_ON(p > 1000000); /* p must not exceed 100% */
@@ -650,15 +646,17 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p)
f = tfrc_calc_x_lookup[index][0];
}
- /* The following computes X = s/(R*f(p)) in bytes per second. Since f(p)
- * and R are both scaled by 1000000, we need to multiply by 1000000^2.
- * ==> DO NOT alter this unless you test against overflow on 32 bit */
- tmp1 = ((u64)s * 100000000);
- tmp2 = ((u64)R * (u64)f);
- do_div(tmp2, 10000);
- do_div(tmp1, tmp2);
-
- return (u32)tmp1;
+ /*
+ * Compute X = s/(R*f(p)) in bytes per second.
+ * Since f(p) and R are both scaled by 1000000, we need to multiply by
+ * 1000000^2. To avoid overflow, the result is computed in two stages.
+ * This works under almost all reasonable operational conditions, for a
+ * wide range of parameters. Yet, should some strange combination of
+ * parameters result in overflow, the use of scaled_div32 will catch
+ * this and return UINT_MAX - which is a logically adequate consequence.
+ */
+ result = scaled_div(s, R);
+ return scaled_div32(result, f);
}
EXPORT_SYMBOL_GPL(tfrc_calc_x);