madwifi: sync with trunk
authorNicolas Thill <nico@openwrt.org>
Tue, 28 Apr 2009 00:14:31 +0000 (00:14 +0000)
committerNicolas Thill <nico@openwrt.org>
Tue, 28 Apr 2009 00:14:31 +0000 (00:14 +0000)
SVN-Revision: 15465

43 files changed:
package/madwifi/Config.in
package/madwifi/Makefile
package/madwifi/files/lib/wifi/madwifi.sh
package/madwifi/patches/330-beaconcal.patch
package/madwifi/patches/332-reset_beacons.patch
package/madwifi/patches/343-txqueue_races.patch
package/madwifi/patches/345-minstrel_sampling.patch
package/madwifi/patches/347-tuning.patch
package/madwifi/patches/348-ackcts.patch
package/madwifi/patches/349-reset.patch
package/madwifi/patches/352-ani_fix.patch
package/madwifi/patches/355-eap_auth_disassoc.patch
package/madwifi/patches/366-bstuck_thresh.patch
package/madwifi/patches/370-wdsvap.patch
package/madwifi/patches/374-nbtt_fix.patch
package/madwifi/patches/375-atim_tsf_update.patch
package/madwifi/patches/381-ibss_modes.patch
package/madwifi/patches/383-ibss_hostap.patch
package/madwifi/patches/384-hwdetect.patch
package/madwifi/patches/385-antenna_fix.patch
package/madwifi/patches/389-autochannel.patch
package/madwifi/patches/391-vap_auth.patch [new file with mode: 0644]
package/madwifi/patches/392-remove_wds_nodetracking.patch [new file with mode: 0644]
package/madwifi/patches/393-mbss_vap_auth.patch [new file with mode: 0644]
package/madwifi/patches/394-probereq.patch
package/madwifi/patches/395-ath_ff_unmap.patch
package/madwifi/patches/396-napi_ff_fix.patch [new file with mode: 0644]
package/madwifi/patches/400-changeset_r3402.patch [deleted file]
package/madwifi/patches/400-new_hal.patch [new file with mode: 0644]
package/madwifi/patches/405-retransmit_check.patch
package/madwifi/patches/406-monitor_r3711.patch
package/madwifi/patches/408-changeset_r3337.patch
package/madwifi/patches/410-ar231x_2.6.28.patch [new file with mode: 0644]
package/madwifi/patches/411-autochannel_multi.patch [new file with mode: 0644]
package/madwifi/patches/412-fragmentation_fix.patch [new file with mode: 0644]
package/madwifi/patches/413-rxorn.patch [new file with mode: 0644]
package/madwifi/patches/414-txpower.patch [new file with mode: 0644]
package/madwifi/patches/415-chan_switch.patch [new file with mode: 0644]
package/madwifi/patches/417-beacon_txpower.patch [new file with mode: 0644]
package/madwifi/patches/418-turbo.patch [new file with mode: 0644]
package/madwifi/patches/419-skb_unmap_crash.patch [new file with mode: 0644]
package/madwifi/patches/420-diversity_fix.patch [new file with mode: 0644]
package/madwifi/patches/450-new_hal.patch [deleted file]

index 0a5412a74fad7f0ff65b3fe75e98e13249a45d46..126639552a4f2e13070b519b04c4a4d37d153db3 100644 (file)
@@ -16,6 +16,7 @@ config MADWIFI_STABLE
        bool "Use the OpenWrt stable version of madwifi"
 
 config MADWIFI_UPSTREAM
+       depends BROKEN
        depends !LINUX_2_6_26
        depends !TARGET_atheros
        bool "Use the upstream release version 0.9.4"
index 22aa904f8b00e11584fc2671f17482780d27b602..f787ffb4c2cadaffc7e7827f823de4d50bcdcd6c 100644 (file)
@@ -13,7 +13,7 @@ PKG_NAME:=madwifi
 
 ifneq ($(CONFIG_MADWIFI_UPSTREAM),)
   PKG_VERSION:=0.9.4
-  PKG_RELEASE:=2
+  PKG_RELEASE:=2.1
 
   PKG_SOURCE:=madwifi-$(PKG_VERSION).tar.gz
   PKG_SOURCE_URL:=http://downloads.sourceforge.net/madwifi/
@@ -26,7 +26,7 @@ else
 # PKG_BRANCH:=madwifi-dfs
   PKG_REV:=3314
   PKG_VERSION:=r$(PKG_REV)
-  PKG_RELEASE:=2
+  PKG_RELEASE:=2.1
 
   PKG_SOURCE_PROTO:=svn
   PKG_SOURCE_VERSION:=$(PKG_REV)
index eae82a7f04764ee7bb7fd242d47feb33f195673e..8c4a75426e94fce4d0bf9a5429d3cadf16ba1a31 100755 (executable)
@@ -42,7 +42,7 @@ scan_atheros() {
                *) echo "$device: Invalid mode combination in config"; return 1;;
        esac
 
-       config_set "$device" vifs "${ap:+$ap }${adhoc:+$adhoc }${ahdemo:+$ahdemo }${sta:+$sta }${wds:+$wds }${monitor:+$monitor}"
+       config_set "$device" vifs "${sta:+$sta }${ap:+$ap }${adhoc:+$adhoc }${ahdemo:+$ahdemo }${wds:+$wds }${monitor:+$monitor}"
 }
 
 
@@ -67,6 +67,15 @@ disable_atheros() (
 
 enable_atheros() {
        local device="$1"
+       # Can only set the country code to one setting for the entire system. The last country code is the one that will be applied.
+       config_get country "$device" country
+       [ -z "$country" ] && country="0"
+       local cc="0"
+       [ -e /proc/sys/dev/$device/countrycode ] && cc="$(cat /proc/sys/dev/$device/countrycode)"
+       if [ ! "$cc" = "$country" ] ; then
+               rmmod ath_pci
+               insmod ath_pci countrycode=$country
+       fi
        config_get channel "$device" channel
        config_get vifs "$device" vifs
        config_get txpower "$device" txpower
@@ -111,10 +120,10 @@ enable_atheros() {
                        *fh) hwmode=fh;;
                        *) hwmode=auto;;
                esac
-               iwpriv "$ifname" mode "$hwmode"
                iwpriv "$ifname" pureg "$pureg"
 
                [ "$first" = 1 ] && {
+                       iwpriv "$ifname" mode "$hwmode"
                        iwconfig "$ifname" channel "$channel" >/dev/null 2>/dev/null 
                }
        
@@ -158,7 +167,7 @@ enable_atheros() {
                esac
 
                case "$mode" in
-                       adhoc|ahdemo)
+                       sta|adhoc|ahdemo)
                                config_get addr "$vif" bssid
                                [ -z "$addr" ] || { 
                                        iwconfig "$ifname" ap "$addr"
@@ -212,9 +221,6 @@ enable_atheros() {
                config_get distance "$device" distance
                [ -n "$distance" ] && athctrl -i "$device" -d "$distance" >&-
 
-               config_get txpwr "$vif" txpower
-               [ -n "$txpwr" ] && iwconfig "$ifname" txpower "${txpwr%%.*}"
-
                config_get rate "$vif" rate
                [ -n "$rate" ] && iwconfig "$ifname" rate "${rate%%.*}"
 
@@ -251,6 +257,9 @@ enable_atheros() {
                config_get_bool turbo "$vif" turbo
                [ -n "$turbo" ] && iwpriv "$ifname" turbo "$turbo"
 
+               config_get_bool beacon_power "$vif" beacon_power
+               [ -n "$beacon_power" ] && iwpriv "$ifname" beacon_pwr "$beacon_power"
+
                config_get_bool doth "$vif" doth 0
                [ -n "$doth" ] && iwpriv "$ifname" doth "$doth"
 
@@ -281,6 +290,7 @@ enable_atheros() {
                esac
 
                ifconfig "$ifname" up
+
                local net_cfg bridge
                net_cfg="$(find_net_config "$vif")"
                [ -z "$net_cfg" ] || {
index 8556e0bb1d74827d94e5d6a900936039b9610da6..2b4895f359815eabe7aad5e890fa19bde846f702 100644 (file)
         * Convert to a HAL channel description with the flags
         * constrained to reflect the current operating mode.
         */
-@@ -5154,6 +5178,8 @@ ath_beacon_send(struct ath_softc *sc, in
+@@ -5154,6 +5178,10 @@ 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);
-+              if (sc->sc_beacon_cal && (jiffies > sc->sc_lastcal + (ath_calinterval * HZ)))
-+                      ath_calibrate((unsigned long) sc->sc_dev);
++              if (sc->sc_beacon_cal && (jiffies > sc->sc_lastcal + (ath_calinterval * HZ))) {
++                      sc->sc_cal_ch.expires = jiffies + msecs_to_jiffies(10);
++                      add_timer(&sc->sc_cal_ch);
++              }
  
                sc->sc_stats.ast_be_xmit++;             /* XXX per-VAP? */
        }
-@@ -5403,6 +5429,7 @@ ath_beacon_config(struct ath_softc *sc, 
+@@ -5403,6 +5431,7 @@ ath_beacon_config(struct ath_softc *sc, 
                ath_hal_beacontimers(ah, &bs);
                sc->sc_imask |= HAL_INT_BMISS;
                ath_hal_intrset(ah, sc->sc_imask);
@@ -85,7 +87,7 @@
        } else {
                ath_hal_intrset(ah, 0);
                if (reset_tsf)
-@@ -5414,8 +5441,11 @@ ath_beacon_config(struct ath_softc *sc, 
+@@ -5414,8 +5443,11 @@ ath_beacon_config(struct ath_softc *sc, 
                         */
                        intval |= HAL_BEACON_ENA;
                        sc->sc_imask |= HAL_INT_SWBA;
  #ifdef ATH_SUPERG_DYNTURBO
                ath_beacon_dturbo_config(vap, intval &
                                ~(HAL_BEACON_RESET_TSF | HAL_BEACON_ENA));
-@@ -8879,6 +8909,9 @@ ath_chan_set(struct ath_softc *sc, struc
+@@ -8879,6 +8911,9 @@ ath_chan_set(struct ath_softc *sc, struc
                        /* Enter DFS wait period */
                        mod_timer(&sc->sc_dfs_cac_timer,
                                jiffies + (sc->sc_dfs_cac_period * HZ));
                }
                /*
                 * re configure beacons when it is a turbo mode switch.
-@@ -8988,8 +9021,11 @@ ath_calibrate(unsigned long arg)
+@@ -8988,8 +9023,11 @@ ath_calibrate(unsigned long arg)
                sc->sc_curchan.channel, sc->sc_curchan.channelFlags,
                isIQdone ? "done" : "not done");
  
  }
  
  static void
-@@ -9096,7 +9132,8 @@ ath_newstate(struct ieee80211vap *vap, e
+@@ -9096,7 +9134,8 @@ 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 */
-@@ -9321,7 +9358,8 @@ ath_newstate(struct ieee80211vap *vap, e
+@@ -9321,7 +9360,8 @@ ath_newstate(struct ieee80211vap *vap, e
                                "VAP -> DFSWAIT_PENDING \n");
                        /* start calibration timer with a really small value 
                         * 1/10 sec */
                        /* wake the receiver */
                        netif_wake_queue(dev);
                        /* don't do the other usual stuff... */
-@@ -9364,7 +9402,7 @@ done:
+@@ -9364,7 +9404,7 @@ done:
        error = avp->av_newstate(vap, nstate, arg);
  
        /* Finally, start any timers. */
index 283f7f4f293df18841866ea2641dca164820a117..b776426f204f7720135b6ff844d3ece7b944c18e 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8920,7 +8920,7 @@ ath_chan_set(struct ath_softc *sc, struc
+@@ -8922,7 +8922,7 @@ ath_chan_set(struct ath_softc *sc, struc
                 * re configure beacons when it is a turbo mode switch.
                 * HW seems to turn off beacons during turbo mode switch.
                 */
index 4ae287e49dab087884983b52b2145edc4f52dd44..a2b14d69a8abd2e04117f03ab93af06c89105e0a 100644 (file)
@@ -2,7 +2,7 @@ Merged from madwifi trunk r3551, r3552
 
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8251,6 +8251,17 @@ ath_tx_processq(struct ath_softc *sc, st
+@@ -8253,6 +8253,17 @@ ath_tx_processq(struct ath_softc *sc, st
                        goto bf_fail;
                }
  
index cf278a496fbb61967f4527be9ea1c308b5a25379..d89990c837bb3ba73a1eea7f4da908bc02f5c6e1 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8101,6 +8101,7 @@ ath_tx_start(struct net_device *dev, str
+@@ -8103,6 +8103,7 @@ ath_tx_start(struct net_device *dev, str
                ath_hal_setupxtxdesc(sc->sc_ah, ds, mrr.rate1, mrr.retries1,
                                     mrr.rate2, mrr.retries2,
                                     mrr.rate3, mrr.retries3);
index ca005e7d766c2ee2c01c688e44337a1dc1fbf3d4..1a73c4274769bf3a282560ee07ae917fae1ee97a 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -10274,11 +10274,11 @@ ath_setcurmode(struct ath_softc *sc, enu
+@@ -10276,11 +10276,11 @@ ath_setcurmode(struct ath_softc *sc, enu
        sc->sc_currates = rt;
        sc->sc_curmode = mode;
        /*
index 957e8ad55f52a970a8314c50c9afd9d77ac758e6..42b6fe2613febe7039ef61a56d44443ce6549570 100644 (file)
@@ -10,7 +10,7 @@
        if (ar_device(sc->devid) == 5212 || ar_device(sc->devid) == 5213) {
                /* set ack to be sent at low bit-rate */
                /* registers taken from the OpenBSD 5212 HAL */
-@@ -10789,8 +10792,13 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+@@ -10791,8 +10794,13 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
                                break;
  #endif
                        case ATH_ACKRATE:
index 599948de0b8318924cf96cfe8661fa803295e722..06e3fa86f7da13769e22e6386f5f538437341686 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8862,8 +8862,7 @@ ath_chan_set(struct ath_softc *sc, struc
+@@ -8864,8 +8864,7 @@ ath_chan_set(struct ath_softc *sc, struc
                 * needed to do the reset with chanchange = AH_FALSE in order
                 * to receive traffic when peforming high velocity channel
                 * changes. */
index af00f5e850b2e32e57f22aae4b0ed53f06bc7ab0..e8dce0cbe40daa1f0be723796b92c0216316da59 100644 (file)
        if (sc->sc_curchan.privFlags & CHANNEL_DFS)
                rfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR);
        return rfilt;
-@@ -6524,9 +6563,6 @@ process_rx_again:
+@@ -6526,9 +6565,6 @@ process_rx_again:
                        rs->rs_rssi = 0;
  
                len = rs->rs_datalen;
  
                if (rs->rs_more) {
                        /*
-@@ -8874,9 +8910,7 @@ ath_chan_set(struct ath_softc *sc, struc
+@@ -8876,9 +8912,7 @@ ath_chan_set(struct ath_softc *sc, struc
                if (sc->sc_softled)
                        ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
  
                sc->sc_curchan = hchan;
                ath_update_txpow(sc);           /* update tx power state */
                ath_radar_update(sc);
-@@ -10653,9 +10687,54 @@ enum {
+@@ -10655,9 +10689,54 @@ enum {
        ATH_RP_IGNORED          = 24,
        ATH_RADAR_IGNORED       = 25,
        ATH_MAXVAPS             = 26,
  ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
  {
        struct ath_softc *sc = ctl->extra1;
-@@ -10841,6 +10920,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+@@ -10843,6 +10922,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
                        case ATH_RADAR_IGNORED:
                                sc->sc_radar_ignored = val;
                                break;
                        default:
                                ret = -EINVAL;
                                break;
-@@ -10907,6 +10991,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
+@@ -10909,6 +10993,11 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
                case ATH_RADAR_IGNORED:
                        val = sc->sc_radar_ignored;
                        break;
                default:
                        ret = -EINVAL;
                        break;
-@@ -11084,6 +11173,24 @@ static const ctl_table ath_sysctl_templa
+@@ -11086,6 +11175,24 @@ static const ctl_table ath_sysctl_templa
          .proc_handler = ath_sysctl_halparam,
          .extra2       = (void *)ATH_RADAR_IGNORED,
        },
index 23cde7bcda812474dafa3c5b95d77d612ec9bf9f..8bb1e9323642c501fb5aabcb34df209756e9be2e 100644 (file)
@@ -5,7 +5,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -8332,6 +8332,14 @@ ath_tx_processq(struct ath_softc *sc, st
+@@ -8334,6 +8334,14 @@ ath_tx_processq(struct ath_softc *sc, st
  #endif
                                if (ts->ts_status & HAL_TXERR_XRETRY) {
                                        sc->sc_stats.ast_tx_xretries++;
index f5a94c6b61a966d0460bec0ec5fe2468952305b1..cde1f5c98ce422e1e8128cc9b6aabb08ba5db9d7 100644 (file)
@@ -41,7 +41,7 @@
                        ATH_SCHEDULE_TQUEUE(&sc->sc_bstucktq, needmark);
                return;
        }
-@@ -5228,7 +5232,7 @@ ath_bstuck_tasklet(TQUEUE_ARG data)
+@@ -5230,7 +5234,7 @@ ath_bstuck_tasklet(TQUEUE_ARG data)
         *     check will be true, in which case return
         *     without resetting the driver.
         */
index f35e65772530a972e51bc3dfb1ad59cfe10668b3..d68973737e6d7345cb36ab5c4160976e683f1b92 100644 (file)
  
        if (ic->ic_dev->flags & IFF_RUNNING) {
                /* needs to disable hardware too */
-@@ -1271,8 +1269,11 @@ ath_vap_create(struct ieee80211com *ic, 
+@@ -1271,8 +1269,12 @@ ath_vap_create(struct ieee80211com *ic, 
                } else
                        ic_opmode = opmode;
                break;
 -      case IEEE80211_M_HOSTAP:
        case IEEE80211_M_WDS:
++              ic_opmode = ic->ic_opmode;
 +              if (!master)
 +                      return NULL;
 +              break;
@@ -57,7 +58,7 @@
                /* permit multiple APs and/or WDS links */
                /* XXX sta+ap for repeater/bridge application */
                if ((sc->sc_nvaps != 0) && (ic->ic_opmode == IEEE80211_M_STA))
-@@ -1304,7 +1305,7 @@ ath_vap_create(struct ieee80211com *ic, 
+@@ -1304,7 +1306,7 @@ ath_vap_create(struct ieee80211com *ic, 
        }
  
        avp = dev->priv;
@@ -66,7 +67,7 @@
        /* override with driver methods */
        vap = &avp->av_vap;
        avp->av_newstate = vap->iv_newstate;
-@@ -4209,8 +4210,7 @@ ath_calcrxfilter(struct ath_softc *sc)
+@@ -4209,8 +4211,7 @@ ath_calcrxfilter(struct ath_softc *sc)
        if (ic->ic_opmode == IEEE80211_M_STA ||
            sc->sc_opmode == HAL_M_IBSS ||      /* NB: AHDEMO too */
            (sc->sc_nostabeacons) || sc->sc_scanning ||
@@ -76,7 +77,7 @@
                rfilt |= HAL_RX_FILTER_BEACON;
        if (sc->sc_nmonvaps > 0)
                rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
-@@ -9030,8 +9030,6 @@ ath_calibrate(unsigned long arg)
+@@ -9032,8 +9033,6 @@ ath_calibrate(unsigned long arg)
                 * set sc->beacons if we might need to restart
                   * them after ath_reset. */
                if (!sc->sc_beacons &&
                        }
                        break;
                case IEEE80211_M_IBSS:
-@@ -540,16 +548,32 @@ ieee80211_input(struct ieee80211vap * va
+@@ -540,16 +548,28 @@ ieee80211_input(struct ieee80211vap * va
                                vap->iv_stats.is_rx_notassoc++;
                                goto err;
                        }
-+
-+                      /* subif isn't fully set up yet, drop the frame */
-+                      if (ni->ni_subif == ni->ni_vap)
-+                              goto err;
 +
                        /*
                         * If we're a 4 address packet, make sure we have an entry in
  
                                if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) {
                                        IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
-@@ -557,7 +581,6 @@ ieee80211_input(struct ieee80211vap * va
+@@ -557,7 +577,6 @@ ieee80211_input(struct ieee80211vap * va
                                        goto err;
                                }
                                wh4 = (struct ieee80211_frame_addr4 *)skb->data;
                                ni_wds = ieee80211_find_wds_node(nt, wh4->i_addr4);
                                /* Last call increments ref count if !NULL */
                                if ((ni_wds != NULL) && (ni_wds != ni)) {
-@@ -608,6 +631,11 @@ ieee80211_input(struct ieee80211vap * va
+@@ -608,6 +627,11 @@ ieee80211_input(struct ieee80211vap * va
                        goto out;
                }
  
                /*
                 * Handle privacy requirements.  Note that we
                 * must not be preempted from here until after
-@@ -680,8 +708,12 @@ ieee80211_input(struct ieee80211vap * va
+@@ -680,8 +704,12 @@ ieee80211_input(struct ieee80211vap * va
                if (! accept_data_frame(vap, ni, key, skb, eh))
                        goto out;
  
                IEEE80211_NODE_STAT(ni, rx_data);
                IEEE80211_NODE_STAT_ADD(ni, rx_bytes, skb->len);
                ic->ic_lastdata = jiffies;
-@@ -1114,6 +1146,13 @@ ieee80211_deliver_data(struct ieee80211_
+@@ -1114,6 +1142,17 @@ ieee80211_deliver_data(struct ieee80211_
                dev = vap->iv_xrvap->iv_dev;
  #endif
  
 +      /* if the node has a wds subif, move data frames there,
 +       * but keep EAP traffic on the master */
 +      if (ni->ni_subif && ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE))) {
-+              vap = ni->ni_subif;
-+              dev = vap->iv_dev;
++              if (ni->ni_vap == ni->ni_subif) {
++                      ieee80211_dev_kfree_skb(&skb);
++              } else {
++                      vap = ni->ni_subif;
++                      dev = vap->iv_dev;
++              }
 +      }
 +
        /* perform as a bridge within the vap */
 +                               (vap->iv_opmode == IEEE80211_M_WDS)) &&
 +                              (scan.capinfo & IEEE80211_CAPINFO_ESS))) {
 +                      struct ieee80211vap *avp = NULL;
++                      int found = 0;
 +
 +                      IEEE80211_LOCK_IRQ(vap->iv_ic);
 +                      if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
-+                              int found = 0;
-+
 +                              TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
 +                                      if (!memcmp(avp->wds_mac, wh->i_addr2, IEEE80211_ADDR_LEN)) {
 +                                              if (avp->iv_state != IEEE80211_S_RUN)
 +                                              break;
 +                                      }
 +                              }
-+                              if (!found)
-+                                      break;
-+
-+                              ni = ni_or_null = avp->iv_wdsnode;
++                              if (found)
++                                      ni = ni_or_null = avp->iv_wdsnode;
 +                      } else if (vap->iv_opmode == IEEE80211_M_WDS) {
++                              found = 1;
 +                              ni = ni_or_null = vap->iv_wdsnode;
 +                      }
 +                      IEEE80211_UNLOCK_IRQ(vap->iv_ic);
 +
++                      if (!found)
++                              break;
 +
                        if (ni_or_null == NULL) {
 -                              /* Create a new entry in the neighbor table. */
  }
  
  /* This is overridden by ath_node_alloc in ath/if_ath.c, and so
-@@ -1134,6 +1145,62 @@ ieee80211_alloc_node(struct ieee80211vap
+@@ -1134,6 +1145,65 @@ ieee80211_alloc_node(struct ieee80211vap
        return ni;
  }
  
 +      if (ni->ni_subif)
 +              return;
 +
++      if (!ni->ni_table)
++              return;
++
 +      ieee80211_ref_node(ni);
 +      ni->ni_subif = ni->ni_vap;
 +      IEEE80211_INIT_WORK(&ni->ni_create, ieee80211_wds_do_addif);
  /* Add wds address to the node table */
  int
  #ifdef IEEE80211_DEBUG_REFCNT
-@@ -1553,22 +1620,39 @@ ieee80211_find_rxnode(struct ieee80211co
+@@ -1553,22 +1623,39 @@ ieee80211_find_rxnode(struct ieee80211co
        ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
        struct ieee80211_node_table *nt;
        struct ieee80211_node *ni;
  #endif
        IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
  
-@@ -1596,9 +1680,19 @@ ieee80211_find_txnode_debug(struct ieee8
+@@ -1596,9 +1683,19 @@ ieee80211_find_txnode_debug(struct ieee8
  ieee80211_find_txnode(struct ieee80211vap *vap, const u_int8_t *mac)
  #endif
  {
        /*
         * The destination address should be in the node table
         * unless we are operating in station mode or this is a
-@@ -1669,6 +1763,11 @@ ieee80211_free_node(struct ieee80211_nod
+@@ -1669,6 +1766,11 @@ ieee80211_free_node(struct ieee80211_nod
  {
        struct ieee80211vap *vap = ni->ni_vap;
  
        atomic_dec(&ni->ni_ic->ic_node_counter);
        node_print_message(IEEE80211_MSG_NODE|IEEE80211_MSG_NODE_REF,
                           1 /* show counter */, 
-@@ -1781,22 +1880,6 @@ restart:
+@@ -1781,22 +1883,6 @@ restart:
                    jiffies > ni->ni_rxfragstamp + HZ) {
                        ieee80211_dev_kfree_skb(&ni->ni_rxfrag);
                }
                ni->ni_inact--;
                if (ni->ni_associd != 0 || isadhoc) {
                        struct ieee80211vap *vap = ni->ni_vap;
-@@ -2263,6 +2346,36 @@ ieee80211_node_leave_11g(struct ieee8021
+@@ -2263,6 +2349,35 @@ ieee80211_node_leave_11g(struct ieee8021
        }
  }
  
 +      struct ieee80211vap *vap;
 +      struct ieee80211com *ic;
 +
++      /* wait for full initialization before we start the teardown
++       * otherwise we could leak interfaces */
++      while (ni->ni_subif == ni->ni_vap)
++              schedule();
++
 +      rtnl_lock();
 +      vap = ni->ni_subif;
 +
-+      /* if addif is waiting for the timer to fire, cancel! */
-+      if (vap == ni->ni_vap) {
-+              ni->ni_subif = NULL;
-+              goto done;
-+      }
-+
 +      if (!vap)
 +              goto done;
 +
  /*
   * Handle bookkeeping for a station/neighbor leaving
   * the bss when operating in ap or adhoc modes.
-@@ -2279,6 +2392,12 @@ ieee80211_node_leave(struct ieee80211_no
+@@ -2279,6 +2394,12 @@ ieee80211_node_leave(struct ieee80211_no
                        ni, "station with aid %d leaves (refcnt %u)",
                        IEEE80211_NODE_AID(ni), atomic_read(&ni->ni_refcnt));
  
index b3237aef995d53112b992566ff6ed4e46fa21a0e..0a2982799f9ea7cc8ef518a12c432005e60ec28b 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -5483,6 +5483,9 @@ ath_beacon_config(struct ath_softc *sc, 
+@@ -5486,6 +5486,9 @@ ath_beacon_config(struct ath_softc *sc, 
                ath_beacon_dturbo_config(vap, intval &
                                ~(HAL_BEACON_RESET_TSF | HAL_BEACON_ENA));
  #endif
index 64bd1c1973ba472159a8127670edc653aa1a12af..9381f8a818461810b18f33bcb2672f86e2372703 100644 (file)
@@ -8,7 +8,7 @@
  static int ath_desc_alloc(struct ath_softc *);
  static void ath_desc_free(struct ath_softc *);
  static void ath_desc_swap(struct ath_desc *);
-@@ -2792,6 +2793,72 @@ ath_set_ack_bitrate(struct ath_softc *sc
+@@ -2793,6 +2794,72 @@ ath_set_ack_bitrate(struct ath_softc *sc
        return 1;
  }
  
@@ -81,7 +81,7 @@
  /*
   * Reset the hardware w/o losing operational state.  This is
   * basically a more efficient way of doing ath_stop, ath_init,
-@@ -5291,6 +5358,7 @@ ath_beacon_config(struct ath_softc *sc, 
+@@ -5294,6 +5361,7 @@ ath_beacon_config(struct ath_softc *sc, 
        u_int64_t tsf, hw_tsf;
        u_int32_t tsftu, hw_tsftu;
        u_int32_t intval, nexttbtt = 0;
@@ -89,7 +89,7 @@
        int reset_tsf = 0;
  
        if (vap == NULL)
-@@ -5298,6 +5366,9 @@ ath_beacon_config(struct ath_softc *sc, 
+@@ -5301,6 +5369,9 @@ ath_beacon_config(struct ath_softc *sc, 
  
        ni = vap->iv_bss;
  
@@ -99,7 +99,7 @@
        hw_tsf = ath_hal_gettsf64(ah);
        tsf = le64_to_cpu(ni->ni_tstamp.tsf);
        hw_tsftu = hw_tsf >> 10;
-@@ -5487,15 +5558,27 @@ ath_beacon_config(struct ath_softc *sc, 
+@@ -5490,15 +5561,27 @@ ath_beacon_config(struct ath_softc *sc, 
                                <= ath_hal_sw_beacon_response_time)
                        nexttbtt += intval;
                sc->sc_nexttbtt = nexttbtt;
        /* We print all debug messages here, in order to preserve the
         * time critical aspect of this function */
        DPRINTF(sc, ATH_DEBUG_BEACON,
-@@ -6398,6 +6481,11 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+@@ -6401,6 +6484,11 @@ ath_recv_mgmt(struct ieee80211vap * vap,
                        DPRINTF(sc, ATH_DEBUG_BEACON, 
                                "Updated beacon timers\n");
                }
index ec04276dff3c49e69dfe30572d71163461b1ebd5..f904ed9721b8c5b3262f153503cf30b3e52eebaa 100644 (file)
@@ -12,7 +12,7 @@
                break;
        case IEEE80211_M_AHDEMO:
        case IEEE80211_M_MONITOR:
-@@ -1454,7 +1457,7 @@ ath_vap_create(struct ieee80211com *ic, 
+@@ -1455,7 +1458,7 @@ ath_vap_create(struct ieee80211com *ic, 
         * frames.  Other modes carry over directly to the HAL.
         */
        if (ic->ic_opmode == IEEE80211_M_AHDEMO)
index 445f537373a523e308a609cb07ce0a3650914d4d..a91753cc15c1cb7a13b06d4a36b5cbe1975638e0 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -1451,6 +1451,23 @@ ath_vap_create(struct ieee80211com *ic, 
+@@ -1452,6 +1452,23 @@ ath_vap_create(struct ieee80211com *ic, 
                sc->sc_nstavaps++;
        else if (opmode == IEEE80211_M_MONITOR)
                sc->sc_nmonvaps++;
@@ -24,7 +24,7 @@
        /*
         * Adhoc demo mode is a pseudo mode; to the HAL it's
         * just IBSS mode and the driver doesn't use management
-@@ -4278,7 +4295,8 @@ ath_calcrxfilter(struct ath_softc *sc)
+@@ -4279,7 +4296,8 @@ ath_calcrxfilter(struct ath_softc *sc)
        if (ic->ic_opmode != IEEE80211_M_HOSTAP && (dev->flags & IFF_PROMISC))
                rfilt |= HAL_RX_FILTER_PROM;
        if (ic->ic_opmode == IEEE80211_M_STA ||
@@ -34,7 +34,7 @@
            (sc->sc_nostabeacons) || sc->sc_scanning ||
                (ic->ic_opmode == IEEE80211_M_HOSTAP))
                rfilt |= HAL_RX_FILTER_BEACON;
-@@ -6432,6 +6450,33 @@ ath_capture(struct net_device *dev, cons
+@@ -6435,6 +6453,33 @@ ath_capture(struct net_device *dev, cons
  }
  
  /*
@@ -68,7 +68,7 @@
   * Intercept management frames to collect beacon RSSI data and to do
   * ibss merges. This function is called for all management frames,
   * including those belonging to other BSS.
-@@ -6484,10 +6529,19 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+@@ -6487,10 +6532,19 @@ ath_recv_mgmt(struct ieee80211vap * vap,
                        DPRINTF(sc, ATH_DEBUG_BEACON, 
                                "Updated beacon timers\n");
                }
@@ -92,7 +92,7 @@
                }
                /* NB: Fall Through */
        case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
-@@ -6560,6 +6614,10 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+@@ -6563,6 +6617,10 @@ ath_recv_mgmt(struct ieee80211vap * vap,
  #endif
                        if (do_merge)
                                ieee80211_ibss_merge(ni);
index aeaf8f66986449d0449815128494f15c2601832c..397b69c2e1a6ef9ae71b34afc0969b22862921f8 100644 (file)
@@ -33,7 +33,7 @@
        /* Allocate space for dynamically determined maximum VAP count */
        sc->sc_bslot = 
                kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL);
-@@ -1507,6 +1519,28 @@ ath_vap_create(struct ieee80211com *ic, 
+@@ -1508,6 +1520,28 @@ ath_vap_create(struct ieee80211com *ic, 
        return vap;
  }
  
@@ -62,7 +62,7 @@
  static void
  ath_vap_delete(struct ieee80211vap *vap)
  {
-@@ -10818,6 +10852,12 @@ ath_ioctl(struct net_device *dev, struct
+@@ -10821,6 +10855,12 @@ ath_ioctl(struct net_device *dev, struct
   * is to add module parameters.
   */
  
@@ -75,7 +75,7 @@
  /*
   * Dynamic (i.e. per-device) sysctls.  These are automatically
   * mirrored in /proc/sys.
-@@ -10897,6 +10937,38 @@ ath_sysctl_get_intmit(struct ath_softc *
+@@ -10900,6 +10940,38 @@ ath_sysctl_get_intmit(struct ath_softc *
  }
  
  static int
  ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
  {
        struct ath_softc *sc = ctl->extra1;
-@@ -11176,6 +11248,24 @@ static int maxint = 0x7fffffff;               /* 32-b
+@@ -11179,6 +11251,24 @@ static int maxint = 0x7fffffff;               /* 32-b
  
  static const ctl_table ath_sysctl_template[] = {
        { .ctl_name     = CTL_AUTO,
index de4e9fe6bde6db36ae7e0c9997e5d17af8abe4a1..9e34304402e20c9856edc17cc09329945963f438 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -6665,6 +6665,7 @@ ath_setdefantenna(struct ath_softc *sc, 
+@@ -6668,6 +6668,7 @@ ath_setdefantenna(struct ath_softc *sc, 
        struct ath_hal *ah = sc->sc_ah;
  
        /* XXX block beacon interrupts */
index 0e4cad873ddc11864368dbc0671eb98e6934cb15..1c62285904d97c3d4e50dff3e7f9b3da731047a9 100644 (file)
@@ -8,7 +8,7 @@
  
  /* calibrate every 30 secs in steady state but check every second at first. */
  static int ath_calinterval = ATH_SHORT_CALINTERVAL;
-@@ -2579,6 +2580,7 @@ ath_init(struct net_device *dev)
+@@ -2580,6 +2581,7 @@ ath_init(struct net_device *dev)
         * be followed by initialization of the appropriate bits
         * and then setup of the interrupt mask.
         */
@@ -16,7 +16,7 @@
        sc->sc_curchan.channel = ic->ic_curchan->ic_freq;
        sc->sc_curchan.channelFlags = ath_chan2flags(ic->ic_curchan);
        if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) {
-@@ -2913,6 +2915,40 @@ ath_hw_check_atim(struct ath_softc *sc, 
+@@ -2914,6 +2916,40 @@ ath_hw_check_atim(struct ath_softc *sc, 
  }
  
  
@@ -57,7 +57,7 @@
  /*
   * Reset the hardware w/o losing operational state.  This is
   * basically a more efficient way of doing ath_stop, ath_init,
-@@ -2939,6 +2975,7 @@ ath_reset(struct net_device *dev)
+@@ -2940,6 +2976,7 @@ ath_reset(struct net_device *dev)
         * Convert to a HAL channel description with the flags
         * constrained to reflect the current operating mode.
         */
@@ -65,7 +65,7 @@
        c = ic->ic_curchan;
        sc->sc_curchan.channel = c->ic_freq;
        sc->sc_curchan.channelFlags = ath_chan2flags(c);
-@@ -9019,6 +9056,7 @@ ath_chan_set(struct ath_softc *sc, struc
+@@ -9022,6 +9059,7 @@ ath_chan_set(struct ath_softc *sc, struc
        u_int8_t channel_change_required = 0;
        struct timeval tv;
  
diff --git a/package/madwifi/patches/391-vap_auth.patch b/package/madwifi/patches/391-vap_auth.patch
new file mode 100644 (file)
index 0000000..b317be0
--- /dev/null
@@ -0,0 +1,29 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1374,7 +1374,7 @@ ieee80211_auth_open(struct ieee80211_nod
+               vap->iv_stats.is_rx_bad_auth++; /* XXX maybe a unique error? */
+               if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+                       if (ni == vap->iv_bss) {
+-                              ni = ieee80211_dup_bss(vap, wh->i_addr2, 0);
++                              ni = ieee80211_dup_bss(vap, wh->i_addr2, 1);
+                               if (ni == NULL)
+                                       return;
+                               tmpnode = 1;
+@@ -1762,6 +1762,8 @@ ieee80211_ssid_mismatch(struct ieee80211
+ }
+ #define       IEEE80211_VERIFY_SSID(_ni, _ssid) do {                          \
++      if ((_ni)->ni_esslen == 0)                                      \
++              return;                                                 \
+       if ((_ssid)[1] != 0 &&                                          \
+           ((_ssid)[1] != (_ni)->ni_esslen ||                          \
+           memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {   \
+@@ -1776,6 +1778,8 @@ ieee80211_ssid_mismatch(struct ieee80211
+ } while (0)
+ #else /* !IEEE80211_DEBUG */
+ #define       IEEE80211_VERIFY_SSID(_ni, _ssid) do {                          \
++      if ((_ni)->ni_esslen == 0)                                      \
++              return;                                                 \
+       if ((_ssid)[1] != 0 &&                                          \
+           ((_ssid)[1] != (_ni)->ni_esslen ||                          \
+           memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {   \
diff --git a/package/madwifi/patches/392-remove_wds_nodetracking.patch b/package/madwifi/patches/392-remove_wds_nodetracking.patch
new file mode 100644 (file)
index 0000000..fb9fb6a
--- /dev/null
@@ -0,0 +1,388 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -568,36 +568,6 @@ ieee80211_input(struct ieee80211vap * va
+                               }
+                       }
+-                      /* XXX: Useless node mgmt API; make better */
+-                      if ((dir == IEEE80211_FC1_DIR_DSTODS) && !vap->iv_wdsnode &&
+-                                      !ni_wds && !ni->ni_subif) {
+-                              struct ieee80211_node_table *nt = &ic->ic_sta;
+-                              struct ieee80211_frame_addr4 *wh4;
+-
+-                              if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) {
+-                                      IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
+-                                              wh, "data", "%s", "4 addr not allowed");
+-                                      goto err;
+-                              }
+-                              wh4 = (struct ieee80211_frame_addr4 *)skb->data;
+-                              ni_wds = ieee80211_find_wds_node(nt, wh4->i_addr4);
+-                              /* Last call increments ref count if !NULL */
+-                              if ((ni_wds != NULL) && (ni_wds != ni)) {
+-                                      /*
+-                                       * node with source address (addr4) moved
+-                                       * to another WDS capable station. remove the
+-                                       * reference to the previous station and add 
+-                                       * reference to the new one
+-                                       */
+-                                       (void) ieee80211_remove_wds_addr(nt, wh4->i_addr4);
+-                                       ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0);
+-                              }
+-                              if (ni_wds == NULL)
+-                                      ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0);
+-                              else
+-                                      ieee80211_unref_node(&ni_wds);
+-                      }
+-
+                       /*
+                        * Check for power save state change.
+                        */
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -122,7 +122,6 @@ static void ieee80211_node_table_init(st
+ static void ieee80211_node_table_cleanup(struct ieee80211_node_table *);
+ static void ieee80211_node_table_reset(struct ieee80211_node_table *,
+       struct ieee80211vap *);
+-static void ieee80211_node_wds_ageout(unsigned long);
+ MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
+@@ -785,10 +784,6 @@ ieee80211_node_table_init(struct ieee802
+       nt->nt_name = name;
+       nt->nt_scangen = 1;
+       nt->nt_inact_init = inact;
+-      init_timer(&nt->nt_wds_aging_timer);
+-      nt->nt_wds_aging_timer.function = ieee80211_node_wds_ageout;
+-      nt->nt_wds_aging_timer.data = (unsigned long) nt;
+-      mod_timer(&nt->nt_wds_aging_timer, jiffies + HZ * WDS_AGING_TIMER_VAL);
+ }
+ static __inline 
+@@ -1204,142 +1199,6 @@ void ieee80211_wds_addif(struct ieee8021
+       schedule_work(&ni->ni_create);
+ }
+-/* Add wds address to the node table */
+-int
+-#ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_add_wds_addr_debug(struct ieee80211_node_table *nt,
+-      struct ieee80211_node *ni, const u_int8_t *macaddr, u_int8_t wds_static,
+-      const char* func, int line)
+-#else
+-ieee80211_add_wds_addr(struct ieee80211_node_table *nt,
+-      struct ieee80211_node *ni, const u_int8_t *macaddr, u_int8_t wds_static)
+-#endif
+-{
+-      int hash;
+-      struct ieee80211_wds_addr *wds;
+-
+-      MALLOC(wds, struct ieee80211_wds_addr *, sizeof(struct ieee80211_wds_addr),
+-              M_80211_WDS, M_NOWAIT | M_ZERO);
+-      if (wds == NULL) {
+-              /* XXX msg */
+-              return 1;
+-      }
+-      if (wds_static)
+-              wds->wds_agingcount = WDS_AGING_STATIC;
+-      else
+-              wds->wds_agingcount = WDS_AGING_COUNT;
+-      hash = IEEE80211_NODE_HASH(macaddr);
+-      IEEE80211_ADDR_COPY(wds->wds_macaddr, macaddr);
+-
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-#ifdef IEEE80211_DEBUG_REFCNT
+-      wds->wds_ni = ieee80211_ref_node_debug(ni, func, line);
+-#else
+-      wds->wds_ni = ieee80211_ref_node(ni);
+-#endif
+-      LIST_INSERT_HEAD(&nt->nt_wds_hash[hash], wds, wds_hash);
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-      return 0;
+-}
+-#ifdef IEEE80211_DEBUG_REFCNT
+-EXPORT_SYMBOL(ieee80211_add_wds_addr_debug);
+-#else
+-EXPORT_SYMBOL(ieee80211_add_wds_addr);
+-#endif
+-
+-/* remove wds address from the wds hash table */
+-void
+-#ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_remove_wds_addr_debug(struct ieee80211_node_table *nt, const u_int8_t *macaddr, 
+-                         const char* func, int line)
+-#else
+-ieee80211_remove_wds_addr(struct ieee80211_node_table *nt, const u_int8_t *macaddr)
+-#endif
+-{
+-      int hash;
+-      struct ieee80211_wds_addr *wds, *twds;
+-
+-      hash = IEEE80211_NODE_HASH(macaddr);
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-      LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) {
+-              if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) {
+-                      LIST_REMOVE(wds, wds_hash);
+-#ifdef IEEE80211_DEBUG_REFCNT
+-                      ieee80211_unref_node_debug(&wds->wds_ni, func, line);
+-#else
+-                      ieee80211_unref_node(&wds->wds_ni);
+-#endif
+-                      FREE(wds, M_80211_WDS);
+-                      break;
+-              }
+-      }
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-}
+-#ifdef IEEE80211_DEBUG_REFCNT
+-EXPORT_SYMBOL(ieee80211_remove_wds_addr_debug);
+-#else
+-EXPORT_SYMBOL(ieee80211_remove_wds_addr);
+-#endif
+-
+-/* Remove node references from wds table */
+-void
+-#ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_del_wds_node_debug(struct ieee80211_node_table *nt, struct ieee80211_node *ni, 
+-                      const char* func, int line)
+-#else
+-ieee80211_del_wds_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
+-#endif
+-{
+-      int hash;
+-      struct ieee80211_wds_addr *wds, *twds;
+-
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-      for (hash = 0; hash < IEEE80211_NODE_HASHSIZE; hash++) {
+-              LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) {
+-                      if (wds->wds_ni == ni) {
+-                              LIST_REMOVE(wds, wds_hash);
+-#ifdef IEEE80211_DEBUG_REFCNT
+-                              ieee80211_unref_node_debug(&wds->wds_ni, func, line);
+-#else
+-                              ieee80211_unref_node(&wds->wds_ni);
+-#endif
+-                              FREE(wds, M_80211_WDS);
+-                      }
+-              }
+-      }
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-}
+-#ifdef IEEE80211_DEBUG_REFCNT
+-EXPORT_SYMBOL(ieee80211_del_wds_node_debug);
+-#else
+-EXPORT_SYMBOL(ieee80211_del_wds_node);
+-#endif
+-
+-static void
+-ieee80211_node_wds_ageout(unsigned long data)
+-{
+-      struct ieee80211_node_table *nt = (struct ieee80211_node_table *)data;
+-      int hash;
+-      struct ieee80211_wds_addr *wds, *twds;
+-
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-      for (hash = 0; hash < IEEE80211_NODE_HASHSIZE; hash++) {
+-              LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) {
+-                      if (wds->wds_agingcount != WDS_AGING_STATIC) {
+-                              if (!wds->wds_agingcount) {
+-                                      LIST_REMOVE(wds, wds_hash);
+-                                      ieee80211_unref_node(&wds->wds_ni);
+-                                      FREE(wds, M_80211_WDS);
+-                              } else
+-                                      wds->wds_agingcount--;
+-                      }
+-              }
+-      }
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-      mod_timer(&nt->nt_wds_aging_timer, jiffies + HZ * WDS_AGING_TIMER_VAL);
+-}
+-
+-
+ /* Add the specified station to the station table.
+  * Allocates a new ieee80211_node* that has a reference count of one
+  * If tmp is 0, it is added to the node table and the reference is used.
+@@ -1385,34 +1244,6 @@ ieee80211_dup_bss(struct ieee80211vap *v
+       return ni;
+ }
+-static struct ieee80211_node *
+-#ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_find_wds_node_locked_debug(struct ieee80211_node_table *nt, 
+-                       const u_int8_t *macaddr, const char* func, int line)
+-#else
+-ieee80211_find_wds_node_locked(struct ieee80211_node_table *nt, 
+-                       const u_int8_t *macaddr)
+-#endif
+-{
+-      struct ieee80211_wds_addr *wds;
+-      int hash;
+-      IEEE80211_NODE_TABLE_LOCK_ASSERT(nt);
+-
+-      hash = IEEE80211_NODE_HASH(macaddr);
+-      LIST_FOREACH(wds, &nt->nt_wds_hash[hash], wds_hash) {
+-              if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) {
+-                      if (wds->wds_agingcount != WDS_AGING_STATIC)
+-                              wds->wds_agingcount = WDS_AGING_COUNT; /* reset the aging count */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-                      return ieee80211_ref_node_debug(wds->wds_ni, func, line);
+-#else
+-                      return ieee80211_ref_node(wds->wds_ni);
+-#endif
+-              }
+-      }
+-      return NULL;
+-}
+-
+ /* NB: A node reference is acquired here; the caller MUST release it. */
+ #ifdef IEEE80211_DEBUG_REFCNT
+ #define       ieee80211_find_node_locked(nt, mac) \
+@@ -1430,7 +1261,6 @@ ieee80211_find_node_locked(struct ieee80
+ {
+       struct ieee80211_node *ni;
+       int hash;
+-      struct ieee80211_wds_addr *wds;
+       IEEE80211_NODE_TABLE_LOCK_ASSERT(nt);
+@@ -1445,48 +1275,11 @@ ieee80211_find_node_locked(struct ieee80
+                       return ni;
+               }
+       }
+-
+-      /* Now, we look for the desired mac address in the 4 address
+-         nodes. */
+-      LIST_FOREACH(wds, &nt->nt_wds_hash[hash], wds_hash) {
+-              if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) {
+-#ifdef IEEE80211_DEBUG_REFCNT
+-                      return ieee80211_ref_node_debug(wds->wds_ni, func, line);
+-#else
+-                      return ieee80211_ref_node(wds->wds_ni);
+-#endif 
+-              }
+-      }
+       return NULL;
+ }
+ struct ieee80211_node *
+ #ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_find_wds_node_debug(struct ieee80211_node_table *nt, const u_int8_t *macaddr, 
+-                       const char* func, int line)
+-#else
+-ieee80211_find_wds_node(struct ieee80211_node_table *nt, const u_int8_t *macaddr)
+-#endif
+-{
+-      struct ieee80211_node *ni;
+-
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-#ifdef IEEE80211_DEBUG_REFCNT
+-      ni = ieee80211_find_wds_node_locked_debug(nt, macaddr, func, line);
+-#else
+-      ni = ieee80211_find_wds_node_locked(nt, macaddr);
+-#endif
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-      return ni;
+-}
+-#ifdef IEEE80211_DEBUG_REFCNT
+-EXPORT_SYMBOL(ieee80211_find_wds_node_debug);
+-#else
+-EXPORT_SYMBOL(ieee80211_find_wds_node);
+-#endif
+-
+-struct ieee80211_node *
+-#ifdef IEEE80211_DEBUG_REFCNT
+ ieee80211_find_node_debug(struct ieee80211_node_table *nt,
+       const u_int8_t *macaddr, const char *func, int line)
+ #else
+@@ -1838,7 +1631,6 @@ ieee80211_node_table_cleanup(struct ieee
+               ic->ic_node_cleanup(ni);
+ #endif
+       }
+-      del_timer(&nt->nt_wds_aging_timer);
+       IEEE80211_SCAN_LOCK_DESTROY(nt);
+       IEEE80211_NODE_TABLE_LOCK_DESTROY(nt);
+ }
+@@ -2404,8 +2196,6 @@ ieee80211_node_leave(struct ieee80211_no
+        * so no more references are generated
+        */
+       if (nt) {
+-              ieee80211_remove_wds_addr(nt, ni->ni_macaddr);
+-              ieee80211_del_wds_node(nt, ni);
+               IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+               node_table_leave_locked(nt, ni);
+               IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+--- a/net80211/ieee80211_node.h
++++ b/net80211/ieee80211_node.h
+@@ -231,13 +231,6 @@ void ieee80211_sta_leave(struct ieee8021
+ #define WDS_AGING_STATIC      0xffff
+ #define WDS_AGING_TIMER_VAL   (WDS_AGING_TIME / 2)
+-struct ieee80211_wds_addr {
+-      LIST_ENTRY(ieee80211_wds_addr) wds_hash;
+-      u_int8_t        wds_macaddr[IEEE80211_ADDR_LEN];
+-      struct ieee80211_node *wds_ni;
+-      u_int16_t wds_agingcount;
+-};
+-
+ /*
+  * Table of ieee80211_node instances.  Each ieee80211com
+  * has at least one for holding the scan candidates.
+@@ -250,11 +243,9 @@ struct ieee80211_node_table {
+       ieee80211_node_table_lock_t nt_nodelock;        /* on node table */
+       TAILQ_HEAD(, ieee80211_node) nt_node;   /* information of all nodes */
+       ATH_LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE];
+-      ATH_LIST_HEAD(, ieee80211_wds_addr) nt_wds_hash[IEEE80211_NODE_HASHSIZE];
+       ieee80211_scan_lock_t nt_scanlock;      /* on nt_scangen */
+       u_int nt_scangen;                       /* gen# for timeout scan */
+       int nt_inact_init;                      /* initial node inact setting */
+-      struct timer_list nt_wds_aging_timer;   /* timer to age out wds entries */
+ };
+ /* Allocates a new ieee80211_node* that has a reference count of one, and 
+@@ -363,47 +354,6 @@ void
+ ieee80211_unref_node(struct ieee80211_node **pni);
+ #endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+-/* Increments reference count of ieee80211_node *ni */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_add_wds_addr(_table, _node, _mac, _static) \
+-      ieee80211_add_wds_addr_debug(_table, _node, _mac, _static, __func__, __LINE__)
+-int ieee80211_add_wds_addr_debug(struct ieee80211_node_table *, struct ieee80211_node *,
+-      const u_int8_t *, u_int8_t, const char* func, int line);
+-#else
+-int ieee80211_add_wds_addr(struct ieee80211_node_table *, struct ieee80211_node *,
+-      const u_int8_t *, u_int8_t);
+-#endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+-
+-/* Decrements reference count of ieee80211_node *ni */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_remove_wds_addr(_table, _mac) \
+-      ieee80211_remove_wds_addr_debug(_table, _mac, __func__, __LINE__)
+-void ieee80211_remove_wds_addr_debug(struct ieee80211_node_table *, const u_int8_t *,
+-                             const char* func, int line);
+-#else
+-void ieee80211_remove_wds_addr(struct ieee80211_node_table *, const u_int8_t *);
+-#endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+-
+-/* Decrements reference count of node, if found */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_del_wds_node(_table, _node) \
+-      ieee80211_del_wds_node_debug(_table, _node, __func__, __LINE__)
+-void ieee80211_del_wds_node_debug(struct ieee80211_node_table *, struct ieee80211_node *,
+-                          const char* func, int line);
+-#else
+-void ieee80211_del_wds_node(struct ieee80211_node_table *, struct ieee80211_node *);
+-#endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+-
+-/* Increments reference count of node, if found */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_find_wds_node(_table, _mac) \
+-      ieee80211_find_wds_node_debug(_table, _mac, __func__, __LINE__)
+-struct ieee80211_node *ieee80211_find_wds_node_debug(struct ieee80211_node_table *,
+-      const u_int8_t *, const char* func, int line);
+-#else
+-struct ieee80211_node *ieee80211_find_wds_node(struct ieee80211_node_table *,
+-      const u_int8_t *);
+-#endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+ typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
+ void ieee80211_iterate_nodes(struct ieee80211_node_table *,
+       ieee80211_iter_func *, void *);
diff --git a/package/madwifi/patches/393-mbss_vap_auth.patch b/package/madwifi/patches/393-mbss_vap_auth.patch
new file mode 100644 (file)
index 0000000..233aeed
--- /dev/null
@@ -0,0 +1,454 @@
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -123,6 +123,9 @@ static void ieee80211_node_table_cleanup
+ static void ieee80211_node_table_reset(struct ieee80211_node_table *,
+       struct ieee80211vap *);
++static struct ieee80211_node *
++lookup_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap, const u_int8_t *addr);
++
+ MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
+ void
+@@ -697,7 +700,7 @@ ieee80211_sta_join(struct ieee80211vap *
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node *ni;
+-      ni = ieee80211_find_node(&ic->ic_sta, se->se_macaddr);
++      ni = lookup_rxnode(ic, vap, se->se_macaddr);
+       if (ni == NULL) {
+               ni = ieee80211_alloc_node_table(vap, se->se_macaddr);
+               IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
+@@ -1394,6 +1397,53 @@ ieee80211_add_neighbor(struct ieee80211v
+       return ni;
+ }
++struct ieee80211vap *
++ieee80211_find_rxvap(struct ieee80211com *ic, const u_int8_t *mac)
++{
++      struct ieee80211vap *vap;
++
++      TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++              if (IEEE80211_ADDR_EQ(vap->iv_myaddr, mac))
++                      return vap;
++      }
++      return NULL;
++}
++EXPORT_SYMBOL(ieee80211_find_rxvap);
++
++static struct ieee80211_node *
++lookup_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap,
++      const u_int8_t *addr)
++{
++      struct ieee80211_node_table *nt;
++      struct ieee80211_node *ni = NULL;
++      int use_bss = 0;
++      int hash;
++
++      nt = &ic->ic_sta;
++      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
++      hash = IEEE80211_NODE_HASH(addr);
++      LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
++              if (IEEE80211_ADDR_EQ(ni->ni_macaddr, addr)) {
++                      /* allow multiple nodes on different vaps */
++                      if (vap && (ni->ni_vap != vap))
++                              continue;
++
++                      ieee80211_ref_node(ni);
++                      goto out;
++              }
++      }
++
++      /* no match found */
++      ni = NULL;
++
++out:
++      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
++      return ni;
++#undef IS_PSPOLL
++#undef IS_CTL
++}
++
++
+ /*
+  * Return the node for the sender of a frame; if the sender is unknown return 
+  * NULL. The caller is expected to deal with this. (The frame is sent to all 
+@@ -1403,10 +1453,10 @@ ieee80211_add_neighbor(struct ieee80211v
+  */
+ struct ieee80211_node *
+ #ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_find_rxnode_debug(struct ieee80211com *ic,
++ieee80211_find_rxnode_debug(struct ieee80211com *ic, struct ieee80211vap *vap,
+       const struct ieee80211_frame_min *wh, const char *func, int line)
+ #else
+-ieee80211_find_rxnode(struct ieee80211com *ic,
++ieee80211_find_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap,
+       const struct ieee80211_frame_min *wh)
+ #endif
+ {
+@@ -1414,9 +1464,8 @@ ieee80211_find_rxnode(struct ieee80211co
+       ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
+ #define       IS_PSPOLL(wh) \
+       ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
+-      struct ieee80211_node_table *nt;
+-      struct ieee80211_node *ni;
+-      struct ieee80211vap *vap, *avp;
++      struct ieee80211_node *ni = NULL;
++      struct ieee80211vap *avp;
+       const u_int8_t *addr;
+       if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
+@@ -1429,32 +1478,25 @@ ieee80211_find_rxnode(struct ieee80211co
+       /* XXX check ic_bss first in station mode */
+       /* XXX 4-address frames? */
+-      nt = &ic->ic_sta;
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+       if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
+-              TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++              if (vap) { /* assume unicast if vap is set, mcast not supported for wds */
+                       TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
+-                              if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac))
++                              if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac) ||
++                                      !IEEE80211_ADDR_EQ(wh->i_addr1, avp->iv_myaddr))
+                                       continue;
+                               if (avp->iv_wdsnode)
+-                                      return ieee80211_ref_node(avp->iv_wdsnode);
+-                              else
+-                                      return NULL;
++                                      ni = ieee80211_ref_node(avp->iv_wdsnode);
++                              return ni;
+                       }
++                      if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS))
++                              return NULL;
++              } else {
++                      return NULL;
+               }
+       }
+-#ifdef IEEE80211_DEBUG_REFCNT
+-      ni = ieee80211_find_node_locked_debug(nt, addr, func, line);
+-#else
+-      ni = ieee80211_find_node_locked(nt, addr);
+-#endif
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-
+-      return ni;
+-#undef IS_PSPOLL
+-#undef IS_CTL
++      return lookup_rxnode(ic, vap, addr);
+ }
+ #ifdef IEEE80211_DEBUG_REFCNT
+ EXPORT_SYMBOL(ieee80211_find_rxnode_debug);
+@@ -1479,15 +1521,14 @@ ieee80211_find_txnode(struct ieee80211va
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node_table *nt;
+       struct ieee80211_node *ni = NULL;
++      int hash;
+-      IEEE80211_LOCK_IRQ(ic);
+       if (vap->iv_opmode == IEEE80211_M_WDS) {
+               if (vap->iv_wdsnode && (vap->iv_state == IEEE80211_S_RUN))
+                       return ieee80211_ref_node(vap->iv_wdsnode);
+               else
+                       return NULL;
+       }
+-      IEEE80211_UNLOCK_IRQ(ic);
+       /*
+        * The destination address should be in the node table
+@@ -1505,11 +1546,22 @@ ieee80211_find_txnode(struct ieee80211va
+       /* XXX: Can't hold lock across dup_bss due to recursive locking. */
+       nt = &vap->iv_ic->ic_sta;
+       IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
++      hash = IEEE80211_NODE_HASH(mac);
++      LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
++              if (ni->ni_vap != vap)
++                      continue;
++
++              if (IEEE80211_ADDR_EQ(ni->ni_macaddr, mac)) {
+ #ifdef IEEE80211_DEBUG_REFCNT
+-      ni = ieee80211_find_node_locked_debug(nt, mac, func, line);
++                      ieee80211_ref_node_debug(ni, func, line);
+ #else
+-      ni = ieee80211_find_node_locked(nt, mac);
++                      ieee80211_ref_node(ni);
+ #endif
++                      goto found;
++              }
++      }
++      ni = NULL;
++found:
+       IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+       if (ni == NULL) {
+@@ -1964,13 +2016,32 @@ remove_worse_nodes(void *arg, struct iee
+               }
+ }
++static void
++remove_duplicate_nodes(void *arg, struct ieee80211_node *ni)
++{
++      struct ieee80211_node *rni = arg;
++
++      if (ni == rni)
++              return;
++
++      if (ni->ni_vap == rni->ni_vap)
++              return;
++
++      if (!IEEE80211_ADDR_EQ(rni->ni_macaddr, ni->ni_macaddr))
++              return;
++
++      ieee80211_node_leave(ni);
++}
++
+ void
+ ieee80211_node_join(struct ieee80211_node *ni, int resp)
+ {
+       struct ieee80211com *ic = ni->ni_ic;
+       struct ieee80211vap *vap = ni->ni_vap;
++      struct ieee80211_node *tni;
+       int newassoc;
++      ieee80211_iterate_nodes(&ic->ic_sta, remove_duplicate_nodes, ni);
+       if (ni->ni_associd == 0) {
+               u_int16_t aid;
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -216,16 +216,14 @@ ieee80211_input(struct ieee80211vap * va
+       type = -1;                      /* undefined */
+-      if (!vap)
+-              goto out;
++      if (!vap || !vap->iv_bss || !vap->iv_dev || !vap->iv_ic)
++              goto discard;
+       ic = vap->iv_ic;
+-      if (!ic)
+-              goto out;
+-
+       dev = vap->iv_dev;
+-      if (!dev)
+-              goto out;
++
++      if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
++              goto discard;
+       /* initialize ni as in the previous API */
+       if (ni_or_null == NULL) {
+@@ -233,9 +231,10 @@ ieee80211_input(struct ieee80211vap * va
+                 * guarantee its existence during the following call, hence
+                 * briefly grab our own reference. */
+               ni = ieee80211_ref_node(vap->iv_bss);
++              KASSERT(ni != NULL, ("null node"));
++      } else {
++              ni->ni_inact = ni->ni_inact_reload;
+       }
+-      KASSERT(ni != NULL, ("null node"));
+-      ni->ni_inact = ni->ni_inact_reload;
+       KASSERT(skb->len >= sizeof(struct ieee80211_frame_min),
+               ("frame length too short: %u", skb->len));
+@@ -844,10 +843,11 @@ ieee80211_input(struct ieee80211vap * va
+ err:
+       vap->iv_devstats.rx_errors++;
+ out:
+-      if (skb != NULL)
+-              ieee80211_dev_kfree_skb(&skb);
+       if (ni_or_null == NULL)
+               ieee80211_unref_node(&ni);
++discard:
++      if (skb != NULL)
++              ieee80211_dev_kfree_skb(&skb);
+       return type;
+ #undef HAS_SEQ
+ }
+@@ -929,16 +929,23 @@ int
+ ieee80211_input_all(struct ieee80211com *ic,
+       struct sk_buff *skb, int rssi, u_int64_t rtsf)
+ {
++      struct ieee80211_frame_min *wh = (struct ieee80211_frame_min *) skb->data;
+       struct ieee80211vap *vap;
+       int type = -1;
+       /* XXX locking */
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++              struct ieee80211_node *ni = NULL;
+               struct sk_buff *skb1;
+               if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+                       continue;
++              if ((vap->iv_opmode == IEEE80211_M_HOSTAP) &&
++                      !IEEE80211_IS_MULTICAST(wh->i_addr1))
++                      continue;
++
++              ni = ieee80211_find_rxnode(ic, vap, wh);
+               if (TAILQ_NEXT(vap, iv_next) != NULL) {
+                       skb1 = skb_copy(skb, GFP_ATOMIC);
+                       if (skb1 == NULL) {
+@@ -950,8 +957,10 @@ ieee80211_input_all(struct ieee80211com 
+                       skb1 = skb;
+                       skb = NULL;
+               }
+-              type = ieee80211_input(vap, NULL, skb1, rssi, rtsf);
++              type = ieee80211_input(vap, ni, skb1, rssi, rtsf);
+       }
++
++out:
+       if (skb != NULL)                /* no vaps, reclaim skb */
+               ieee80211_dev_kfree_skb(&skb);
+       return type;
+@@ -1146,11 +1155,9 @@ ieee80211_deliver_data(struct ieee80211_
+                        * sending it will not work; just let it be
+                        * delivered normally.
+                        */
+-                      struct ieee80211_node *ni1 = ieee80211_find_node(
+-                              &vap->iv_ic->ic_sta, eh->ether_dhost);
++                      struct ieee80211_node *ni1 = ieee80211_find_txnode(vap, eh->ether_dhost);
+                       if (ni1 != NULL) {
+-                              if (ni1->ni_vap == vap &&
+-                                  ieee80211_node_is_authorized(ni1) &&
++                              if (ieee80211_node_is_authorized(ni1) &&
+                                       !ni1->ni_subif &&
+                                   ni1 != vap->iv_bss) {
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6580,9 +6580,8 @@ 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,
++      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");
+@@ -6737,7 +6736,9 @@ ath_rx_poll(struct net_device *dev, int 
+       struct ath_desc *ds;
+       struct ath_rx_status *rs;
+       struct sk_buff *skb = NULL;
++      struct ieee80211vap *vap;
+       struct ieee80211_node *ni;
++      const struct ieee80211_frame_min *wh;
+       unsigned int len;
+       int type;
+       u_int phyerr;
+@@ -6892,12 +6893,15 @@ rx_accept:
+               skb_trim(skb, skb->len - IEEE80211_CRC_LEN);
+               if (mic_fail) {
++                      wh = (const struct ieee80211_frame_min *) skb->data;
++
+                       /* Ignore control frames which are reported with mic error */
+-                  if ((((struct ieee80211_frame *)skb->data)->i_fc[0] &
++                  if ((wh->i_fc[0] &
+                                       IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
+                               goto drop_micfail;
+-                      ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) skb->data);
++                      vap = ieee80211_find_rxvap(ic, wh->i_addr1);
++                      ni = ieee80211_find_rxnode(ic, vap, wh);
+                       if (ni && ni->ni_table) {
+                               ieee80211_check_mic(ni, skb);
+@@ -6959,11 +6963,24 @@ drop_micfail:
+                * for its use.  If the sender is unknown spam the
+                * frame; it'll be dropped where it's not wanted.
+                */
+-              if (rs->rs_keyix != HAL_RXKEYIX_INVALID &&
++              wh = (const struct ieee80211_frame_min *) skb->data;
++              if ((rs->rs_keyix != HAL_RXKEYIX_INVALID) &&
+                   (ni = sc->sc_keyixmap[rs->rs_keyix]) != NULL) {
+                       /* Fast path: node is present in the key map;
+                        * grab a reference for processing the frame. */
+-                      ni = ieee80211_ref_node(ni);
++                      ieee80211_ref_node(ni);
++                      if ((ATH_GET_VAP_ID(wh->i_addr1) !=
++                           ATH_GET_VAP_ID(ni->ni_vap->iv_myaddr)) ||
++                              ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
++                               IEEE80211_FC1_DIR_DSTODS)) {
++                              /* key cache node lookup is fast, but it can
++                               * lead to problems in multi-bss (foreign vap
++                               * node reference) or wds (wdsap node ref instead
++                               * of base ap node ref).
++                               * use slowpath lookup in both cases
++                               */
++                              goto lookup_slowpath;
++                      }
+                       ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
+                       type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
+                       ieee80211_unref_node(&ni);
+@@ -6972,24 +6989,35 @@ drop_micfail:
+                        * No key index or no entry, do a lookup and
+                        * add the node to the mapping table if possible.
+                        */
+-                      ni = ieee80211_find_rxnode(ic,
+-                              (const struct ieee80211_frame_min *)skb->data);
++
++lookup_slowpath:
++                      vap = ieee80211_find_rxvap(ic, wh->i_addr1);
++                      if (vap)
++                              ni = ieee80211_find_rxnode(ic, vap, wh);
++                      else
++                              ni = NULL;
++
+                       if (ni != NULL) {
+                               ieee80211_keyix_t keyix;
+                               ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
+-                              type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
++                              type = ieee80211_input(vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
+                               /*
+                                * If the station has a key cache slot assigned
+                                * update the key->node mapping table.
+                                */
+                               keyix = ni->ni_ucastkey.wk_keyix;
+                               if (keyix != IEEE80211_KEYIX_NONE &&
+-                                  sc->sc_keyixmap[keyix] == NULL)
++                                  sc->sc_keyixmap[keyix] == NULL) {
+                                       sc->sc_keyixmap[keyix] = ieee80211_ref_node(ni);
++                              }
+                               ieee80211_unref_node(&ni);
+-                      } else
+-                              type = ieee80211_input_all(ic, skb, rs->rs_rssi, bf->bf_tsf);
++                      } else {
++                              if (vap)
++                                      type = ieee80211_input(vap, NULL, skb, rs->rs_rssi, bf->bf_tsf);
++                              else
++                                      type = ieee80211_input_all(ic, skb, rs->rs_rssi, bf->bf_tsf);
++                      }
+               }
+               if (sc->sc_diversity) {
+--- a/net80211/ieee80211_node.h
++++ b/net80211/ieee80211_node.h
+@@ -286,15 +286,18 @@ struct ieee80211_node *ieee80211_find_no
+       const u_int8_t *);
+ #endif /* #ifdef IEEE80211_DEBUG_REFCNT */
++struct ieee80211vap *
++ieee80211_find_rxvap(struct ieee80211com *ic, const u_int8_t *mac);
++
+ /* Returns a ieee80211_node* with refcount incremented, if found */
+ #ifdef IEEE80211_DEBUG_REFCNT
+-#define       ieee80211_find_rxnode(_nt, _wh) \
+-      ieee80211_find_rxnode_debug(_nt, _wh, __func__, __LINE__)
++#define       ieee80211_find_rxnode(_nt, _vap, _wh) \
++      ieee80211_find_rxnode_debug(_nt, _vap, _wh, __func__, __LINE__)
+ struct ieee80211_node *ieee80211_find_rxnode_debug(struct ieee80211com *,
+-      const struct ieee80211_frame_min *, const char *, int);
++      struct ieee80211vap *, const struct ieee80211_frame_min *, const char *, int);
+ #else
+ struct ieee80211_node *ieee80211_find_rxnode(struct ieee80211com *,
+-      const struct ieee80211_frame_min *);
++      struct ieee80211vap *, const struct ieee80211_frame_min *);
+ #endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+ /* Returns a ieee80211_node* with refcount incremented, if found */
index fc8cda0d5440e2989738a855c42e275b42e955bc..6d8b7c744b87a230ec45baa5b2a7b006816a9d21 100644 (file)
@@ -1,6 +1,6 @@
 --- a/net80211/ieee80211_input.c
 +++ b/net80211/ieee80211_input.c
-@@ -3604,6 +3604,8 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+@@ -3611,6 +3611,8 @@ ieee80211_recv_mgmt(struct ieee80211vap 
                        vap->iv_stats.is_rx_mgtdiscard++;
                        return;
                }
index 595c43d5b16c088c5d0dadfe11e1dce8da373d4b..4c32995c877d6b3353007e0acaf20a9ed63ffc3a 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -13508,7 +13508,7 @@ cleanup_ath_buf(struct ath_softc *sc, st
+@@ -13511,7 +13511,7 @@ cleanup_ath_buf(struct ath_softc *sc, st
                                bus_unmap_single(
                                        sc->sc_bdev,
                                        bf->bf_skbaddrff[i], 
diff --git a/package/madwifi/patches/396-napi_ff_fix.patch b/package/madwifi/patches/396-napi_ff_fix.patch
new file mode 100644 (file)
index 0000000..0b9acdf
--- /dev/null
@@ -0,0 +1,65 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6725,10 +6725,10 @@ ath_rx_poll(struct net_device *dev, int 
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+       struct ath_softc *sc = container_of(napi, struct ath_softc, sc_napi);
+       struct net_device *dev = sc->sc_dev;
+-      u_int rx_limit = budget;
++      int rx_limit = budget;
+ #else
+       struct ath_softc *sc = dev->priv;
+-      u_int rx_limit = min(dev->quota, *budget);
++      int rx_limit = min(dev->quota, *budget);
+ #endif
+       struct ath_buf *bf;
+       struct ieee80211com *ic = &sc->sc_ic;
+@@ -6771,13 +6771,15 @@ process_rx_again:
+                       break;
+               }
+-              if (rx_limit-- < 2) {
++              processed += ic->ic_recv;
++              rx_limit -= ic->ic_recv;
++              ic->ic_recv = 0;
++
++              /* keep a reserve for napi */
++              if (rx_limit < 4) {
+                       early_stop = 1;
+                       break;
+               }
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+-              processed++;
+-#endif
+               skb = bf->bf_skb;
+               if (skb == NULL) {
+@@ -7061,8 +7063,8 @@ rx_next:
+               if (sc->sc_isr & HAL_INT_RX) {
+                       u_int64_t hw_tsf = ath_hal_gettsf64(ah);
+                       sc->sc_isr &= ~HAL_INT_RX;
+-                      local_irq_restore(flags);
+                       ath_uapsd_processtriggers(sc, hw_tsf);
++                      local_irq_restore(flags);
+                       goto process_rx_again;
+               }
+               local_irq_restore(flags);
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1203,6 +1203,7 @@ ieee80211_deliver_data(struct ieee80211_
+               }
+       }
++      vap->iv_ic->ic_recv++;
+       if (skb != NULL) {
+               skb->dev = dev;
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -323,6 +323,7 @@ struct ieee80211com {
+       struct ifmedia ic_media;                /* interface media config */
+       u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
+       struct timer_list ic_inact;             /* mgmt/inactivity timer */
++      u_int ic_recv;                                  /* frame received counter */
+       unsigned int ic_subifs;
+       u_int32_t ic_flags;                     /* state flags */
diff --git a/package/madwifi/patches/400-changeset_r3402.patch b/package/madwifi/patches/400-changeset_r3402.patch
deleted file mode 100644 (file)
index f43a6d9..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
---- a/ath_hal/ah_os.h
-+++ b/ath_hal/ah_os.h
-@@ -194,10 +194,6 @@ extern u_int32_t __ahdecl ath_hal_getupt
-  */
- #if (AH_BYTE_ORDER == AH_BIG_ENDIAN)
- #define is_reg_le(__reg) ((0x4000 <= (__reg) && (__reg) < 0x5000))
--#else
--#define is_reg_le(__reg) 1
--#endif
--
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
- #define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
-        is_reg_le(_reg) ?                                      \
-@@ -219,6 +215,21 @@ extern u_int32_t __ahdecl ath_hal_getupt
-        readl((_ah)->ah_sh + (_reg)) :                         \
-        cpu_to_le32(readl((_ah)->ah_sh + (_reg))))
- #endif                                /* KERNEL_VERSION(2,6,12) */
-+#else                         /* AH_BYTE_ORDER != AH_BIG_ENDIAN */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
-+#define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
-+       iowrite32((_val), (_ah)->ah_sh + (_reg));              \
-+      } while (0)
-+#define _OS_REG_READ(_ah, _reg)                                       \
-+      ioread32((_ah)->ah_sh + (_reg))
-+#else
-+#define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
-+       writel((_val), (_ah)->ah_sh + (_reg));                 \
-+      } while (0)
-+#define _OS_REG_READ(_ah, _reg)                                       \
-+      readl((_ah)->ah_sh + (_reg))
-+#endif                                /* KERNEL_VERSION(2,6,12) */
-+#endif                                /* AH_BYTE_ORDER != AH_BIG_ENDIAN */
- /*
-  * The functions in this section are not intended to be invoked by MadWifi
diff --git a/package/madwifi/patches/400-new_hal.patch b/package/madwifi/patches/400-new_hal.patch
new file mode 100644 (file)
index 0000000..0db4168
--- /dev/null
@@ -0,0 +1,124 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -606,6 +606,14 @@ ath_attach(u_int16_t devid, struct net_d
+       }
+       sc->sc_ah = ah;
++      /* WAR for AR7100 PCI bug */
++#ifdef CONFIG_ATHEROS_AR71XX
++      if ((ar_device(sc->devid) >= 5210) && (ar_device(sc->devid) < 5416)) {
++              ath_hal_setcapability(ah, HAL_CAP_DMABURST_RX, 0, HAL_DMABURST_4B, NULL);
++              ath_hal_setcapability(ah, HAL_CAP_DMABURST_TX, 0, HAL_DMABURST_4B, NULL);
++      }
++#endif
++
+       /*
+        * Check if the MAC has multi-rate retry support.
+        * We do this by trying to setup a fake extended
+@@ -7555,7 +7563,7 @@ ath_txq_setup(struct ath_softc *sc, int 
+       if (qtype == HAL_TX_QUEUE_UAPSD)
+               qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE;
+       else
+-              qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | 
++              qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXOKINT_ENABLE |
+                       HAL_TXQ_TXDESCINT_ENABLE;
+       qnum = ath_hal_setuptxqueue(ah, qtype, &qi);
+       if (qnum == -1) {
+--- a/ath_hal/ah_os.c
++++ b/ath_hal/ah_os.c
+@@ -126,6 +126,13 @@ ath_hal_printf(struct ath_hal *ah, const
+ }
+ EXPORT_SYMBOL(ath_hal_printf);
++void __ahdecl
++ath_hal_printstr(struct ath_hal *ah, const char *str)
++{
++      printk("%s", str);
++}
++EXPORT_SYMBOL(ath_hal_printstr);
++
+ /*
+  * Format an Ethernet MAC for printing.
+  */
+--- a/ath_hal/ah_os.h
++++ b/ath_hal/ah_os.h
+@@ -156,69 +156,23 @@ extern u_int32_t __ahdecl ath_hal_getupt
+ #endif
+ #endif                                /* AH_BYTE_ORDER */
+-/*
+- * Some big-endian architectures don't set CONFIG_GENERIC_IOMAP, but fail to
+- * implement iowrite32be and ioread32be.  Provide compatibility macros when
+- * it's needed.
+- *
+- * As of Linux 2.6.24, only MIPS, PARISC and PowerPC implement iowrite32be and
+- * ioread32be as functions.
+- *
+- * The downside or the replacement macros it that we may be byte-swapping data
+- * for the second time, so the native implementations should be preferred.
+- */
+-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) && \
+-      !defined(CONFIG_GENERIC_IOMAP) && (AH_BYTE_ORDER == AH_BIG_ENDIAN) && \
+-      !defined(__mips__) && !defined(__hppa__) && !defined(__powerpc__)
+-# ifndef iowrite32be
+-#  define iowrite32be(_val, _addr) iowrite32(swab32((_val)), (_addr))
+-# endif
+-# ifndef ioread32be
+-#  define ioread32be(_addr) swab32(ioread32((_addr)))
+-# endif
+-#endif
++#define IS_SWAPPED(_ah, _reg) \
++      ((_ah)->ah_swapped && \
++              (((0x4000 <= (_reg)) && ((_reg) < 0x5000)) || \
++               ((0x7000 <= (_reg)) && ((_reg) < 0x8000))))
++
++#define SWAPREG(_ah, _reg, _val) \
++      (IS_SWAPPED(_ah, _reg) ? cpu_to_le32(_val) : (_val))
+ /*
+  * The register accesses are done using target-specific functions when
+  * debugging is enabled (AH_DEBUG) or it's explicitly requested for the target.
+- *
+- * The hardware registers use little-endian byte order natively.  Big-endian
+- * systems are configured by HAL to enable hardware byte-swap of register reads
+- * and writes at reset.  This avoid the need to byte-swap the data in software.
+- * However, the registers in a certain area from 0x4000 to 0x4fff (PCI clock
+- * domain registers) are not byte swapped!
+- *
+- * Since Linux I/O primitives default to little-endian operations, we only
+- * need to suppress byte-swapping on big-endian systems outside the area used
+- * by the PCI clock domain registers.
+  */
+-#if (AH_BYTE_ORDER == AH_BIG_ENDIAN)
+-#define is_reg_le(__reg) ((0x4000 <= (__reg) && (__reg) < 0x5000))
+-#else
+-#define is_reg_le(__reg) 1
+-#endif
+-
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+-#define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
+-       is_reg_le(_reg) ?                                      \
+-       iowrite32((_val), (_ah)->ah_sh + (_reg)) :             \
+-       iowrite32be((_val), (_ah)->ah_sh + (_reg));            \
+-      } while (0)
+-#define _OS_REG_READ(_ah, _reg)                                       \
+-      (is_reg_le(_reg) ?                                      \
+-       ioread32((_ah)->ah_sh + (_reg)) :                      \
+-       ioread32be((_ah)->ah_sh + (_reg)))
+-#else
+ #define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
+-       writel(is_reg_le(_reg) ?                               \
+-              (_val) : cpu_to_le32(_val),                     \
+-              (_ah)->ah_sh + (_reg));                         \
+-      } while (0)
++       __raw_writel(SWAPREG(_ah, _reg, _val), (_ah)->ah_sh + (_reg));         \
++} while (0)
+ #define _OS_REG_READ(_ah, _reg)                                       \
+-      (is_reg_le(_reg) ?                                      \
+-       readl((_ah)->ah_sh + (_reg)) :                         \
+-       cpu_to_le32(readl((_ah)->ah_sh + (_reg))))
+-#endif                                /* KERNEL_VERSION(2,6,12) */
++       SWAPREG(_ah, _reg, __raw_readl((_ah)->ah_sh + (_reg)))
+ /*
+  * The functions in this section are not intended to be invoked by MadWifi
index b03232ad5ec4d7425e9aada3fa9ebf64e4e00470..11e78aba87916763fc09eb4957a47c24880d9f2c 100644 (file)
@@ -11,7 +11,7 @@
  #define       IEEE80211_QOS_TXOP                      0x00ff
 --- a/net80211/ieee80211_input.c
 +++ b/net80211/ieee80211_input.c
-@@ -429,7 +429,7 @@ ieee80211_input(struct ieee80211vap * va
+@@ -428,7 +428,7 @@ ieee80211_input(struct ieee80211vap * va
                                tid = 0;
                        rxseq = le16toh(*(__le16 *)wh->i_seq);
                        if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
index 64f19e0b8c4c145500bf0c666fccdd5cdd77586b..af02edce857a8e20e98814d3794d4dafb34887dc 100644 (file)
@@ -1,6 +1,6 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -6510,7 +6510,7 @@ ath_capture(struct net_device *dev, cons
+@@ -6521,7 +6521,7 @@ ath_capture(struct net_device *dev, cons
  
        /* Never copy the SKB, as it is ours on the RX side, and this is the 
         * last process on the TX side and we only modify our own headers. */
@@ -9,7 +9,7 @@
        if (tskb == NULL) {
                DPRINTF(sc, ATH_DEBUG_ANY,
                        "Dropping; ath_skb_removepad failed!\n");
-@@ -6518,6 +6518,8 @@ ath_capture(struct net_device *dev, cons
+@@ -6529,6 +6529,8 @@ ath_capture(struct net_device *dev, cons
        }
        
        ieee80211_input_monitor(ic, tskb, bf, tx, tsf, sc);
index 00f0955fa425d1a505c4a6bcd47fc481eb2dc41f..b7980824126fd68a77a679381217c3cd2b5815d2 100644 (file)
@@ -10,7 +10,7 @@
  Please let us know if you think your name should be mentioned here!
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -3129,7 +3129,7 @@ ath_tx_startraw(struct net_device *dev, 
+@@ -3138,7 +3138,7 @@ ath_tx_startraw(struct net_device *dev, 
        struct ath_softc *sc = dev->priv;
        struct ath_hal *ah = sc->sc_ah;
        struct ieee80211_phy_params *ph = (struct ieee80211_phy_params *)
diff --git a/package/madwifi/patches/410-ar231x_2.6.28.patch b/package/madwifi/patches/410-ar231x_2.6.28.patch
new file mode 100644 (file)
index 0000000..87177c3
--- /dev/null
@@ -0,0 +1,281 @@
+--- a/ath/if_ath_ahb.c
++++ b/ath/if_ath_ahb.c
+@@ -33,20 +33,15 @@
+ #include "if_ath_ahb.h"
+ #include "ah_soc.h"
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+-#error "Kernel versions older than 2.6.19 are not supported!"
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
++#include <ar231x_platform.h>
+ #endif
+ struct ath_ahb_softc {
+       struct ath_softc        aps_sc;
+-#ifdef CONFIG_PM
+-      u32 aps_pmstate[16];
+-#endif
++      struct ar531x_config aps_config;
+ };
+-static struct ath_ahb_softc *sclist[2] = {NULL, NULL};
+-static u_int8_t num_activesc = 0;
+-
+ /*
+  * Module glue.
+  */
+@@ -101,13 +96,13 @@ ahb_enable_wmac(u_int16_t devid, u_int16
+               while (REG_READ(AR5315_PCI_MAC_PCICFG) & AR5315_PCI_MAC_PCICFG_SPWR_DN);
+       } else {
+               switch (wlanNum) {
+-              case AR531X_WLAN0_NUM:
++              case 0:
+                       reset = (AR531X_RESET_WLAN0 |
+                               AR531X_RESET_WARM_WLAN0_MAC |
+                               AR531X_RESET_WARM_WLAN0_BB);
+                       enable = AR531X_ENABLE_WLAN0;
+                       break;
+-              case AR531X_WLAN1_NUM:
++              case 1:
+                       reset = (AR531X_RESET_WLAN1 |
+                               AR531X_RESET_WARM_WLAN1_MAC |
+                               AR531X_RESET_WARM_WLAN1_BB);
+@@ -144,10 +139,10 @@ ahb_disable_wmac(u_int16_t devid, u_int1
+               *en &= ~AR5315_ARB_WLAN;
+       } else {
+               switch (wlanNum) {
+-              case AR531X_WLAN0_NUM:
++              case 0:
+                       enable = AR531X_ENABLE_WLAN0;
+                       break;
+-              case AR531X_WLAN1_NUM:
++              case 1:
+                       enable = AR531X_ENABLE_WLAN1;
+                       break;
+               default:
+@@ -159,29 +154,6 @@ ahb_disable_wmac(u_int16_t devid, u_int1
+ }
+-static int
+-exit_ath_wmac(u_int16_t wlanNum, struct ar531x_config *config)
+-{
+-      struct ath_ahb_softc *sc = sclist[wlanNum];
+-      struct net_device *dev;
+-      u_int16_t devid;
+-
+-      if (sc == NULL)
+-              return -ENODEV; /* XXX: correct return value? */
+-
+-      dev = sc->aps_sc.sc_dev;
+-      ath_detach(dev);
+-      if (dev->irq)
+-              free_irq(dev->irq, dev);
+-      devid = sc->aps_sc.devid;
+-      config->tag = (void *)((unsigned long) devid);
+-
+-      ahb_disable_wmac(devid, wlanNum);
+-      free_netdev(dev);
+-      sclist[wlanNum] = NULL;
+-      return 0;
+-}
+-
+ static const char ubnt[] = "Ubiquiti Networks";
+ static const struct ath_hw_detect cards[] = {
+       {
+@@ -266,6 +238,114 @@ static const struct ath_hw_detect cards[
+       },
+ };
++static void
++ahb_hw_detect(struct ath_ahb_softc *sc, const char *radio)
++{
++      u16 *radio_data = (u16 *) radio;
++      if (radio_data) {
++              u16 vendor, id, subvendor, subid;
++              vendor = radio_data[1];
++              id = radio_data[0];
++              subvendor = radio_data[8];
++              subid = radio_data[7];
++              ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards), vendor, id, subvendor, subid);
++      }
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
++
++static int ahb_wmac_probe(struct platform_device *pdev)
++{
++      struct ar231x_board_config *bcfg = pdev->dev.platform_data;
++      struct ath_ahb_softc *sc;
++      struct net_device *dev;
++      struct resource *res;
++      const char *athname;
++      int err;
++
++      ahb_enable_wmac(bcfg->devid, pdev->id);
++      dev = alloc_netdev(sizeof(struct ath_ahb_softc), "wifi%d", ether_setup);
++      if (!dev)
++              return -ENOMEM;
++
++      sc = dev->priv;
++      sc->aps_sc.sc_dev = dev;
++
++      dev->irq = platform_get_irq(pdev, 0);
++      if (dev->irq <= 0) {
++              printk("%s: Cannot find IRQ resource\n", dev->name);
++              goto error;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!res) {
++              printk("%s: Cannot find MMIO resource\n", dev->name);
++              goto error;
++      }
++
++      dev->mem_start = KSEG1ADDR(res->start);
++      dev->mem_end = KSEG1ADDR(res->end);
++      sc->aps_sc.sc_iobase = (void __iomem *) dev->mem_start;
++      sc->aps_sc.sc_bdev = NULL;
++
++      /* bus information for the HAL */
++      sc->aps_config.board = (const struct ar531x_boarddata *) bcfg->config;
++      sc->aps_config.radio = bcfg->radio;
++      sc->aps_config.unit = pdev->id;
++      sc->aps_config.tag = NULL;
++
++      err = ath_attach(bcfg->devid, dev, &sc->aps_config);
++      if (err != 0) {
++              printk("%s: ath_attach failed: %d\n", dev->name, err);
++              goto error;
++      }
++
++      athname = ath_hal_probe(ATHEROS_VENDOR_ID, bcfg->devid);
++      printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n",
++              dev_info, dev->name, athname ? athname : "Atheros ???", dev->mem_start, dev->irq);
++
++      if (request_irq(dev->irq, ath_intr, IRQF_SHARED|IRQF_DISABLED, dev->name, dev)) {
++              printk(KERN_WARNING "%s: %s: request_irq failed\n", dev_info, dev->name);
++              goto error;
++      }
++
++      sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */
++      sc->aps_sc.sc_ledpin = bcfg->config->sysLedGpio;
++      sc->aps_sc.sc_invalid = 0;
++      ahb_hw_detect(sc, bcfg->radio);
++      platform_set_drvdata(pdev, dev);
++      return 0;
++
++error_dev:
++      free_irq(dev->irq, dev);
++error:
++      free_netdev(dev);
++
++      return -ENODEV;
++}
++
++
++static int ahb_wmac_remove(struct platform_device *pdev)
++{
++      struct ar231x_board_config *bcfg = pdev->dev.platform_data;
++      struct net_device *dev;
++
++      dev = platform_get_drvdata(pdev);
++      ath_detach(dev);
++
++      if (dev->irq)
++              free_irq(dev->irq, dev);
++
++      ahb_disable_wmac(bcfg->devid, pdev->id);
++      free_netdev(dev);
++
++      return 0;
++}
++
++#else
++
++static struct ath_ahb_softc *sclist[2] = {NULL, NULL};
++
+ static int
+ init_ath_wmac(u_int16_t devid, u_int16_t wlanNum, struct ar531x_config *config)
+ {
+@@ -318,7 +398,7 @@ init_ath_wmac(u_int16_t devid, u_int16_t
+       sc->aps_sc.sc_iobase = (void __iomem *) dev->mem_start;
+       sc->aps_sc.sc_bdev = NULL;
+-      if (request_irq(dev->irq, ath_intr, IRQF_SHARED, dev->name, dev)) {
++      if (request_irq(dev->irq, ath_intr, IRQF_SHARED|IRQF_DISABLED, dev->name, dev)) {
+               printk(KERN_WARNING "%s: %s: request_irq failed\n", dev_info, dev->name);
+               goto bad3;
+       }
+@@ -328,21 +408,12 @@ init_ath_wmac(u_int16_t devid, u_int16_t
+       athname = ath_hal_probe(ATHEROS_VENDOR_ID, devid);
+       printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n",
+               dev_info, dev->name, athname ? athname : "Atheros ???", dev->mem_start, dev->irq);
+-      num_activesc++;
+       /* Ready to process interrupts */
+       sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */
+       sc->aps_sc.sc_ledpin = config->board->sysLedGpio;
+       sc->aps_sc.sc_invalid = 0;
+-      radio_data = (u16 *) config->radio;
+-      if (radio_data) {
+-              u16 vendor, id, subvendor, subid;
+-              vendor = radio_data[1];
+-              id = radio_data[0];
+-              subvendor = radio_data[8];
+-              subid = radio_data[7];
+-              ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards), vendor, id, subvendor, subid);
+-      }
++      ahb_hw_detect(sc, config->radio);
+       return 0;
+@@ -357,6 +428,29 @@ init_ath_wmac(u_int16_t devid, u_int16_t
+       return -ENODEV;
+ }
++static int
++exit_ath_wmac(u_int16_t wlanNum, struct ar531x_config *config)
++{
++      struct ath_ahb_softc *sc = sclist[wlanNum];
++      struct net_device *dev;
++      u_int16_t devid;
++
++      if (sc == NULL)
++              return -ENODEV; /* XXX: correct return value? */
++
++      dev = sc->aps_sc.sc_dev;
++      ath_detach(dev);
++      if (dev->irq)
++              free_irq(dev->irq, dev);
++      devid = sc->aps_sc.devid;
++      config->tag = (void *)((unsigned long) devid);
++
++      ahb_disable_wmac(devid, wlanNum);
++      free_netdev(dev);
++      sclist[wlanNum] = NULL;
++      return 0;
++}
++
+ static int ahb_wmac_probe(struct platform_device *pdev)
+ {
+       u_int16_t devid;
+@@ -377,11 +471,18 @@ static int ahb_wmac_remove(struct platfo
+       return 0;
+ }
++#endif
++
+ static struct platform_driver ahb_wmac_driver = {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
++      .driver.name = "ar231x-wmac",
++#else
+       .driver.name = "ar531x-wmac",
++#endif
+       .probe = ahb_wmac_probe,
+       .remove = ahb_wmac_remove
+ };
++
+ int
+ ath_ioctl_ethtool(struct ath_softc *sc, int cmd, void __user *addr)
+ {
diff --git a/package/madwifi/patches/411-autochannel_multi.patch b/package/madwifi/patches/411-autochannel_multi.patch
new file mode 100644 (file)
index 0000000..ab48e70
--- /dev/null
@@ -0,0 +1,347 @@
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -97,6 +97,123 @@ struct scan_state {
+ static void scan_restart_pwrsav(unsigned long);
+ static void scan_next(unsigned long);
++spinlock_t channel_lock = SPIN_LOCK_UNLOCKED;
++static LIST_HEAD(channels_inuse);
++
++struct channel_inuse {
++      struct list_head list;
++      struct ieee80211com *ic;
++      u16 freq;
++      u8 bw;
++};
++
++static inline u32
++get_signal(u8 bw, u8 distance)
++{
++      u32 v;
++
++      /* signal = 1 - (distance / bw)^2 [scale: 100] */
++      v = 100 * distance / bw;
++      v = (100 - ((v * v) / 100));
++      return v;
++}
++
++static u32
++get_overlap(u16 f1, u16 f2, u8 b1, u8 b2)
++{
++      u32 v;
++      u16 d, c;
++
++      /* add offsets for sidechannel interference */
++      b1 += (b1 / 5);
++      b2 += (b2 / 5);
++
++      /* use only one direction */
++      b1 /= 2;
++      b2 /= 2;
++
++      if (f1 + b1 < f2 - b2)
++              return 0;
++
++      d = f2 - f1;
++      c = d * b1 / (b1 + b2);
++      v = get_signal(b1, c);
++
++      return v * v / 100;
++}
++
++static u8
++get_channel_bw(struct ieee80211_channel *c)
++{
++      switch(c->ic_flags & (
++              IEEE80211_CHAN_HALF |
++              IEEE80211_CHAN_QUARTER |
++              IEEE80211_CHAN_TURBO |
++              IEEE80211_CHAN_STURBO)) {
++      case IEEE80211_CHAN_QUARTER:
++              return 5;
++      case IEEE80211_CHAN_HALF:
++              return 10;
++      case IEEE80211_CHAN_TURBO:
++      case IEEE80211_CHAN_STURBO:
++              return 40;
++      default:
++              return 20;
++      }
++}
++
++/* must be called with channel_lock held */
++u32
++ieee80211_scan_get_bias(struct ieee80211_channel *c)
++{
++      struct channel_inuse *ch;
++      u8 bw = get_channel_bw(c);
++      u32 bias = 0;
++
++      list_for_each_entry(ch, &channels_inuse, list) {
++              if (ch->freq == c->ic_freq) {
++                      bias += 50;
++                      continue;
++              }
++              if (c->ic_freq < ch->freq)
++                      bias += get_overlap(c->ic_freq, ch->freq, bw, ch->bw);
++              else
++                      bias += get_overlap(ch->freq, c->ic_freq, ch->bw, bw);
++      }
++      return min(bias, (u32) 100);
++}
++EXPORT_SYMBOL(ieee80211_scan_get_bias);
++
++/* must be called with channel_lock held */
++void
++ieee80211_scan_set_bss_channel(struct ieee80211com *ic, struct ieee80211_channel *c)
++{
++      unsigned long flags;
++      struct channel_inuse *ch;
++
++      list_for_each_entry(ch, &channels_inuse, list) {
++              if (ch->ic == ic)
++                      goto found;
++      }
++      ch = NULL;
++found:
++      if (c && (c != IEEE80211_CHAN_ANYC)) {
++              if (!ch) {
++                      ch = kmalloc(sizeof(struct channel_inuse), GFP_ATOMIC);
++                      ch->ic = ic;
++                      INIT_LIST_HEAD(&ch->list);
++                      list_add(&ch->list, &channels_inuse);
++              }
++              ch->freq = c->ic_freq;
++              ch->bw = get_channel_bw(c);
++      } else if (ch) {
++              list_del(&ch->list);
++              kfree(ch);
++      }
++}
++EXPORT_SYMBOL(ieee80211_scan_set_bss_channel);
++
++
+ void
+ ieee80211_scan_attach(struct ieee80211com *ic)
+ {
+@@ -1155,7 +1272,7 @@ ieee80211_scan_dfs_action(struct ieee802
+                               IEEE80211_RADAR_CHANCHANGE_TBTT_COUNT;
+                       ic->ic_flags |= IEEE80211_F_CHANSWITCH;
+               } else {
+-
++                      unsigned long flags;
+                       IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
+                                       "%s: directly switching to channel "
+                                       "%3d (%4d MHz)\n", __func__,
+@@ -1166,6 +1283,9 @@ ieee80211_scan_dfs_action(struct ieee802
+                        * change the channel here. */
+                       change_channel(ic, new_channel);
+                       ic->ic_bsschan = new_channel;
++                      spin_lock_irqsave(&channel_lock, flags);
++                      ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
++                      spin_unlock_irqrestore(&channel_lock, flags);
+                       if (vap->iv_bss)
+                               vap->iv_bss->ni_chan = new_channel;
+               }
+--- a/net80211/ieee80211_scan.h
++++ b/net80211/ieee80211_scan.h
+@@ -35,6 +35,7 @@
+ #define       IEEE80211_SCAN_MAX      IEEE80211_CHAN_MAX
++extern spinlock_t channel_lock;
+ struct ieee80211_scanner;
+ struct ieee80211_scan_entry;
+@@ -116,6 +117,8 @@ void ieee80211_scan_flush(struct ieee802
+ struct ieee80211_scan_entry;
+ typedef int ieee80211_scan_iter_func(void *, const struct ieee80211_scan_entry *);
+ int ieee80211_scan_iterate(struct ieee80211com *, ieee80211_scan_iter_func *, void *);
++u32 ieee80211_scan_get_bias(struct ieee80211_channel *c);
++void ieee80211_scan_set_bss_channel(struct ieee80211com *ic, struct ieee80211_channel *c);
+ /*
+  * Parameters supplied when adding/updating an entry in a
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -373,8 +373,16 @@ void
+ ieee80211_ifdetach(struct ieee80211com *ic)
+ {
+       struct ieee80211vap *vap;
++      unsigned long flags;
+       int count;
++      /* mark the channel as no longer in use */
++      ic->ic_bsschan = IEEE80211_CHAN_ANYC;
++      spin_lock_irqsave(&channel_lock, flags);
++      ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
++      spin_unlock_irqrestore(&channel_lock, flags);
++
++
+       /* bring down all vaps */
+       TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+               ieee80211_stop(vap->iv_dev);
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -2772,6 +2772,7 @@ static void
+ ieee80211_doth_switch_channel(struct ieee80211vap *vap)
+ {
+       struct ieee80211com *ic = vap->iv_ic;
++      unsigned long flags;
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
+                         "%s: Channel switch to %3d (%4d MHz) NOW!\n",
+@@ -2794,6 +2795,9 @@ ieee80211_doth_switch_channel(struct iee
+       ic->ic_curchan = ic->ic_bsschan = vap->iv_csa_chan;
+       ic->ic_set_channel(ic);
++      spin_lock_irqsave(&channel_lock, flags);
++      ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
++      spin_unlock_irqrestore(&channel_lock, flags);
+ }
+ static void
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -308,6 +308,7 @@ ieee80211_create_ibss(struct ieee80211va
+ {
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_node *ni;
++      unsigned long flags;
+       IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+               "%s: creating ibss on channel %u\n", __func__,
+@@ -386,6 +387,9 @@ ieee80211_create_ibss(struct ieee80211va
+       ic->ic_bsschan = chan;
+       ieee80211_node_set_chan(ic, ni);
+       ic->ic_curmode = ieee80211_chan2mode(chan);
++      spin_lock_irqsave(&channel_lock, flags);
++      ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
++      spin_unlock_irqrestore(&channel_lock, flags);
+       /* Update country ie information */
+       ieee80211_build_countryie(ic);
+@@ -622,6 +626,7 @@ ieee80211_sta_join1(struct ieee80211_nod
+       struct ieee80211vap *vap = selbs->ni_vap;
+       struct ieee80211com *ic = selbs->ni_ic;
+       struct ieee80211_node *obss;
++      unsigned long flags;
+       int canreassoc;
+       if (vap->iv_opmode == IEEE80211_M_IBSS) {
+@@ -650,6 +655,9 @@ ieee80211_sta_join1(struct ieee80211_nod
+       ic->ic_curchan = ic->ic_bsschan;
+       ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
+       ic->ic_set_channel(ic);
++      spin_lock_irqsave(&channel_lock, flags);
++      ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
++      spin_unlock_irqrestore(&channel_lock, flags);
+       /*
+        * Set the erp state (mostly the slot time) to deal with
+        * the auto-select case; this should be redundant if the
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -1225,6 +1225,7 @@ ieee80211_dturbo_switch(struct ieee80211
+       struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+ #endif
+       struct ieee80211_channel *chan;
++      unsigned long flags;
+       chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags);
+       if (chan == NULL) {             /* XXX should not happen */
+@@ -1243,6 +1244,9 @@ ieee80211_dturbo_switch(struct ieee80211
+       ic->ic_bsschan = chan;
+       ic->ic_curchan = chan;
+       ic->ic_set_channel(ic);
++      spin_lock_irqsave(&channel_lock, flags);
++      ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
++      spin_unlock_irqrestore(&channel_lock, flags);
+       /* NB: do not need to reset ERP state because in sta mode */
+ }
+ EXPORT_SYMBOL(ieee80211_dturbo_switch);
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -4076,8 +4076,13 @@ ieee80211_ioctl_setchanlist(struct net_d
+       if (nchan == 0)                 /* no valid channels, disallow */
+               return -EINVAL;
+       if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&    /* XXX */
+-          isclr(chanlist, ic->ic_bsschan->ic_ieee))
++          isclr(chanlist, ic->ic_bsschan->ic_ieee)) {
++              unsigned long flags;
+               ic->ic_bsschan = IEEE80211_CHAN_ANYC;   /* invalidate */
++              spin_lock_irqsave(&channel_lock, flags);
++              ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
++              spin_unlock_irqrestore(&channel_lock, flags);
++      }
+       memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
+       /* update Supported Channels information element */
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -213,9 +213,15 @@ ap_start(struct ieee80211_scan_state *ss
+       struct ieee80211com *ic     = NULL;
+       int i;
+       unsigned int mode = 0;
++      unsigned long sflags;
+       SCAN_AP_LOCK_IRQ(as);
+       ic = vap->iv_ic;
++
++      spin_lock_irqsave(&channel_lock, sflags);
++      ieee80211_scan_set_bss_channel(ic, NULL);
++      spin_unlock_irqrestore(&channel_lock, sflags);
++
+       /* Determine mode flags to match, or leave zero for auto mode */
+       as->as_vap_desired_mode = vap->iv_des_mode;
+       as->as_required_mode    = 0;
+@@ -429,8 +435,10 @@ pc_cmp_idletime(struct ieee80211_channel
+       if (!a->ic_idletime || !b->ic_idletime)
+               return 0;
+-      /* a is better than b (return < 0) when a has more idle time than b */
+-      return b->ic_idletime - a->ic_idletime;
++      /* a is better than b (return < 0) when a has more idle and less bias time than b */
++      return
++              ((100 - (u32) a->ic_idletime) + ieee80211_scan_get_bias(a)) -
++              ((100 - (u32) b->ic_idletime) + ieee80211_scan_get_bias(b));
+ }
+@@ -616,6 +624,7 @@ ap_end(struct ieee80211_scan_state *ss, 
+       struct ap_state *as = ss->ss_priv;
+       struct ieee80211_channel *bestchan = NULL;
+       struct ieee80211com *ic = NULL;
++      unsigned long sflags;
+       int res = 1;
+       SCAN_AP_LOCK_IRQ(as);
+@@ -624,8 +633,11 @@ ap_end(struct ieee80211_scan_state *ss, 
+               ("wrong opmode %u", vap->iv_opmode));
+       ic = vap->iv_ic;
++      spin_lock_irqsave(&channel_lock, sflags);
++      ieee80211_scan_set_bss_channel(ic, NULL);
+       bestchan = pick_channel(ss, vap, flags);
+       if (bestchan == NULL) {
++              spin_unlock_irqrestore(&channel_lock, sflags);
+               if (ss->ss_last > 0) {
+                       /* no suitable channel, should not happen */
+                       printk(KERN_ERR "%s: %s: no suitable channel! "
+@@ -644,6 +656,7 @@ ap_end(struct ieee80211_scan_state *ss, 
+                                       bestchan->ic_freq, bestchan->ic_flags &
+                                       ~IEEE80211_CHAN_TURBO)) == NULL) {
+                               /* should never happen ?? */
++                              spin_unlock_irqrestore(&channel_lock, sflags);
+                               SCAN_AP_UNLOCK_IRQ_EARLY(as);
+                               return 0;
+                       }
+@@ -656,6 +669,9 @@ ap_end(struct ieee80211_scan_state *ss, 
+                       as->as_action = action;
+               as->as_selbss = se;
++              ieee80211_scan_set_bss_channel(ic, bestchan);
++              spin_unlock_irqrestore(&channel_lock, sflags);
++
+               /* Must defer action to avoid possible recursive call through 
+                * 80211 state machine, which would result in recursive 
+                * locking. */
diff --git a/package/madwifi/patches/412-fragmentation_fix.patch b/package/madwifi/patches/412-fragmentation_fix.patch
new file mode 100644 (file)
index 0000000..8c72f54
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -3675,6 +3675,7 @@ ff_bypass:
+                *  already alloc'd
+                */
+               ATH_TXBUF_LOCK_IRQ(sc);
++              STAILQ_INSERT_TAIL(&bf_head, bf, bf_list);
+               for (bfcnt = 1; bfcnt < framecnt; ++bfcnt) {
+                       tbf = ath_take_txbuf_locked(sc);
+                       if (tbf == NULL)
diff --git a/package/madwifi/patches/413-rxorn.patch b/package/madwifi/patches/413-rxorn.patch
new file mode 100644 (file)
index 0000000..b417471
--- /dev/null
@@ -0,0 +1,31 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -2307,6 +2307,17 @@ ath_intr(int irq, void *dev_id, struct p
+       sc->sc_isr = status;
+       status &= sc->sc_imask;                 /* discard unasked for bits */
++
++      /* Treat RXORN as non-fatal. Either the bus is busy or the CPU
++       * is not fast enough to process all frames. Treat it like
++       * an Rx interrupt
++       */
++      if (status & HAL_INT_RXORN) {
++              sc->sc_stats.ast_rxorn++;
++              status &= ~HAL_INT_RXORN;
++              status |= HAL_INT_RX;
++      }
++
+       /* As soon as we know we have a real interrupt we intend to service, 
+        * we will check to see if we need an initial hardware TSF reading. 
+        * Normally we would just populate this all the time to keep things
+@@ -2319,10 +2330,6 @@ ath_intr(int irq, void *dev_id, struct p
+               sc->sc_stats.ast_hardware++;
+               ath_hal_intrset(ah, 0);         /* disable intr's until reset */
+               ATH_SCHEDULE_TQUEUE(&sc->sc_fataltq, &needmark);
+-      } else if (status & HAL_INT_RXORN) {
+-              sc->sc_stats.ast_rxorn++;
+-              ath_hal_intrset(ah, 0);         /* disable intr's until reset */
+-              ATH_SCHEDULE_TQUEUE(&sc->sc_rxorntq, &needmark);
+       } else {
+               if (status & HAL_INT_SWBA) {
+                       struct ieee80211vap * vap;
diff --git a/package/madwifi/patches/414-txpower.patch b/package/madwifi/patches/414-txpower.patch
new file mode 100644 (file)
index 0000000..5300de9
--- /dev/null
@@ -0,0 +1,247 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -270,6 +270,7 @@ ieee80211_ifattach(struct ieee80211com *
+               ("invalid number of channels specified: %u", ic->ic_nchans));
+       memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
+       ic->ic_modecaps |= 1 << IEEE80211_MODE_AUTO;
++      ic->ic_max_txpower = IEEE80211_TXPOWER_MIN;
+       for (i = 0; i < ic->ic_nchans; i++) {
+               c = &ic->ic_channels[i];
+@@ -277,6 +278,7 @@ ieee80211_ifattach(struct ieee80211com *
+               KASSERT(c->ic_ieee < IEEE80211_CHAN_MAX,
+                       ("channel with bogus ieee number %u", c->ic_ieee));
+               setbit(ic->ic_chan_avail, c->ic_ieee);
++              ic->ic_max_txpower = max(ic->ic_max_txpower, (u16) c->ic_maxpower * 2);
+               if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT)
+                       c->ic_scanflags |= IEEE80211_NOSCAN_SET;
+@@ -346,8 +348,6 @@ ieee80211_ifattach(struct ieee80211com *
+       TAILQ_INIT(&ic->ic_vaps);
+       ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
+-      ic->ic_txpowlimit = IEEE80211_TXPOWER_MIN;
+-      ic->ic_newtxpowlimit = IEEE80211_TXPOWER_MAX;
+       init_timer(&ic->ic_dfs_excl_timer);
+       ic->ic_dfs_excl_timer.function = 
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -1125,7 +1125,7 @@ ieee80211_alloc_node(struct ieee80211vap
+               ni->ni_chan = IEEE80211_CHAN_ANYC;
+               ni->ni_authmode = IEEE80211_AUTH_OPEN;
+-              ni->ni_txpower = ic->ic_txpowlimit;
++              ni->ni_txpower = IEEE80211_TXPOWER_MAX;
+               ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey,
+                       IEEE80211_KEYIX_NONE);
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -343,8 +343,9 @@ struct ieee80211com {
+       u_int16_t ic_holdover;                  /* PM hold over duration */
+       u_int16_t ic_bmissthreshold;            /* beacon miss threshold (# beacons) */
+       unsigned long ic_bmiss_guard;           /* when to cease ignoring bmiss (jiffies) */
+-      u_int16_t ic_txpowlimit;                /* global tx power limit (in 0.5 dBm) */
+-      u_int16_t ic_newtxpowlimit;             /* tx power limit to change to (in 0.5 dBm) */
++      u_int16_t ic_txpowlimit;                /* configured global tx power limit (in 0.5 dBm) */
++      u_int16_t ic_max_txpower;                       /* global hardware tx power limit */
++      u_int16_t ic_cur_txpower;                       /* current tx power */
+       u_int16_t ic_uapsdmaxtriggers;          /* max triggers that could arrive */
+       u_int8_t ic_coverageclass;              /* coverage class */
+       u_int8_t ic_protmode_rssi;                      /* rssi threshold for protection mode */
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -920,17 +920,23 @@ ieee80211_ioctl_giwrange(struct net_devi
+       u_int8_t reported[IEEE80211_CHAN_BYTES];        /* XXX stack usage? */
+       int i, r;
+       int step = 0;
++      u_int16_t power;
+       data->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
++      power = ic->ic_max_txpower;
++      if (ic->ic_bsschan && (ic->ic_bsschan != IEEE80211_CHAN_ANYC))
++              power = min(power, (u_int16_t) ic->ic_bsschan->ic_maxpower);
++
+       /* txpower (128 values, but will print out only IW_MAX_TXPOWER) */
+-      range->num_txpower = (ic->ic_txpowlimit >= 8) ? IW_MAX_TXPOWER : ic->ic_txpowlimit;
+-      step = ic->ic_txpowlimit / (2 * (IW_MAX_TXPOWER - 1));
++      power /= 2; /* Unit: 0.5 dBm */
++      range->num_txpower = (power >= 8) ? IW_MAX_TXPOWER : power;
++      step = power / (IW_MAX_TXPOWER - 1);
+       range->txpower[0] = 0;
+       for (i = 1; i < IW_MAX_TXPOWER; i++)
+-              range->txpower[i] = (ic->ic_txpowlimit/2)
++              range->txpower[i] = power
+                       - (IW_MAX_TXPOWER - i - 1) * step;
+       range->txpower_capa = IW_TXPOW_DBM;
+@@ -1379,13 +1385,11 @@ ieee80211_ioctl_siwtxpow(struct net_devi
+       int fixed, disabled;
+       fixed = (ic->ic_flags & IEEE80211_F_TXPOW_FIXED);
+-      disabled = (fixed && vap->iv_bss->ni_txpower == 0);
++      disabled = (fixed && ic->ic_txpowlimit == 0);
+       if (rrq->disabled) {
+               if (!disabled) {
+-                      if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
+-                              return -EOPNOTSUPP;
+                       ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+-                      vap->iv_bss->ni_txpower = 0;
++                      ic->ic_txpowlimit = 0;
+                       goto done;
+               }
+               return 0;
+@@ -1396,30 +1400,12 @@ ieee80211_ioctl_siwtxpow(struct net_devi
+                       return -EOPNOTSUPP;
+               if (rrq->flags != IW_TXPOW_DBM)
+                       return -EINVAL;
+-              if (ic->ic_bsschan != IEEE80211_CHAN_ANYC) {
+-                      if ((ic->ic_bsschan->ic_maxregpower >= rrq->value) &&
+-                          (ic->ic_txpowlimit/2 >= rrq->value)) {
+-                              vap->iv_bss->ni_txpower = 2 * rrq->value;
+-                              ic->ic_newtxpowlimit = 2 * rrq->value;
+-                              ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+-                      } else
+-                              return -EINVAL;
+-              } else {
+-                      /*
+-                       * No channel set yet
+-                       */
+-                      if (ic->ic_txpowlimit/2 >= rrq->value) {
+-                              vap->iv_bss->ni_txpower = 2 * rrq->value;
+-                              ic->ic_newtxpowlimit = 2 * rrq->value;
+-                              ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+-                      }
+-                      else
+-                              return -EINVAL;
+-              }
++              ic->ic_txpowlimit = 2 * rrq->value;
++              ic->ic_flags |= IEEE80211_F_TXPOW_FIXED;
+       } else {
+               if (!fixed)             /* no change */
+                       return 0;
+-              ic->ic_newtxpowlimit = IEEE80211_TXPOWER_MAX;
++              ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
+               ic->ic_flags &= ~IEEE80211_F_TXPOW_FIXED;
+       }
+ done:
+@@ -1588,9 +1574,22 @@ ieee80211_ioctl_giwtxpow(struct net_devi
+ {
+       struct ieee80211vap *vap = dev->priv;
+       struct ieee80211com *ic = vap->iv_ic;
+-
+-      rrq->value = vap->iv_bss->ni_txpower / 2;
+-      rrq->fixed = (ic->ic_flags & IEEE80211_F_TXPOW_FIXED) != 0;
++      unsigned int power = ic->ic_txpowlimit;
++      struct ieee80211_channel *c;
++      u_int16_t txp = ic->ic_max_txpower;
++
++      if (ic->ic_bsschan && (ic->ic_bsschan != IEEE80211_CHAN_ANYC)) {
++              txp = min(txp, (u16) ic->ic_bsschan->ic_maxpower);
++      } else if (ic->ic_cur_txpower > 0) {
++              txp = min(txp, ic->ic_cur_txpower);
++      }
++      if (ic->ic_flags & IEEE80211_F_TXPOW_FIXED) {
++              txp = min(txp, ic->ic_txpowlimit);
++              rrq->fixed = 1;
++      } else {
++              rrq->fixed = 0;
++      }
++      rrq->value = txp / 2;
+       rrq->disabled = (rrq->fixed && rrq->value == 0);
+       rrq->flags = IW_TXPOW_DBM;
+       return 0;
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -380,7 +380,6 @@ static unsigned int ath_dump_hal_map(str
+ static u_int32_t ath_get_clamped_maxtxpower(struct ath_softc *sc);
+ static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, 
+               u_int32_t new_clamped_maxtxpower);
+-static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc);
+ static void ath_poll_disable(struct net_device *dev);
+ static void ath_poll_enable(struct net_device *dev);
+@@ -3159,7 +3158,7 @@ ath_tx_startraw(struct net_device *dev, 
+       try0 = ph->try0;
+       rt = sc->sc_currates;
+       txrate = dot11_to_ratecode(sc, rt, ph->rate0);
+-      power = ph->power > 60 ? 60 : ph->power;
++      power = ph->power > 63 ? 63 : ph->power;
+       hdrlen = ieee80211_anyhdrsize(wh);
+       pktlen = skb->len + IEEE80211_CRC_LEN;
+@@ -8381,7 +8380,7 @@ ath_tx_start(struct net_device *dev, str
+                           pktlen,                     /* packet length */
+                           hdrlen,                     /* header length */
+                           atype,                      /* Atheros packet type */
+-                          MIN(ni->ni_txpower, 60),    /* txpower */
++                          MIN(ni->ni_txpower, 63),    /* txpower */
+                           txrate, try0,               /* series 0 rate/tries */
+                           keyix,                      /* key cache index */
+                           antenna,                    /* antenna mode */
+@@ -10364,59 +10363,16 @@ ath_get_clamped_maxtxpower(struct ath_so
+ /* XXX: this function needs some locking to avoid being called 
+  * twice/interrupted */
+-/* 1. Save the currently specified maximum txpower (as clamped by madwifi)
+- * 2. Determine the real maximum txpower the card can support by
+- *    setting a value that exceeds the maximum range (by one) and
+- *    finding out what it limits us to.
+- * 3. Restore the saved maxtxpower value we had previously specified */
+-static u_int32_t
+-ath_get_real_maxtxpower(struct ath_softc *sc)
+-{
+-      u_int32_t saved_clamped_maxtxpower;
+-      u_int32_t real_maxtxpower;
+-
+-      saved_clamped_maxtxpower = ath_get_clamped_maxtxpower(sc);
+-      real_maxtxpower = 
+-              ath_set_clamped_maxtxpower(sc, IEEE80211_TXPOWER_MAX + 1);
+-      ath_set_clamped_maxtxpower(sc, saved_clamped_maxtxpower);
+-      return real_maxtxpower;
+-}
+-
+-
+-/* XXX: this function needs some locking to avoid being called 
+- * twice/interrupted */
+ static void
+ ath_update_txpow(struct ath_softc *sc)
+ {
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ieee80211vap *vap = NULL;
+       struct ath_hal *ah = sc->sc_ah;
+-      u_int32_t prev_clamped_maxtxpower = 0;
+-      u_int32_t new_clamped_maxtxpower = 0;
+       /* Determine the previous value of maxtxpower */
+-      prev_clamped_maxtxpower = ath_get_clamped_maxtxpower(sc);
+-      /* Determine the real maximum txpower the card can support */
+-      ic->ic_txpowlimit = ath_get_real_maxtxpower(sc);
+-      /* Grab the new maxtxpower setting (which may have changed) */
+-      new_clamped_maxtxpower = ic->ic_newtxpowlimit;
+-      /* Make sure the change is within limits, clamp it otherwise */
+-      if (ic->ic_newtxpowlimit > ic->ic_txpowlimit)
+-              new_clamped_maxtxpower = ic->ic_txpowlimit;
+-      /* Search for the VAP that needs a txpow change, if any */
+-      TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+-              if (!tpc || ic->ic_newtxpowlimit != vap->iv_bss->ni_txpower) {
+-                      vap->iv_bss->ni_txpower = new_clamped_maxtxpower;
+-                      ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, 
+-                                      set_node_txpower, 
+-                                      &new_clamped_maxtxpower);
+-              }
+-      }
+-
+-      /* Store the assigned (clamped) maximum txpower and update the HAL */
+-      sc->sc_curtxpow = new_clamped_maxtxpower;
+-      if (new_clamped_maxtxpower != prev_clamped_maxtxpower)
+-              ath_hal_settxpowlimit(ah, new_clamped_maxtxpower);
++      ath_set_clamped_maxtxpower(sc, ic->ic_txpowlimit);
++      ic->ic_cur_txpower = ath_get_clamped_maxtxpower(sc);
+ }
+ #ifdef ATH_SUPERG_XR
diff --git a/package/madwifi/patches/415-chan_switch.patch b/package/madwifi/patches/415-chan_switch.patch
new file mode 100644 (file)
index 0000000..8505064
--- /dev/null
@@ -0,0 +1,187 @@
+--- a/net80211/ieee80211_beacon.c
++++ b/net80211/ieee80211_beacon.c
+@@ -224,18 +224,18 @@ ieee80211_beacon_alloc(struct ieee80211_
+       pktlen = 8                                      /* time stamp */
+                + sizeof(u_int16_t)                    /* beacon interval */
+                + sizeof(u_int16_t)                    /* capability information */
+-               + 2 + ni->ni_esslen                    /* ssid */
++               + 2 + IEEE80211_NWID_LEN                       /* ssid */
+                + 2 + IEEE80211_RATE_SIZE              /* supported rates */
+                + 7                                    /* FH/DS parameters max(7,3) */
+-               + 2 + 4 + vap->iv_tim_len              /* IBSS/TIM parameter set*/
++               + sizeof(struct ieee80211_tim_ie) + 128 /* IBSS/TIM parameter set*/
+                + ic->ic_country_ie.country_len + 2    /* country code */
+                + 3                                    /* power constraint */
+                + 5                                    /* channel switch announcement */
+                + 3                                    /* ERP */
+                + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) /* Ext. Supp. Rates */
+-               + (vap->iv_caps & IEEE80211_C_WME ?    /* WME */
++               + (ic->ic_caps & IEEE80211_C_WME ?     /* WME */
+                       sizeof(struct ieee80211_wme_param) : 0)
+-               + (vap->iv_caps & IEEE80211_C_WPA ?    /* WPA 1+2 */
++               + (ic->ic_caps & IEEE80211_C_WPA ?     /* WPA 1+2 */
+                       2 * sizeof(struct ieee80211_ie_wpa) : 0)
+                + sizeof(struct ieee80211_ie_athAdvCap)
+ #ifdef ATH_SUPERG_XR
+@@ -290,17 +290,26 @@ ieee80211_beacon_update(struct ieee80211
+       IEEE80211_LOCK_IRQ(ic);
+       /* Check if we need to change channel right now */
+-      if ((ic->ic_flags & IEEE80211_F_DOTH) &&
+-          (vap->iv_flags & IEEE80211_F_CHANSWITCH)) {
+-              struct ieee80211_channel *c = 
++      if (ic->ic_flags & IEEE80211_F_CHANSWITCH) {
++              struct ieee80211_channel *c =
+                       ieee80211_doth_findchan(vap, ic->ic_chanchange_chan);
+-              
+-              if (!vap->iv_chanchange_count && !c) {
+-                      vap->iv_flags &= ~IEEE80211_F_CHANSWITCH;
+-                      ic->ic_flags &= ~IEEE80211_F_CHANSWITCH;
+-              } else if (vap->iv_chanchange_count &&
+-                         ((!ic->ic_chanchange_tbtt) ||
+-                          (vap->iv_chanchange_count == ic->ic_chanchange_tbtt))) {
++              struct ieee80211vap *avp;
++              int do_switch = 1;
++
++              TAILQ_FOREACH(avp, &ic->ic_vaps, iv_next) {
++                      if (!(avp->iv_flags & IEEE80211_F_CHANSWITCH))
++                              continue;
++
++                      do_switch = 0;
++                      break;
++              }
++              if (vap->iv_flags & IEEE80211_F_CHANSWITCH) {
++                      if (vap->iv_chanchange_count-- <= 1) {
++                              vap->iv_flags &= ~IEEE80211_F_CHANSWITCH;
++                              vap->iv_chanchange_count = 0;
++                      }
++              }
++              if (do_switch) {
+                       u_int8_t *frm;
+                       IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
+@@ -316,16 +325,7 @@ ieee80211_beacon_update(struct ieee80211
+                       } else
+                               ic->ic_bsschan = c;
+-                      skb_pull(skb, sizeof(struct ieee80211_frame));
+-                      skb_trim(skb, 0);
+-                      frm = skb->data;
+-                      skb_put(skb, ieee80211_beacon_init(ni, bo, frm) - frm);
+-                      skb_push(skb, sizeof(struct ieee80211_frame));
+-
+-                      vap->iv_chanchange_count = 0;
+-                      vap->iv_flags &= ~IEEE80211_F_CHANSWITCH;
+                       ic->ic_flags &= ~IEEE80211_F_CHANSWITCH;
+-
+                       /* NB: Only for the first VAP to get here, and when we
+                        * have a valid channel to which to change. */
+                       if (c && (ic->ic_curchan != c)) {
+@@ -488,22 +488,20 @@ ieee80211_beacon_update(struct ieee80211
+       if (IEEE80211_IS_MODE_BEACON(vap->iv_opmode)) {
+-              if ((ic->ic_flags & IEEE80211_F_DOTH) &&
+-                  (ic->ic_flags & IEEE80211_F_CHANSWITCH)) {
++              if (ic->ic_flags & IEEE80211_F_CHANSWITCH) {
+                       struct ieee80211_ie_csa *csa_ie =
+                               (struct ieee80211_ie_csa *)bo->bo_chanswitch;
+-                      IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, 
++                      if (csa_ie->csa_len == 0) {
++                              IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
+                                       "%s: Sending 802.11h chanswitch IE: "
+                                       "%d/%d\n", __func__, 
+                                       ic->ic_chanchange_chan, 
+                                       ic->ic_chanchange_tbtt);
+-                      if (!vap->iv_chanchange_count) {
+-                              vap->iv_flags |= IEEE80211_F_CHANSWITCH;
+                               /* copy out trailer to open up a slot */
+                               memmove(bo->bo_chanswitch + sizeof(*csa_ie),
+-                                      bo->bo_chanswitch, 
++                                      bo->bo_chanswitch,
+                                       bo->bo_chanswitch_trailerlen);
+                               /* add ie in opened slot */
+@@ -523,17 +521,15 @@ ieee80211_beacon_update(struct ieee80211
+                               bo->bo_ath_caps += sizeof(*csa_ie);
+                               bo->bo_xr += sizeof(*csa_ie);
+-                              /* indicate new beacon length so other layers 
++                              /* indicate new beacon length so other layers
+                                * may manage memory */
+                               skb_put(skb, sizeof(*csa_ie));
+                               len_changed = 1;
+-                      } else if(csa_ie->csa_count)
+-                              csa_ie->csa_count--;
+-                      
+-                      vap->iv_chanchange_count++;
+-                      IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
+-                              "%s: CHANSWITCH IE, change in %d TBTT\n",
+-                              __func__, csa_ie->csa_count);
++
++                              IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
++                                      "%s: CHANSWITCH IE, change in %d TBTT\n",
++                                      __func__, csa_ie->csa_count);
++                      }
+               }
+ #ifdef ATH_SUPERG_XR
+               if (vap->iv_flags & IEEE80211_F_XRUPDATE) {
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -699,39 +699,11 @@ ieee80211_ioctl_siwfreq(struct net_devic
+                       if (c == NULL)                  /* no channel */
+                               return -EINVAL;
+               }
+-              /*
+-               * Fine tune channel selection based on desired mode:
+-               *   if 11b is requested, find the 11b version of any
+-               *      11g channel returned,
+-               *   if static turbo, find the turbo version of any
+-               *      11a channel return,
+-               *   otherwise we should be ok with what we've got.
+-               */
+-              switch (vap->iv_des_mode) {
+-              case IEEE80211_MODE_11B:
+-                      if (IEEE80211_IS_CHAN_ANYG(c)) {
+-                              c2 = findchannel(ic, i, IEEE80211_MODE_11B);
+-                              /* NB: should not happen, =>'s 11g w/o 11b */
+-                              if (c2 != NULL)
+-                                      c = c2;
+-                      }
+-                      break;
+-              case IEEE80211_MODE_TURBO_A:
+-                      if (IEEE80211_IS_CHAN_A(c)) {
+-                              c2 = findchannel(ic, i, IEEE80211_MODE_TURBO_A);
+-                              if (c2 != NULL)
+-                                      c = c2;
+-                      }
+-                      break;
+-              default:                /* NB: no static turboG */
+-                      break;
+-              }
++
+               if (ieee80211_check_mode_consistency(ic, vap->iv_des_mode, c)) {
+                       if (vap->iv_opmode == IEEE80211_M_HOSTAP)
+                               return -EINVAL;
+               }
+-              if ((vap->iv_state == IEEE80211_S_RUN) && (c == vap->iv_des_chan))
+-                      return 0;                       /* no change, return */
+               /* Don't allow to change to channel with radar found */
+               if (c->ic_flags & IEEE80211_CHAN_RADAR)
+@@ -4625,7 +4597,13 @@ static void
+ pre_announced_chanswitch(struct net_device *dev, u_int32_t channel, u_int32_t tbtt) {
+       struct ieee80211vap *vap = dev->priv;
+       struct ieee80211com *ic = vap->iv_ic;
++      struct ieee80211vap *avp;
++
+       /* now flag the beacon update to include the channel switch IE */
++      TAILQ_FOREACH(avp, &ic->ic_vaps, iv_next) {
++              avp->iv_flags |= IEEE80211_F_CHANSWITCH;
++              avp->iv_chanchange_count = tbtt;
++      }
+       ic->ic_flags |= IEEE80211_F_CHANSWITCH;
+       ic->ic_chanchange_chan = channel;
+       ic->ic_chanchange_tbtt = tbtt;
diff --git a/package/madwifi/patches/417-beacon_txpower.patch b/package/madwifi/patches/417-beacon_txpower.patch
new file mode 100644 (file)
index 0000000..4746116
--- /dev/null
@@ -0,0 +1,81 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -395,7 +395,7 @@ static int bstuck_thresh = BSTUCK_THRESH
+ static char *autocreate = NULL;
+ static char *ratectl = DEF_RATE_CTL;
+ static int rfkill = 0;
+-static int tpc = 0;
++static int tpc = 1;
+ static int countrycode = -1;
+ static int maxvaps = -1;
+ static int outdoor = -1;
+@@ -4923,6 +4923,7 @@ ath_beacon_setup(struct ath_softc *sc, s
+       (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\
+               == IEEE80211_F_SHPREAMBLE)
+       struct ieee80211com *ic = bf->bf_node->ni_ic;
++      struct ieee80211vap *vap = bf->bf_node->ni_vap;
+       struct sk_buff *skb = bf->bf_skb;
+       struct ath_hal *ah = sc->sc_ah;
+       struct ath_desc *ds;
+@@ -4990,7 +4991,7 @@ ath_beacon_setup(struct ath_softc *sc, s
+               skb->len + IEEE80211_CRC_LEN,   /* frame length */
+               sizeof(struct ieee80211_frame), /* header length */
+               HAL_PKT_TYPE_BEACON,            /* Atheros packet type */
+-              bf->bf_node->ni_txpower,        /* txpower XXX */
++              (vap->iv_beacon_txpow ? vap->iv_beacon_txpow : 63),
+               rate, 1,                        /* series 0 rate/tries */
+               HAL_TXKEYIX_INVALID,            /* no encryption */
+               antenna,                        /* antenna mode */
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -652,6 +652,7 @@ enum {
+       IEEE80211_PARAM_WDS_SEP                 = 82,   /* move wds stations into separate interfaces */
+       IEEE80211_PARAM_MAXASSOC                = 83,   /* maximum associated stations */
+       IEEE80211_PARAM_PROBEREQ                = 84,   /* enable handling of probe requests */
++      IEEE80211_PARAM_BEACON_TXP              = 85,   /* set beacon tx power */
+ };
+ #define       SIOCG80211STATS                 (SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -254,6 +254,7 @@ struct ieee80211vap {
+       u_int8_t iv_dtim_period;                        /* DTIM period */
+       u_int8_t iv_dtim_count;                         /* DTIM count from last bcn */
+                                                       /* set/unset aid pwrsav state */
++      u_int8_t iv_beacon_txpow;                       /* beacon tx power */
+       void (*iv_set_tim)(struct ieee80211_node *, int);
+       u_int8_t iv_uapsdinfo;                          /* sta mode QoS Info flags */
+       struct ieee80211_node *iv_bss;                  /* information for this node */
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2862,6 +2862,9 @@ ieee80211_ioctl_setparam(struct net_devi
+       case IEEE80211_PARAM_PROBEREQ:
+               vap->iv_no_probereq = !value;
+               break;
++      case IEEE80211_PARAM_BEACON_TXP:
++              vap->iv_beacon_txpow = value;
++              break;
+ #ifdef ATH_REVERSE_ENGINEERING
+       case IEEE80211_PARAM_DUMPREGS:
+               ieee80211_dump_registers(dev, info, w, extra);
+@@ -3227,6 +3230,9 @@ ieee80211_ioctl_getparam(struct net_devi
+       case IEEE80211_PARAM_PROBEREQ:
+               param[0] = !vap->iv_no_probereq;
+               break;
++      case IEEE80211_PARAM_BEACON_TXP:
++              param[0] = vap->iv_beacon_txpow;
++              break;
+       default:
+               return -EOPNOTSUPP;
+       }
+@@ -5801,6 +5807,10 @@ static const struct iw_priv_args ieee802
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "probereq"},
+       { IEEE80211_PARAM_PROBEREQ,
+        0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_probereq"},
++      { IEEE80211_PARAM_BEACON_TXP,
++       IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_pwr"},
++      { IEEE80211_PARAM_BEACON_TXP,
++       0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_beacon_pwr"},
+ #ifdef ATH_REVERSE_ENGINEERING
+       /*
diff --git a/package/madwifi/patches/418-turbo.patch b/package/madwifi/patches/418-turbo.patch
new file mode 100644 (file)
index 0000000..4e13f90
--- /dev/null
@@ -0,0 +1,15 @@
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -1129,7 +1129,11 @@ ieee80211_scan_add_channels(struct ieee8
+                       continue;
+               if (c->ic_scanflags & IEEE80211_NOSCAN_SET)
+                       continue;
+-              if (modeflags &&
++              if (ss->ss_vap->iv_opmode == IEEE80211_M_HOSTAP) {
++                      if ((c->ic_flags & (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)) !=
++                          (modeflags & (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)))
++                              continue;
++              } else if (modeflags &&
+                       ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
+                        (modeflags & IEEE80211_CHAN_ALLTURBO)))
+                       continue;
diff --git a/package/madwifi/patches/419-skb_unmap_crash.patch b/package/madwifi/patches/419-skb_unmap_crash.patch
new file mode 100644 (file)
index 0000000..28e7274
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -13477,7 +13477,7 @@ cleanup_ath_buf(struct ath_softc *sc, st
+       if (bf == NULL) 
+               return bf;
+-      if (bf->bf_skbaddr) {
++      if (bf->bf_skb && bf->bf_skbaddr) {
+               bus_unmap_single(
+                       sc->sc_bdev,
+                       bf->bf_skbaddr, 
+@@ -13485,8 +13485,6 @@ cleanup_ath_buf(struct ath_softc *sc, st
+                               sc->sc_rxbufsize : bf->bf_skb->len),
+                       direction);
+               bf->bf_skbaddr = 0;
+-              bf->bf_desc->ds_link = 0;
+-              bf->bf_desc->ds_data = 0;
+       }
+ #ifdef ATH_SUPERG_FF
diff --git a/package/madwifi/patches/420-diversity_fix.patch b/package/madwifi/patches/420-diversity_fix.patch
new file mode 100644 (file)
index 0000000..b7d26d9
--- /dev/null
@@ -0,0 +1,30 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -5344,27 +5344,6 @@ ath_beacon_send(struct ath_softc *sc, in
+       } else if ((sc->sc_updateslot == COMMIT) && (sc->sc_slotupdate == slot))
+               ath_setslottime(sc);            /* commit change to hardware */
+-      if ((!sc->sc_stagbeacons || slot == 0) && (!sc->sc_diversity)) {
+-              unsigned int otherant;
+-              /*
+-               * Check recent per-antenna transmit statistics and flip
+-               * the default rx antenna if noticeably more frames went out
+-               * on the non-default antenna.  Only do this if rx diversity
+-               * is off.
+-               * XXX assumes 2 antennae
+-               */
+-              otherant = sc->sc_defant & 1 ? 2 : 1;
+-              if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 
+-                              ATH_ANTENNA_DIFF) {
+-                      DPRINTF(sc, ATH_DEBUG_BEACON,
+-                              "Flip default antenna to %u, %u > %u\n",
+-                              otherant, sc->sc_ant_tx[otherant],
+-                              sc->sc_ant_tx[sc->sc_defant]);
+-                      ath_setdefantenna(sc, otherant);
+-              }
+-              sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
+-      }
+-
+       if (bfaddr != 0) {
+               /*
+                * Stop any current DMA and put the new frame(s) on the queue.
diff --git a/package/madwifi/patches/450-new_hal.patch b/package/madwifi/patches/450-new_hal.patch
deleted file mode 100644 (file)
index 324f7dd..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
---- a/ath_hal/ah_os.h
-+++ b/ath_hal/ah_os.h
-@@ -156,80 +156,23 @@ extern u_int32_t __ahdecl ath_hal_getupt
- #endif
- #endif                                /* AH_BYTE_ORDER */
--/*
-- * Some big-endian architectures don't set CONFIG_GENERIC_IOMAP, but fail to
-- * implement iowrite32be and ioread32be.  Provide compatibility macros when
-- * it's needed.
-- *
-- * As of Linux 2.6.24, only MIPS, PARISC and PowerPC implement iowrite32be and
-- * ioread32be as functions.
-- *
-- * The downside or the replacement macros it that we may be byte-swapping data
-- * for the second time, so the native implementations should be preferred.
-- */
--#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) && \
--      !defined(CONFIG_GENERIC_IOMAP) && (AH_BYTE_ORDER == AH_BIG_ENDIAN) && \
--      !defined(__mips__) && !defined(__hppa__) && !defined(__powerpc__)
--# ifndef iowrite32be
--#  define iowrite32be(_val, _addr) iowrite32(swab32((_val)), (_addr))
--# endif
--# ifndef ioread32be
--#  define ioread32be(_addr) swab32(ioread32((_addr)))
--# endif
--#endif
-+#define IS_SWAPPED(_ah, _reg) \
-+      ((_ah)->ah_swapped && \
-+              (((0x4000 <= (_reg)) && ((_reg) < 0x5000)) || \
-+               ((0x7000 <= (_reg)) && ((_reg) < 0x8000))))
-+
-+#define SWAPREG(_ah, _reg, _val) \
-+      (IS_SWAPPED(_ah, _reg) ? cpu_to_le32(_val) : (_val))
- /*
-  * The register accesses are done using target-specific functions when
-  * debugging is enabled (AH_DEBUG) or it's explicitly requested for the target.
-- *
-- * The hardware registers use little-endian byte order natively.  Big-endian
-- * systems are configured by HAL to enable hardware byte-swap of register reads
-- * and writes at reset.  This avoid the need to byte-swap the data in software.
-- * However, the registers in a certain area from 0x4000 to 0x4fff (PCI clock
-- * domain registers) are not byte swapped!
-- *
-- * Since Linux I/O primitives default to little-endian operations, we only
-- * need to suppress byte-swapping on big-endian systems outside the area used
-- * by the PCI clock domain registers.
-  */
--#if (AH_BYTE_ORDER == AH_BIG_ENDIAN)
--#define is_reg_le(__reg) ((0x4000 <= (__reg) && (__reg) < 0x5000))
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
--#define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
--       is_reg_le(_reg) ?                                      \
--       iowrite32((_val), (_ah)->ah_sh + (_reg)) :             \
--       iowrite32be((_val), (_ah)->ah_sh + (_reg));            \
--      } while (0)
--#define _OS_REG_READ(_ah, _reg)                                       \
--      (is_reg_le(_reg) ?                                      \
--       ioread32((_ah)->ah_sh + (_reg)) :                      \
--       ioread32be((_ah)->ah_sh + (_reg)))
--#else
--#define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
--       writel(is_reg_le(_reg) ?                               \
--              (_val) : cpu_to_le32(_val),                     \
--              (_ah)->ah_sh + (_reg));                         \
--      } while (0)
--#define _OS_REG_READ(_ah, _reg)                                       \
--      (is_reg_le(_reg) ?                                      \
--       readl((_ah)->ah_sh + (_reg)) :                         \
--       cpu_to_le32(readl((_ah)->ah_sh + (_reg))))
--#endif                                /* KERNEL_VERSION(2,6,12) */
--#else                         /* AH_BYTE_ORDER != AH_BIG_ENDIAN */
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
--#define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
--       iowrite32((_val), (_ah)->ah_sh + (_reg));              \
--      } while (0)
--#define _OS_REG_READ(_ah, _reg)                                       \
--      ioread32((_ah)->ah_sh + (_reg))
--#else
- #define _OS_REG_WRITE(_ah, _reg, _val) do {                   \
--       writel((_val), (_ah)->ah_sh + (_reg));                 \
--      } while (0)
-+       __raw_writel(SWAPREG(_ah, _reg, _val), (_ah)->ah_sh + (_reg));         \
-+} while (0)
- #define _OS_REG_READ(_ah, _reg)                                       \
--      readl((_ah)->ah_sh + (_reg))
--#endif                                /* KERNEL_VERSION(2,6,12) */
--#endif                                /* AH_BYTE_ORDER != AH_BIG_ENDIAN */
-+       SWAPREG(_ah, _reg, __raw_readl((_ah)->ah_sh + (_reg)))
- /*
-  * The functions in this section are not intended to be invoked by MadWifi
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -606,6 +606,14 @@ ath_attach(u_int16_t devid, struct net_d
-       }
-       sc->sc_ah = ah;
-+      /* WAR for AR7100 PCI bug */
-+#ifdef CONFIG_ATHEROS_AR71XX
-+      if ((ar_device(sc->devid) >= 5210) && (ar_device(sc->devid) < 5416)) {
-+              ath_hal_setcapability(ah, HAL_CAP_DMABURST_RX, 0, HAL_DMABURST_4B, NULL);
-+              ath_hal_setcapability(ah, HAL_CAP_DMABURST_TX, 0, HAL_DMABURST_4B, NULL);
-+      }
-+#endif
-+
-       /*
-        * Check if the MAC has multi-rate retry support.
-        * We do this by trying to setup a fake extended
-@@ -7524,7 +7532,7 @@ ath_txq_setup(struct ath_softc *sc, int 
-       if (qtype == HAL_TX_QUEUE_UAPSD)
-               qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE;
-       else
--              qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | 
-+              qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXOKINT_ENABLE |
-                       HAL_TXQ_TXDESCINT_ENABLE;
-       qnum = ath_hal_setuptxqueue(ah, qtype, &qi);
-       if (qnum == -1) {
---- a/ath_hal/ah_os.c
-+++ b/ath_hal/ah_os.c
-@@ -126,6 +126,13 @@ ath_hal_printf(struct ath_hal *ah, const
- }
- EXPORT_SYMBOL(ath_hal_printf);
-+void __ahdecl
-+ath_hal_printstr(struct ath_hal *ah, const char *str)
-+{
-+      printk("%s", str);
-+}
-+EXPORT_SYMBOL(ath_hal_printstr);
-+
- /*
-  * Format an Ethernet MAC for printing.
-  */