madwifi: clean up handling of various timings such as slot time, ack timeout, eifs...
authorFelix Fietkau <nbd@openwrt.org>
Fri, 8 May 2009 19:25:31 +0000 (19:25 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Fri, 8 May 2009 19:25:31 +0000 (19:25 +0000)
SVN-Revision: 15713

package/madwifi/Makefile
package/madwifi/files/lib/wifi/madwifi.sh
package/madwifi/patches/424-timing.patch [new file with mode: 0644]

index f143f94e6e7ad6787d124a11e37eff53c5850020..8db820e5aa5f9a086fd62357182ab34062795e60 100644 (file)
@@ -151,7 +151,7 @@ ifeq ($(findstring PCI,$(BUS)),PCI)
   MADWIFI_AUTOLOAD+= ath_pci
 endif
 
-MADWIFI_APPLETS:=80211stats athchans athctrl athkey athstats wlanconfig ath_info
+MADWIFI_APPLETS:=80211stats athchans athkey athstats wlanconfig ath_info
 ifdef CONFIG_MADWIFI_DEBUG
   MADWIFI_APPLETS += athdebug 80211debug
 endif
index a3cf4d75e16035d5013438535f96fd87ee0b14ce..1e5b0db4e9dd9df8144f8251452439e8754ce3db 100755 (executable)
@@ -219,9 +219,7 @@ enable_atheros() {
                [ -n "$antrx" ] && sysctl -w dev."$device".rxantenna="$antrx" >&-
                [ -n "$anttx" ] && sysctl -w dev."$device".txantenna="$anttx" >&-
                [ -n "$softled" ] && sysctl -w dev."$device".softled="$softled" >&-
-
-               config_get distance "$device" distance
-               [ -n "$distance" ] && athctrl -i "$device" -d "$distance" >&-
+               [ -n "$distance" ] && sysctl -w dev."$device".distance="$distance" >&-
 
                config_get rate "$vif" rate
                [ -n "$rate" ] && iwconfig "$ifname" rate "${rate%%.*}"
diff --git a/package/madwifi/patches/424-timing.patch b/package/madwifi/patches/424-timing.patch
new file mode 100644 (file)
index 0000000..47d08de
--- /dev/null
@@ -0,0 +1,730 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -382,6 +382,7 @@ static u_int32_t ath_set_clamped_maxtxpo
+ static void ath_poll_disable(struct net_device *dev);
+ static void ath_poll_enable(struct net_device *dev);
+ static void ath_fetch_idle_time(struct ath_softc *sc);
++static void ath_set_timing(struct ath_softc *sc);
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+@@ -1185,6 +1186,7 @@ ath_attach(u_int16_t devid, struct net_d
+       sc->sc_intmit = -1;
+       sc->sc_noise_immunity = -1;
+       sc->sc_ofdm_weak_det = -1;
++      sc->sc_coverage = 7; /* 2100 meters */
+       return 0;
+ bad3:
+@@ -2672,6 +2674,7 @@ ath_init(struct net_device *dev)
+        */
+       ath_chan_change(sc, ic->ic_curchan);
+       ath_set_ack_bitrate(sc, sc->sc_ackrate);
++      ath_set_timing(sc);
+       dev->flags |= IFF_RUNNING;              /* we are ready to go */
+       ieee80211_start_running(ic);            /* start all VAPs */
+ #ifdef ATH_TX99_DIAG
+@@ -4483,17 +4486,52 @@ ath_mode_init(struct net_device *dev)
+  * Set the slot time based on the current setting.
+  */
+ static void
+-ath_settiming(struct ath_softc *sc)
++ath_set_timing(struct ath_softc *sc)
+ {
++      struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+-      u_int offset = getTimingOffset(sc);
++      struct ath_timings *t = &sc->sc_timings;
++      u_int offset = 9;
++
++      t->sifs = 16;
++      if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
++              offset = 20;
++              if (ic->ic_flags & IEEE80211_F_SHSLOT)
++                      offset = 9;
++      } else if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) {
++              offset = 9;
++      }
++
++      if (IEEE80211_IS_CHAN_TURBO(ic->ic_curchan)) {
++              offset = 6;
++              t->sifs = 8;
++      } else if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan)) {
++              offset = 13;
++              t->sifs = 32;
++      } else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan)) {
++              offset = 21;
++              t->sifs = 64;
++      }
++
++      t->slot = offset + sc->sc_coverage;
++      t->ack = t->slot * 2 + 3;
++      t->cts = t->slot * 2 + 3;
+       if (sc->sc_slottimeconf > 0)
+-              ath_hal_setslottime(ah, offset + sc->sc_slottimeconf);
++              t->slot = sc->sc_slottimeconf;
+       if (sc->sc_acktimeconf > 0)
+-              ath_hal_setacktimeout(ah, 2 * offset + sc->sc_acktimeconf);
++              t->ack = sc->sc_acktimeconf;
+       if (sc->sc_ctstimeconf > 0)
+-              ath_hal_setctstimeout(ah, 2 * offset + sc->sc_ctstimeconf);
++              t->cts = sc->sc_ctstimeconf;
++
++      t->difs = 2 * t->sifs + t->slot;
++      t->eifs = t->sifs + t->difs + 3;
++
++      ath_hal_setslottime(ah, t->slot);
++      ath_hal_setacktimeout(ah, t->ack);
++      ath_hal_setctstimeout(ah, t->cts);
++      ath_hal_seteifstime(ah, t->eifs);
++
+       sc->sc_updateslot = OK;
+ }
+@@ -4515,7 +4553,7 @@ ath_updateslot(struct net_device *dev)
+       if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+               sc->sc_updateslot = UPDATE;
+       else if (dev->flags & IFF_RUNNING)
+-              ath_settiming(sc);
++              ath_set_timing(sc);
+ }
+ #ifdef ATH_SUPERG_DYNTURBO
+@@ -5359,7 +5397,7 @@ ath_beacon_send(struct ath_softc *sc, in
+               sc->sc_updateslot = COMMIT;     /* commit next beacon */
+               sc->sc_slotupdate = slot;
+       } else if ((sc->sc_updateslot == COMMIT) && (sc->sc_slotupdate == slot))
+-              ath_settiming(sc);              /* commit change to hardware */
++              ath_set_timing(sc);             /* commit change to hardware */
+       if (bfaddr != 0) {
+               /*
+@@ -9429,7 +9467,8 @@ ath_set_coverageclass(struct ieee80211co
+ {
+       struct ath_softc *sc = ic->ic_dev->priv;
+-      ath_hal_setcoverageclass(sc->sc_ah, ic->ic_coverageclass, 0);
++      sc->sc_coverage = ic->ic_coverageclass * 3;
++      ath_set_timing(sc);
+       return;
+ }
+@@ -10950,6 +10989,7 @@ enum {
+       ATH_OFDM_WEAK_DET       = 29,
+       ATH_CHANBW              = 30,
+       ATH_OUTDOOR             = 31,
++      ATH_DISTANCE    = 32,
+ };
+ /*
+@@ -11162,21 +11202,31 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+                                       sc->sc_slottimeconf = val;
+                               else
+                                       sc->sc_slottimeconf = 0;
+-                              ath_settiming(sc);
++                              ath_set_timing(sc);
+                               break;
+                       case ATH_ACKTIMEOUT:
+                               if (val > 0)
+                                       sc->sc_acktimeconf = val;
+                               else
+                                       sc->sc_acktimeconf = 0;
+-                              ath_settiming(sc);
++                              ath_set_timing(sc);
+                               break;
+                       case ATH_CTSTIMEOUT:
+                               if (val > 0)
+                                       sc->sc_ctstimeconf = val;
+                               else
+                                       sc->sc_ctstimeconf = 0;
+-                              ath_settiming(sc);
++                              ath_set_timing(sc);
++                              break;
++                      case ATH_DISTANCE:
++                              if (val > 0) {
++                                      sc->sc_coverage = ((val - 1) / 300) + 1;
++                                      ic->ic_coverageclass = ((sc->sc_coverage - 1) / 3) + 1;
++                              } else {
++                                      sc->sc_coverage = 0;
++                                      ic->ic_coverageclass = 0;
++                              }
++                              ath_set_timing(sc);
+                               break;
+                       case ATH_SOFTLED:
+                               if (val != sc->sc_softled) {
+@@ -11332,6 +11382,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_CHANBW:
+                       val = sc->sc_chanbw ?: 20;
+                       break;
++              case ATH_DISTANCE:
++                      val = sc->sc_coverage * 300;
++                      break;
+               case ATH_SLOTTIME:
+                       val = ath_hal_getslottime(ah);
+                       break;
+@@ -11453,6 +11506,12 @@ static const ctl_table ath_sysctl_templa
+         .extra2       = (void *)ATH_CTSTIMEOUT,
+       },
+       { .ctl_name     = CTL_AUTO,
++        .procname     = "distance",
++        .mode         = 0644,
++        .proc_handler = ath_sysctl_halparam,
++        .extra2       = (void *)ATH_DISTANCE,
++      },
++      { .ctl_name     = CTL_AUTO,
+         .procname     = "softled",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+--- a/ath/if_ath_hal.h
++++ b/ath/if_ath_hal.h
+@@ -284,6 +284,17 @@ static inline u_int ath_hal_getslottime(
+       return ret;
+ }
++static inline u_int ath_hal_geteifstime(struct ath_hal *ah)
++{
++      u_int ret;
++      ATH_HAL_LOCK_IRQ(ah->ah_sc);
++      ath_hal_set_function(__func__);
++      ret = ah->ah_getEifsTime(ah);
++      ath_hal_set_function(NULL);
++      ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
++      return ret;
++}
++
+ static inline void ath_hal_beaconinit(struct ath_hal *ah, u_int32_t nexttbtt,
+                                     u_int32_t intval)
+ {
+@@ -841,6 +852,17 @@ static inline HAL_BOOL ath_hal_setslotti
+       return ret;
+ }
++static inline HAL_BOOL ath_hal_seteifstime(struct ath_hal *ah, u_int a1)
++{
++      HAL_BOOL ret;
++      ATH_HAL_LOCK_IRQ(ah->ah_sc);
++      ath_hal_set_function(__func__);
++      ret = ah->ah_setEifsTime(ah, a1);
++      ath_hal_set_function(NULL);
++      ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
++      return ret;
++}
++
+ static inline void ath_hal_setledstate(struct ath_hal *ah, HAL_LED_STATE a1)
+ {
+       ATH_HAL_LOCK_IRQ(ah->ah_sc);
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -613,6 +613,15 @@ struct ath_rp {
+       int       rp_analyzed;
+ };
++struct ath_timings {
++      u_int   slot;
++      u_int   ack;
++      u_int   cts;
++      u_int   sifs;
++      u_int   difs;
++      u_int   eifs;
++};
++
+ struct ath_softc {
+       struct ieee80211com sc_ic;              /* NB: must be first */
+       struct net_device *sc_dev;
+@@ -838,6 +847,8 @@ struct ath_softc {
+                                                * detected radars */
+       u_int32_t sc_nexttbtt;
+       u_int64_t sc_last_tsf;
++      u_int sc_coverage;
++      struct ath_timings sc_timings;
+ };
+ typedef void (*ath_callback) (struct ath_softc *);
+@@ -945,49 +956,76 @@ int ar_device(int devid);
+         DEV_NAME(_v->iv_ic->ic_dev))
+ void ath_radar_detected(struct ath_softc *sc, const char* message);
+-static inline u_int getTimingOffset(struct ath_softc *sc)
+-{
+-      struct ieee80211com *ic = &sc->sc_ic;
+-      u_int usec = 9;
+-      if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
+-              usec = 20;
+-              if (ic->ic_flags & IEEE80211_F_SHSLOT)
+-                      usec = 9;
+-      } else if (IEEE80211_IS_CHAN_A(ic->ic_curchan))
+-              usec = 9;
+-
+-      if (IEEE80211_IS_CHAN_TURBO(ic->ic_curchan))
+-              usec = 6;
+-
+-      if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan))
+-              usec = 13;
+-      else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan))
+-              usec = 21;
+-      return usec;
+-}
+-static inline void ath_get_timings(struct ath_softc *sc, u_int *t_slot, u_int *t_sifs, u_int *t_difs)
+-{
+-      struct ieee80211_channel *c = sc->sc_ic.ic_curchan;
++#ifndef MIN
++#define MIN(a,b)        ((a) < (b) ? (a) : (b))
++#endif
++#ifndef MAX
++#define MAX(a,b)        ((a) > (b) ? (a) : (b))
++#endif
+-      *t_slot = getTimingOffset(sc) + sc->sc_slottimeconf;
+-      if (IEEE80211_IS_CHAN_HALF(c)) {
+-              *t_sifs = 32;
+-              *t_difs = 56;
+-      } else if (IEEE80211_IS_CHAN_QUARTER(c)) {
+-              *t_sifs = 64;
+-              *t_difs = 112;
+-      } else if (IEEE80211_IS_CHAN_TURBO(c)) {
+-              *t_sifs = 8;
+-              *t_difs = 28;
+-      } else {
+-              *t_sifs = 16;
+-              *t_difs = 28;
+-      }
++/* Calculate the transmit duration of a frame. */
++static inline unsigned
++calc_usecs_unicast_packet(struct ath_softc *sc, int length,
++              int rix, int short_retries, int long_retries)
++{
++              const HAL_RATE_TABLE *rt = sc->sc_currates;
++              struct ieee80211com *ic = &sc->sc_ic;
++              struct ath_timings *t = &sc->sc_timings;
++              unsigned int x = 0, tt = 0;
++              unsigned int cix = rt->info[rix].controlRate;
++              int rts = 0, cts = 0;
++              int cw = ATH_DEFAULT_CWMIN;
++
++              KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
++
++              if (!rt->info[rix].rateKbps) {
++                      printk(KERN_WARNING "rix %d (%d) bad ratekbps %d mode %u\n",
++                             rix, rt->info[rix].dot11Rate,
++                             rt->info[rix].rateKbps,
++                             sc->sc_curmode);
++                      return 0;
++              }
++
++              if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
++                      (rt->info[rix].phy == IEEE80211_T_OFDM)) {
++
++                      if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
++                              rts = 1;
++                      else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
++                              cts = 1;
++
++                      cix = rt->info[sc->sc_protrix].controlRate;
++              }
++
++              if ((rts || cts) && rt->info[cix].rateKbps) {
++                      int ctsrate = rt->info[cix].rateCode;
++                      int ctsduration = 0;
++
++                      ctsrate |= rt->info[cix].shortPreamble;
++                      if (rts)        /* SIFS + CTS */
++                              ctsduration += rt->info[cix].spAckDuration;
++
++                      ctsduration += ath_hal_computetxtime(sc->sc_ah,
++                                                           rt, length, rix, AH_TRUE);
++
++                      if (cts)        /* SIFS + ACK */
++                              ctsduration += rt->info[cix].spAckDuration;
++
++                      tt += (short_retries + 1) * ctsduration;
++              }
++              tt += t->difs;
++              tt += (long_retries + 1) * (t->sifs + rt->info[rix].spAckDuration);
++              tt += (long_retries + 1) * ath_hal_computetxtime(sc->sc_ah, rt, length,
++                                                      rix, AH_TRUE);
++              for (x = 0; x <= short_retries + long_retries; x++) {
++                      cw = MIN(ATH_DEFAULT_CWMAX, (cw + 1) * 2);
++                      tt += (t->slot * cw / 2);
++              }
++              return tt;
+ }
+-
+ struct ath_hw_detect {
+       const char *vendor_name;
+       const char *card_name;
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -170,85 +170,6 @@ rate_to_ndx(struct minstrel_node *sn, in
+               return -1;
+ }
+-/* Calculate the transmit duration of a frame. */
+-static unsigned
+-calc_usecs_unicast_packet(struct ath_softc *sc, int length,
+-              int rix, int short_retries, int long_retries)
+-{
+-              const HAL_RATE_TABLE *rt = sc->sc_currates;
+-              struct ieee80211com *ic = &sc->sc_ic;
+-              unsigned t_slot = 20;
+-              unsigned t_difs = 50;
+-              unsigned t_sifs = 10;
+-              unsigned int x = 0, tt = 0;
+-              unsigned int cix = rt->info[rix].controlRate;
+-              int rts = 0, cts = 0;
+-              int cw = ATH_DEFAULT_CWMIN;
+-
+-              KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+-
+-              if (!rt->info[rix].rateKbps) {
+-                      printk(KERN_WARNING "rix %d (%d) bad ratekbps %d mode %u\n",
+-                             rix, rt->info[rix].dot11Rate,
+-                             rt->info[rix].rateKbps,
+-                             sc->sc_curmode);
+-                      return 0;
+-              }
+-
+-              ath_get_timings(sc, &t_slot, &t_sifs, &t_difs);
+-              if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+-              (rt->info[rix].phy == IEEE80211_T_OFDM)) {
+-                      if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+-                              rts = 1;
+-                      else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+-                              cts = 1;
+-
+-                      cix = rt->info[sc->sc_protrix].controlRate;
+-              }
+-
+-#if 0
+-              if (length > ic->ic_rtsthreshold)
+-                      rts = 1;
+-#endif
+-
+-              if (rts || cts) {
+-                      int ctsrate = rt->info[cix].rateCode;
+-                      int ctsduration = 0;
+-
+-                      if (!rt->info[cix].rateKbps) {
+-#if 0
+-                              printk(KERN_WARNING "cix %d (%d) bad ratekbps %d mode %u\n",
+-                                     cix, rt->info[cix].dot11Rate,
+-                                     rt->info[cix].rateKbps,
+-                                     sc->sc_curmode);
+-#endif
+-                              return 0;
+-                      }
+-
+-
+-                      ctsrate |= rt->info[cix].shortPreamble;
+-                      if (rts)        /* SIFS + CTS */
+-                              ctsduration += rt->info[cix].spAckDuration;
+-
+-                      ctsduration += ath_hal_computetxtime(sc->sc_ah,
+-                                                           rt, length, rix, AH_TRUE);
+-
+-                      if (cts)        /* SIFS + ACK */
+-                              ctsduration += rt->info[cix].spAckDuration;
+-
+-                      tt += (short_retries + 1) * ctsduration;
+-              }
+-              tt += t_difs;
+-              tt += (long_retries + 1) * (t_sifs + rt->info[rix].spAckDuration);
+-              tt += (long_retries + 1) * ath_hal_computetxtime(sc->sc_ah, rt, length,
+-                                                      rix, AH_TRUE);
+-              for (x = 0; x <= short_retries + long_retries; x++) {
+-                      cw = MIN(ATH_DEFAULT_CWMAX, (cw + 1) * 2);
+-                      tt += (t_slot * cw / 2);
+-              }
+-              return tt;
+-}
+-
+ static void
+ ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
+ {
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -137,92 +137,6 @@ rate_to_ndx(struct sample_node *sn, int 
+       return -1;
+ }
+-/*
+- * Calculate the transmit duration of a frame.
+- */
+-static unsigned
+-calc_usecs_unicast_packet(struct ath_softc *sc, int length,
+-      int rix, int short_retries, int long_retries)
+-{
+-      const HAL_RATE_TABLE *rt = sc->sc_currates;
+-      int rts, cts;
+-
+-      unsigned t_slot;
+-      unsigned t_difs;
+-      unsigned t_sifs;
+-      struct ieee80211com *ic = &sc->sc_ic;
+-      unsigned int tt = 0;
+-      unsigned int x;
+-      unsigned int cw = ATH_DEFAULT_CWMIN;
+-      unsigned int cix = rt->info[rix].controlRate;
+-      KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+-
+-      if (!rt->info[rix].rateKbps) {
+-              printk(KERN_WARNING "rix %u (%u) bad ratekbps %u mode %u\n",
+-                     rix, rt->info[rix].dot11Rate,
+-                     rt->info[rix].rateKbps,
+-                     sc->sc_curmode);
+-
+-              return 0;
+-      }
+-
+-      cix = rt->info[rix].controlRate;
+-      /* 
+-       * XXX getting mac/phy level timings should be fixed for turbo
+-       * rates, and there is probably a way to get this from the
+-       * hal...
+-       */
+-      ath_get_timings(sc, &t_slot, &t_sifs, &t_difs);
+-      rts = cts = 0;
+-
+-      if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+-          rt->info[rix].phy == IEEE80211_T_OFDM) {
+-              if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+-                      rts = 1;
+-              else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+-                      cts = 1;
+-
+-              cix = rt->info[sc->sc_protrix].controlRate;
+-      }
+-
+-      if (0 /*length > ic->ic_rtsthreshold */)
+-              rts = 1;
+-
+-      if (rts || cts) {
+-              int ctsrate;
+-              int ctsduration = 0;
+-
+-              if (!rt->info[cix].rateKbps) {
+-                      printk(KERN_WARNING "cix %u (%u) bad ratekbps %u mode %u\n",
+-                             cix, rt->info[cix].dot11Rate,
+-                             rt->info[cix].rateKbps,
+-                             sc->sc_curmode);
+-                      return 0;
+-              }
+-
+-
+-              ctsrate = rt->info[cix].rateCode | rt->info[cix].shortPreamble;
+-              if (rts)                /* SIFS + CTS */
+-                      ctsduration += rt->info[cix].spAckDuration;
+-
+-              ctsduration += ath_hal_computetxtime(sc->sc_ah,
+-                                                   rt, length, rix, AH_TRUE);
+-
+-              if (cts)        /* SIFS + ACK */
+-                      ctsduration += rt->info[cix].spAckDuration;
+-
+-              tt += (short_retries + 1) * ctsduration;
+-      }
+-      tt += t_difs;
+-      tt += (long_retries+1)*(t_sifs + rt->info[rix].spAckDuration);
+-      tt += (long_retries+1)*ath_hal_computetxtime(sc->sc_ah, rt, length,
+-                                              rix, AH_TRUE);
+-      for (x = 0; x <= short_retries + long_retries; x++) {
+-              cw = MIN(ATH_DEFAULT_CWMAX, (cw + 1) * 2);
+-              tt += (t_slot * cw / 2);
+-      }
+-      return tt;
+-}
+ static void
+ ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2736,6 +2736,7 @@ ieee80211_ioctl_setparam(struct net_devi
+       case IEEE80211_PARAM_COVERAGE_CLASS:
+               if (value <= IEEE80211_COVERAGE_CLASS_MAX) {
+                       ic->ic_coverageclass = value;
++                      ic->ic_set_coverageclass(ic);
+                       if (IS_UP_AUTO(vap))
+                               ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
+                       retv = 0;
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -94,7 +94,7 @@
+ #define IEEE80211_BGSCAN_TRIGGER_INTVL 20 /* min trigger interval for thresh based bgscan (secs) */
+-#define IEEE80211_COVERAGE_CLASS_MAX  31      /* max coverage class */
++#define IEEE80211_COVERAGE_CLASS_MAX  255     /* max coverage class */
+ #define IEEE80211_REGCLASSIDS_MAX     10      /* max regclass id list */
+ #define       IEEE80211_PS_SLEEP      0x1             /* STA is in power saving mode */
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -50,7 +50,7 @@ all: compile
+ DEBUG = -DAR_DEBUG
+-ALLPROGS=     athstats 80211stats athkey athchans athctrl \
++ALLPROGS=     athstats 80211stats athkey athchans \
+       athdebug 80211debug wlanconfig ath_info
+ OBJS= $(patsubst %,%.o,$(ALLPROGS))
+--- a/tools/athctrl.c
++++ /dev/null
+@@ -1,133 +0,0 @@
+-/*-
+- * Copyright (c) 2002-2004 Gunter Burchardt, Local-Web AG
+- * All rights reserved.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- *    notice, this list of conditions and the following disclaimer,
+- *    without modification.
+- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+- *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+- *    redistribution must be conditioned upon including a substantially
+- *    similar Disclaimer requirement for further binary redistribution.
+- * 3. Neither the names of the above-listed copyright holders nor the names
+- *    of any contributors may be used to endorse or promote products derived
+- *    from this software without specific prior written permission.
+- *
+- * Alternatively, this software may be distributed under the terms of the
+- * GNU General Public License ("GPL") version 2 as published by the Free
+- * Software Foundation.
+- *
+- * NO WARRANTY
+- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+- * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+- * THE POSSIBILITY OF SUCH DAMAGES.
+- *
+- * $Id: athctrl.c 2394 2007-05-30 01:41:18Z mtaylor $
+- */
+-
+-/*
+- * Simple Atheros-specific tool to inspect and set atheros specific values
+- * athctrl [-i interface] [-d distance]
+- * (default interface is wifi0).  
+- */
+-#include <sys/types.h>
+-#include <sys/file.h>
+-
+-#include <getopt.h>
+-
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-#include <err.h>
+-
+-#include <net/if.h>
+-#include "do_multi.h"
+-
+-static int
+-setsysctrl(const char *dev, const char *control , u_long value)
+-{
+-      char buffer[256];
+-      FILE * fd;
+-
+-      snprintf(buffer, sizeof(buffer), "/proc/sys/dev/%s/%s", dev, control);
+-      fd = fopen(buffer, "w");
+-      if (fd != NULL) {
+-              fprintf(fd, "%li", value);
+-              fclose(fd);
+-      } else
+-              fprintf(stderr, "Could not open %s for writing!\n", buffer);
+-
+-      return 0;
+-}
+-
+-static void usage(void)
+-{
+-      fprintf(stderr,
+-          "Atheros driver control\n"
+-          "Copyright (c) 2002-2004 Gunter Burchardt, Local-Web AG\n"
+-          "\n"
+-          "usage: athctrl [-i interface] [-d distance]\n"
+-          "\n"
+-          "options:\n"
+-          "   -h   show this usage\n"
+-      "   -i   interface (default interface is wifi0)\n"
+-          "   -d   specify the maximum distance of a sta or the distance\n"
+-      "        of the master\n");
+-
+-      exit(1);
+-}
+-
+-int
+-CMD(athctrl)(int argc, char *argv[])
+-{
+-      char device[IFNAMSIZ + 1];
+-      int distance = -1;
+-      int c;
+-
+-      strncpy(device, "wifi0", sizeof (device));
+-
+-      for (;;) {
+-              c = getopt(argc, argv, "d:i:h");
+-              if (c < 0)
+-                      break;
+-              switch (c) {
+-              case 'h':
+-                      usage();
+-                      break;
+-              case 'd':
+-                      distance = atoi(optarg);
+-                      break;
+-              case 'i':
+-                      strncpy(device, optarg, sizeof (device));
+-                      break;
+-              default:
+-                      usage();
+-                      break;
+-              }
+-      }
+-
+-      if (distance >= 0) {
+-              int slottime = (distance / 300) + ((distance % 300) ? 1 : 0);
+-              int acktimeout = slottime * 2 + 3;
+-              int ctstimeout = slottime * 2 + 3;
+-
+-              printf("Setting distance on interface %s to %i meters\n",
+-                      device, distance);
+-              setsysctrl(device, "slottime", slottime);
+-              setsysctrl(device, "acktimeout", acktimeout);
+-              setsysctrl(device, "ctstimeout", ctstimeout);
+-      } else
+-              usage();
+-      return 0;
+-}
+--- a/tools/do_multi.c
++++ b/tools/do_multi.c
+@@ -18,8 +18,6 @@ main(int argc, char *argv[])
+       ret = a80211stats_init(argc, argv);
+     if(strcmp(progname, "athchans") == 0)
+       ret = athchans_init(argc, argv);
+-    if(strcmp(progname, "athctrl") == 0)
+-      ret =  athctrl_init(argc, argv);
+ #ifdef AR_DEBUG
+     if(strcmp(progname, "athdebug") == 0)
+       ret =  athdebug_init(argc, argv);
+--- a/tools/do_multi.h
++++ b/tools/do_multi.h
+@@ -2,7 +2,6 @@
+ int a80211debug_init(int argc, char *argv[]);
+ int a80211stats_init(int argc, char *argv[]);
+ int athchans_init(int argc, char *argv[]);
+-int athctrl_init(int argc, char *argv[]);
+ int athdebug_init(int argc, char *argv[]);
+ int athkey_init(int argc, char *argv[]);
+ int athstats_init(int argc, char *argv[]);