madwifi: merge fixes from trunk
authorFelix Fietkau <nbd@openwrt.org>
Sat, 17 Oct 2009 05:02:13 +0000 (05:02 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sat, 17 Oct 2009 05:02:13 +0000 (05:02 +0000)
SVN-Revision: 18054

package/madwifi/patches/421-channel_handling.patch
package/madwifi/patches/430-use_netdev_priv.patch
package/madwifi/patches/432-netdev_ops.patch
package/madwifi/patches/446-single_module.patch
package/madwifi/patches/447-sta_reconnect.patch
package/madwifi/patches/448-beacon_handling_fixes.patch
package/madwifi/patches/449-fix_txbuf_leak.patch
package/madwifi/patches/450-calibration.patch
package/madwifi/patches/451-ibss_race_fix.patch [new file with mode: 0644]
package/madwifi/patches/452-minstrel_no_timer.patch [new file with mode: 0644]

index e5302c1..8424321 100644 (file)
        }
        /* Initialize candidate channels to all available */
        memcpy(ic->ic_chan_active, ic->ic_chan_avail,
-@@ -311,11 +296,58 @@ ieee80211_ifattach(struct ieee80211com *
+@@ -311,11 +296,59 @@ ieee80211_ifattach(struct ieee80211com *
         * When 11g is supported, force the rate set to
         * include basic rates suitable for a mixed b/g bss.
         */
 +      if (init)
 +              return;
 +
++      ifmedia_removeall(&ic->ic_media);
 +      ieee80211_media_setup(ic, &ic->ic_media, ic->ic_caps, NULL, NULL);
 +      ieee80211com_media_status(ic->ic_dev, &imr);
 +      ifmedia_set(&ic->ic_media, imr.ifm_active);
        /* Setup initial channel settings */
        ic->ic_bsschan = IEEE80211_CHAN_ANYC;
        /* Arbitrarily pick the first channel */
-@@ -327,6 +359,7 @@ ieee80211_ifattach(struct ieee80211com *
+@@ -327,6 +360,7 @@ ieee80211_ifattach(struct ieee80211com *
        /* Enable WME by default, if we're capable. */
        if (ic->ic_caps & IEEE80211_C_WME)
                ic->ic_flags |= IEEE80211_F_WME;
        (void) ieee80211_setmode(ic, ic->ic_curmode);
  
        /* Store default beacon interval, as nec. */
-@@ -763,7 +796,8 @@ ieee80211_media_setup(struct ieee80211co
+@@ -763,7 +797,8 @@ ieee80211_media_setup(struct ieee80211co
        struct ieee80211_rateset allrates;
  
        /* Fill in media characteristics. */
        maxrate = 0;
        memset(&allrates, 0, sizeof(allrates));
  
-@@ -793,7 +827,7 @@ ieee80211_media_setup(struct ieee80211co
+@@ -793,7 +828,7 @@ ieee80211_media_setup(struct ieee80211co
                        ADD(media, IFM_AUTO, mopt | IFM_IEEE80211_WDS);
                if (mode == IEEE80211_MODE_AUTO)
                        continue;
  
                for (i = 0; i < rs->rs_nrates; i++) {
                        rate = rs->rs_rates[i];
-@@ -1207,7 +1241,7 @@ ieee80211_announce(struct ieee80211com *
+@@ -1207,7 +1242,7 @@ ieee80211_announce(struct ieee80211com *
                if ((ic->ic_modecaps & (1 << mode)) == 0)
                        continue;
                if_printf(dev, "%s rates: ", ieee80211_phymode_name[mode]);
                for (i = 0; i < rs->rs_nrates; i++) {
                        rate = rs->rs_rates[i];
                        mword = ieee80211_rate2media(ic, rate, mode);
-@@ -1417,7 +1451,7 @@ ieee80211com_media_change(struct net_dev
+@@ -1417,7 +1452,7 @@ ieee80211com_media_change(struct net_dev
                         * now so drivers have a consistent state.
                         */
                        KASSERT(vap->iv_bss != NULL, ("no bss node"));
                }
                error = -ENETRESET;
        }
-@@ -1435,7 +1469,7 @@ findrate(struct ieee80211com *ic, enum i
+@@ -1435,7 +1470,7 @@ findrate(struct ieee80211com *ic, enum i
  {
  #define       IEEERATE(_ic,_m,_i) \
        ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
        for (i = 0; i < nrates; i++)
                if (IEEERATE(ic, mode, i) == rate)
                        return i;
-@@ -1877,11 +1911,6 @@ ieee80211_build_countryie(struct ieee802
+@@ -1877,11 +1912,6 @@ ieee80211_build_countryie(struct ieee802
                        if (ieee80211_chan2mode(c) != curmode_noturbo)
                                continue;
  
                        if (*cur_runlen == 0) {
                                (*cur_runlen)++;
                                *cur_pow = c->ic_maxregpower;
-@@ -1915,7 +1944,7 @@ void
+@@ -1915,7 +1945,7 @@ void
  ieee80211_build_sc_ie(struct ieee80211com *ic)
  {
        struct ieee80211_ie_sc *ie = &ic->ic_sc_ie;
index ad2b6d4..642a9d2 100644 (file)
  #define skb_tail_pointer(_skb) ((_skb)->tail)
 --- a/net80211/ieee80211.c
 +++ b/net80211/ieee80211.c
-@@ -457,7 +457,7 @@ ieee80211_vap_setup(struct ieee80211com 
+@@ -458,7 +458,7 @@ ieee80211_vap_setup(struct ieee80211com 
  #define       IEEE80211_C_OPMODE \
        (IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \
         IEEE80211_C_MONITOR)
        struct net_device *parent = ic->ic_dev;
        int err;
  
-@@ -1354,7 +1354,7 @@ media_status(enum ieee80211_opmode opmod
+@@ -1355,7 +1355,7 @@ media_status(enum ieee80211_opmode opmod
  static void
  ieee80211com_media_status(struct net_device *dev, struct ifmediareq *imr)
  {
  
        imr->ifm_status = IFM_AVALID;
        if (!TAILQ_EMPTY(&ic->ic_vaps))
-@@ -1406,7 +1406,7 @@ media2mode(const struct ifmedia_entry *i
+@@ -1407,7 +1407,7 @@ media2mode(const struct ifmedia_entry *i
  static int
  ieee80211com_media_change(struct net_device *dev)
  {
        struct ieee80211vap *vap;
        struct ifmedia_entry *ime = ic->ic_media.ifm_cur;
        enum ieee80211_phymode newphymode;
-@@ -1510,7 +1510,7 @@ checkrate(struct ieee80211com *ic, enum 
+@@ -1511,7 +1511,7 @@ checkrate(struct ieee80211com *ic, enum 
  int
  ieee80211_media_change(struct net_device *dev)
  {
        struct ieee80211com *ic = vap->iv_ic;
        struct ifmedia_entry *ime = vap->iv_media.ifm_cur;
        enum ieee80211_phymode newmode;
-@@ -1544,7 +1544,7 @@ EXPORT_SYMBOL(ieee80211_media_change);
+@@ -1545,7 +1545,7 @@ EXPORT_SYMBOL(ieee80211_media_change);
  void
  ieee80211_media_status(struct net_device *dev, struct ifmediareq *imr)
  {
        struct ieee80211com *ic = vap->iv_ic;
        enum ieee80211_phymode mode;
        struct ieee80211_rateset *rs;
-@@ -1750,7 +1750,7 @@ EXPORT_SYMBOL(ieee80211_media2rate);
+@@ -1751,7 +1751,7 @@ EXPORT_SYMBOL(ieee80211_media2rate);
  static struct net_device_stats *
  ieee80211_getstats(struct net_device *dev)
  {
        struct net_device_stats *stats = &vap->iv_devstats;
  
        /* XXX: Total guess as to what to count where */
-@@ -1789,7 +1789,7 @@ ieee80211_change_mtu(struct net_device *
+@@ -1790,7 +1790,7 @@ ieee80211_change_mtu(struct net_device *
  static void
  ieee80211_set_multicast_list(struct net_device *dev)
  {
index 372000f..2e542bf 100644 (file)
@@ -69,7 +69,7 @@ http://madwifi-project.org/changeset/4005
        case NETDEV_CHANGENAME:
 --- a/net80211/ieee80211.c
 +++ b/net80211/ieee80211.c
-@@ -450,6 +450,18 @@ ieee80211_ifdetach(struct ieee80211com *
+@@ -451,6 +451,18 @@ ieee80211_ifdetach(struct ieee80211com *
  }
  EXPORT_SYMBOL(ieee80211_ifdetach);
  
@@ -88,7 +88,7 @@ http://madwifi-project.org/changeset/4005
  int
  ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev,
        const char *name, int opmode, int flags, struct ieee80211vap *master)
-@@ -470,16 +482,21 @@ ieee80211_vap_setup(struct ieee80211com 
+@@ -471,16 +483,21 @@ ieee80211_vap_setup(struct ieee80211com 
                } else
                        strncpy(dev->name, name, sizeof(dev->name));
        }
@@ -110,7 +110,7 @@ http://madwifi-project.org/changeset/4005
        dev->tx_queue_len = 0;                  /* NB: bypass queuing */
        dev->hard_header_len = parent->hard_header_len;
        /*
-@@ -1823,7 +1840,11 @@ ieee80211_set_multicast_list(struct net_
+@@ -1824,7 +1841,11 @@ ieee80211_set_multicast_list(struct net_
        IEEE80211_UNLOCK_IRQ(ic);
  
        /* XXX: Merge multicast list into parent device */
index ed02ae8..e546b05 100644 (file)
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/netdevice.h>
-@@ -2014,3 +2015,65 @@ ieee80211_build_sc_ie(struct ieee80211co
+@@ -2015,3 +2016,65 @@ ieee80211_build_sc_ie(struct ieee80211co
  int ath_debug_global = 0;
  EXPORT_SYMBOL(ath_debug_global);
  
index e6f019e..960d1b8 100644 (file)
        ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
 --- a/net80211/ieee80211_proto.c
 +++ b/net80211/ieee80211_proto.c
-@@ -1512,14 +1512,13 @@ __ieee80211_newstate(struct ieee80211vap
-                       if (arg != 0)
-                               ieee80211_scan_assoc_fail(ic,
-                                       vap->iv_bss->ni_macaddr, arg);
-+                      ieee80211_node_leave(vap->iv_bss);
-                       if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
-                               ieee80211_check_scan(vap,
-                                       IEEE80211_SCAN_ACTIVE,
-                                       IEEE80211_SCAN_FOREVER,
-                                       vap->iv_des_nssid, vap->iv_des_ssid,
-                                       NULL);
--                      else
--                              ieee80211_node_leave(vap->iv_bss);
+@@ -1602,7 +1602,6 @@ __ieee80211_newstate(struct ieee80211vap
+                               IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
                        break;
-               case IEEE80211_S_RUN:           /* beacon miss */
-                       if (vap->iv_opmode == IEEE80211_M_STA) {
+               case IEEE80211_S_RUN:
+-                      ieee80211_node_leave(ni);
+                       if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
+                               /* NB: caller specifies ASSOC/REASSOC by arg */
+                               IEEE80211_SEND_MGMT(ni, arg ?
index 7fe1251..3fa97e2 100644 (file)
@@ -1,26 +1,87 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -512,7 +512,7 @@ MODULE_PARM_DESC(ieee80211_debug, "Load-
+@@ -160,7 +160,7 @@ static int ath_check_beacon_done(struct 
+ static void ath_beacon_send(struct ath_softc *, int *, uint64_t hw_tsf);
+ static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
+ static void ath_beacon_free(struct ath_softc *);
+-static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
++static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *, int);
+ static void ath_hw_beacon_stop(struct ath_softc *sc);
+ static int ath_desc_alloc(struct ath_softc *);
+ static void ath_desc_free(struct ath_softc *);
+@@ -387,13 +387,11 @@ static void ath_set_timing(struct ath_so
+ /* calibrate every 30 secs in steady state but check every second at first. */
+ static int ath_calinterval = ATH_SHORT_CALINTERVAL;
+ static int ath_xchanmode = AH_TRUE;           /* enable extended channels */
+-static int ath_maxvaps = ATH_MAXVAPS_DEFAULT;   /* set default maximum vaps */
+ static int bstuck_thresh = BSTUCK_THRESH;       /* Stuck beacon count required for reset */
+ static char *autocreate = NULL;
+ static char *ratectl = DEF_RATE_CTL;
+ static int rfkill = 0;
+ static int tpc = 1;
+-static int maxvaps = -1;
+ static int xchanmode = -1;
+ #include "ath_wprobe.c"
+ static int beacon_cal = 1;
+@@ -432,7 +430,6 @@ static struct notifier_block ath_event_b
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(beacon_cal, "i");
+-MODULE_PARM(maxvaps, "i");
+ MODULE_PARM(xchanmode, "i");
+ MODULE_PARM(rfkill, "i");
+ #ifdef ATH_CAP_TPC
+@@ -444,7 +441,6 @@ MODULE_PARM(ratectl, "s");
+ #else
+ #include <linux/moduleparam.h>
+ module_param(beacon_cal, int, 0600);
+-module_param(maxvaps, int, 0600);
+ module_param(xchanmode, int, 0600);
+ module_param(rfkill, int, 0600);
+ #ifdef ATH_CAP_TPC
+@@ -454,7 +450,6 @@ module_param(bstuck_thresh, int, 0600);
+ module_param(autocreate, charp, 0600);
+ module_param(ratectl, charp, 0600);
+ #endif
+-MODULE_PARM_DESC(maxvaps, "Maximum VAPs");
+ MODULE_PARM_DESC(xchanmode, "Enable/disable extended channel mode");
+ MODULE_PARM_DESC(rfkill, "Enable/disable RFKILL capability");
+ #ifdef ATH_CAP_TPC
+@@ -512,7 +507,7 @@ MODULE_PARM_DESC(ieee80211_debug, "Load-
   * and use the higher bits as the index of the VAP.
   */
  #define ATH_SET_VAP_BSSID_MASK(bssid_mask)                            \
 -      ((bssid_mask)[0] &= ~(((ath_maxvaps-1) << 2) | 0x02))
-+      ((bssid_mask)[0] &= ~(((ATH_MAXVAPS_MAX-1) << 2) | 0x02))
++      ((bssid_mask)[0] &= ~(((ATH_MAXVAPS_BCN-1) << 2) | 0x02))
  #define ATH_GET_VAP_ID(bssid)                   ((bssid)[0] >> 2)
  #define ATH_SET_VAP_BSSID(bssid, id)                                  \
                do {                                                    \
-@@ -604,8 +604,8 @@ ath_attach(u_int16_t devid, struct net_d
+@@ -604,8 +599,8 @@ ath_attach(u_int16_t devid, struct net_d
  
        /* Allocate space for dynamically determined maximum VAP count */
        sc->sc_bslot = 
 -              kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL);
 -      memset(sc->sc_bslot, 0, ath_maxvaps * sizeof(struct ieee80211vap*));
-+              kmalloc(ATH_MAXVAPS_MAX * sizeof(struct ieee80211vap*), GFP_KERNEL);
-+      memset(sc->sc_bslot, 0, ATH_MAXVAPS_MAX * sizeof(struct ieee80211vap*));
++              kmalloc(ATH_MAXVAPS_BCN * sizeof(struct ieee80211vap*), GFP_KERNEL);
++      memset(sc->sc_bslot, 0, ATH_MAXVAPS_BCN * sizeof(struct ieee80211vap*));
  
        /*
         * Cache line size is used to size and align various
-@@ -1349,11 +1349,8 @@ ath_vap_create(struct ieee80211com *ic, 
+@@ -694,13 +689,6 @@ ath_attach(u_int16_t devid, struct net_d
+       for (i = 0; i < sc->sc_keymax; i++)
+               ath_hal_keyreset(ah, i);
+-      if (maxvaps != -1) {
+-              ath_maxvaps = maxvaps;
+-              if (ath_maxvaps < ATH_MAXVAPS_MIN)
+-                      ath_maxvaps = ATH_MAXVAPS_MIN;
+-              else if (ath_maxvaps > ATH_MAXVAPS_MAX)
+-                      ath_maxvaps = ATH_MAXVAPS_MAX;
+-      }
+       if (xchanmode != -1)
+               ath_xchanmode = xchanmode;
+       error = ath_getchannels(dev);
+@@ -1349,12 +1337,6 @@ ath_vap_create(struct ieee80211com *ic, 
                return NULL;
        }
  
 -                              sc->sc_nvaps);
 -              return NULL;
 -      }
-+      if ((sc->sc_nvaps >= ath_maxvaps) && (ath_maxvaps < ATH_MAXVAPS_MAX))
-+              ath_maxvaps++;
+-
        dev = alloc_etherdev(sizeof(struct ath_vap) + sc->sc_rc->arc_vap_space);
        if (dev == NULL) {
-@@ -1451,11 +1448,11 @@ ath_vap_create(struct ieee80211com *ic, 
+               /* XXX msg */
+@@ -1424,7 +1406,7 @@ ath_vap_create(struct ieee80211com *ic, 
+               TAILQ_FOREACH(v, &ic->ic_vaps, iv_next)
+                       id_mask |= (1 << ATH_GET_VAP_ID(v->iv_myaddr));
+-              for (id = 0; id < ath_maxvaps; id++) {
++              for (id = 0; id < ATH_MAXVAPS_BCN; id++) {
+                       /* get the first available slot */
+                       if ((id_mask & (1 << id)) == 0) {
+                               ATH_SET_VAP_BSSID(vap->iv_myaddr, id);
+@@ -1451,11 +1433,11 @@ ath_vap_create(struct ieee80211com *ic, 
                /* Assign the VAP to a beacon xmit slot.  As
                 * above, this cannot fail to find one. */
                avp->av_bslot = 0;
 -              for (slot = 0; slot < ath_maxvaps; slot++)
-+              for (slot = 0; slot < ATH_MAXVAPS_MAX; slot++)
++              for (slot = 0; slot < ATH_MAXVAPS_BCN; slot++)
                        if (sc->sc_bslot[slot] == NULL) {
                                /* XXX: Hack, space out slots to better
                                 * deal with misses. */
 -                              if (slot + 1 < ath_maxvaps &&
-+                              if (slot + 1 < ATH_MAXVAPS_DEFAULT &&
++                              if (slot + 1 < ATH_MAXVAPS_BCN &&
                                    sc->sc_bslot[slot+1] == NULL) {
                                        avp->av_bslot = slot + 1;
                                        break;
-@@ -1463,11 +1460,16 @@ ath_vap_create(struct ieee80211com *ic, 
+@@ -1463,8 +1445,11 @@ ath_vap_create(struct ieee80211com *ic, 
                                avp->av_bslot = slot;
                                /* NB: keep looking for a double slot */
                        }
 -              KASSERT(sc->sc_bslot[avp->av_bslot] == NULL,
 -                      ("beacon slot %u not empty?", avp->av_bslot));
-+
-+              /* No beacon slot found? */
 +              if (sc->sc_bslot[avp->av_bslot]) {
 +                      free_netdev(dev);
 +                      return NULL;
 +              }
++
                sc->sc_bslot[avp->av_bslot] = vap;
                sc->sc_nbcnvaps++;
  
-+#if 0
-               if ((opmode == IEEE80211_M_HOSTAP) && (sc->sc_hastsfadd)) {
-                       /*
-                        * Multiple VAPs are to transmit beacons and we
-@@ -1485,6 +1487,9 @@ ath_vap_create(struct ieee80211com *ic, 
-                               sc->sc_stagbeacons = 1;
-                       }
+@@ -1475,15 +1460,7 @@ ath_vap_create(struct ieee80211com *ic, 
+                        * of staggered beacons.
+                        */
+                       /* XXX check for beacon interval too small */
+-                      if (ath_maxvaps > 4) {
+-                              DPRINTF(sc, ATH_DEBUG_BEACON, 
+-                                              "Staggered beacons are not "
+-                                              "possible with maxvaps set "
+-                                              "to %d.\n", ath_maxvaps);
+-                              sc->sc_stagbeacons = 0;
+-                      } else {
+-                              sc->sc_stagbeacons = 1;
+-                      }
++                      sc->sc_stagbeacons = 1;
                }
-+#else
-+              sc->sc_stagbeacons = sc->sc_hastsfadd;
-+#endif
                DPRINTF(sc, ATH_DEBUG_BEACON, "sc->sc_stagbeacons %sabled\n", 
                                (sc->sc_stagbeacons ? "en" : "dis"));
+@@ -1553,7 +1530,7 @@ ath_vap_create(struct ieee80211com *ic, 
+               if (ath_startrecv(sc) != 0)     /* restart recv */
+                       EPRINTF(sc, "Unable to start receive logic.\n");
+               if (sc->sc_beacons)
+-                      ath_beacon_config(sc, NULL);    /* restart beacons */
++                      ath_beacon_config(sc, NULL, 0); /* restart beacons */
+               ath_hal_intrset(ah, sc->sc_imask);
        }
-@@ -4968,7 +4973,7 @@ ath_beacon_alloc_internal(struct ath_sof
+@@ -1681,7 +1658,7 @@ ath_vap_delete(struct ieee80211vap *vap)
+               if (ath_startrecv(sc) != 0)             /* restart recv. */
+                       EPRINTF(sc, "Unable to start receive logic.\n");
+               if (sc->sc_beacons)
+-                      ath_beacon_config(sc, NULL);    /* restart beacons */
++                      ath_beacon_config(sc, NULL, 0); /* restart beacons */
+               ath_hal_intrset(ah, sc->sc_imask);
+       }
+ }
+@@ -3066,7 +3043,7 @@ ath_reset(struct net_device *dev)
+        */
+       ath_chan_change(sc, c);
+       if (sc->sc_beacons)
+-              ath_beacon_config(sc, NULL);    /* restart beacons */
++              ath_beacon_config(sc, NULL, 1); /* restart beacons */
+       ath_hal_intrset(ah, sc->sc_imask);
+       ath_set_ack_bitrate(sc, sc->sc_ackrate);
+       netif_wake_queue(dev);          /* restart xmit */
+@@ -4763,7 +4740,7 @@ ath_check_beacon_done(struct ath_softc *
+       /*
+        * check if the last beacon went out with the mode change flag set.
+        */
+-      for (slot = 0; slot < ath_maxvaps; slot++) {
++      for (slot = 0; slot < ATH_MAXVAPS_BCN; slot++) {
+               if (sc->sc_bslot[slot]) {
+                       vap = sc->sc_bslot[slot];
+                       break;
+@@ -4968,7 +4945,7 @@ ath_beacon_alloc_internal(struct ath_sof
                 * has a timestamp in one beacon interval while the
                 * others get a timestamp aligned to the next interval.
                 */
 -              tuadjust = (ni->ni_intval * (ath_maxvaps - avp->av_bslot)) / ath_maxvaps;
-+              tuadjust = (ni->ni_intval * (ATH_MAXVAPS_DEFAULT - avp->av_bslot)) / ATH_MAXVAPS_DEFAULT;
++              tuadjust = (ni->ni_intval * (ATH_MAXVAPS_BCN - avp->av_bslot)) / ATH_MAXVAPS_BCN;
                tsfadjust = cpu_to_le64(tuadjust << 10);        /* TU->TSF */
  
                DPRINTF(sc, ATH_DEBUG_BEACON,
-@@ -5358,21 +5363,40 @@ ath_beacon_send(struct ath_softc *sc, in
-        */
-       if (sc->sc_stagbeacons) {               /* staggered beacons */
-               struct ieee80211com *ic = &sc->sc_ic;
-+              u_int32_t *bflink = NULL;
+@@ -5361,8 +5338,8 @@ ath_beacon_send(struct ath_softc *sc, in
                u_int32_t tsftu;
  
                tsftu = hw_tsf >> 10; /* NB: 64 -> 32: See note far above. */
 -              slot = ((tsftu % ic->ic_lintval) * ath_maxvaps) / ic->ic_lintval;
 -              vap = sc->sc_bslot[(slot + 1) % ath_maxvaps];
-+              slot = ((tsftu % ic->ic_lintval) * ATH_MAXVAPS_DEFAULT) / ic->ic_lintval;
++              slot = ((tsftu % ic->ic_lintval) * ATH_MAXVAPS_BCN) / ic->ic_lintval;
++              vap = sc->sc_bslot[(slot + 1) % ATH_MAXVAPS_BCN];
                DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
                        "Slot %d [tsf %llu tsftu %llu intval %u] vap %p\n",
                        slot, (unsigned long long)hw_tsf, 
-                       (unsigned long long)tsftu, ic->ic_lintval, vap);
-               bfaddr = 0;
--              if (vap != NULL) {
-+              while (slot < ATH_MAXVAPS_MAX) {
-+                      vap = sc->sc_bslot[slot];
-+                      if (vap == NULL)
-+                              goto next;
-+
-                       bf = ath_beacon_generate(sc, vap, needmark);
--                      if (bf != NULL)
-+                      if (bf == NULL)
-+                              break;
-+
-+                      if (bflink != NULL)
-+#ifdef AH_NEED_DESC_SWAP
-+                              *bflink = cpu_to_le32(bf->bf_daddr);
-+#else
-+                              *bflink = bf->bf_daddr;
-+#endif
-+                      else
-                               bfaddr = bf->bf_daddr;
-+
-+                      bflink = &bf->bf_desc->ds_link;
-+next:
-+                      slot += ATH_MAXVAPS_DEFAULT;
-               }
-+              if (bflink != NULL)
-+                      *bflink = 0;            /* link of last frame */
-       } else {                                /* burst'd beacons */
+@@ -5377,7 +5354,7 @@ ath_beacon_send(struct ath_softc *sc, in
                u_int32_t *bflink = NULL;
  
-@@ -5567,7 +5591,7 @@ ath_beacon_config(struct ath_softc *sc, 
+               /* XXX: rotate/randomize order? */
+-              for (slot = 0; slot < ath_maxvaps; slot++) {
++              for (slot = 0; slot < ATH_MAXVAPS_BCN; slot++) {
+                       if ((vap = sc->sc_bslot[slot]) != NULL) {
+                               if ((bf = ath_beacon_generate(
+                                               sc, vap, 
+@@ -5418,7 +5395,7 @@ ath_beacon_send(struct ath_softc *sc, in
+        *     again.  If we miss a beacon for that slot then we'll be
+        *     slow to transition but we'll be sure at least one beacon
+        *     interval has passed.  When bursting slot is always left
+-       *     set to ath_maxvaps so this check is a no-op.
++       *     set to ATH_MAXVAPS_BCN so this check is a no-op.
+        */
+       /* XXX locking */
+       if (sc->sc_updateslot == UPDATE) {
+@@ -5526,7 +5503,7 @@ ath_beacon_free(struct ath_softc *sc)
+  * (2^(32 + 10 - 1) - 1)us is a really long time.
+  */
+ static void
+-ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
++ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap, int reset)
+ {
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ath_hal *ah = sc->sc_ah;
+@@ -5553,7 +5530,7 @@ ath_beacon_config(struct ath_softc *sc, 
+       /* We should reset hw TSF only once, so we increment
+        * ni_tstamp.tsf to avoid resetting the hw TSF multiple
+        * times */
+-      if (tsf == 0) {
++      if (tsf == 0 || reset) {
+               reset_tsf = 1;
+               ni->ni_tstamp.tsf = cpu_to_le64(1);
+       }
+@@ -5567,7 +5544,7 @@ ath_beacon_config(struct ath_softc *sc, 
                /* NB: the beacon interval is kept internally in TUs */
                intval = ic->ic_lintval & HAL_BEACON_PERIOD;
                if (sc->sc_stagbeacons)
 -                      intval /= ath_maxvaps;  /* for staggered beacons */
-+                      intval /= ATH_MAXVAPS_DEFAULT;  /* for staggered beacons */
++                      intval /= ATH_MAXVAPS_BCN;      /* for staggered beacons */
                if ((sc->sc_nostabeacons) &&
                    (vap->iv_opmode == IEEE80211_M_HOSTAP))
                        reset_tsf = 1;
-@@ -5889,7 +5913,7 @@ ath_desc_alloc(struct ath_softc *sc)
+@@ -5583,31 +5560,24 @@ ath_beacon_config(struct ath_softc *sc, 
+                * time */
+               nexttbtt = intval;
+       } else if (intval) {    /* NB: can be 0 for monitor mode */
+-              if (tsf == 1) {
+-                      /* We have not received any beacons or probe
+-                       * responses. Since a beacon should be sent
+-                       * every 'intval' ms, we compute the next
+-                       * beacon timestamp using the hardware TSF. We
+-                       * ensure that it is at least FUDGE TUs ahead
+-                       * of the current TSF. Otherwise, we use the
+-                       * next beacon timestamp again */
+-                      nexttbtt = roundup(hw_tsftu + FUDGE, intval);
+-              } 
+-              else if (ic->ic_opmode == IEEE80211_M_IBSS) {
+-                      if (tsf > hw_tsf) {
+-                              /* We received a beacon, but the HW TSF has
+-                               * not been updated (otherwise hw_tsf > tsf)
+-                               * We cannot use the hardware TSF, so we
+-                               * wait to synchronize beacons again. */
+-                              sc->sc_syncbeacon = 1;
+-                              goto ath_beacon_config_debug;
+-                      } else {
+-                              /* Normal case: we received a beacon to which
+-                               * we have synchronized. Make sure that nexttbtt
+-                               * is at least FUDGE TU ahead of hw_tsf */
+-                              nexttbtt = tsftu + roundup(hw_tsftu + FUDGE - 
+-                                              tsftu, intval);
+-                      }
++              if ((tsf > hw_tsf) && (ic->ic_opmode == IEEE80211_M_IBSS)) {
++                      /* We received a beacon, but the HW TSF has
++                       * not been updated (otherwise hw_tsf > tsf)
++                       * We cannot use the hardware TSF, so we
++                       * wait to synchronize beacons again. */
++                      sc->sc_syncbeacon = 1;
++                      goto ath_beacon_config_debug;
++              } else if ((tsftu + FUDGE) > hw_tsftu) {
++                      if (tsftu > hw_tsftu + 2 * intval)
++                              nexttbtt = roundup(hw_tsftu + FUDGE, intval);
++                      else
++                              nexttbtt = tsftu;
++              } else {
++                      /* Normal case: we received a beacon to which
++                       * we have synchronized. Make sure that nexttbtt
++                       * is at least FUDGE TU ahead of hw_tsf */
++                      nexttbtt = tsftu + roundup(hw_tsftu + FUDGE -
++                                      tsftu, intval);
+               }
+       }
+@@ -5730,9 +5700,6 @@ ath_beacon_config(struct ath_softc *sc, 
+               ath_beacon_dturbo_config(vap, intval &
+                               ~(HAL_BEACON_RESET_TSF | HAL_BEACON_ENA));
+ #endif
+-              if ((nexttbtt & HAL_BEACON_PERIOD) - (ath_hal_gettsf32(ah) >> 10)
+-                              <= ath_hal_sw_beacon_response_time)
+-                      nexttbtt += intval;
+               sc->sc_nexttbtt = nexttbtt;
+               /* stop beacons before reconfiguring the timers to avoid race
+@@ -5889,7 +5856,7 @@ ath_desc_alloc(struct ath_softc *sc)
  
        /* XXX allocate beacon state together with VAP */
        error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
 -                      "beacon", ath_maxvaps, 1);
-+                      "beacon", ATH_MAXVAPS_MAX, 1);
++                      "beacon", ATH_MAXVAPS_BCN, 1);
        if (error != 0) {
                ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf,
                        BUS_DMA_TODEVICE);
+@@ -6680,7 +6647,7 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                       /* Resync beacon timers using the tsf of the
+                        * beacon frame we just received. */
+                       vap->iv_flags_ext &= ~IEEE80211_FEXT_APPIE_UPDATE;
+-                      ath_beacon_config(sc, vap);
++                      ath_beacon_config(sc, vap, 0);
+                       DPRINTF(sc, ATH_DEBUG_BEACON, 
+                               "Updated beacon timers\n");
+               }
+@@ -9359,7 +9326,7 @@ ath_chan_set(struct ath_softc *sc, struc
+                * HW seems to turn off beacons during turbo mode switch.
+                */
+               if (sc->sc_beacons && !sc->sc_dfs_cac)
+-                      ath_beacon_config(sc, NULL);
++                      ath_beacon_config(sc, NULL, 0);
+               /*
+                * Re-enable interrupts.
+                */
+@@ -9813,7 +9780,7 @@ ath_newstate(struct ieee80211vap *vap, e
+                                       ATH_DEBUG_BEACON_PROC, 
+                               "Beacons reconfigured by %p[%s]!\n",
+                               vap, vap->iv_nickname);
+-                      ath_beacon_config(sc, vap);
++                      ath_beacon_config(sc, vap, 1);
+                       sc->sc_beacons = 1;
+               }
+       } else {
+@@ -9948,9 +9915,6 @@ ath_dfs_cac_completed(unsigned long data
+               }
+               netif_wake_queue(dev);
+               ath_reset(dev);
+-              if (sc->sc_beacons) {
+-                      ath_beacon_config(sc, NULL);
+-              }
+               dev->watchdog_timeo = 5 * HZ; /* restore normal timeout */
+       } else {
+               do_gettimeofday(&tv);
+@@ -11473,9 +11437,6 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+               case ATH_OUTDOOR:
+                       val = ic->ic_country_outdoor;
+                       break;
+-              case ATH_MAXVAPS:
+-                      val = ath_maxvaps;
+-                      break;
+               case ATH_REGDOMAIN:
+                       ath_hal_getregdomain(ah, &val);
+                       break;
+@@ -11606,12 +11567,6 @@ static const ctl_table ath_sysctl_templa
+         .extra2       = (void *)ATH_OUTDOOR,
+       },
+       { .ctl_name     = CTL_AUTO,
+-        .procname     = "maxvaps",
+-        .mode         = 0444,
+-        .proc_handler = ath_sysctl_halparam,
+-        .extra2       = (void *)ATH_MAXVAPS,
+-      },
+-      { .ctl_name     = CTL_AUTO,
+         .procname     = "regdomain",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+@@ -11928,13 +11883,6 @@ static ctl_table ath_static_sysctls[] = 
+       },
+ #endif
+       { .ctl_name     = CTL_AUTO,
+-        .procname     = "maxvaps",
+-        .mode         = 0444,
+-        .data         = &ath_maxvaps,
+-        .maxlen       = sizeof(ath_maxvaps),
+-        .proc_handler = proc_dointvec
+-      },
+-      { .ctl_name     = CTL_AUTO,
+         .procname     = "xchanmode",
+         .mode         = 0444,
+         .data         = &ath_xchanmode,
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -211,9 +211,7 @@ static inline struct net_device *_alloc_
+ #define       ATH_RXBUF       40              /* number of RX buffers */
+ #define       ATH_TXBUF       200             /* number of TX buffers */
+-#define ATH_MAXVAPS_MIN       2       /* minimum number of beacon buffers */
+-#define ATH_MAXVAPS_MAX       64      /* maximum number of beacon buffers */
+-#define ATH_MAXVAPS_DEFAULT   4       /* default number of beacon buffers */
++#define ATH_MAXVAPS_BCN               4       /* maximum number of beacon buffers */
+ /* free buffer threshold to restart net dev */
+ #define       ATH_TXBUF_FREE_THRESHOLD  (ATH_TXBUF / 20)
index 9fd5ecb..31f2fef 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -3725,6 +3725,7 @@ ff_bypass:
+@@ -3697,6 +3697,7 @@ ff_bypass:
         */
        skb = ieee80211_encap(ni, skb, &framecnt);
        if (skb == NULL) {
index 76ff7a7..8739790 100644 (file)
@@ -1,30 +1,30 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -396,7 +396,6 @@ static int tpc = 1;
- static int maxvaps = -1;
+@@ -394,7 +394,6 @@ static int rfkill = 0;
+ static int tpc = 1;
  static int xchanmode = -1;
  #include "ath_wprobe.c"
 -static int beacon_cal = 1;
  
  static const struct ath_hw_detect generic_hw_info = {
        .vendor_name = "Unknown",
-@@ -431,7 +430,6 @@ static struct notifier_block ath_event_b
+@@ -429,7 +428,6 @@ static struct notifier_block ath_event_b
  };
  
  #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
 -MODULE_PARM(beacon_cal, "i");
- MODULE_PARM(maxvaps, "i");
  MODULE_PARM(xchanmode, "i");
  MODULE_PARM(rfkill, "i");
-@@ -443,7 +441,6 @@ MODULE_PARM(autocreate, "s");
+ #ifdef ATH_CAP_TPC
+@@ -440,7 +438,6 @@ MODULE_PARM(autocreate, "s");
  MODULE_PARM(ratectl, "s");
  #else
  #include <linux/moduleparam.h>
 -module_param(beacon_cal, int, 0600);
- module_param(maxvaps, int, 0600);
  module_param(xchanmode, int, 0600);
  module_param(rfkill, int, 0600);
-@@ -837,6 +834,7 @@ ath_attach(u_int16_t devid, struct net_d
+ #ifdef ATH_CAP_TPC
+@@ -825,6 +822,7 @@ ath_attach(u_int16_t devid, struct net_d
                error = EIO;
                goto bad2;
        }
@@ -32,7 +32,7 @@
        init_timer(&sc->sc_cal_ch);
        sc->sc_cal_ch.function = ath_calibrate;
        sc->sc_cal_ch.data = (unsigned long) dev;
-@@ -2765,8 +2763,7 @@ ath_stop_locked(struct net_device *dev)
+@@ -2737,8 +2735,7 @@ ath_stop_locked(struct net_device *dev)
                }
                if (!sc->sc_invalid) {
                        del_timer_sync(&sc->sc_dfs_cac_timer);
@@ -42,7 +42,7 @@
                }
                ath_draintxq(sc);
                if (!sc->sc_invalid) {
-@@ -2791,10 +2788,9 @@ static void ath_set_beacon_cal(struct at
+@@ -2763,10 +2760,9 @@ static void ath_set_beacon_cal(struct at
        if (val) {
                del_timer_sync(&sc->sc_cal_ch);
        } else {
@@ -55,7 +55,7 @@
  }
  
  /*
-@@ -3036,7 +3032,7 @@ ath_reset(struct net_device *dev)
+@@ -3008,7 +3004,7 @@ ath_reset(struct net_device *dev)
         * XXX: starting the calibration too early seems to lead to
         * problems with the beacons.
         */
@@ -64,7 +64,7 @@
  
        /*
         * Convert to a HAL channel description with the flags
-@@ -5477,10 +5473,9 @@ next:
+@@ -5430,10 +5426,9 @@ ath_beacon_send(struct ath_softc *sc, in
                        "Invoking ath_hal_txstart with sc_bhalq: %d\n",
                        sc->sc_bhalq);
                ath_hal_txstart(ah, sc->sc_bhalq);
@@ -78,7 +78,7 @@
  
                sc->sc_stats.ast_be_xmit++;             /* XXX per-VAP? */
        }
-@@ -9161,6 +9156,7 @@ ath_startrecv(struct ath_softc *sc)
+@@ -9104,6 +9099,7 @@ ath_startrecv(struct ath_softc *sc)
                dev->mtu, sc->sc_cachelsz, sc->sc_rxbufsize);
  
        sc->sc_rxlink = NULL;
@@ -86,7 +86,7 @@
        STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
                int error = ath_rxbuf_init(sc, bf);
                ATH_RXBUF_RESET(bf);
-@@ -9377,7 +9373,7 @@ ath_chan_set(struct ath_softc *sc, struc
+@@ -9320,7 +9316,7 @@ ath_chan_set(struct ath_softc *sc, struc
                                jiffies + (sc->sc_dfs_cac_period * HZ));
  
                        /* This is a good time to start a calibration */
@@ -95,7 +95,7 @@
                }
                /*
                 * re configure beacons when it is a turbo mode switch.
-@@ -9471,25 +9467,23 @@ ath_calibrate(unsigned long arg)
+@@ -9414,25 +9410,23 @@ ath_calibrate(unsigned long arg)
        if (isIQdone == AH_TRUE) {
                /* Unless user has overridden calibration interval,
                 * upgrade to less frequent calibration */
  }
  
  static void
-@@ -9597,9 +9591,6 @@ ath_newstate(struct ieee80211vap *vap, e
+@@ -9540,9 +9534,6 @@ ath_newstate(struct ieee80211vap *vap, e
                ieee80211_state_name[vap->iv_state],
                ieee80211_state_name[nstate]);
  
        ath_hal_setledstate(ah, leds[nstate]);  /* set LED */
        netif_stop_queue(dev);                  /* before we do anything else */
  
-@@ -9821,10 +9812,7 @@ ath_newstate(struct ieee80211vap *vap, e
+@@ -9764,10 +9755,7 @@ ath_newstate(struct ieee80211vap *vap, e
                                IEEE80211_IS_MODE_DFS_MASTER(vap->iv_opmode)) {
                        DPRINTF(sc, ATH_DEBUG_STATE | ATH_DEBUG_DOTH, 
                                "VAP -> DFSWAIT_PENDING \n");
                        /* wake the receiver */
                        netif_wake_queue(dev);
                        /* don't do the other usual stuff... */
-@@ -9866,12 +9854,6 @@ done:
+@@ -9809,12 +9797,6 @@ done:
        /* Invoke the parent method to complete the work. */
        error = avp->av_newstate(vap, nstate, arg);
  
                nstate == IEEE80211_S_RUN)
 --- a/ath/if_athvar.h
 +++ b/ath/if_athvar.h
-@@ -834,7 +834,8 @@ struct ath_softc {
+@@ -832,7 +832,8 @@ struct ath_softc {
  
        struct ieee80211_channel *sc_last_chan;
        int sc_beacon_cal;                      /* use beacon timer for calibration */
diff --git a/package/madwifi/patches/451-ibss_race_fix.patch b/package/madwifi/patches/451-ibss_race_fix.patch
new file mode 100644 (file)
index 0000000..9be3311
--- /dev/null
@@ -0,0 +1,353 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -294,10 +294,10 @@ ieee80211_input(struct ieee80211vap * va
+                       break;
+               case IEEE80211_M_IBSS:
+               case IEEE80211_M_AHDEMO:
+-                      if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid) ||
++                      if ((!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid) ||
+                           (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr) &&
+-                           !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+-                           (subtype != IEEE80211_FC0_SUBTYPE_BEACON))) {
++                           !IEEE80211_IS_MULTICAST(wh->i_addr1))) &&
++                           (type == IEEE80211_FC0_TYPE_DATA)) {
+                               if (!(vap->iv_dev->flags & IFF_PROMISC)) {
+                                       IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+                                               bssid, NULL, "%s", "not to bss");
+@@ -322,22 +322,15 @@ ieee80211_input(struct ieee80211vap * va
+                       }
+                       /* Do not try to find a node reference if the packet really did come from the BSS */
+                       if (type == IEEE80211_FC0_TYPE_DATA && ni == vap->iv_bss &&
+-                                      !IEEE80211_ADDR_EQ(vap->iv_bss->ni_macaddr, wh->i_addr2) &&
+                                       IEEE80211_ADDR_EQ(vap->iv_bssid, wh->i_addr3)) {
+                               /* Try to find sender in local node table. */
+-                              ni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
++                              if (!ni_or_null) {
++                                      ieee80211_unref_node(&ni);
++                                      ni = ieee80211_find_txnode(vap, wh->i_addr2);
++                              }
+                               if (ni == NULL) {
+-                                      /*
+-                                       * Fake up a node for this newly discovered
+-                                       * member of the IBSS.  This should probably
+-                                       * done after an ACL check.
+-                                       */
+-                                      ni = ieee80211_fakeup_adhoc_node(vap,
+-                                                      wh->i_addr2);
+-                                      if (ni == NULL) {
+-                                              /* NB: stat kept for alloc failure */
+-                                              goto err;
+-                                      }
++                                      /* NB: stat kept for alloc failure */
++                                      goto discard;
+                               }
+                       }
+                       iwspy_event(vap, ni, rssi);
+@@ -3553,8 +3546,8 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+                               (((vap->iv_opmode == IEEE80211_M_HOSTAP) ||
+                                (vap->iv_opmode == IEEE80211_M_WDS)) &&
+                               (scan.capinfo & IEEE80211_CAPINFO_ESS))) {
++                      struct ieee80211_node *tni = NULL;
+                       struct ieee80211vap *avp = NULL;
+-                      int do_unref = 0;
+                       int found = 0;
+                       IEEE80211_LOCK_IRQ(vap->iv_ic);
+@@ -3568,14 +3561,12 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+                                       }
+                               }
+                               if (found)
+-                                      ni = ni_or_null = avp->iv_wdsnode;
++                                      tni = ieee80211_ref_node(avp->iv_wdsnode);
+                       } else if (vap->iv_opmode == IEEE80211_M_WDS) {
+                               found = 1;
+-                              ni = ni_or_null = vap->iv_wdsnode;
+-                      } else if (vap->iv_opmode == IEEE80211_M_IBSS) {
+-                              ni_or_null = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
+-                              if (ni_or_null)
+-                                      ni = ni_or_null;
++                              tni = ieee80211_ref_node(vap->iv_wdsnode);
++                      } else if ((vap->iv_opmode == IEEE80211_M_IBSS) && (vap->iv_state == IEEE80211_S_RUN)) {
++                              tni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
+                               found = 1;
+                       }
+                       IEEE80211_UNLOCK_IRQ(vap->iv_ic);
+@@ -3583,20 +3574,21 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+                       if (!found)
+                               break;
+-                      if (ni_or_null == NULL) {
++                      memcpy(&SKB_CB(skb)->beacon_tsf, scan.tstamp, sizeof(u_int64_t));
++
++                      if (tni == NULL) {
+                               if (avp) {
+                                       IEEE80211_LOCK_IRQ(ic);
+-                                      ni = ieee80211_add_neighbor(avp, wh, &scan);
++                                      tni = ieee80211_add_neighbor(avp, wh, &scan);
+                                       /* force assoc */
+-                                      ni->ni_associd |= 0xc000;
+-                                      avp->iv_wdsnode = ieee80211_ref_node(ni);
++                                      tni->ni_associd |= 0xc000;
++                                      avp->iv_wdsnode = ieee80211_ref_node(tni);
+                                       IEEE80211_UNLOCK_IRQ(ic);
+                               } else if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
+                                          IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid)) {
+                                       /* Create a new entry in the neighbor table. */
+-                                      ni = ieee80211_add_neighbor(vap, wh, &scan);
++                                      tni = ieee80211_add_neighbor(vap, wh, &scan);
+                               }
+-                              do_unref = 1;
+                       } else {
+                               /*
+                                * Copy data from beacon to neighbor table.
+@@ -3604,39 +3596,38 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+                                * ieee80211_add_neighbor(), so we just copy
+                                * everything over to be safe.
+                                */
+-                              ni->ni_esslen = scan.ssid[1];
+-                              memcpy(ni->ni_essid, scan.ssid + 2, scan.ssid[1]);
+-                              IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
+-                              memcpy(ni->ni_tstamp.data, scan.tstamp,
+-                                      sizeof(ni->ni_tstamp));
+-                              ni->ni_inact = ni->ni_inact_reload;
+-                              ni->ni_intval = 
++                              tni->ni_esslen = scan.ssid[1];
++                              memcpy(tni->ni_essid, scan.ssid + 2, scan.ssid[1]);
++                              IEEE80211_ADDR_COPY(tni->ni_bssid, wh->i_addr3);
++                              memcpy(tni->ni_tstamp.data, scan.tstamp,
++                                      sizeof(tni->ni_tstamp));
++                              tni->ni_inact = tni->ni_inact_reload;
++                              tni->ni_intval =
+                                       IEEE80211_BINTVAL_SANITISE(scan.bintval);
+-                              ni->ni_capinfo = scan.capinfo;
+-                              ni->ni_chan = ic->ic_curchan;
+-                              ni->ni_fhdwell = scan.fhdwell;
+-                              ni->ni_fhindex = scan.fhindex;
+-                              ni->ni_erp = scan.erp;
+-                              ni->ni_timoff = scan.timoff;
++                              tni->ni_capinfo = scan.capinfo;
++                              tni->ni_chan = ic->ic_curchan;
++                              tni->ni_fhdwell = scan.fhdwell;
++                              tni->ni_fhindex = scan.fhindex;
++                              tni->ni_erp = scan.erp;
++                              tni->ni_timoff = scan.timoff;
+                               if (scan.wme != NULL)
+-                                      ieee80211_saveie(&ni->ni_wme_ie, scan.wme);
++                                      ieee80211_saveie(&tni->ni_wme_ie, scan.wme);
+                               if (scan.wpa != NULL)
+-                                      ieee80211_saveie(&ni->ni_wpa_ie, scan.wpa);
++                                      ieee80211_saveie(&tni->ni_wpa_ie, scan.wpa);
+                               if (scan.rsn != NULL)
+-                                      ieee80211_saveie(&ni->ni_rsn_ie, scan.rsn);
++                                      ieee80211_saveie(&tni->ni_rsn_ie, scan.rsn);
+                               if (scan.ath != NULL)
+-                                      ieee80211_saveath(ni, scan.ath);
++                                      ieee80211_saveath(tni, scan.ath);
+                               /* NB: must be after ni_chan is setup */
+-                              ieee80211_setup_rates(ni, scan.rates,
++                              ieee80211_setup_rates(tni, scan.rates,
+                                       scan.xrates, IEEE80211_F_DOSORT);
+                       }
+-                      if (ni != NULL) {
+-                              ni->ni_rssi = rssi;
+-                              ni->ni_rtsf = rtsf;
+-                              ni->ni_last_rx = jiffies;
+-                              if (do_unref)
+-                                      ieee80211_unref_node(&ni);
++                      if (tni != NULL) {
++                              tni->ni_rssi = rssi;
++                              tni->ni_rtsf = rtsf;
++                              tni->ni_last_rx = jiffies;
++                              ieee80211_unref_node(&tni);
+                       }
+               }
+               break;
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -53,6 +53,7 @@
+ #include <net80211/ieee80211_var.h>
+ #include <net80211/if_athproto.h>
++#include <net80211/ieee80211_node.h>
+ /*
+  * Association IDs are managed with a bit vector.
+@@ -317,16 +318,11 @@ ieee80211_create_ibss(struct ieee80211va
+       /* Check to see if we already have a node for this mac
+        * NB: we gain a node reference here
+        */
+-      ni = ieee80211_find_txnode(vap, vap->iv_myaddr);
++      ieee80211_node_table_reset(&ic->ic_sta, vap);
++      ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
+       if (ni == NULL) {
+-              ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
+-              IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
+-                                "%s: ni:%p allocated for " MAC_FMT "\n",
+-                                __func__, ni, MAC_ADDR(vap->iv_myaddr));
+-              if (ni == NULL) {
+-                      /* XXX recovery? */
+-                      return;
+-              }
++              /* XXX recovery? */
++              return;
+       }
+       IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr);
+@@ -429,8 +425,8 @@ ieee80211_reset_bss(struct ieee80211vap 
+                         __func__, ni, MAC_ADDR(vap->iv_myaddr));
+       KASSERT(ni != NULL, ("unable to setup inital BSS node"));
+-      vap->iv_bss = ieee80211_ref_node(ni);
+-      KASSERT((atomic_read(&vap->iv_bss->ni_refcnt) == 3), 
++      vap->iv_bss = ni;
++      KASSERT((atomic_read(&vap->iv_bss->ni_refcnt) == 2),
+               ("wrong refcount for new node."));
+       if (obss != NULL) {
+@@ -647,7 +643,7 @@ ieee80211_sta_join1(struct ieee80211_nod
+               (vap->iv_state == IEEE80211_S_RUN) && bssid_equal(obss, selbs)); */
+       vap->iv_bss = selbs;
+       IEEE80211_ADDR_COPY(vap->iv_bssid, selbs->ni_bssid);
+-      if (obss != NULL) {
++      if ((obss != NULL) && (obss != selbs)) {
+               if (obss->ni_table)
+                       ieee80211_node_leave(obss);
+               ieee80211_unref_node(&obss);
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6625,14 +6625,6 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+       sc->sc_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf);
+-      /* Lookup the new node if any (this grabs a reference to it) */
+-      ni = ieee80211_find_rxnode(vap->iv_ic, vap,
+-               (const struct ieee80211_frame_min *)skb->data);
+-      if (ni == NULL) {
+-              DPRINTF(sc, ATH_DEBUG_BEACON, "Dropping; node unknown.\n");
+-              return;
+-      }
+-
+       switch (subtype) {
+       case IEEE80211_FC0_SUBTYPE_BEACON:
+               /* update RSSI statistics for use by the HAL */
+@@ -6654,11 +6646,9 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                        * we do the IBSS merging in software. Also do not merge
+                        * if the difference it too small. Otherwise we are playing
+                        * tsf-pingpong with other vendors drivers */
+-                      beacon_tsf = le64_to_cpu(ni->ni_tstamp.tsf);
+-                      if (beacon_tsf > rtsf + 0xffff) {
++                      beacon_tsf = le64_to_cpu(SKB_CB(skb)->beacon_tsf);
++                      if (beacon_tsf > rtsf + 0xffff)
+                               ath_hal_settsf64(sc->sc_ah, beacon_tsf - rtsf);
+-                              ieee80211_ibss_merge(ni);
+-                      }
+                       break;
+               }
+               /* NB: Fall Through */
+@@ -6680,13 +6670,21 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                       hw_tsf = ath_hal_gettsf64(sc->sc_ah);
+                       hw_tu  = hw_tsf >> 10;
+-                      beacon_tsf = le64_to_cpu(ni->ni_tstamp.tsf);
++                      beacon_tsf = le64_to_cpu(SKB_CB(skb)->beacon_tsf);
+                       beacon_tu  = beacon_tsf >> 10;
++                      if (!beacon_tsf)
++                              break;
++
++                      if (IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid))
++                              break;
++
+                       DPRINTF(sc, ATH_DEBUG_BEACON,
+-                                      "Beacon transmitted at %10llx, "
++                                      "Beacon transmitted from "MAC_FMT" ("MAC_FMT") at %10llx, "
+                                       "received at %10llx(%lld), hw TSF "
+                                       "%10llx(%lld)\n",
++                                      MAC_ADDR(wh->i_addr3),
++                                      MAC_ADDR(vap->iv_bssid),
+                                       beacon_tsf,
+                                       rtsf, rtsf - beacon_tsf,
+                                       hw_tsf, hw_tsf - beacon_tsf);
+@@ -6699,39 +6697,13 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+                               do_merge = 1;
+                       }
+-                      /* Check sc_nexttbtt */
+-                      if (sc->sc_nexttbtt < hw_tu) {
+-                              DPRINTF(sc, ATH_DEBUG_BEACON,
+-                                      "sc_nexttbtt (%8x TU) is in the past "
+-                                      "(tsf %8x TU), updating timers\n",
+-                                      sc->sc_nexttbtt, hw_tu);
+-                              do_merge = 1;
+-                      }
+-
+-                      intval = ni->ni_intval & HAL_BEACON_PERIOD;
+-#if 0
+-                      /* This code is disabled since it would produce
+-                       * unwanted merge. For instance, in a two nodes network
+-                       * A & B, A can merge to B and at the same time, B will
+-                       * merge to A, still having a split */
+-                      if (intval != 0) {
+-                              if ((sc->sc_nexttbtt % intval) !=
+-                                              (beacon_tu % intval)) {
+-                                      DPRINTF(sc, ATH_DEBUG_BEACON,
+-                                                      "ibss merge: "
+-                                                      "sc_nexttbtt %10x TU "
+-                                                      "(%3d) beacon %10x TU "
+-                                                      "(%3d)\n",
+-                                                      sc->sc_nexttbtt,
+-                                                      sc->sc_nexttbtt % intval,
+-                                                      beacon_tu,
+-                                                      beacon_tu % intval);
+-                                      do_merge = 1;
+-                              }
+-                      }
+-#endif
+-                      if (do_merge)
++                      if (do_merge) {
++                              /* Lookup the new node if any (this grabs a reference to it) */
++                              ni = ieee80211_find_txnode(vap, wh->i_addr2);
++                              memcpy(ni->ni_bssid, wh->i_addr3, IEEE80211_ADDR_LEN);
+                               ieee80211_ibss_merge(ni);
++                              ieee80211_unref_node(&ni);
++                      }
+                       if ((sc->sc_opmode == HAL_M_IBSS) &&
+                                       ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval))
+@@ -6739,8 +6711,6 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+               }
+               break;
+       }
+-
+-      ieee80211_unref_node(&ni);
+ }
+ static void
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -411,7 +411,7 @@ typedef spinlock_t acl_lock_t;
+  *     8 bytes so we reserve/avoid it.
+  */
+       struct ieee80211_cb {
+-      u_int8_t vlan[8];                       /* reserve for vlan tag info */
++      u_int64_t beacon_tsf;
+       struct ieee80211_node *ni;
+       u_int32_t flags;
+ #define       M_LINK0         0x01                    /* frame needs WEP encryption */
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -1125,11 +1125,8 @@ adhoc_default_action(struct ieee80211vap
+       u_int8_t zeroMacAddr[IEEE80211_ADDR_LEN];
+       memset(&zeroMacAddr, 0, IEEE80211_ADDR_LEN);
+-      if (IEEE80211_ADDR_EQ(se->se_bssid, &zeroMacAddr[0])) {
+-              ieee80211_create_ibss(vap, se->se_chan);
+-              return 1;
+-      } else
+-              return ieee80211_sta_join(vap, se);
++      ieee80211_create_ibss(vap, se->se_chan);
++      return 1;
+ }
+ static const struct ieee80211_scanner adhoc_default = {
diff --git a/package/madwifi/patches/452-minstrel_no_timer.patch b/package/madwifi/patches/452-minstrel_no_timer.patch
new file mode 100644 (file)
index 0000000..e7f2dea
--- /dev/null
@@ -0,0 +1,134 @@
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -119,6 +119,7 @@
+ #include "minstrel.h"
+ #define ONE_SECOND (1000 * 1000)  /* 1 second, or 1000 milliseconds; eternity, in other words */
++#define TIMER_INTERVAL 100 /* msecs */
+ #include "release.h"
+@@ -128,9 +129,6 @@ static char *dev_info = "ath_rate_minstr
+ #define STALE_FAILURE_TIMEOUT_MS 10000
+ #define ENABLE_MRR 1
+-static int ath_timer_interval = (1000 / 10); /* every 1/10 second, timer runs */
+-static void ath_timer_function(unsigned long data);
+-
+ /* 10% of the time, send a packet at something other than the optimal rate, which fills
+  * the statistics tables nicely. This percentage is applied to the first packet of the
+  * multi rate retry chain. */
+@@ -142,7 +140,7 @@ static void ath_rate_ctl_reset(struct at
+ /* Calculate the throughput and probability of success for each node
+  * we are talking on, based on the statistics collected during the
+  * last timer period. */
+-static void ath_rate_statistics(void *arg, struct ieee80211_node *ni);
++static void ath_rate_statistics(struct ieee80211_node *ni);
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+@@ -204,6 +202,11 @@ ath_rate_findrate(struct ath_softc *sc, 
+               unsigned int ndx, offset;
+               int mrr;
++
++              if (sn->last_update + msecs_to_jiffies(TIMER_INTERVAL) < jiffies) {
++                      ath_rate_statistics(&an->an_node);
++                      sn->last_update = jiffies;
++              }
+               if (sn->num_rates <= 0) {
+                           printk(KERN_WARNING "%s: no rates for " MAC_FMT "?\n",
+                                  dev_info,
+@@ -640,54 +643,11 @@ ath_rate_newstate(struct ieee80211vap *v
+               }
+ }
+-static void
+-ath_timer_function(unsigned long data)
+-{
+-              struct minstrel_softc *ssc = (struct minstrel_softc *) data;
+-              struct ath_softc *sc = ssc->sc;
+-              struct ieee80211com *ic;
+-              struct net_device *dev = ssc->sc_dev;
+-              struct timer_list *timer;
+-              unsigned int interval = ath_timer_interval;
+-
+-              if (dev == NULL)
+-                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: 'dev' is null in this timer \n", __func__);
+-
+-              if (sc == NULL)
+-                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: 'sc' is null in this timer\n", __func__);
+-
+-              ic = &sc->sc_ic;
+-
+-              if (ssc->close_timer_now)
+-                      return;
+-
+-              if (dev->flags & IFF_RUNNING) {
+-                      sc->sc_stats.ast_rate_calls++;
+-
+-                      if (ic->ic_opmode == IEEE80211_M_STA) {
+-                              struct ieee80211vap *tmpvap;
+-                              TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
+-                                      ath_rate_statistics(sc, tmpvap->iv_bss);/* NB: no reference */
+-                              }
+-                      } else
+-                                  ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_statistics, sc);
+-              }
+-
+-              if (ic->ic_opmode == IEEE80211_M_STA)
+-                      interval = ath_timer_interval >> 1;
+-
+-              timer  = &(ssc->timer);
+-              if (timer == NULL)
+-                      DPRINTF(sc, ATH_DEBUG_RATE, "%s: timer is null - leave it\n", __func__);
+-
+-              timer->expires = jiffies + ((HZ * interval) / 1000);
+-              add_timer(timer);
+-}
+ static void
+-ath_rate_statistics(void *arg, struct ieee80211_node *ni)
++ath_rate_statistics(struct ieee80211_node *ni)
+ {
+-              struct ath_node *an = (struct ath_node *) ni;
++              struct ath_node *an = ATH_NODE(ni);
+               struct ieee80211_rateset *rs = &ni->ni_rates;
+               struct minstrel_node *rn = ATH_NODE_MINSTREL(an);
+               unsigned int i;
+@@ -786,15 +746,8 @@ ath_rate_attach(struct ath_softc *sc)
+               osc->arc.arc_space = sizeof(struct minstrel_node);
+               osc->arc.arc_vap_space = 0;
+-              osc->close_timer_now = 0;
+-              init_timer(&osc->timer);
+       osc->sc          = sc;
+               osc->sc_dev      = sc->sc_dev;
+-              osc->timer.function = ath_timer_function;
+-              osc->timer.data = (unsigned long)osc;
+-
+-              osc->timer.expires = jiffies + HZ;
+-              add_timer(&osc->timer);
+               return &osc->arc;
+ }
+@@ -803,8 +756,6 @@ static void
+ ath_rate_detach(struct ath_ratectrl *arc)
+ {
+       struct minstrel_softc *osc = (struct minstrel_softc *) arc;
+-              osc->close_timer_now = 1;
+-              del_timer(&osc->timer);
+               kfree(osc);
+               _MOD_DEC_USE(THIS_MODULE);
+ }
+--- a/ath_rate/minstrel/minstrel.h
++++ b/ath_rate/minstrel/minstrel.h
+@@ -167,6 +167,8 @@ struct minstrel_node {
+              packet, or a packet at an optimal rate.*/
+       int random_n;
+       int a, b;          /**Coefficients of the random thing */
++
++      unsigned long last_update;
+ };