summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstsp <stsp@openbsd.org>2017-01-28 16:01:36 +0000
committerstsp <stsp@openbsd.org>2017-01-28 16:01:36 +0000
commitd8e0f7e4d6c88da99b44119362fe09d34dadfbed (patch)
tree04eae71bdf414a4e963d25338951e6bd0562640e
parentBack out make(obj) hack: it doesn't solve the problem entirely and may (diff)
downloadwireguard-openbsd-d8e0f7e4d6c88da99b44119362fe09d34dadfbed.tar.xz
wireguard-openbsd-d8e0f7e4d6c88da99b44119362fe09d34dadfbed.zip
Make mira cope with out-of-range single frame error rate (SFER) values.
These are either due to driver bugs or rounding errors in fixed point math but can be dealt with gracefully and don't occur often (only one instance of this problem has been reported in the wild so far). Turn related panics into debug printfs. With 'ifconfig athn0 debug' the kernel now prints notifications about out-of-range SFER values in dmesg. Compile a kernel with 'option MIRA_DEBUG' to get a dump of driver stats in dmesg as well. This change should prevent an undesirable panic reported by Peter Kay, though it does not actually address the root cause of the problem. ok tb@
-rw-r--r--sys/net80211/ieee80211_mira.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/sys/net80211/ieee80211_mira.c b/sys/net80211/ieee80211_mira.c
index 0ca11234e33..1b261b04e15 100644
--- a/sys/net80211/ieee80211_mira.c
+++ b/sys/net80211/ieee80211_mira.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_mira.c,v 1.9 2017/01/28 11:57:19 stsp Exp $ */
+/* $OpenBSD: ieee80211_mira.c,v 1.10 2017/01/28 16:01:36 stsp Exp $ */
/*
* Copyright (c) 2016 Stefan Sperling <stsp@openbsd.org>
@@ -136,6 +136,17 @@ mira_fp_sprintf(uint64_t fp)
return buf;
}
+
+void
+mira_print_driver_stats(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni) {
+ DPRINTF(("%s driver stats:\n", ether_sprintf(ni->ni_macaddr)));
+ DPRINTF(("mn->frames = %u\n", mn->frames));
+ DPRINTF(("mn->retries = %u\n", mn->retries));
+ DPRINTF(("mn->txfail = %u\n", mn->txfail));
+ DPRINTF(("mn->ampdu_size = %u\n", mn->ampdu_size));
+ DPRINTF(("mn->agglen = %u\n", mn->agglen));
+}
#endif /* MIRA_DEBUG */
/*
@@ -428,12 +439,33 @@ ieee80211_mira_update_stats(struct ieee80211_mira_node *mn,
/* Compute Sub-Frame Error Rate (see section 2.2 in MiRA paper). */
sfer = (mn->frames * mn->retries + mn->txfail);
- if ((sfer >> MIRA_FP_SHIFT) != 0)
- panic("sfer overflow"); /* bug in wifi driver */
+ if ((sfer >> MIRA_FP_SHIFT) != 0) { /* bug in wifi driver */
+ if (ic->ic_if.if_flags & IFF_DEBUG) {
+#ifdef DIAGNOSTIC
+ printf("%s: mira sfer overflow\n",
+ ether_sprintf(ni->ni_macaddr));
+#endif
+#ifdef MIRA_DEBUG
+ mira_print_driver_stats(mn, ni);
+#endif
+ }
+ ieee80211_mira_probe_done(mn);
+ return;
+ }
sfer <<= MIRA_FP_SHIFT; /* convert to fixed-point */
sfer /= ((mn->retries + 1) * mn->frames);
- if (sfer > MIRA_FP_1)
- panic("sfer > 1"); /* bug in wifi driver */
+ if (sfer > MIRA_FP_1) { /* bug in wifi driver */
+ if (ic->ic_if.if_flags & IFF_DEBUG) {
+#ifdef DIAGNOSTIC
+ printf("%s: mira sfer > 1\n",
+ ether_sprintf(ni->ni_macaddr));
+#endif
+#ifdef MIRA_DEBUG
+ mira_print_driver_stats(mn, ni);
+#endif
+ }
+ sfer = MIRA_FP_1; /* round down */
+ }
/* Store current loss percentage SFER. */
g->loss = sfer * 100;
@@ -1004,13 +1036,10 @@ ieee80211_mira_choose(struct ieee80211_mira_node *mn, struct ieee80211com *ic,
if (mn->valid_rates == 0)
mn->valid_rates = ieee80211_mira_valid_rates(ic, ni);
- DPRINTFN(5, ("%s: driver stats:\n", __func__));
- DPRINTFN(5, ("mn->frames = %u\n", mn->frames));
- DPRINTFN(5, ("mn->retries = %u\n", mn->retries));
- DPRINTFN(5, ("mn->txfail = %u\n", mn->txfail));
- DPRINTFN(5, ("mn->ampdu_size = %u\n", mn->ampdu_size));
- DPRINTFN(5, ("mn->agglen = %u\n", mn->agglen));
-
+#ifdef MIRA_DEBUG
+ if (mira_debug >= 5)
+ mira_print_driver_stats(mn, ni);
+#endif
ieee80211_mira_update_stats(mn, ic, ni);
if (mn->probing) {